17

I wrote a WCF service, but the data stored in the Service implementation doesn't persists between calls, not even if stored in a static variable. What can I do?

The service implementation is as follows:

public class Storage : IStorage
{
    protected static object[] _data;

    #region IStorage Members

    public void Insert(object[] data)
    {
        lock (_data)
        {
             _data = _data.Concat(data).ToArray();
        }
    }

    public object[] SelectAll()
    {
        lock (_data)
        {
            return (object[])_data.Clone();
        }
    }

    #endregion
}

The service host is a console application:

static void Main(string[] args)
{
    ServiceHost serviceHost =
       new ServiceHost(typeof(TimeSpanStorage));
    serviceHost.Open();
    Console.WriteLine("Service running.  Please 'Enter' to exit...");
    Console.ReadLine();
}
Jader Dias
  • 88,211
  • 155
  • 421
  • 625

4 Answers4

19

By default WCF instanceMode is set to Per call, meaning data used in the service is specific to that client for that method call.

On your implementation try adding

[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single, ConcurrencyMode=ConcurrencyMode.Single)]
public class MyService: IService

This makes the service essentially a singleton.

MattC
  • 3,984
  • 1
  • 33
  • 49
  • 1
    Setting the context mode to `Single` is not necessarily the right thing to do - that will not allow per-transaction state. Using a `DurableOperation` is a much better choice. – Andrew Hare Dec 01 '09 at 14:08
  • I agree it wont allow the transactional control a Durable service does. And the singleton pattern defo has it's limits when you want to scale. The "data ... doesn't persists between calls" just made me think the OP was after something simple. – MattC Dec 01 '09 at 14:11
  • Setting the InstanceContextMode to Single is a horrible idea - your WCF service class is a singleton now, and either you have serialized the handling of all your requests (killing any performance), or you need to deal with multithreading issues (hard and error prone). THe best choice are durable services, which really simply store their state in a persistant store (a.k.a. a database). – marc_s Dec 01 '09 at 14:31
  • Again, I agree that would be the way to finally implement the service should it be required to be durable/performant. If you just want an array to stick around between calls while you play with WCF then that might be a bit heavy. OP didn't specify. – MattC Dec 01 '09 at 14:48
  • It worked in my tests. I don't care if it loses data when the service stops, so I don't have any complaints about this approach. – Jader Dias Dec 01 '09 at 15:27
  • Great but the other commenters are more relevent when the time comes to rework a prototype to a more solid system. – MattC Dec 01 '09 at 16:42
  • "Wrong" would suggest there is only one way to achieve the in-memory persistence the OP was looking for. As the comments above state, this isn't the best design approach but it does get the job done in this specific case. – MattC Jan 05 '15 at 11:04
8

What you are looking to do is create a durable service:

WCF Durable services are WCF services in which the operations can remember the values of private variables (=the state of the service) inbetween restarts of the serivcehost and/or client.

MattC
  • 3,984
  • 1
  • 33
  • 49
Andrew Hare
  • 344,730
  • 71
  • 640
  • 635
  • thank you for your answer. I didn't found a memory persistence option within Durable services. Is there any? Or just database persistence options? – Jader Dias Dec 01 '09 at 15:25
3

Are you wanting to persist the data beyond the lifetime of your ServiceHost instance? If so, then I agree that a durable service makes sense.

However, if you are only wanting to persist data between calls to your WCF service while the service is alive, then a durable service is overkill in my humble opinion. Using static data is perfectly acceptable; it is precisely what I do in my WCF project. In fact, the code that you've shown should work, so something else is going on here.

Is the Main() method actually as you've shown it? If so, then that's a problem. As soon as your WCF-enabled console application starts up, it immediately shuts back down, taking the WCF service with it. You need to have some logic in there to keep the console application alive because the WCF service will only remain 'hosted' while the console application is running.

If this is not the problem, let me know, and I'll add the full code of a simple application that demonstrates how to do this.

Matt Davis
  • 45,297
  • 16
  • 93
  • 124
  • No the Main method had a Console.ReadLine call. The question was edited to reflect this. – Jader Dias Dec 01 '09 at 15:19
  • What "while the service is alive" means? It means "while the service host console application is running" ? – Jader Dias Dec 01 '09 at 15:20
  • 2
    @Jader Dias: Yes, if you are only wanting to persist data while the `ServiceHost` console application is running, then there's no reason to use the durable service approach. The durable service approach will work, but so will the static data approach (again, that's what I'm using in my WCF service project). – Matt Davis Dec 01 '09 at 16:07
  • Thanks for the confirmation of my suspicions – Jader Dias Dec 01 '09 at 16:17
-3

Add:

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

Above your class and you'll have a service that is a single instance (i.e. the class proterties remain the same) and allows multiple concurrent connections.

Now you have to take care of your property read/write, i.e. use locks as you've already done (or some other technique).

LordWilmore
  • 2,829
  • 2
  • 25
  • 30