Pavel Voronin
Pavel Voronin

Reputation: 14015

Which WCF's extension point should be used for setting context for each operation?

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.

Upvotes: 1

Views: 337

Answers (1)

Pavel Voronin
Pavel Voronin

Reputation: 14015

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); 

Upvotes: 2

Related Questions