【问题标题】:Wcf Duplex Service Resetting Static Data on Internal CallsWcf 双工服务重置内部调用的静态数据
【发布时间】:2012-07-20 17:38:13
【问题描述】:

所以我只有几天时间才能了解 wcf 服务,特别是双工服务,并且我开始使用测试应用程序。目标是拥有一个服务,该服务具有一个存储变量的内部(静态?)类,以及一个获取这些变量的客户端。

目前我在 Storage 类中有两个变量,一个是订阅者列表 (ObservableCollection<IMyContractCallBack>),另一个是 ObservableCollection<string>,其中每个字符串在回调方法中发送到客户端。

我希望能够让客户端Fetch(如果尚未订阅,则首先订阅,通过将其上下文添加到服务器端的集合)服务器端集合中的字符串。该部分按预期工作。但是,我还想将Push 一个字符串从服务器发送到订阅列表中的每个客户端,以及将Add 字符串发送到字符串集合。这就是我的问题出现的地方。

任何时候我Fetch,它都会添加到字符串列表“test1...”和“test2...”并发送它们,然后客户端更新一个文本块 UI (wpa),所以如果我获取两次,我将拥有"test1...","test2...","test1...","test2..." 因为现在没有检查重复项。这证明集合可以在服务器端从Fetch 更新和记忆到Fetch。但是,当我尝试AddSend 给定文本时,所有变量都被遗忘了,因此订阅者列表为空,而要添加的列表为空。然而,当我再次Fetch 时,旧列表又回来了(现在有 6 个东西,test1...,test2... etc...

我上课前有这个

[ServiceBehavior(InstanceContextMode= InstanceContextMode.PerSession, ConcurrencyMode = ConcurrencyMode.Single)]

我还尝试了单例上下文模式,但无济于事。将 ConcurrencyMode 更改为 Multiple 也没有任何不同。关于为什么我的 static 数据仅在内部命令来自服务器本身时才被重置的任何想法?

这是我的服务的代码:

namespace WcfService3
{   
[ServiceBehavior(InstanceContextMode= InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Single)]
public class Service1 : IService1
{
    public static event Action NullContext;

    public static ObservableCollection<IMyContractCallBack> Subscriptions;

    public void     NormalFunction()
    {

        //Only sends to Subs that are STILL Open
        foreach (IMyContractCallBack user in Subscriptions)
        {
            //Removes the Closed users, because they are hanging around from last session
            if (((ICommunicationObject)user).State != CommunicationState.Opened)
            {
                Subscriptions.Remove(user);
            }
            else
            {
                ObservableCollection<string> holder = Storage.GetList();

                foreach (string str in holder)
                {
                    user.CallBackFunction(str);
                }
            }
        }
    }
    public static void Send(string str)
    {
        try
        {
            foreach (IMyContractCallBack user in Subscriptions)
            {
                user.CallBackFunction(str);
            }
        }
        catch
        {
            //For some reason 'Subscriptions' is always null
            NullContext.Invoke();
        }
    }
    public static void Add(string str)
    {
        //For some reason 'SendList' is always null here, too
        Storage.AddToList(str);
        if (Subscriptions != null)
        {
            //For same reason 'Subscriptions' is always null
            foreach (IMyContractCallBack user in Subscriptions)
            {
                user.CallBackFunction(str);
            }
        }
    }

    public void Subscribe()
    {
        //Adds the callback client to a list of Subscribers
        IMyContractCallBack callback = OperationContext.Current.GetCallbackChannel<IMyContractCallBack>();
        if (Subscriptions == null)
        {
            Subscriptions = new ObservableCollection<IMyContractCallBack>();
        }
        if(!Subscriptions.Contains(callback))
        {
            Subscriptions.Add(callback);
        }
    }

这是我的 Storage 类代码:

namespace WcfService3
{
public static class Storage
{

    public static readonly ObservableCollection<string> SendList = new ObservableCollection<string>();

    public static IMyContractCallBack callback;

    public static ObservableCollection<string> GetList()
    {

        if (SendList.Count == 0)
        {
            AddToList("Test1...");
            AddToList("Test2...");
        }

        return SendList;
    }

    public static void AddToList(string str)
    {


            SendList.Add(str);

    }
}

}

如果需要,我可以提供更多代码。

【问题讨论】:

  • 看起来问题出在您的代码中,因此您必须发布代码才能让他人帮助您。
  • 好的,我添加了 svc.cs 文件的代码
  • 该代码与您在问题中的描述不一致。 Storage 是什么? Fetch() 在哪里?
  • Storage是一个静态类,现在在上面添加,Fetch()是来自客户端的调用,触发回调函数NormalFunction

标签: c# wcf duplex


【解决方案1】:

您是否在任何地方使用ThreadStatic 属性? (只需快速搜索)这是一个真正的远景,可能不是你的问题。

您可能遇到线程问题。您的所有客户端是否同时连接(我的意思是连续连接?)如果是,您将在 Subscribe 方法中遇到此代码的线程问题:

   if (Subscriptions == null)
    {
        Subscriptions = new ObservableCollection<IMyContractCallBack>();
    }

您应该更好地限制对您的 Subscriptions 方法的访问,这样您就可以查看谁修改了它以及何时修改它,并使用控制台语句找出您出错的地方。

【讨论】:

  • 是的,我真的认为这是一个线程问题,所以我在 Storage 类中添加了 ThreadStatic 到 holder(现在显示在上面),但这只是在从服务调用时使其为空,而不是空的,因为它被初始化了。所以ThreadStatic 让它只初始化一次,但在服务线程上仍然为空
  • 嗯,这就是你的答案,没有办法应该是 ThreadStatic,因为它会被一堆不同的线程访问。删除它并查看它有什么影响(和/或发布更多代码)。你知道ThreadStatic会产生什么影响吗?
  • 也许不是?我认为它会在线程之间保持静态。我一开始没有ThreadStatic,但是当它不能正常工作时,我将它添加到测试中,但效果更差。如果没有ThreadStatic,它的行为就像我原来的问题中描述的那样:当Service1 调用它时,它会重新初始化。
  • 哦,我想我正在寻找 ThreadStatic 的反面。我希望它在线程之间同步,但是我也尝试过lock
  • ThreadStatic 的反面是根本没有定义它。 “线程之间同步”,即您希望它是一个全局(静态)变量。?你也说过,没有Threadstatic,它会重新初始化——什么是重新初始化它?添加一个 console.writeline 或设置一个断点,以便您知道它何时重新初始化
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-04-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多