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

Wcf

Wcf Problem Overview


While my service executes, many classes will need to access User.Current (that is my own User class). Can I safely store _currentUser in a [ThreadStatic] variable? Does WCF reuse its threads? If that is the case, when will it clean-up the ThreadStatic data? If using ThreadStatic is not safe, where should I put that data? Is there a place inside OperationContext.Current where I can store that kind of data?

Edit 12/14/2009: I can assert that using a ThreadStatic variable is not safe. WCF threads are in a thread pool and the ThreadStatic variable are never reinitialized.

Wcf Solutions


Solution 1 - Wcf

There's a blog post which suggests implementing an IExtension<T>. You may also take a look at this discussion.

Here's a suggested implementation:

public class WcfOperationContext : IExtension<OperationContext>
{
    private readonly IDictionary<string, object> items;

    private WcfOperationContext()
    {
        items = new Dictionary<string, object>();
    }

    public IDictionary<string, object> Items
    {
        get { return items; }
    }

    public static WcfOperationContext Current
    {
        get
        {
            WcfOperationContext context = OperationContext.Current.Extensions.Find<WcfOperationContext>();
            if (context == null)
            {
                context = new WcfOperationContext();
                OperationContext.Current.Extensions.Add(context);
            }
            return context;
        }
    }

    public void Attach(OperationContext owner) { }
    public void Detach(OperationContext owner) { }
}

Which you could use like that:

WcfOperationContext.Current.Items["user"] = _currentUser;
var user = WcfOperationContext.Current.Items["user"] as MyUser;

Solution 2 - Wcf

An alternative solution without adding extra drived class.

    OperationContext operationContext = OperationContext.Current;
    operationContext.IncomingMessageProperties.Add("SessionKey", "ABCDEFG");

To get the value

var ccc = aaa.IncomingMessageProperties["SessionKey"];

That's it

Solution 3 - Wcf

I found that we miss the data or current context when we make async call with multiple thread switching. To handle such scenario you can try to use CallContext. It's supposed to be used in .NET remoting but it should also work in such scenario.

Set the data in the CallContext:

DataObject data = new DataObject() { RequestId = "1234" };
CallContext.SetData("DataSet", data);

Retrieving shared data from the CallContext:

var data = CallContext.GetData("DataSet") as DataObject;

// Shared data object has to implement ILogicalThreadAffinative

public class DataObject : ILogicalThreadAffinative
{
  public string Message { get; set; }
  public string Status { get; set; }
}

Why ILogicalThreadAffinative ?

When a remote method call is made to an object in another AppDomain,the current CallContext class generates a LogicalCallContext that travels along with the call to the remote location.

Only objects that expose the ILogicalThreadAffinative interface and are stored in the CallContext are propagated outside the AppDomain.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionSylvainView Question on Stackoverflow
Solution 1 - WcfDarin DimitrovView Answer on Stackoverflow
Solution 2 - WcfValidfroMView Answer on Stackoverflow
Solution 3 - WcfAkshay tiwariView Answer on Stackoverflow