【问题标题】:Does a self hosted wcf service have state?自托管的 wcf 服务是否有状态?
【发布时间】:2012-10-01 18:08:45
【问题描述】:

我有一个在 silverlight 应用程序中使用的自托管 WCF 服务。我正在尝试将用户 guid 列表存储在 IDictionary 对象中。每次用户点击服务时,它都会更新用户的日期时间,以便我可以跟踪哪些用户有活动的“会话”。问题是,每次我点击服务时,列表都是空的。它似乎正在删除每个肥皂请求的值?

您能否将信息存储在可跨多个服务请求使用的自托管服务中?

提前致谢!

【问题讨论】:

  • 用户列表等持久信息属于持久存储(例如数据库)
  • 如何自托管(控制台应用程序、Windows 服务等)?

标签: c# wcf service


【解决方案1】:

这是基于每个实例的。即默认无会话。

看看this

当服务合同设置 System.ServiceModel.ServiceContractAttribute.SessionMode 属性为 System.ServiceModel.SessionMode.Required,该合同是这样说的 所有调用(即支持 通话)必须是同一对话的一部分。

【讨论】:

    【解决方案2】:

    如果您需要在请求之间存储内容,则需要创建一个具有适当锁定的静态字典来存储这些请求,或者将此信息存储在数据库(或其他外部存储)中并检查看看它是否存在于每个方法调用中。这样做的原因是服务类在每个客户端请求上都会被实例化。

    由于您已经在用户点击服务时更新了用户的日期时间,因此最好通过与日期时间字段进行比较来查看这是否是活跃用户。这样做的好处是每次调用都准确(如果重新启动服务,字典可能与数据库不同步)。数据库已经有了处理并发的机制,因此您可以将复杂性推到数据存储中,而不是围绕单个对象滚动您自己的锁定解决方案。

    如果第二个解决方案不够快(并且您已经分析了应用程序并确定它是瓶颈),那么另一个选择是在数据库前面使用某种缓存解决方案,以便可以首先签入数据去数据库之前的内存。这个缓存对象需要像字典一样是静态的,并且与任何其他多线程应用程序一样具有相同的锁定缺陷。

    编辑:如果此托管 WCF 服务被用作 silverlight 应用程序用户的会话存储,并且数据没有存储在外部数据存储中,那么您最好确保跟踪它们是否处于活动状态不是任务危急。无法保证此数据与描述的一样正确。

    根据接受的答案,如果您的服务出现故障并需要重新启动(因为这是自托管的,建议您监控故障事件),您必须处置服务主机并实例化一个新主机。保留 Guid 数据的唯一方法是在重新启动之间将其重新绑定到服务(假设主机应用程序本身没有重新启动,这是一个不同的问题)。

    private Dictionary<Guid,string> _session;
    
    Service service = new Service(_session);
    _serviceHost = new ServiceHost(service, GetUriMethodInHostApp());
    

    最好将其存储在外部并按照@marc_s 的建议进行查找。然后这种复杂性就消失了。

    【讨论】:

    • 我试图将我的字典设为静态,但它仍然会丢失每个请求的数据。即使我在服务上指定了 [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]。
    【解决方案3】:

    您需要更改InstanceContextMode。您可以通过将以下编译器指令添加到您的 WCF 类来做到这一点:

    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
    

    这会将 WCF 服务作为单例运行。查看更多关于WCF Instance Context Mode

    然后你应该用你的单例对象来构建你的服务主机。这是一个工作示例中的代码,我正在做类似的事情:

                private ServiceHost serviceHost;
    
                if (serviceHost != null)
                    serviceHost.Close();
    
                if (log.IsInfoEnabled)
                    log.Info("Starting WCF service host for endpoint: " + ConfiguredWCFEndpoint);
    
                // Create our service instance, and add create a new service host from it
                ServiceLayer.TagWCFService service = new ServiceLayer.TagWCFService(ApplicationName,
                    ApplicationDescription,
                    SiteId,
                    ConfiguredUpdateRateMilliseconds);
    
                serviceHost = new ServiceHost(service, new Uri(ConfiguredWCFEndpoint));
    
                // Open the ServiceHostBase to create listeners and start listening for messages.
                serviceHost.Open();
    

    正如其他人礼貌地指出的那样,如果您不熟悉它的工作原理或者它不适合您的特定应用程序,这可能会产生“后果”。

    【讨论】:

    • 这会产生许多令人毛骨悚然的后果——要么你刚刚成功序列化你的所有请求(例如,你的表现会糟透了 很重要),否则您必须确保 WCF 服务类中的代码完全可重入和线程安全 - 不是简单要完成的任务,即使是高级程序员也不行!避免单身 - 如果可能的话!
    • 我尝试添加该属性,但它仍然没有在请求之间维护字典中的数据。还有什么要补充的吗?
    • 当您创建 ServiceHost 对象时,您将它传递到您的单例对象(您创建的 WCF 类对象)中。我编辑了答案以显示这一点。
    【解决方案4】:

    如果您不涉及锁定和线程安全的特定代码,您可以使用 NoSQL 数据库来存储会话数据,例如 MongoDBRavenDB

    和@marc_s 一样,我认为使用Singleton 模式是有风险的,你必须非常小心地制作自己的线程安全会话机制。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-09
      • 2011-11-07
      • 1970-01-01
      • 1970-01-01
      • 2013-06-09
      相关资源
      最近更新 更多