wcfwas

WCF service not persisting Reference types in service


I have a WAS service configured on Windows 10 IIS 1511. I created a simple test app to get all major problem areas sorted before I start with my actuall project. I have my service configured with concurrency multiple and Instance to single. I have a concurrent dictionary to manage the concurrency. I do 2 calls to the service with 2 different proxy objects to subscribe to my observer/subject. the subscribe method adds subscribers to the dictionary. after the second proxy call there are only one item in the dictionary and I was expecting 2. So it seems my service is not persisting my changes to the dictionary. However if I use the Hello operation, which just increase a counter (value type) then the count is 2 after second call. Here is my client console code:

static void Main(string[] args)
    {
        string personErnie = "Ernie";
        string personAlvin = "James";

        //using (PersonTracker.PersonTrackerClient personTracker1 =
        //  new PersonTracker.PersonTrackerClient("PersonTrackerPipeEndPoint"))
        //using (PersonTracker.PersonTrackerClient personTracker2 =
        //  new PersonTracker.PersonTrackerClient("PersonTrackerPipeEndPoint"))
        using (PersonTracker.PersonTrackerClient personTracker1 =
            new PersonTracker.PersonTrackerClient("PersonTrackerHTTPEndPoint"))
        using (PersonTracker.PersonTrackerClient personTracker2 =
                new PersonTracker.PersonTrackerClient("PersonTrackerHTTPEndPoint"))
        {

            string h1 = personTracker1.Hello(personErnie); //Output: Hello Ernie, Seems like you using the http protocol, count = 1
            string h2 = personTracker1.Hello(personAlvin); //Output: Hello James, Seems like you using the http protocol, count = 2

            PersonObserver personObserverErnie = new PersonObserver(personErnie);
            object disposeObserverErnie = personTracker1.Subscribe(personObserverErnie); // Dictionary Count = 1

            PersonObserver personObserverJames = new PersonObserver(personAlvin);
            object disposeObserverJames = personTracker2.Subscribe(personObserverJames); // Dictionary Count = 1
        }
    }

Here is my service class:

[ServiceBehavior(
        ConcurrencyMode = ConcurrencyMode.Multiple,
        InstanceContextMode =InstanceContextMode.Single)]
public class PersonTracker : IPersonTracker
{

    public static ConcurrentDictionary<string, PersonObserver> observers = null;
    int Counter;

    public string Hello(string name)
    {
        string protocol = OperationContext.Current.Channel.LocalAddress.Uri.Scheme;
        return string.Format("Hello {0}, Seems like you using the {1} protocol, count = {2}",name, protocol,Counter++);
    }

    public UnsibscribePerson Subscribe(PersonObserver observer)
    {
        if (observers == null)
        {
            observers = new ConcurrentDictionary<string, PersonObserver>();
        }
        if (!observers.ContainsKey(observer.Name))
        {
            observers.AddOrUpdate(observer.Name, observer, (key, oldValue) => { return new PersonObserver(oldValue.Name); });
        }

        return new UnsibscribePerson(observers, observer);
    }
}

Here is my Contract interface:

[ServiceContract(SessionMode = SessionMode.Required)]
public interface IPersonTracker 
{
    [OperationContract]
    string Hello(string name);

    [OperationContract]
    UnsibscribePerson Subscribe(PersonObserver observer);
}

The unsubscribe class is a class extending the IDisposable for the client to de-register itself once I have remoting (Pipes) sorted.

Question: Why does the dictionary not persist my observers i add but for the counter it does...

UPDATE:

So just by removing the UnsibscribePerson object in the return type of my Subscribe operation I have my issue resolved, however I need to return this object. Is this something to do with my UnsibscribePerson object, here is my changes made and my UnsibscribePerson object:

[ServiceContract]
public interface IPersonTracker 
{
    [OperationContract]
    string Hello(string name);

    [OperationContract(IsInitiating = true)]
    void Subscribe(PersonObserver observer);
}

And here is my UnsibscribePerson object:

[DataContract(IsReference = true)]
public class UnsibscribePerson : IDisposable
{
    [DataMember(EmitDefaultValue = false)]
    private PersonObserver observer;

    [DataMember(EmitDefaultValue = false)]
    private ConcurrentDictionary<string, PersonObserver> persons;

    public UnsibscribePerson(ConcurrentDictionary<string, PersonObserver> persons, PersonObserver observer)
    {
        this.persons = persons;
        this.observer = observer;
    }

    public void Dispose()
    {
        if (observer != null && persons.ContainsKey(observer.Name))
        {
            PersonObserver person = null;

            persons.TryRemove(observer.Name, out person);
        }
    }
}

I also change the return type to a value type (returning the count of the list) and I got the results (count of 1 and 2). This still seem to be related to reference types and value types?


Solution

  • This is embarrassing :) My dispose method on UnsibscribePerson class gets called which removes my subscriber right after it was added....

    So solution for me was to not implement IDisposbale interface