使用Lazy <t>在IIS环境中创建Singleton </t>

时间:2013-06-18 08:48:10

标签: c# wcf iis singleton

我们正尝试在具有WCF服务的IIS环境中使用Singleton。

我们在此链接http://csharpindepth.com/articles/general/singleton.aspx

中遵循第六版中的建议
    private static readonly Lazy<VedtaksbehandlingRuleService> lazy = new Lazy<VedtaksbehandlingRuleService>(() => new VedtaksbehandlingRuleService());

    public static VedtaksbehandlingRuleService Instance { get { return lazy.Value; } }

    private VedtaksbehandlingRuleService()
    {
        m_Container = StaticServiceContainer.Instance;
        logger = m_Container.Resolve<ILoggerUtility>();
        InitRuleService();
    }

使用:

调用
VedtaksbehandlingBusObjResponse resp = VedtaksbehandlingRuleService.Instance.BehandleVedtak(req);

当我们在单元测试中尝试此代码时,它可以正常工作。

当我们将它部署到IIS时,它适用于第一个调用者,它可以多次调用WCF服务而不会出错。

但是如果另一个客户端调用该服务,则会使用以下文本获得异常:

<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
    <s:Body>
        <s:Fault>
            <s:Code>
                <s:Value>s:Receiver</s:Value>
                <s:Subcode>
                    <s:Value xmlns:a="http://schemas.microsoft.com/net/2005/12/windowscommunicationfoundation/dispatcher">a:InternalServiceFault</s:Value>
                </s:Subcode>
            </s:Code>
            <s:Reason>
                <s:Text xml:lang="nb-NO">Tjenestekallet vedtaRefusjonskravOgBeregnPensjon feilet</s:Text>
            </s:Reason>
            <s:Detail>
                <ExceptionDetail xmlns="http://schemas.datacontract.org/2004/07/System.ServiceModel" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
                    <HelpLink i:nil="true" />
                    <InnerException>
                        <HelpLink i:nil="true" />
                        <InnerException i:nil="true" />
                        <Message>Failure to create a Deployment Manager Server Manager  for 'VedtaksbehandlingRuleServiceDManager'</Message>
                        <StackTrace>
                            Server stack trace:     at com.blazesoft.server.deploy.manager.NdDeploymentManager.createDeploymentManagerServerManagers(NdDeploymentManagerConfig config) at
                            com.blazesoft.server.deploy.manager.NdDeploymentManager.configure() at
                            com.blazesoft.server.deploy.manager.NdDeploymentManager.createDeploymentManager  (NdDeploymentManagerConfig deploymentManagerConfig) at
                            XXX.Liv.Pensjon.Forretningstjenester.Regelserver.DManager..ctor(String dManagerConfig) at
                            XXX.Liv.Pensjon.Forretningstjenester.Regelserver.RuleServerFactory.CreateRulesServer[T](String serverConfig, String dmanagerConfig, ILoggerUtility logger) at
                            XXX.Liv.Pensjon.Forretningstjenester.Vedtaksbehandlingstjeneste.VedtaksbehandlingRuleService.CreateRuleServer() at
                            XXX.Liv.Pensjon.Forretningstjenester.Vedtaksbehandlingstjeneste.VedtaksbehandlingRuleService.&lt;.cctor&gt;b__0() at 
                            System.Lazy`1.CreateValue()


                            Exception rethrown at [0]: at
                            com.blazesoft.server.deploy.manager.NdDeploymentManager.createDeploymentManagerServerManagers(NdDeploymentManagerConfig config) at
                            com.blazesoft.server.deploy.manager.NdDeploymentManager.configure() at
                            com.blazesoft.server.deploy.manager.NdDeploymentManager.createDeploymentManager(NdDeploymentManagerConfig deploymentManagerConfig) at
                            XXX.Liv.Pensjon.Forretningstjenester.Regelserver.DManager..ctor(String dManagerConfig) at
                            XXX.Liv.Pensjon.Forretningstjenester.Regelserver.RuleServerFactory.CreateRulesServer[T](String serverConfig, String dmanagerConfig, ILoggerUtility logger) at
                            XXX.Liv.Pensjon.Forretningstjenester.Vedtaksbehandlingstjeneste.VedtaksbehandlingRuleService.CreateRuleServer() at
                            XXX.Liv.Pensjon.Forretningstjenester.Vedtaksbehandlingstjeneste.VedtaksbehandlingRuleService.&lt;.cctor&gt;b__0() at
                            System.Lazy`1.CreateValue() at
                            System.Lazy`1.LazyInitValue() at  
                            XXX.Liv.Pensjon.Forretningstjenester.Vedtaksbehandlingstjeneste.Vedtaksbehandlingstjeneste.vedtaRefusjonskravOgBeregnPensjon(vedtaRefusjonskravOgBeregnPensjonRequest1 request)
                        </StackTrace>
                        <Type>com.blazesoft.server.deploy.manager.NdDeploymentManagerException</Type>
                    </InnerException>
                    <Message>Tjenestekallet vedtaRefusjonskravOgBeregnPensjon feilet</Message>
                    <StackTrace>
                        at    
                        XXX.Liv.Pensjon.Forretningstjenester.Vedtaksbehandlingstjeneste.Vedtaksbehandlingstjeneste.vedtaRefusjonskravOgBeregnPensjon(vedtaRefusjonskravOgBeregnPensjonRequest1 request) at 
                        SyncInvokevedtaRefusjonskravOgBeregnPensjon(Object , Object[] , Object[] ) at
                        System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(Object instance, Object[] inputs, Object[]&amp; outputs) at
                        System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc&amp; rpc) at
                        System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc&amp; rpc) at
                        System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage31(MessageRpc&amp; rpc) at 
                        System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)
                    </StackTrace>
                    <Type>System.Exception</Type>
                </ExceptionDetail>
            </s:Detail>
        </s:Fault>
    </s:Body>
</s:Envelope>

我们没有设置实例化模式,所以应该是每次调用。该服务是每次调用,但在堆栈中我们有一个用于访问规则引擎的类,它必须是一个单例

任何人都知道是什么导致了这个问题,或者有更好的解决方案?

2 个答案:

答案 0 :(得分:1)

我认为Lazy<T>没有错 - 它会按预期为AppDomain创建一个单例实例。

也许您的问题是IIS托管:

  1. 您的应用程序池可能配置为生成多个工作进程=&gt;多个appdomains =&gt;现在你有多个单身实例。
  2. 也许某些事情会导致您的应用池回收=&gt;它将创建新的AppDomain =&gt;现在你又有了多个单身实例。
  3. IIS通常会为每个为该应用程序池配置的应用程序创建一个AppDomain。但是,在某些特殊情况下,它可能会创建多个应用程序域。
  4. 您的IoC容器可能正在创建应用程序域(但是,默认安全IIS可能不允许这样做)
  5. 因此,重要的是您可能需要验证是否创建了多个应用程序域。您可以使用Process Explorer检查w3wp.exe。转到属性&gt; .NET程序集 - 您将看到在工作进程中创建的所有appdomains。

    如果你真的想要单身行为,你可能想重新考虑你的WCF托管机制。

    PS:默认实例化模式是每个会话 - 不是每次通话。

答案 1 :(得分:0)

你的方法有很多问题,但只是为了解决你的问题 - 如果你需要的是一个每个调用对象(静态是为整个AppDomain共享)然后使它成为ThreadStatic,提供一个Clear()方法它并在EndRequest事件上调用它。这样,没有2个单独的调用将共享该对象,并且您将获得“懒惰”行为。