Retrieve IP and Port number of remote endpoint request sender

I wanted to track which IP addresses were sending requests to my WCF service. So I did some investigation and apparently it’s not so hard to retrieve this data. The RemoteEndpointMessageProperty class makes the client IP address and port number associated with the remote endpoint from which a message was sent available. Underneath is a snippet of code that will show how it works.

   1: public string TrackIP()
   2: {
   3:     OperationContext oc = OperationContext.Current;
   4:     MessageProperties mp = oc.IncomingMessageProperties;
   5:     RemoteEndpointMessageProperty remp = mp[RemoteEndpointMessageProperty.Name] as RemoteEndpointMessageProperty;
   6:  
   7:     return string.Format("Request sent from {0} and port is {1}", remp.Address, remp.Port);
   8: }

ProtocolException while transfering ArrayList to WCF service

Today I created a method in my WCF service that would process an ArrayList.
There was no possibility to pass a generic list due to interoperability reasons.

In this ArrayList I would place objects of a certain type. This would then be processed server side.

When calling this simple method my client threw a ProtocolException with the following message:

The formatter threw an exception while trying to deserialize the message: There was an error while trying to deserialize parameter http://tempuri.org/:handlingunits. The InnerException message was ‘Error in line 1 position 342. Element ‘http://schemas.microsoft.com/2003/10/Serialization/Arrays:anyType’ contains data of the ‘http://schemas.mshelp.com/HandlingUnit:HandlingUnit’ data contract. The deserializer has no knowledge of any type that maps to this contract. Add the type corresponding to ‘HandlingUnit’ to the list of known types – for example, by using the KnownTypeAttribute attribute or by adding it to the list of known types passed to DataContractSerializer.’.  Please see InnerException for more details.

The problem here is that WCF does not know how to serialize the type of the object that is contained within the ArrayList.
The solution to this is actually very simple, you just need to make the type known to your service.

You can do this by using the ServiceKnownType attribute. You need to place this above your service interface. This looks like this:

   1: [ServiceContract]
   2: [ServiceKnownType(typeof(HandlingUnit))]
   3: public interface IMyWCFService
   4: {
   5:     //Your operations
   6: }

How to configure a WCF proxy to return a generic list

In this post I will explain to you how you can configure your WCF proxy client to return a generic list as a collection type instead of an array. When you specify in your service contract that an operation should return a generic list, WCF will by default send your collection over the wire as an array.

If WCF sends this to the client you will lose the point of trying to pass a generic collection to your client. So let’s say you have the following operation:

   1: [OperationContract]
   2: ICollection<Material> GetMaterials(string warehouseCode);

Now if you are going to consume the service and try to call the method that we just created you will see that you will not receive your generic collection. Instead you will just receive an array of Materials.

image

You can actually let the WCF service return all sort of collection types, it’s just a matter of configuration. So let’s properly configure it!

Right mouse click on the service reference that we created and select “Configure Service Reference”. Here you will immediately see that you can specify something for the Collection type and the Directory collection type. That’s right…here we can set the correct collection type that the service should return. The directory collection type can also be set here. Let’s configure it to return a generic list.

image

Now when you hover over the function call, you will see the following:

image

If you want to use the svcutil.exe to generate your proxy class, you need to use the /collectionType (/ct) switch to specify the correct collection.

For more details check out the ServiceModel MetaData Utility Tool on MSDN library

Serializing and deserializing multiple generic collections using DataContractSerializer

The DataContractSerializer class is the successor of the XmlSerializer class. Introduced together with WCF. This one is also being used by WCF for serialization by default. You can of course always switch back to the good old XmlSerializer if you want to.

Anyway, if you wanted to serialize a collection with the XmlSerializer you had to use the XmlArrayAttribute

With the DataContractSerializer you get the CollectionDataContractAttribute class. Personally, I think that serializing a generic list via the DataContractSerializer is easier then with the XmlSerializer. Even with the DataContractSerializer I think they could have done it easier. You’ll see what I mean in a minute.

Let’s look at some code.

The example

The example will be a simple to-do list. You can specify a name, a due data and multiple tags.

Creating the necessary classes

   1: [DataContract(Name = "TodoList", Namespace = "http://www.mshelp.be")]

   2: public class TodoList

   3: {

   4:     [DataMember(Name = "Todos")]

   5:     public InternalTodoList Todo { get; set; }

   6:     public TodoList()

   7:     {

   8:         Todo = new InternalTodoList();

   9:     }

  10: }

  11: [DataContract(Name = "Todo")]

  12: public class Todo

  13: {

  14:     public Todo()

  15:     {

  16:         Name = String.Empty;

  17:         DueDate = DateTime.Now;

  18:         Tags = new TagList();

  19:     }

  20:     [DataMember(Name = "Name")]

  21:     public string Name { get; set; }

  22:     [DataMember(Name = "DueDate")]

  23:     public DateTime DueDate { get; set; }

  24:     [DataMember(Name = "Tags")]

  25:     public TagList Tags { get; set; }

  26: }

  27: [CollectionDataContract(ItemName = "Tag")]

  28: public class TagList : List<string> { }

  29:  

  30: [CollectionDataContract(ItemName = "Todo")]

  31: public class InternalTodoList : List<Todo> { }

The class TodoList will contain all the different todo’s and the Todo class contains the properties we already discussed. As you can see I also have two other classes. The TagList and the InternalTodoList, both marked with the CollectionDataContract attribute. You also see that these classes contain the generic lists. I did this because you can only add the CollectionDataContract attribute to a class or struct.

How to Serialize

As you can see I use the XmlDictionaryWriter class, which was also introduced with .NET 3.0.

   1: static void SerializeTodoList()

   2: {

   3:     var dcs = new DataContractSerializer(typeof(TodoList));

   4:     var ds = new FileStream(@"c:\MyTodoList.xml",FileMode.Create);

   5:     var xdw = XmlDictionaryWriter.CreateTextWriter(ds, Encoding.UTF8);

   6:     dcs.WriteObject(xdw, _myTodoList);

   7:     xdw.Flush();

   8:     someStream.Flush();

   9: }

How to Deserialize

For the desrialization we’ll use the XmlDictionaryReader class together with the DataContractSerializer.

   1: static void DeserializeTodoList()

   2: {

   3:     var dcs = new DataContractSerializer(typeof(TodoList));

   4:     var ds = new FileStream(@"c:\MyTodoList.xml", FileMode.Open);

   5:     var xdr = XmlDictionaryReader.CreateTextReader(ds, new XmlDictionaryReaderQuotas());

   6:     _myTodoList = (TodoList)dcs.ReadObject(xdr);

   7: }

Testing the code

Now for a simple test, let’s add some to-do’s. Don’t forget to define the _myTodoList, which is of course an instance of the TodoList class.

   1: static void InitTodoList()

   2: {

   3:     _myTodoList = new TodoList();

   4:     var todo1 = new Todo {Name = "Fix some issues"};

   5:     var tlist1 = new TagList {"fix", "issues"};

   6:     todo1.Tags = tlist1;

   7:     _myTodoList.Todo.Add(todo1);

   8:  

   9:     var todo2 = new Todo {Name = "Fix stuff"};

  10:     var tlist2 = new TagList {"fix", "stuff"};

  11:     todo2.Tags = tlist2;

  12:     _myTodoList.Todo.Add(todo2);

  13: }

The aforementioned code will generate the following XML.

   1: <TodoList xmlns="http://www.mshelp.be" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">

   2: <Todos xmlns:a="http://schemas.datacontract.org/2004/07/CollectionDataContractAtt">

   3: <a:Todo>

   4: <a:DueDate>2009-06-20T15:19:57.196+02:00</a:DueDate> 

   5: <a:Name>Fix some issues</a:Name> 

   6: <a:Tags>

   7: <a:Tag>fix</a:Tag> 

   8: <a:Tag>issues</a:Tag> 

   9: </a:Tags>

  10: </a:Todo>

  11: <a:Todo>

  12: <a:DueDate>2009-06-20T15:19:57.201+02:00</a:DueDate> 

  13: <a:Name>Fix stuff</a:Name> 

  14: <a:Tags>

  15: <a:Tag>fix</a:Tag> 

  16: <a:Tag>stuff</a:Tag> 

  17: </a:Tags>

  18: </a:Todo>

  19: </Todos>

  20: </TodoList>

Hope this post was informative and if you have comments, remarks. Please let me know, any constructive feedback is welcome.

kick it on DotNetKicks.com Shout it Progg itvote it on WebDevVote.com

How to host a WCF service that uses Castle Windsor in a Windows Service

Setup

Currently I’m working on a web application project that also uses a WCF service for some operations. We are a big fan of using ALT.NET and are using Castle Windsor to do IoC (Inversion of Control)/Dependency Injection. The problem we were having was the small delay to start up the worker process in IIS. Which is not much you can do about within IIS. (As far as I know) Except for maybe making a wake up service that calls a simple method every x minutes. Just to keep the worker process alive.

If you don’t want to wake up the IIS worker process you can always host your WCF service in a managed application, a windows service for instance. This is something that is always running (if it automatically starts and is not stopped manually of course).

Castle Windsor

I’m not going to go into the details on why you should use Castle Windsor. Maybe another post. The main goal of this post is to get the WCF service that uses Castle Windsor hosted within the Windows Service. You’re maybe wondering..is this then so complex? Well it can give some problems. You will find many posts on the Internet concerning this matter. However many of these posts focus on hosting the WCF Service in IIS.

What I’m not going to discuss

Like I’m not going to go into the details of Windsor, I’m also not going to say how you create a WCF service or how you create a Windows Service. MSDN Library is a very handy resource for this.

Make Windsor work

To make Castle Windsor work you’ll need to do several things:

  • Reference the necessary libraries
  • Create a windsor.config or windsor.boo file (or both)
  • Create a windsor container
    • Add a facility
    • Load the config file
    • Register the container

One thing I’m going to say is that the Castle project has done a lot of effort into making it all work out. To make WCF and Windsor play nice together you have to use Castle.Facilities.WcfIntegration. This contains a factory for hosting the service, namely the ServiceHostFactory.

The difference between IIS and a managed application

The difference isn’t really all that big..you just have to do the proper config and make sure you do all the aforementioned prep work like you would do it when hosting the service via IIS.

When you would host the WCF service in IIS, you would do all the prep work in the global.asax. You don’t have this in a Windows Service or a console application. So just do this somewhere else. I’m not saying hosting the WCF service in IIS is bad..it has it’s advantages.

Let’s put this into practice

1) Reference the necessary libraries:

   1: using System;
   2: using Castle.Facilities.WcfIntegration;
   3: using Castle.Windsor;
   4: using Castle.Windsor.Installer;
   5: using Rhino.Commons;

2) Create a windsor.config or windsor.boo file (or both)

   1: <?xml version="1.0" encoding="utf-8" ?>
   2: <configuration>
   3:   <components>
   4:     <component id="MyWCFService"
   5:                    service="WCFServices.IMyWCFService, WCFServices"
   6:            type="WCFServices.MyWCFService, WCFServices">
   7:     </component>
   8:   </components>
   9: </configuration>

3) Create and register the WindsorContainer (IWindsorContainer). Normally you would do this in the global.asax. Now you need to define a method where you will do this part.

Now I’ll create a method that will create and register the necessary container. This method looks like this:

Declare a public WindsorContainer:

   1: IWindsorContainer Container { get; private set; }

Create the method, PrepWindsor (This will be called in our main method):

   1: Container = new WindsorContainer()
   2:       .AddFacility<WcfFacility>()
   3:       .Install(Configuration.FromXmlFile("Windsor.config"));
   4:  
   5: DefaultServiceHostFactory.RegisterContainer(Container.Kernel);

Now we have done all of the prepwork for Windsor. Now let’s create the ServiceHost. We will use the following class for this: Castle.Facilities.WcfIntegration.DefaultServiceHostFactory

   1: PrepWindsor();
   2:             
   3: using(var host = new Castle.Facilities.WcfIntegration.DefaultServiceHostFactory().CreateServiceHost(typeof(WCFServices.IMyWCFService).AssemblyQualifiedName,new Uri[0]))
   4: {
   5:      host.Open();
   6: }

As you can see I don’t create any endpoints programmatically. This happens via a config file that I have added. My App.config looks like this:

   1: <?xml version="1.0" encoding="utf-8" ?>
   2: <configuration>
   3:   <system.serviceModel>
   4:     <behaviors>
   5:       <serviceBehaviors>
   6:         <behavior name="WCFServices.WCFServiceBehavior">
   7:           <serviceMetadata httpGetEnabled="true" />
   8:           <serviceDebug includeExceptionDetailInFaults="true" />
   9:         </behavior>
  10:       </serviceBehaviors>
  11:     </behaviors>
  12:     <services>
  13:           <service behaviorConfiguration="WCFServices.WCFServiceBehavior"
  14:         name="WCFServices.MyWCFService">
  15:         <endpoint address="WCFServices" binding="basicHttpBinding" contract="WCFServices.IMyWCFService">
  16:           <identity>
  17:             <dns value="localhost" />
  18:           </identity>
  19:         </endpoint>
  20:         <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
  21:         <host>
  22:           <baseAddresses>
  23:             <add baseAddress="http://localhost:8000/" />
  24:           </baseAddresses>
  25:         </host>
  26:       </service>
  27:     </services>
  28:   </system.serviceModel>
  29: </configuration>

Ok that should be it! Now you should be able to properly host the service in the managed application.

I would love to hear some feedback or if you have questions/remarks, please let me know.

kick it on DotNetKicks.com Shout it Progg it vote it on WebDevVote.com