Click here to Skip to main content
15,867,453 members
Articles / Programming Languages / C#
Article

Automatic Culture Flowing with WCF by using Custom Behaviour

Rate me:
Please Sign up or sign in to vote.
5.00/5 (12 votes)
30 Nov 2007CPOL3 min read 63.8K   1.2K   21   12
An article to demonstrate culture flow from Windows client to Windows server using WCF.
Screenshot - CultureServer.png

Contents

Introduction

On a project I am working on, we use WCF to communicate from an internet client to a Windows service. WCF automatically lets the windows identity flow from the client to the server. This is great but it is not the case for the culture of the client. If the culture would also flow from the client to the server reading localised data from, for example, the resource file could be completely transparent for the application. This example demonstrates how you could implement such a solution by implementing a custom WCF MessageInspector.

Background

The given extension should only be used if you are controlling both ends of the wire (client and server). If you are only creating the server and care about interop you are better off using a more standard method like the one described in Globalization Patterns in WCF (WS-I18N implementation) by Pablo Cibraro.

WCF has several extension points; in this example a custom MessageInspector is used. A custom MessageInspector can be used to inspect or modify messages as they pass through a WCF client or server object. To inspect or modify messages as they pass through a client, you should implement the IClientMessageInspector interface. To inspect or modify messages as they pass through a server, you should implement the IDispatchMessageInspector interface. The custom MessageInspector in this example implements both interfaces.

The custom MessageInspector adds a custom Message Header to the request at the client which contains the culture info of the thread running the client. At the server side, the custom MessageInspector retrieves the culture info from the custom Message Header and sets the culture info on the running thread.

To use the custom message inspector, a custom behaviour also needs to be created which implements IEndpointBehavior. This behaviour is then added to the behaviours collection of the WCF endpoint.

Using the Code

The solution is divided into four projects: the server, the client, the extension and the service interface. The interesting part is the extension project. In the example, the client sets the culture info of the current thread and calls a simple "hello world" method on the server. The server responds with a Console.Writeline with the culture of the running thread.

MessageInspector

This is the custom Message Inspector where the BeforeSendRequest at the client adds the message header and the AfterReceiveRequest at the server extracts the custom header and sets the culture of the currently executing thread.

C#
public class CultureMessageInspector : 
    IClientMessageInspector, IDispatchMessageInspector
{
  private const string HeaderKey = "culture";

  public object BeforeSendRequest
        (ref System.ServiceModel.Channels.Message request,
        System.ServiceModel.IClientChannel channel)
  {
    request.Headers.Add(MessageHeader.CreateHeader
        (HeaderKey, string.Empty, Thread.CurrentThread.CurrentUICulture.Name));
    return null;
  }

  public object AfterReceiveRequest
        (ref System.ServiceModel.Channels.Message request, 
        System.ServiceModel.IClientChannel channel,
        System.ServiceModel.InstanceContext instanceContext)
  {
    int headerIndex = request.Headers.FindHeader(HeaderKey, string.Empty);
    if (headerIndex != -1)
    {
      Thread.CurrentThread.CurrentUICulture = 
            new CultureInfo(request.Headers.GetHeader<string />(headerIndex));
    }
    return null;
  }
  ...

Custom Behaviour

The custom behaviour is created like this:

C#
public class CultureBehaviour : IEndpointBehavior
{
  public void ApplyClientBehavior(ServiceEndpoint endpoint, 
        System.ServiceModel.Dispatcher.ClientRuntime clientRuntime)
  {
    clientRuntime.MessageInspectors.Add(new CultureMessageInspector());
  }

  public void ApplyDispatchBehavior(ServiceEndpoint endpoint, 
        System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher)
  {
    endpointDispatcher.DispatchRuntime.MessageInspectors.Add
                    (new CultureMessageInspector());
  }
  ...

Creating the Service Host

When creating the ServiceHost, the custom behaviour is added to the behaviours collection of the ServiceEndPoint. This could also be configured in the configuration file.

C#
Server server = new Server();
ServiceHost host = 
    new ServiceHost(server, new Uri("net.tcp://localhost:8080"));
NetTcpBinding binding = new NetTcpBinding();
ServiceEndpoint endPoint = 
    host.AddServiceEndpoint(typeof(IHelloWorld), binding, "Server");
endPoint.Behaviors.Add(new CultureBehaviour());

Creating the Client Channel

When creating the client channel, the custom behaviour is also added to the behaviours collection of the ServiceEndPoint. This could also be configured in the configuration file.

C#
ServiceEndpoint tcpEndPoint = new ServiceEndpoint(
    ContractDescription.GetContract(typeof(IHelloWorld)), 
        new NetTcpBinding(), new EndpointAddress
        ("net.tcp://localhost:8080/server"));
ChannelFactory<ihelloworld /> factory = new ChannelFactory<ihelloworld />(tcpEndPoint);
factory.Endpoint.Behaviors.Add(new CultureBehaviour());
return factory.CreateChannel();

Points of Interest

I did not know for sure that the thread running the AfterReceiveRequest would be the same as the thread running the actual server code. In this case it was. If you need the data from the message header in another part of the WCF pipeline, you should add the data to the properties collection of the request.

After I found the right extension point, the actual implementation was simple. There are many extension points, finding the right one is the difficult part.

History

  • v1.0 27/11/2007: Initial release

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect http://www.simpletechture.nl
Netherlands Netherlands
Patrick Kalkman is a senior Software Architect with more than 20 years professional development experience. He works for SimpleTechture where he helps teams develop state of the art web applications.

Patrick enjoys writing his blog. It discusses agile software development. Patrick can be reached at patrick@simpletechture.nl.

Published Windows 8 apps:


Published Windows Phone apps:


Awards:

Best Mobile article of March 2012
Best Mobile article of June 2012

Comments and Discussions

 
QuestionInteroperability Pin
wiwiedbulu9-Jul-14 21:30
wiwiedbulu9-Jul-14 21:30 
QuestionHow to make it work on WCF hosted on IIS Pin
Member 241951915-Feb-13 2:12
Member 241951915-Feb-13 2:12 
Questionunable to invoke the AfterReceiveRequest method Pin
doe joh16-Aug-12 14:08
doe joh16-Aug-12 14:08 
AnswerRe: unable to invoke the AfterReceiveRequest method Pin
Patrick Kalkman8-Oct-12 22:03
Patrick Kalkman8-Oct-12 22:03 
QuestionCan get this code to work with service hosted by iis Pin
doe joh16-Aug-12 11:10
doe joh16-Aug-12 11:10 
AnswerRe: Can get this code to work with service hosted by iis Pin
Patrick Kalkman8-Oct-12 22:04
Patrick Kalkman8-Oct-12 22:04 
QuestionThanks Pin
doe joh14-Aug-12 14:25
doe joh14-Aug-12 14:25 
AnswerRe: Thanks Pin
Patrick Kalkman14-Aug-12 23:04
Patrick Kalkman14-Aug-12 23:04 
GeneralBehaviourExtension Pin
BlueLeaf7-May-09 10:33
BlueLeaf7-May-09 10:33 
GeneralRe: BehaviourExtension Pin
Patrick Kalkman1-Mar-11 2:55
Patrick Kalkman1-Mar-11 2:55 
GeneralGood job Pin
Member 36886039-Dec-08 22:27
Member 36886039-Dec-08 22:27 
GeneralRe: Good job Pin
Patrick Kalkman1-Mar-11 2:55
Patrick Kalkman1-Mar-11 2:55 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.