简体   繁体   中英

Wcf Duplex Service Resetting Static Data on Internal Calls

So I am only a few days into learning about wcf services, specifically duplex, and I am starting with a test app. The goal is to have a Service that has an internal (static?) class which stores variables, and a Client that fetches for those variables.

Currently I have two variables in the Storage class, one which is a list of Subscribers ( ObservableCollection<IMyContractCallBack> ) and one which is an ObservableCollection<string> , where each string gets sent in the callback method to the client.

I would like to be able to have the client Fetch (which first Subscribes if not already, by adding its context to the collection on the server side) the strings in the collection on the server side. That part works as expected. However, I would also like to Push a string from the server to every client in the subscription list, as well as Add strings to the collection of strings. That's where my issues crop up.

Anytime I Fetch , it adds to string list "test1..." and "test2..." and sends them, then the client updates a textblock UI (wpa) so if I fetch twice I'll have "test1...","test2...","test1...","test2..." because right now there's no checking for duplicates. That proves that the collection can get updated and remembered on the server side from Fetch to Fetch . However, when I try to Add or Send a given text, all variables are forgotten, so the subscriber list is null, and the list-to-add-to is empty. Yet when I then Fetch again, the old list is back (now with 6 things, test1...,test2... etc... )

I have this before the class

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

and I also tried a Singleton context mode to no avail. Changing the ConcurrencyMode to Multiple doesn't do anything different either. Any ideas as to why my static data is being reset only when internal commands come from the server itself?

Here is the code for my Service:

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

and here is my code for the Storage class:

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

    }
}

}

I can provide more code if needed.

Are you using the ThreadStatic attribute anywhere? (just do a quick search) Thats a real long shot and probably not your issue.

You probably have a threading issue. Do all your clients connect at the same time (i really mean in close succession?) If yes, you are going to have threading issues with this code in your Subscribe method:

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

You should better constrain access to your Subscriptions method so you can see who modifies it and when and use Console statments to figure out where you're going wrong.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM