Search code examples
c#wcfwcf-sessions

WCF own EndpointBehavior read client Session


I have an IClientMessageInspector interface with BeforeSendRequest() method implemented. In this method I want to retrieve the Session object set in the client. Something like.

    public object BeforeSendRequest(ref Message request, IClientChannel channel)
    {
        //Instantiate new HeaderObject with values from ClientContext;
        var dataToSend = new MyCustomHeader
            {
                MyValue = HowDoIGetClientSession["abcValue"];
            };

        var typedHeader = new MessageHeader<CustomHeader>(dataToSend);
        var untypedHeader = typedHeader.GetUntypedHeader("custom-header", "s");

        request.Headers.Add(untypedHeader);
        return null;
    }

I think I need something very similar as in this question.


Solution

  • I ended up using an approach like in this tutorial. I add the relevant information in a cookie as key-value pairs and read it in the service implementation. Instead of service reference I am using ChannelFactory, but basically the main idea is the same as in the tutorial.

    My BeforeSendRequest method is:

            public object BeforeSendRequest(ref System.ServiceModel.Channels.Message request,
                System.ServiceModel.IClientChannel channel)
            {
                HttpRequestMessageProperty httpRequestMessage;
                object httpRequestMessageObject;
                if (request.Properties.TryGetValue(HttpRequestMessageProperty.Name
                    , out httpRequestMessageObject))
                {
                    httpRequestMessage = httpRequestMessageObject as HttpRequestMessageProperty;
                    if (string.IsNullOrEmpty(httpRequestMessage.Headers["Cookie"]))
                    {
                        httpRequestMessage.Headers["Cookie"] = cookie;
                    }
                }
                else
                {
                    httpRequestMessage = new HttpRequestMessageProperty();
                    httpRequestMessage.Headers.Add("Cookie", cookie);
                    request.Properties.Add(HttpRequestMessageProperty.Name
                        , httpRequestMessage);
                }
    
                return null;
            }
    

    The binding settings is:

                <basicHttpBinding>
                    <binding name="basicHttp" closeTimeout="00:01:00"
                        openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
                        allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
                        maxBufferPoolSize="20000000" maxBufferSize="20000000" maxReceivedMessageSize="20000000"
                        textEncoding="utf-8" transferMode="Buffered" useDefaultWebProxy="true"
                        messageEncoding="Text">
                        <readerQuotas maxDepth="32" maxStringContentLength="200000000" maxArrayLength="200000000"
                            maxBytesPerRead="4096" maxNameTableCharCount="16384" />
                        <security mode="None">
                            <transport clientCredentialType="None" proxyCredentialType="None"
                                realm="" />
                            <message clientCredentialType="UserName" algorithmSuite="Default" />
                        </security>
                    </binding>
                </basicHttpBinding>
    

    In the client app I needed (in web.config system.serviceModel):

    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true"/>
    

    And in the service implementation class annotation:

        [AspNetCompatibilityRequirements(RequirementsMode =
        AspNetCompatibilityRequirementsMode.Required)]
        public class MyService : IMyService {
           // ...
        }
    

    For service calls I am using a wrapper object which implements IDisposable, takes case of proper disposal and adding to EndpointBehaior to the ChannelFactory before creating the channel.

        _factory = new ChannelFactory<T>( );
        _factory.Endpoint.Behaviors.Add(new CookieEndpointBehavior(cookieStr));
        _channel = _factory.CreateChannel();
    

    I am using the service wrapper class in using block, which will call Dispose, once it reaches out of scope.