Reputation: 1789
We have a web service that sends requests to a windows service which hosts a WCF service for processing.
The interface is simple:
namespace MyApp
{
[ServiceContract]
public interface IMyApp
{
[OperationContract]
string DoSomething(string xml);
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
class MyAppWcf : IMyApp
{
public string DoSomething(string xml)
{
Customer customer = GlobalObject.GetCustomer(xml); //millisecs
return customer.DoSomething(xml); //Takes 5-10 seconds
}
}
}
GlobalObject is instantiated on the WindowsService.OnStart() and contains all the static data the customer objects need. The interface DoSomething() will be called up to ca. 30 different clients.
Questions:
1. What is the default threading behaviour now? Will each call have to wait until the last one is finished?
2. What effect will changing InstanceContextMode?
REAL question:
There are up to 1000 customer objects, 2 different customer objects can be called in parallel, but the same one cannot. e.g.
DoSomething("Customer 1"); => Goes ahead. Answer in 10 seconds
DoSomething("Customer 2"); => Goes ahead in parallel with the above call.
DoSomething("Customer 2"); => Will wait for last call of DoSomething("Customer 2") to finish
What should my service behavior settings be and do I have to implement a lock mechanism to prevent the same object being processed more than once in parallel?
Thanks.
Edit 2: GlobalObject.GetCustomer() just retrieves the customer mentioned in the XML from a dictionary.
Upvotes: 3
Views: 1954
Reputation: 46044
OK. I'm not sure I knew that ConcurrencyMode
is ignored when using PerCall
instancing, but looking at my own project, I use PerCall
instancing and don't specify any value for ConcurrencyMode
. So apparently, I did know this at one point and just failed to document it in my code. That is now corrected.
My project works a lot like you've described yours, and I use InstanceContextMode.PerCall
as I've already mentioned. Here's what this means.
MyAppWcfInst.DoSomething( "<customer id=A/>" );
MyAppWcfInst.DoSomething( "<customer id=B/>" );
MyAppWcfInst.DoSomething( "<customer id=B/>" );
All three clients will interact with your WCF service simultaneously, but each of them will have its own instance and operate within a separate thread. So while each call by each client is single-threaded, they can be active at the same time. This means that the list of Customer objects can be accessed by multiple clients at the same time.
Client1 and Client2 can be operating in parallel since they deal with different Customer objects, but Client3 needs to wait until Client2 is finished before it can "do something" with CustomerB. All this means is that you need to synchronize access within each Customer object. In other words, the logic inside the Customer.DoSomething()
method needs to have a synchronization lock to prevent multiple clients from operating on the Customer at the same time.
class Customer
{
private object _sync = new object();
public string DoSomething( string xml )
{
lock (_sync)
{
// put your logic here...
}
}
}
This is the way my WCF service works. Hope this helps.
Upvotes: 2
Reputation: 12135
With PerCall, you will have requests to the service processed in parallel, each on a different instance of the MyAppWcf class. Requests will only have to wait for an earlier one to finish if there is not a free .NET threadpool thread available to dispatch them. If you changed it to Single then the requests would be serialized unless you set ConcurrencyMode to Multiple.
Your real concern ought to be how safe for concurrent access the GobalObject method is: if that is not thead safe, the above code is not either.
Likewise with the Customer.DoSomething method, if it touches any shared data (such as itself calling the GlobalObject).
I didn't understand what you meant by "only one customer object can be handled at a time". If that is literally true, then you need to avoid parallel execution anyway.
Upvotes: 1