1

I want to setup ambient context (similar to how Thread.CurrentPrincipal works) for every operation of all services running inside the host.

What extension mechanism should I use? There are plenty of them so I'm confused since I have almost no experience of working with WCF.

Pavel Voronin
  • 13,503
  • 7
  • 71
  • 137
  • If the "context" you want isn't WCF-specific and global to all services, wouldn't a simple static class do? – Jeroen Mostert Nov 24 '14 at 18:07
  • @JeroenMostert It requires some initialization on each request for correct flowing with async operations. – Pavel Voronin Nov 24 '14 at 18:13
  • 1
    In that case, your context is per call and you probably want an [`ICallContextInitializer`](http://blogs.msdn.com/b/drnick/archive/2007/04/23/icallcontextinitializer-example.aspx). I have no experience using this, but maybe someone can forge this information into a proper answer. – Jeroen Mostert Nov 24 '14 at 18:17
  • A couple of links http://blogs.msdn.com/b/carlosfigueira/archive/2012/02/14/wcf-extensibility-initializers-instance-context-channel-call-context.aspx. http://wcfpro.wordpress.com/2011/01/14/icallcontextinitializer/ – Pavel Voronin Nov 24 '14 at 20:38
  • @JeroenMostert Make your comment as an answer, I'll accept it. Everything works. Thanks – Pavel Voronin Nov 25 '14 at 09:35
  • If you have working code, you could post it as an answer and accept it yourself -- that's better than me getting reputation for a one-word answer. – Jeroen Mostert Nov 25 '14 at 12:05
  • Ok. I think it doesn't matter how many words it had. The answer was correct! ;-) – Pavel Voronin Nov 25 '14 at 12:07
  • Ideally, the question and its answer should help future readers with the same issue, so working code definitely beats someone shouting "ICallContextInitializer". If you don't have the time, though, that's fine -- we'll just leave it like this. – Jeroen Mostert Nov 25 '14 at 12:09
  • @JeroenMostert I'll add my code a bit later – Pavel Voronin Nov 25 '14 at 12:39

1 Answers1

2

Here is the solution:

First, we create the endpoint behavior which adds initializers to operations:

public class CallContextInitializerBehavior : IEndpointBehavior
{
    private readonly ICallContextInitializer callContextInitializer;
    private ServiceHost serviceHost;

    public CallContextInitializerBehavior(ICallContextInitializer callContextInitializer)
    {
        this.callContextInitializer = callContextInitializer;
    }

    public void AddToHost(ServiceHost host)
    {
        // only add to host once
        if (this.serviceHost != null)
        {
            return;
        }

        this.serviceHost = host;

        foreach (ServiceEndpoint endpoint in this.serviceHost.Description.Endpoints)
        {
            endpoint.Behaviors.Add(this);
        }
    }

    public void Validate(ServiceEndpoint endpoint)
    {
    }

    public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
    {
    }

    public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
    {
        foreach (DispatchOperation operation in endpointDispatcher.DispatchRuntime.Operations)
        {
            operation.CallContextInitializers.Add(callContextInitializer);
        }
    }

    public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
    {
    }
}

Then we create our own implementation of ICallContextInitializer:

public class MyCallContextInitializer : ICallContextInitializer
{
    public object BeforeInvoke(InstanceContext instanceContext, IClientChannel channel, Message messa
    {
        ...do domething here...

        return myCorrelationState; // or null if not important;
    }

    public void AfterInvoke(object correlationState)
    {
        UserInfo userInfoBeforeInvoke = (UserInfo) correlationState;

        AmbientContext.Context.SetCurrent(userInfoBeforeInvoke);
    }
}

Finally apply behavior by calling (sure, it's better to use IoC):

var initializer = new MyCallContextInitializer();
var behavior = new CallContextInitializerBehavior(initilizer);
behvior.AddToHost(serviceHost); 
Pavel Voronin
  • 13,503
  • 7
  • 71
  • 137