WCF服务的PerCall InstanceContextMode行为

4
我有一个WCF服务,使用basicHttpBinding暴露了一个ServiceContract,所以根据我的理解,InstanceContextMode将被设置为PerCall(因为basicHttpBinding不支持会话),而ConcurrenyMode将被设置为Single。
这个WCF的客户端是一个Windows服务,它同时调用服务中的4个不同操作,在服务中我们使用了一个单例类和一些静态变量。我们一直面临一个问题,就是一些错误的值被传递给了一些DB存储过程。
通过PerCall InstanceContextMode和Single并发模式,我明白每次调用都会创建一个新的服务实例,因此我认为即使在服务实现中有一些单例类(我们没有使其线程安全)和静态变量,所有对象都将被销毁,但我们观察到在运行SQL分析器时,旧值仍然会被传递给DB。
我们以一种三层架构的方式编写了WCF服务代码,我指的是ServiceClass、BusinessLogicLayer和DataAccessLayer,当我们将instanceContextMode设置为PerCall时,当客户端请求完成后,服务实例是否意味着我们销毁了ServiceClass、BusinessLogicLayer和DataAccessLayer中的所有对象?
请帮我理解可能出了什么问题。

1
你使用单例模式的原因是什么?这似乎在你的架构中非常不合适。如果不使用单例并进行一些适当的调试,应该就没问题了。 - nvoigt
3个回答

0

尽管静态变量在任何情况下都需要进行线程安全保护,作为最佳实践。 静态变量不会在服务停止/应用程序池重置之前被销毁。

对于发生故障转移的分布式 Web farm,不建议使用静态变量来存储数据,因为这些数据不太安全。

Visual Studio 2012 及以上版本带有内存分析器。但是,在对象构造函数中使用计数器(仅用于测试)可以轻松地判断每个请求是否创建了新实例。

   [ServiceBehavior(InstanceContextMode=InstanceContextMode.PerCall,ConcurrencyMode=ConcurrencyMode.Single)]
public class TestServiceWithStaticVars : ITestServiceWithStaticVars
{
   static int instanceCount = 0;
    public TestServiceWithStaticVars()
    {
        Interlocked.Decrement(ref instanceCount);
    }
    public string GetInstanceCount()
    {
        return string.Format("You have created {0} instance", instanceCount);
    }

如果有更好的实例计数器可供使用,我会让你知道。

[编辑]由于我现在无法评论。

重新分配静态变量将采用您所说的新值。静态变量加载到HighFrequencyHeap中以进行频繁访问。有关更多信息,请参见http://www.codeproject.com/Articles/15269/Static-Keyword-Demystified


谢谢,在我的情况下,我有一个导致所有问题的静态变量,我现在理解它将存储在相应服务的AppDomain中,如果我的代码重新初始化该静态变量,那么变量会采用新值吗?您可以帮助我理解它是如何工作的吗? - CSharped

0

InstanceContextMode的PerCall表示每次调用都会实例化您的服务的新类。 AppDomain中的静态变量不会被重置。只要您的AppPool没有被回收,它们将在服务调用之间保持不变。

从代码中删除所有静态变量,包括单例。它们本来就不属于您的架构。


谢谢@nvoigt,这帮助我更好地理解了。有没有什么工具,比如内存分析工具,可以在服务调用期间和之后了解/可视化哪些对象在内存中,哪些对象不在呢? - CSharped
@CSharped 你可以尝试一些在这里提到的性能分析工具:https://dev59.com/FnVD5IYBdhLWcg3wXaYd。 - nvoigt

0

许多WCF请求共享同一个AppDomain。静态变量是每个AppDomain的。WCF对这些变量不做任何处理(事实上,它甚至无法找到它们的存在)。您需要负责维护它们。

WCF不会销毁任何对象,因为它既不理解它们的含义,也不知道它们的存在

您提到的设置仅与服务对象相关。

关于有状态服务器应用程序,我的通常建议是:您在这里使用了不良实践。您需要确保线程安全。如果工作进程关闭(部署、自动重启、服务器重启、应用程序错误导致进程崩溃、电源故障、硬件故障等),则数据将丢失。


谢谢@usr,这帮助我更好地理解了。有没有什么工具,比如内存分析工具,可以在服务调用期间和之后了解/可视化哪些对象在内存中,哪些对象不在内存中? - CSharped
我相信Jetbrains内存分析器有一个快照差异工具。但它不会显示仍然存在但已失效(已释放,配置错误等)的对象。我认为手动检查是解决这个问题的方法。审计所有静态变量。 - usr

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接