1

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

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

提前致谢!

4

4 回答 4

2

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

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

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

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

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

private Dictionary<Guid,string> _session;

Service service = new Service(_session);
_serviceHost = new ServiceHost(service, GetUriMethodInHostApp());

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

于 2012-10-01T18:18:33.640 回答
2

它基于每个实例。即默认无会话。

看看这个

当服务合同将 System.ServiceModel.ServiceContractAttribute.SessionMode 属性设置为 System.ServiceModel.SessionMode.Required 时,该合同表示所有调用(即支持调用的底层消息交换)必须是同一对话的一部分.

于 2012-10-01T18:10:50.053 回答
1

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

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

于 2012-10-01T18:31:02.657 回答
1

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

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]

这会将 WCF 服务作为各种单例运行。查看有关WCF 实例上下文模式的更多信息

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

            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();

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

于 2012-10-01T18:15:55.730 回答