tags:

views:

3615

answers:

7

Hi, I have a WCF service that is hosted in a Windows Service. Clients that using this service must pass an identifier every time they're calling service methods (because that identifier is important for what the called method should do). I thought it is a good idea to somehow put this identifier to the WCF header information.

If it is a good idea, how can I add the identifier automatically to the header information. I mean whenever user called the WCF method the identifier automatically added to the header.

UPDATE: Clients that are using the WCF service are both Windows applications and Windows Mobile application (Using Compact Framework).

+1  A: 

You add it to the call using:

using (OperationContextScope scope = new OperationContextScope((IContextChannel)channel))
{
    MessageHeader<string> header = new MessageHeader<string>("secret message");
    var untyped = header.GetUntypedHeader("Identity", "http://www.my-website.com");
    OperationContext.Current.OutgoingMessageHeaders.Add(untyped);

    // now make the WCF call within this using block
}

And then, server-side you grab it using:

MessageHeaders headers = OperationContext.Current.IncomingMessageHeaders;
string identity = headers.GetHeader<string>("Identity", "http://www.my-website.com");
AgileJon
Thanks for you code-snippet. But with this I have to add the header every time I want to call a method. I wanted to make this process transparent. I mean with implementing once, every time the user creates a service client and used a method, the customer header automatically added to the message.
Mohammadreza
+1  A: 

Context bindings in .NET 3.5 might be just what you're looking for. There are three out of the box: BasicHttpContextBinding, NetTcpContextBinding, and WSHttpContextBinding. Context protocol basically passes key-value pairs in the message header. Check out Managing State With Durable Services article on MSDN magazine.

Mehmet Aras
Also note that you only set the context once before establishing a session with the server. Then the context becomes readonly. If you want the context setup to be transparent on the client side, you can derive from the client proxt class and in the contructor you can add the information that make up your context. Then each time the client creates an instance of the client proxt, the context will be automatically created and added to the client proxy instance.
Mehmet Aras
+1  A: 

If I understand your requirement correctly, the simple answer is: you can't.

That's because the client of the WCF service may be generated by any third party that uses your service.

IF you have control of the clients of your service, you can create a base client class that add the desired header and inherit the behavior on the worker classes.

Paulo Santos
+1  A: 

You can specify custom headers in the MessageContract.

You can also use < endpoint> headers that are stored in the configuration file and will be copied allong in the header of all the messages sent by the client/service. This is usefull to add some static header easily.

Philippe
+13  A: 

The advantage to this is that it is applied to every call.

Create a class that implements IClientMessageInspector. In the BeforeSendRequest method, add your custom header to the outgoing message. It might look something like this:

    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[USER_AGENT_HTTP_HEADER]))
        {
            httpRequestMessage.Headers[USER_AGENT_HTTP_HEADER] = this.m_userAgent;
        }
    }
    else
    {
        httpRequestMessage = new HttpRequestMessageProperty();
        httpRequestMessage.Headers.Add(USER_AGENT_HTTP_HEADER, this.m_userAgent);
        request.Properties.Add(HttpRequestMessageProperty.Name, httpRequestMessage);
    }
    return null;
}

Then create an endpoint behavior that applies the message inspector to the client runtime. You can apply the behavior via an attribute or via configuration using a behavior extension element.

Here is a great example of how to add an HTTP user-agent header to all request messages. I am using this in a few of my clients. You can also do the same on the service side by implementing the IDispatchMessageInspector.

Is this what you had in mind?

Update: I found this list of WCF features that are supported by the compact framework. I believe message inspectors classified as 'Channel Extensibility' which, according to this post, are supported by the compact framework.

Mark Good
Thanks. This is exactly what i wanted but does it work in compact framework?
Mohammadreza
Mohammadreza, I'm not sure. The list that I found suggested that they might be, but I haven't been able to confirm.
Mark Good
@Mark,This is a really great answer. Thanks. I've tried this over net.tcp but am using the Headers collection directly (the Http Headers didn't work). I get a Header with my token (Name) in at ServiceHost AfterReceiveRequest event, but not the value (there doesn't even seem to be a property for a value?). Is there something I am missing? I would have expected a name/value pair as when I create the header it asks me for:request.Headers.Add(MessageHeader.CreateHeader(name, ns, value));
Program.X
A: 

Hi Mohammed and Mark

I am trying to achieve the same thing but with the limitations of CF I am unable to move forward.

Have you by any chance got this to work? Could you please update the forum on the status so that it would be useful for other fellow developers?

Vincent Wolf
+1  A: 

If you just want to add the same header to all the requests to the service, you can do it with out any coding!
Just add the headers node with required headers under the endpoint node in your client config file

<client>
<endpoint address="http://localhost/..." >
<headers>
<HeaderName>Value</HeaderName>
</headers>
</endpoint>

NimsDotNet