Convention-based IOC is great … if everyone follows the conventions

Recently I started using Ninject for Inversion Of Control (IOC) and Dependency Injection (DI) on an ASP.Net MVC3 project.  Ninject is a very neat framework and is easy to use BTW and its offers some slick MVC3 integration through the Ninject.Web.Mvc project.

Being a proponent of convention-over-configuration, I also looked for some auto-registration code for Ninject and soon found the Ninject.Extensions.Conventions project.  The default convention here also suits me, since it binds IFooService to FooService in transient scope. Using the Scan extension method, I could now have the following code to initialise my IOC:

kernel.Scan(scanner =>
{
    scanner.FromAssemblyContaining<ProjectRepository>();
    scanner.BindWith<DefaultBindingGenerator>();
});

So far, so good, I thought, and now to apply IOC to my WCF services, which are hosted within the MVC web project (important point!).  Once again, Ninject has an answer, in the form of the Ninject.Extensions.Wcf project.  This project offers a custom ServiceHostFactory that will apply IOC to your service implementation simply by adding the Factory attribute in your .svc file:

<%@ ServiceHost Language="C#" 
                Debug="true" 
                Service="SharpFellows.ScrumToolkit.Web.Services.Authentication" 
                CodeBehind="Authentication.svc.cs" 
                Factory="Ninject.Extensions.Wcf.NinjectServiceHostFactory" %>

Very nice … except that it didn’t work (yet).  This didn’t surprise me much at this stage because both Ninject.Web.Mvc and Ninject.Extensions.Wcf define a custom HttpApplication class and both libraries expect you to derive from this in your global.asax.cs class.  I opted to keep the class for Mvc and patch in the functionality required by the class for Wcf.  [As an aside, this is only possible because of the nature of open source software – hurray for open source]  So here was my first attempt:

kernel.Scan(scanner =>
{
    scanner.FromAssemblyContaining<ProjectRepository>();
    // Ninject.Extensions.Wcf uses some binding internally
    scanner.FromAssemblyContaining<NinjectServiceHostFactory>();
    scanner.BindWith<DefaultBindingGenerator>();
});
// Ninject.Extensions.Wcf expects to find the kernel here
KernelContainer.Kernel = kernel;

Looking good … except that it still didn’t work.  Requests to the WCF service were now all met with this:

The service type provided could not be loaded as a service because it does not have a default (parameter-less) constructor. To fix the problem, add a default constructor to the type, or pass an instance of the type to the host.

After much head-scratching, it turns out that the IOC binding done internally by the Ninject.Extensions.Wcf project is to bind ServiceHost to NinjectServiceHost and this binding does not follow the default conventions laid down by Ninject.Extensions.Convention!  Obvious really, once you understand the conventions and look at the required binding.  So now the fix was pretty simple:

// Conventions pick up most of our IOC bindings  :-)
kernel.Scan(scanner =>
{
    scanner.FromAssemblyContaining<ProjectRepository>();
    scanner.BindWith<DefaultBindingGenerator>();
});

// This binding doesn't follow the convention  :-/
kernel.Bind<ServiceHost>().To<NinjectServiceHost>();

// Ninject.Extensions.Wcf expects to find the kernel here
KernelContainer.Kernel = kernel;

And now everything worked smoothly.  Smile

The moral of the story?  It is possible to get MVC controllers and WCF service classes controlled by the same Ninject kernel.  And if you use conventions, don’t assume that all libraries can and do use them!

June 2 2011

WCF, RouteTables and Castle Windsor

 

We are using the routing functionality to give our RESTful WCF service nice endpoints, however I ran into trouble, none of our services were being injected.

The service had two constructors which seemed odd, an empty one and one with dependencies specified…

public Api()
{
}

public Api(IBasket basketService)
{
    _basketService = basketService;
}

The injected services were NULL, so I removed the public constructor and got:

image

This sounds like the default WCF factory at work, checking the SVC files we get:

<%@ ServiceHost 
    Language="C#" 
    Factory="Castle.Facilities.WcfIntegration.DefaultServiceHostFactory, Castle.Facilities.WcfIntegration" 
    Service="MyProject.Api" 
%>   

That’s also configured correctly, but we have overridden the default routing, let’s take a look at that:

RouteTable.Routes.Add(new ServiceRoute("Api", new ServiceHostFactory(), typeof(Api)));

That looks like the default WCF factory to me… Doh! Let’s fix that up…

RouteTable.Routes.Add(new ServiceRoute("Api", new DefaultServiceHostFactory(container.Kernel), typeof(IApi)));

Great, we are now using the windsor factory, and we can remove the default parameter-less constructor from our API service.

Silverlight duplex communication, part 1

Somebody recently asked me about duplex communications with Silverlight clients (i.e. pushing data out to the client application) and it made me realise that I needed to brush up on some of the basic detail. So I put together a little learning project, and it's something I'd like to share.

Note this has been built with the RC of VS 2010 and SL 4.0.

Network Communications in Silverlight

Mike Taulty has put together a great series of Channel 9 videos where he does a whistle-stop tour of the various network options available within SL 4. Simply put, the main ones are:

  • WCF over HTTP
  • WCF over TCP
  • TCP sockets
  • UDP sockets
  • WebRequest over HTTP

My application will use the two WCF options to implement a real-time chat application, although currently only the duplex HTTP binding is implemented.  Here is a screenshot of it in action, showing two browser windows communicating in real-time:

 image

Architecture of my Sample Application

The Silverlight portion of the application is pretty simple and uses the NavigationFrame (introduced in SL 3) and if you've played with the Silverlight Navigation Application template then you should be fairly familiar with the project layout. The important view is PollingDuplexHttpClient.xaml.

When using the MVVM pattern (which I am) there are a number of ways of hooking the ViewModel into the view (reference). I'm using a simple XAML-based approach to set the DataContext of the Page to the ViewModel:

   1: <navigation:Page.DataContext>
   2:   <app:DuplexHttpClientViewModel />
   3: </navigation:Page.DataContext>

The ViewModel class itself derives from an abstract base class DuplexChatClientViewModelBase. The sole purpose of the concrete ViewModel classes is to specify the actual WCF binding to use (net.tcp or http). And the primary purpose of the base ViewModel class is to co-ordinate the services which do the real work.

There’s a couple of aspects to the application which I think are interesting.  I hope to be posting some further detail on these in future.

Doing the Duplex Communication

The WCF communication is handled in the asynchronous manner typical of Silverlight, and is contained in the PushDataReceiver class.  There are four separate chains of execution in this class:

  • EnsureStarted –> OnOpenCompleteFactory –> CompleteOpenFactory –> OnOpenCompleteChannel –> CompleteOpenChannel
  • Send –> OnSendComplete –> CompleteSend
  • Receive –> OnReceiveComplete –> CompleteReceive
  • Close –> OnCloseComplete –> CompleteClose

Obviously the first and last of these are only called once, whereas the Send and Receive chains are more frequently executed.  The sending operation does not need much explanation:

   1: public void Send(Message message)
   2: {
   3:     IAsyncResult resultChannel = channel.BeginSend(message, new AsyncCallback(OnSend), channel);
   4:  
   5:     if (resultChannel.CompletedSynchronously)
   6:         CompleteOnSend(resultChannel);
   7: }
   8:  
   9: private void OnSend(IAsyncResult result)
  10: {
  11:     if (result.CompletedSynchronously) return;
  12:     CompleteOnSend(result);
  13: }
  14:  
  15: private void CompleteOnSend(IAsyncResult result)
  16: {
  17:     var sendingChannel = (IDuplexSessionChannel) result.AsyncState;
  18:     sendingChannel.EndSend(result);
  19: }

The receiving operation is similar in structure, with the exception that it is recursive and it needs to actually do something with the incoming message.  It is first initiated by the CompleteOpenChannel method

   1: private void ReceiveLoop(IDuplexSessionChannel receivingChannel)
   2: {
   3:     if (receivingChannel.State == CommunicationState.Opened)
   4:     {
   5:         IAsyncResult result = receivingChannel.BeginReceive(new AsyncCallback(OnReceiveComplete), receivingChannel);
   6:         if (result.CompletedSynchronously) CompleteReceive(result);
   7:     }
   8: }
   9:  
  10: private void OnReceiveComplete(IAsyncResult result)
  11: {
  12:     if (result.CompletedSynchronously) return;
  13:     CompleteReceive(result);
  14: }
  15:  
  16: private void CompleteReceive(IAsyncResult result)
  17: {
  18:     var receivingChannel = (IDuplexSessionChannel) result.AsyncState;
  19:  
  20:     Message receivedMessage = receivingChannel.EndReceive(result);
  21:  
  22:     if (receivedMessage != null)
  23:         uiThread.Post(ServiceLocator.Processor.ProcessData, receivedMessage); // Run on UI Thread.
  24:     ReceiveLoop(receivingChannel);
  25: }

Line 33 in the above code snippet is where the recursion happens to ensure that we always wait for incoming data.  Please note that exception handling code has been omitted here for the sake of clarity … it is present in the code download!  ;-)

Now all this seems very clear and straightforward, except for the fact that the server has no way of knowing that we are actually listening.  And this is why the service exposes an InitiateDuplex method.  From the CompleteOpenChannel method, we call Send against this service method.  It is this method which obtains a reference to the back channel to the SilverLight client.

I plan to run some deeper analysis into what’s actually happening on the wire.  Check back here soon for some details.

The WCF Service

There’s some surprising stuff going on in the service implementation here - a timer to keep channels alive, recording of IP addresses and timestamps, etc – but the most important bits are in the service contract (which is attributed to have a CallbackContract) and the InitiateDuplex method.  Here the code is building up a list of clients that will be sent any incoming message:

   1: public void InitiateDuplex(Message receivedMessage)
   2: {
   3:     lock (clients)
   4:     {
   5:         localClient = OperationContext.Current.GetCallbackChannel<IChatRoomClient>();
   6:         clients.Add(localClient);
   7:     }
   8: }

The code which uses the list of back channels is the DispatchToClientsmethod, which gets called whenever a client pushes a message to the SendMessage service method:

   1: private void DispatchToClients(ChatData data)
   2: {
   3:     var clientsToRemove = new List<IChatRoomClient>();
   4:     lock (clients)
   5:     {
   6:         foreach (IChatRoomClient client in clients)
   7:         {
   8:             try
   9:             {
  10:                 //Send data to the client
  11:                 if (client != null)
  12:                 {
  13:                     Message chatMsg = Message.CreateMessage(MessageVersion.Soap12WSAddressing10,
  14:                                                             "Silverlight/IChatRoomService/Receive",
  15:                                                             data,
  16:                                                             serializer);
  17:  
  18:                     chatMsg.Headers.Add(MessageHeader.CreateHeader("Type", "", "DataWrapper"));
  19:                     client.BeginReceive(chatMsg, EndSend, client);
  20:                 }
  21:             }
  22:             catch (Exception)
  23:             {
  24:                 // Exception caught when trying to send message to client so remove them from client list.
  25:                 clientsToRemove.Add(client);
  26:             }
  27:         }
  28:  
  29:         foreach (IChatRoomClient client in clientsToRemove)
  30:         {
  31:             clients.Remove(client);
  32:         }
  33:     }
  34: }

FYI a lot of this code comes fairly directly from Dan Wahlin’s post about duplex communications.

Caveat: the server delivers message to the listed clients one-by-one.  This means that delivery will slow down with the number of connected clients.

Getting Running

If you want to get this running on your machine you will need Visual Studio 2010 RC.  The steps you need to follow are pretty simple to enable HTTP communications:

  • Download the code
  • Build everything in Visual Studio and hit F5 to start the SilverlightTestBed.Web project and the WCF service.

Future Posts

I plan to post a few more articles about this application:

  • Analysing HTTP traffic and communication patterns
  • Enabling net.tcp communication
  • Analysing what that looks like on the wire
  • Refactoring the code to use Rx (Reactive Extensions for .Net)
April 13 2010

WCF Bindings, Security and Bandwidth Utilisation

Good things come to those who measure! I have been recently asked to investigate ways to reduce bandwidth utilisation of a WCF service and thought that it would not be a bad idea to share the results. The test was a relatively simple method call (search operation) performed on the client which would return ~500 objects from the server side. I tested the app using various WCF bindings and the table below contains the sizes of the payloads for the bindings I have tested. (the results have been obtained using Wireshark):

Binding

Payload size (bytes)

Relative size

WS HTTP with message security

2747082

100%

NET-TCP with message security

2068024

75%

NET-TCP with transport level security and encryption

393205

14%

NET-TCP with transport level security and no encryption

392948

14%

Your mileage will obviously vary, this example however illustrates that you can get substantial reduction of payload sizes by changing a couple of configuration files. This is what I call a result! :)

November 13 2009
Newer Posts Older Posts