Consume WCF Service InProcess using Agatha and WCF
- by REA_ANDREW
I have been looking into this lately for a specific reason. Some integration tests I want to write I want to control the types of instances which are used inside the service layer but I want that control from the test class instance. One of the problems with just referencing the service is that a lot of the time this will by default be done inside a different process. I am using StructureMap as my DI of choice and one of the tools which I am using inline with RhinoMocks is StructureMap.AutoMocking. With StructureMap the main entry point is the ObjectFactory. This will be process specific so if I decide that the I want a certain instance of a type to be used inside the ServiceLayer I cannot configure the ObjectFactory from my test class as that will only apply to the process which it belongs to. This is were I started thinking about two things: Running a WCF in process Being able to share mocked instances across processes A colleague in work pointed me to a project which is for the latter but I thought that it would be a better solution if I could run the WCF Service in process. One of the projects which I use when I think about WCF Services is AGATHA, and the one which I have to used to try and get my head around doing this. Another asset I have is a book called Programming WCF Services by Juval Lowy and if you have not heard of it or read it I would definately recommend it. One of the many topics that is inside this book is the type of configuration you need to communicate with a service in the same process, and it turns out to be quite simple from a config point of view. <system.serviceModel>
<services>
<service name="Agatha.ServiceLayer.WCF.WcfRequestProcessor">
<endpoint
address ="net.pipe://localhost/MyPipe"
binding="netNamedPipeBinding"
contract="Agatha.Common.WCF.IWcfRequestProcessor"/>
</service>
</services>
<client>
<endpoint name="MyEndpoint"
address="net.pipe://localhost/MyPipe"
binding="netNamedPipeBinding"
contract="Agatha.Common.WCF.IWcfRequestProcessor"/>
</client>
</system.serviceModel>
You can see here that I am referencing the Agatha object and contract here, but also that my binding and the address is something called Named Pipes. THis is sort of the “Magic” which makes it happen in the same process.
Next I need to open the service prior to calling the methods on a proxy which I also need. My initial attempt at the proxy did not use any Agatha specific coding and one of the pains I found was that you obviously need to give your proxy the known types which the serializer can be aware of. So we need to add to the known types of the proxy programmatically. I came across the following blog post which showed me how easy it was http://bloggingabout.net/blogs/vagif/archive/2009/05/18/how-to-programmatically-define-known-types-in-wcf.aspx.
First Pass
So with this in mind, and inside a console app this was my first pass at consuming a service in process. First here is the proxy which I made making use of the Agatha IWcfRequestProcessor contract.
public class InProcProxy : ClientBase<Agatha.Common.WCF.IWcfRequestProcessor>, Agatha.Common.WCF.IWcfRequestProcessor
{
public InProcProxy()
{ }
public InProcProxy(string configurationName)
: base(configurationName)
{ }
public Agatha.Common.Response[] Process(params Agatha.Common.Request[] requests)
{
return Channel.Process(requests);
}
public void ProcessOneWayRequests(params Agatha.Common.OneWayRequest[] requests)
{
Channel.ProcessOneWayRequests(requests);
}
}
So with the proxy in place I could then use this after opening the service so here is the code which I use inside the console app make the request.
static void Main(string[] args)
{
ComponentRegistration.Register();
ServiceHost serviceHost = new ServiceHost(typeof(Agatha.ServiceLayer.WCF.WcfRequestProcessor));
serviceHost.Open();
Console.WriteLine("Service is running....");
using (var proxy = new InProcProxy())
{
foreach (var operation in proxy.Endpoint.Contract.Operations)
{
foreach (var t in KnownTypeProvider.GetKnownTypes(null))
{
operation.KnownTypes.Add(t);
}
}
var request = new GetProductsRequest();
var responses = proxy.Process(new[] { request });
var response = (GetProductsResponse)responses[0];
Console.WriteLine("{0} Products have been retrieved", response.Products.Count);
}
serviceHost.Close();
Console.WriteLine("Finished");
Console.ReadLine();
}
So what I used here is the KnownTypeProvider of Agatha to easily get all the types I need for the service/proxy and add them to the proxy. My Request handler for this was just a test one which always returned 2 products.
public class GetProductsHandler : RequestHandler<GetProductsRequest,GetProductsResponse>
{
public override Agatha.Common.Response Handle(GetProductsRequest request)
{
return new GetProductsResponse
{
Products = new List<ProductDto>
{
new ProductDto{},
new ProductDto{}
}
};
}
}
Second Pass
Now after I did this I started reading up some more on some resources including more by Davy Brion and others on Agatha. Now it turns out that the work I did above to create a derived class of the ClientBase implementing Agatha.Common.WCF.IWcfRequestProcessor was not necessary due to a nice class which is present inside the Agatha code base, RequestProcessorProxy which takes care of this for you! :-)
So disregarding that class I made for the proxy and changing my code to use it I am now left with the following:
static void Main(string[] args)
{
ComponentRegistration.Register();
ServiceHost serviceHost = new ServiceHost(typeof(Agatha.ServiceLayer.WCF.WcfRequestProcessor));
serviceHost.Open();
Console.WriteLine("Service is running....");
using (var proxy = new RequestProcessorProxy())
{
var request = new GetProductsRequest();
var responses = proxy.Process(new[] { request });
var response = (GetProductsResponse)responses[0];
Console.WriteLine("{0} Products have been retrieved", response.Products.Count);
}
serviceHost.Close();
Console.WriteLine("Finished");
Console.ReadLine();
}
Cheers for now,
Andy
References
Agatha WCF InProcess Without WCF
StructureMap.AutoMocking
Cross Process Mocking
Agatha
Programming WCF Services by Juval Lowy