1

我们正在尝试在带有 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>

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

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

4

2 回答 2

1

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

也许您的问题是 IIS 托管:

  1. 您的应用程序池可能配置为生成多个工作进程 => 多个 appdomains => 现在您有多个单例实例。
  2. 也许某些事情导致您的应用程序池回收=>它将创建新的AppDomain =>现在您再次拥有多个单例实例。
  3. IIS 通常为每个为该应用程序池配置的应用程序创建一个 AppDomain。但是,在某些特殊情况下,它可能会创建多个应用程序域。
  4. 您的 IoC 容器可能正在创建应用程序域(但是,默认安全 IIS 可能不允许这样做)

所以本质是您可能必须验证是否创建了多个应用程序域。您可以使用Process Explorer检查 w3wp.exe。转到属性 > .NET 程序集 - 您将看到在工作进程中创建的所有 appdomains。

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

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

于 2013-06-18T22:11:37.583 回答
0

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

于 2013-06-18T16:03:50.340 回答