WCF Operation.Context not Thread safe?
Asked Answered
S

1

17

I'm code reviewing a WCF service. In the header of each message we inject data that the service is going to use later to build a connection string to a DB. That's because the service is going to be used by a number of different sites, each with its own DB that the service has to query. We use wcf extensibility. We have a custom MessageInspector that, after receiving the request, extracts the data from the message header, creates a context (that implements IExtension) and adds it to OperationContext.Current.Extensions. Before sending the reply the custom context is removed from the Extencions collection.

This is a fairly common pattern, as discussed here:

Where to store data for current WCF call? Is ThreadStatic safe?

and here:

http://social.msdn.microsoft.com/Forums/vstudio/en-US/319cac66-66e8-4dfe-9a82-dfd289c9df1f/wcf-doesnt-have-session-storage-so-where-should-one-store-call-specific-data?forum=wcf

This all works fine as long as the service receives a request, processes it, sends the reply and receives the next request. But what if the service receives a request and before being able to reply it gets a second request? I built a small console application to test it. I send 2 messages from 2 different threads, I made the wcf service wait for 2 seconds, to ensure the second request comes in before the first one is completed and this is what I get:

Site Id : test1450 ; Session: uuid:2caf47cf-7d46-4d72-9275-d9c037fa0e70;id=2 : Thread Id: 6

Site Id : test1450 ; Session: uuid:2caf47cf-7d46-4d72-9275-d9c037fa0e70;id=3 : Thread Id: 22

It looks like wcf creates 2 sessions executing on 2 different threads, but Site Id is the same. It shouldn't. Judging from this it looks like OperationContext.Current.Extensions is a collection shared between threads. Right now I'm inclined to think my test is wrong and I missed something.

Has anyone tried something similar and found out that OperationContext.Current is not thread safe?

Siding answered 10/10, 2013 at 9:34 Comment(0)
A
13

OperationContext.Current like other similar properties such as HttpContext.Current have thread affine (or thread static) values. So they are thread safe in the sense that multiple threads can read them, but different threads will get different instances. They can be thought of as dictionaries between specific threads and instances.

So in this context they are not thread safe.

Requests are served by a thread pool so concurrent requests will have different thread ids. (up to a point where the thread pool is full, then requests will be put on hold)

Anhydrous answered 10/10, 2013 at 9:42 Comment(7)
If this is the case, then I still don't understand why I get the same site Id. If each thread should get different data, then I assume it should get the site Id contained in message it's processing. It looks like the Current Operation Context is different for each thread (different session Id), but still the Extensions collection seems to contain the same instance of the custom Context.Siding
If it may help: I tried to configure the server differently: InstanceContextMode = InstanceContextMode.PerCall, ConcurrencyMode = ConcurrencyMode.SingleSiding
This is how it was originnaly configured;InstanceContextMode = InstanceContextMode.PerSession, ConcurrencyMode = ConcurrencyMode.Multiple. But the issue is the sameSiding
When i say different data i should really say a different instance. Depending on the configuration some properties might have the same values, but the actual instance is tied to the thread. We can think of these properties as a dictionary of threads and objects, each thread gets its own instance. If you'd start a new thread and read this property you'd get null, even though you'd expect the instance tied to the actual requestAnhydrous
note though that wcf keeps track of this, so its only a problem if the service creates threads internally. Callers to the service do not have to worry abut concurrencyAnhydrous
setting the concurrencymode is a way to prevent problems if the service os not thread safe internally. However your test will still work, but the requests will be done serially. They may also not be performed on the same thread, even of they are done in seriesAnhydrous
The service doesn't create any thread internally. So, according to what you say, in theory everything should be handled by WCF. So, If I understand right, each thread should receive its own instance of OperationContext and the instances should contain different Extensions collections. So I still don't understand how I end up with the same SiteId.Siding

© 2022 - 2024 — McMap. All rights reserved.