Request/Response Service Layer: Exposing The Service Layer Through WCF
Posted by Davy Brion on November 11th, 2009
Note: This post is part of a series. Be sure to read the introduction here.
The previous posts in the series already covered everything there is to know about implementing the Request/Response Service Layer (RRSL). In this post, we’ll focus on hosting the RRSL through WCF and the next posts will show you how you can actually use the RRSL from your clients (both synchronously and asynchronously). First, let’s take another look at what our service actually exposes:
public interface IRequestProcessor : IDisposable
{
Response[] Process(params Request[] requests);
}
This interface doesn’t contain the necessary WCF attributes, but we’ll get to that in a minute. The first thing that we need to take care of is to make sure that WCF’s DataContractSerializer can handle the derived Request and Response types without us having to declare the KnownType attribute on each derived class. Luckily for us, WCF has a ServiceKnownType attribute where you can define a class that will provide the KnownTypes to WCF so it can properly serialize and deserialize them. But first, we’ll need a KnownTypeProvider class:
public static class KnownTypeProvider
{
private static HashSet<Type> knownTypes = new HashSet<Type>();
public static void ClearAllKnownTypes()
{
knownTypes = new HashSet<Type>();
}
public static void Register<T>()
{
Register(typeof(T));
}
public static void Register(Type type)
{
knownTypes.Add(type);
}
public static void RegisterDerivedTypesOf<T>(Assembly assembly)
{
RegisterDerivedTypesOf(typeof(T), assembly);
}
public static void RegisterDerivedTypesOf<T>(IEnumerable<Type> types)
{
RegisterDerivedTypesOf(typeof(T), types);
}
public static void RegisterDerivedTypesOf(Type type, Assembly assembly)
{
RegisterDerivedTypesOf(type, assembly.GetTypes());
}
public static void RegisterDerivedTypesOf(Type type, IEnumerable<Type> types)
{
knownTypes.UnionWith(GetDerivedTypesOf(type, types));
}
public static IEnumerable<Type> GetKnownTypes(ICustomAttributeProvider provider)
{
return knownTypes;
}
private static List<Type> GetDerivedTypesOf(Type baseType, IEnumerable<Type> types)
{
return types.Where(t => !t.IsAbstract && t.IsSubclassOf(baseType)).ToList();
}
}
Now we just have to make sure that all of our Request and Response types are registered before the application is initialized. You basically need to make sure that the following code is called before the first request is sent to the service:
private static void RegisterRequestAndResponseTypes(Assembly assembly)
{
KnownTypeProvider.RegisterDerivedTypesOf<Request>(assembly);
KnownTypeProvider.RegisterDerivedTypesOf<Response>(assembly);
}
Now we can actually define our Service Contract. Instead of putting the WCF attributes on the IRequestProcessor interface, i decided to put a different interface next to it. The reason i chose to go that route is merely to make sure that the actual IRequestProcessor interface and it’s implementation isn’t tied to WCF. And that’s why we have the IWcfRequestProcessor interface:
[ServiceContract]
public interface IWcfRequestProcessor
{
[OperationContract(Name = "ProcessRequests")]
[ServiceKnownType("GetKnownTypes", typeof(KnownTypeProvider))]
Response[] Process(params Request[] requests);
}
This is a ‘properly’ defined WCF Service Contract, and we also make sure that WCF knows where to get the list of known types by using the ServiceKnownType attribute and hooking it to our KnownTypeProvider. The implementation of this service contract looks like this:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class WcfRequestProcessor : IWcfRequestProcessor
{
public Response[] Process(params Request[] requests)
{
return IoC.Container.Resolve<IRequestProcessor>().Process(requests);
}
}
As you can see, there’s nothing to it… The implementation of the Process method simply resolves the real IRequestProcessor implementation, calls the Process method and returns the Responses. That’s it.
Now we still need to host the service somewhere. I always host it through IIS but you can use any of the other WCF hosting options as well. In case you’re hosting it in a Web Application, add a RequestProcessorService.svc file to your Web Application with the following content:
<%@ ServiceHost Language="C#" Debug="true" Service="The.Namespace.Of.Your.WcfRequestProcessor" %>
In your web.config (or app.config if you’re hosting it yourself or through a windows service), add the following block:
<system.serviceModel>
<services>
<service name="The.Namespace.Of.Your.WcfRequestProcessor" behaviorConfiguration="RequestProcessorBehavior">
<endpoint address="" contract="The.Namespace.Of.Your.IWcfRequestProcessor"
binding="customBinding" bindingConfiguration="binaryHttpBinding"/>
</service>
</services>
<bindings>
<customBinding>
<binding name="binaryHttpBinding" receiveTimeout="00:30:00" sendTimeout="00:30:00" >
<binaryMessageEncoding>
<readerQuotas maxStringContentLength="2147483647" maxArrayLength="2147483647" />
</binaryMessageEncoding>
<httpTransport maxReceivedMessageSize="2147483647" maxBufferSize="2147483647" />
</binding>
</customBinding>
<basicHttpBinding>
<binding name="basicHttpBinding" receiveTimeout="00:30:00"
sendTimeout="00:30:00" maxReceivedMessageSize="2147483647">
<readerQuotas maxStringContentLength="2147483647" maxArrayLength="2147483647" />
<security mode="None" />
</binding>
</basicHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="RequestProcessorBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true"/>
<dataContractSerializer maxItemsInObjectGraph="2147483647"/>
<serviceThrottling maxConcurrentCalls="100" maxConcurrentInstances="100" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
I included two binding configurations in this example, but you obviously only need one. In this case, the service endpoint is configured to use the custom binaryHttpBinding. This uses binary XML which (in most cases) is more compact and thus, has less bandwidth overhead. If you want to use a regular basicHttpBinding, just modify the service endpoint configuration to point to the other binding. Obviously, you can use wsHttpBinding or any other binding as well if you want to.
And that is it. That’s really all you need to do to host the RRSL through WCF. You’ll never have to edit or add anything to the xml configuration as you add more functionality to your service layer. It works now, and it will keep working.
Just keep in mind that you need to register the Request and Response types with the KnownTypeProvider before the service receives the first request

November 11th, 2009 at 7:38 pm
So it doesn’t bother you to use the container as a global service locator?
November 12th, 2009 at 12:09 am
@Aaron
if that is the only place where it’s used like that, then why would i? what would be the difference between doing it yourself, or having some other kind of infrastructural library doing it for you?
if you were to do that all over the place, then yeah it would definitely bother me. But if it’s only in one place, in a piece of infrastructural code that you never need to change, then i really don’t think there’s any _real_ problem there.
November 12th, 2009 at 10:27 am
[...] Request/Response Service Layer: Exposing The Service Layer Through WCF – Davy Brion continues his series on the Request Response Service Layer with a look at putting his service layer out there via WCF, with plenty of illustrating code [...]
November 13th, 2009 at 6:47 pm
If I’m not mistaken, the known types must be registered before the ServiceHost is created because the GetKnownTypes is called from the CreateDescription method of the ServiceHost.
If the assemblies containing the requests and responses are shared between the client and the server, using the NetDataContractSerializer can help since known types must not be declared for operations.
But you need to tweak the serialization in the fault channel since it keeps using the DataContractSerializer to serialize FaultException
November 13th, 2009 at 11:10 pm
@ Luc
it might be… i thought that registering the know types before the first service request is received was enough… it might be because i primarily use it with IIS and maybe it creates the service host as late as possible or something (as in: when the first requests is received)
June 10th, 2010 at 6:18 pm
Thanks for the great article, I found it very useful. Just an FYI I modified your KnownTypeProvider class in this way
private static IEnumerable GetDerivedTypesOf(Type baseType, IEnumerable types)
{
//return types.Where(t => !t.IsAbstract && t.IsSubclassOf(baseType)).ToList();
return types.Where(t => !t.IsAbstract && baseType.IsAssignableFrom(t)).ToList();
}
This way I can send do something like
KnownTypeProvider(someAssembly);June 10th, 2010 at 6:19 pm
oops.. I meant
KnownTypeProvider.RegisterDerivedTypesOf(assembly);
June 10th, 2010 at 6:20 pm
KnownTypeProvider.RegisterDerivedTypesOf(assembly);
August 9th, 2010 at 11:16 pm
Hi,
I am learning WCF and read your series of articles.
i would like to create WCF service in which client can request with xml.
Server get that xml, parse it, validate it and then send them response.
In client xml there will be username,password and clientid that will differentiate the client with other client so server can easily recognize the client.
After that server send them back response in xml.
The server should be designed in a way that can handle multiple request and response to client.
How I can go about this by request/reply message.
Thanks
August 10th, 2010 at 10:09 am
@Kushal
why would you send xml yourself?
it’s far easier to just define request/response types with the properties of the data that needs to be included in your calls… WCF will serialize/deserialize to xml (well, soap actually) automatically for you
August 10th, 2010 at 4:18 pm
@Davy
Thank for the reply. To be honest I am new to WCF and not have experience in developing web service and wcf service.
You mean to say I just have to create object with the details i want to send, then wcf will automatically serialize/deserialize it to xml.