WCF shares an instance of IClientMessageInspector for multiple clients

I manage a shared cookie when making WCF service calls using this methodology described in the heading << → Centralized cookie management ": http://megakemp.com/2009/02/06/managing-shared-cookies-in-wcf /

I created a custom IClientMessageInspector, IEndpointBehavior, BehaviorExtensionElement, work. My endpoint behavior is added by the message inspector as follows:

public class MyEndpointBehavior : IEndpointBehavior
{
    public void AddBindingParameters(ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
    {
    }
    public void ApplyClientBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime)
    {
        // yuck.. Wish I had an instance of MyClientMessageInspector
        // (which has the auth cookie already) so I could just inject that
        // instance here instead of creating a new instance
        clientRuntime.MessageInspectors.Add(new MyClientMessageInspector());
    }
    public void ApplyDispatchBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher)
    {
    }
    public void Validate(ServiceEndpoint endpoint)
    {
    }
}

Everything works flawlessly , but this solution breaks when you want to share cookies over multiple clients. Since the method ApplyDispatchBehavior()creates a new instance, any other client will not receive the message inspector instance, and thus the auth ticket.

, , :

MyEndpointBehavior(MyClientMessageInspector msgInspector) { ... }

WCF . , WCF , , IInstanceProvider, IServiceBehavior .. , , .

- ?

+3
3

, @carlosfigueira @drew, . my IEndpointBehavior PROGRAMMATICALLY, vs config. . , :

public class MyEndpointBehavior : IEndpointBehavior
{
    private MyClientMessageInspector_myClientMessageInspector;

    public MyClientMessageInspector MyClientMessageInspector
    {
        get
        {
            if (_myClientMessageInspector == null)
            {
                _myClientMessageInspector = new MyClientMessageInspector();
            }
            return _myClientMessageInspector;
         }
    }
    public void AddBindingParameters(ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
    {
    }
    public void ApplyClientBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime)
    {
        clientRuntime.MessageInspectors.Add(MyClientMessageInspector);
    }
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher)
    {
    }
    public void Validate(ServiceEndpoint endpoint)
    {
    }
}

:

var behavior = new MyEndpointBehavior();
client1.Endpoint.Behaviors.Add(behavior);
client2.Endpoint.Behaviors.Add(behavior);

cookie.

0

, cookie , .

, , . , , concurrency . , cookie, , . , ChannelParameterCollection , , mssage cookie. :

// Hold onto a static cookie container
public static CookieContainer MyCookieContainer;

// When instantiating the client add the cookie container to the channel parameters
MyClient client = new MyClient();
client.InnerChannel.GetProperty<ChannelParameterCollection>().Add(MyCookieContainer);

public void BeforeSendMessage(ref Message, IClientChannel clientChannel)
{
    // Find the cookie container for the current channel
    CookieContainer cookieContainer = clientChannel.GetProperty<ChannelParameterCollection>().Select(p => p as CookieContainer).Where(cc => cc != null).First();

    // ... use the cookie container to set header on outgoing context ...
}
+5

You are right, IInstanceProvider will not help in your case - it is used only to provide instances of the service. For your behavior, you do not need a constructor without parameters. A configuration element without parameters is needed for the configuration item, and this class can use some dependency injection class (see below) to create the corresponding inspector class necessary for behavior.

namespace ConsoleApplication4
{
    public class MyEndpointBehavior : IEndpointBehavior
    {
        IClientMessageInspector inspector;
        public MyEndpointBehavior(IClientMessageInspector inspector)
        {
            this.inspector = inspector;
        }

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

        public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
        {
            clientRuntime.MessageInspectors.Add(this.inspector);
        }

        public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
        {
        }

        public void Validate(ServiceEndpoint endpoint)
        {
        }
    }
    public class MyEndpointBehaviorElement : BehaviorExtensionElement
    {
        public override Type BehaviorType
        {
            get { return typeof(MyEndpointBehavior); }
        }

        protected override object CreateBehavior()
        {
            return new MyEndpointBehavior(ClientInspectorFactory.GetClientInspector());
        }
    }
    public class MyClientInspector : IClientMessageInspector
    {
        public MyClientInspector()
        {
        }

        public void AfterReceiveReply(ref Message reply, object correlationState)
        {
            Console.WriteLine("AfterReceiveReply");
        }

        public object BeforeSendRequest(ref Message request, IClientChannel channel)
        {
            Console.WriteLine("BeforeSendRequest");
            return null;
        }
    }
    public static class ClientInspectorFactory
    {
        static IClientMessageInspector instance;
        public static IClientMessageInspector GetClientInspector()
        {
            if (instance == null)
            {
                instance = new MyClientInspector();
            }

            return instance;
        }
    }
    [ServiceContract]
    public interface ITest
    {
        [OperationContract]
        int Add(int x, int y);
    }
    public class Service : ITest
    {
        public int Add(int x, int y) { return x + y; }
    }
    class Program
    {
        static void Main(string[] args)
        {
            ServiceHost host = new ServiceHost(typeof(Service));
            host.Open();
            Console.WriteLine("Host opened");

            ChannelFactory<ITest> factory = new ChannelFactory<ITest>("client1");
            ITest proxy = factory.CreateChannel();
            Console.WriteLine(proxy.Add(3, 4));
            ((IClientChannel)proxy).Close();
            factory.Close();

            factory = new ChannelFactory<ITest>("client2");
            proxy = factory.CreateChannel();
            Console.WriteLine(proxy.Add(5, 8));
            ((IClientChannel)proxy).Close();
            factory.Close();

            host.Close();
        }
    }
}
+2
source

All Articles