Vaccano
Vaccano

Reputation: 82507

Does WCF Run the session on more than one thread?

I have a wcf service (hosted in IIS) that is setup to use sessions. It seems to work. When Application_PostAcquireRequestState is called I have a session ID.

I end up using it like this (in my Global.asax):

if (Context.Handler is IRequiresSessionState)
{
    log4net.ThreadContext.Properties["sessionId"] = Session.SessionID;
}

That seems to work fine. The value is stored off into my log4net property.

But when my service operation begins (my actual WCF service code) the log4net property is null again.

Since the property is stored per thread (ThreadContext), I can only assume that this means that the session is setup on one thread then executed on another thread. Am I right?

Is there anyway to get my log4net property set on the on the correct thread (without having to remember to make the above call at the start of every single service operation)?

Upvotes: 2

Views: 778

Answers (3)

Stefan Egli
Stefan Egli

Reputation: 17028

Custom properties do not need to be strings. So you could store an instance of the following class in the global context:

public class SessionIdProperty 
{
    public override string ToString()
    {
        // error handling omitted
        return Session.SessionID;
    }
}

This way log4net can access the Session object directly when it logs a message. Log4net calls the ToString() method on non-string properties.

Upvotes: 1

ErnieL
ErnieL

Reputation: 5801

There are multiple scenarios where WCF might change threads on you:

  1. The Global.asx thread is not guaranteed to be used for a service call (in fact its unlikely).
  2. If there are multiple calls during the same session, the thread may also change between calls to the same service instance.

In theory state information like this should be stored in an Operation Context object. However because log4net uses thread local storage it becomes an awkward solution.

Is there anyway to get my log4net property set on the on the correct thread (without having to remember to make the above call at the start of every single service operation)?

Yes. Create a custom IOperationInvoker. The best example I know of is Carlos Figueira's blog. If you apply this as a service behavior your log4net property should always be defined for the service code.

One warning: When adding to thread local storage be sure to clean up. That's why log4net.ThreadContext.Stacks[].Push() returns a IDisposable. In other words your Invoke method should look like (incomplete and untested):

public object Invoke(object instance, object[] inputs, out object[] outputs)
{
    using (log4net.ThreadContext.Stacks[key].Push(value))
    {
        return this.originalInvoker.Invoke(instance, inputs, out outputs);
    }
}

See Carlos' blog to understand why you are calling the "originalInvoker". Note that if you want to support async operations that you need to implement additional methods.

Upvotes: 1

Peter Ritchie
Peter Ritchie

Reputation: 35869

Yes, IIS may use multiple thread to service multiple WCF requests. See http://msdn.microsoft.com/en-us/library/cc512374.aspx for more detail.

You might consider using different instances of a logger for each WCF request.

Upvotes: 2

Related Questions