Using a Channel Factory in Silverlight (instead of adding a Service Reference). With cows.

cow_clipartFor a lot of application scenarios, adding a service reference to easily access a service from Silverlight is the way it’s done (note: I’m not going to get into a discussion on whether this is good or evil, I’m just stating a fact ;-)) – you don’t have to worry too much about proxy creation, for example, that’s done for you.  However, in quite a few scenarios, this approach isn’t feasible: if you’re writing a framework, you typically don’t want service references in your Silverlight class libraries.  If you want to make your app pluggable or extendable – for example: through a provider pattern – you might want to create channels conforming to a contract and call the methods as such.  Or you might just not like the generated code you get when adding a service reference.

 

Well, you can avoid using service references by working with a Channel Factory.  Included with this post is a small application which calls a service method, using a Channel Factory, to populate a list of cows.  What?   Cows.

 

 

Disclaimer: I’m not exactly sure who’s blog it was that contained sample code with cow entities, but I kinda liked the idea (at least it’s a nice change from the typical AdventureWorks entities :)). 

 

By the way, did you know a cow only becomes a cow once it starts giving milk?  Which farmers make sure they do by impregnating them regularly (or, to be more precise: they let bulls take care of that part for them :))?  I actually thought that was quite cruel when I found out.  Anyway, enough of this bucolic intermezzo, on to the code 😉

 

This is what the application looks like:

 

slchannelfactorywithcows

 

The service itself is pretty straightforward: a standard WCF service, using basicHttpBinding, implementing the ICowService interface, containing one operation: GetCow(), returning a Cow entity.

 

namespace ChannelFactoryWithCows.Contracts
{
    [ServiceContract(Name = "ICowService")]
    public interface ICowService
    {
        [OperationContract]
        Cow GetCow();
    }
}

 

Now, what do we need to create a channel?  We need to know the binding – check.  We need to know the endpoint address – check.  And we need to know the contract – and this is where the fun starts.  We can’t just create a channel of type ICowService, as this is a sync contract, and as you know: service calls in Silverlight are async.  What we need to do is create a client side contract with async methods matching the GetCow() method.  The contract thus looks as follows:

 

namespace ChannelFactoryWithCows.Contracts
{
    [ServiceContract(Name = "ICowService")]
    public interface ICowService
    {
        [OperationContract(AsyncPattern = true)]
        IAsyncResult BeginGetCow(AsyncCallback callback, Object state);

        Cow EndGetCow(IAsyncResult result);
    }
}

 

BeginGetCow and EndGetCow are the matching async methods for GetCow(), and by providing the ServiceContract attribute with the name ICowService, we effectively match ICowServiceClient with ICowService: we can create a channel of type ICowServiceClient which matches a service implementing ICowService, and call the appropriate methods on it!

 

As we’re going to use a Channel Factory, there’s no automatic proxy generation, so we need to have a Cow class in the Silverlight application.  The important thing to notice about this class is that it must match the Cow class on the server side – this is necessary, as .NET doesn’t know how to cast a “MyApp.Web.Cow” object to a “MyApp.Cow” object.  There are various ways to solve this: one way would be to write code to allow implicit casting, another way would be to create the class on both client and server and have them reside in the same namespace.  In this example, I took another approach: I created a Silverlight class library containing the Cow class, which is referenced by both the Silverlight app and the Web app – this immediately shows off a SL4/.NET 4 feature: you can reference SL assemblies in projects using the full .NET framework.

 

What’s left is effectively creating the channel and calling the service method in an async way.  This is not different than regular async programming, as you can see below:

 

private ICowService GetCowServiceFactoryChannel()
{
    // create ChannelFactory?
    if ((CowServiceChannelFactory == null)
        || (CowServiceChannelFactory.State == CommunicationState.Faulted))
    {
        BasicHttpBinding basicHttpBinding = new BasicHttpBinding();

        EndpointAddress endpointAddress = 
new EndpointAddress(CowServiceEndpointAddress); CowServiceChannelFactory =
new ChannelFactory<ICowService>(basicHttpBinding, endpointAddress); } // create channel? if (CowServiceFactoryChannel == null) { CowServiceFactoryChannel = CowServiceChannelFactory.CreateChannel(); } return CowServiceFactoryChannel; }
private void GetCowExecution()
{
    // call CowService WCF service
    ICowService channel = GetCowServiceFactoryChannel();

    var y = channel.BeginGetCow(
       (asyncResult) =>
       {
           // get Cow
           var returnVal = channel.EndGetCow(asyncResult);

           Deployment.Current.Dispatcher.BeginInvoke(() =>
               {
                   // add to collection
                   Cows.Add(returnVal);
               });
       }
       , null);
}

 

Just one more thing: as you can see, I’m calling Dispatcher.BeginInvoke in the callback method.  This is necessary because we’re accessing the UI thread; omitting this will result in an invalid cross thread access exception.

 

And with that’, we’re done! Using this method, you can write highly reusable code: just pass in a matching endpoint, and your code will work.  Next to that, any service implementing your contract can be used, so you could easily create, for example, a mocking service.  Happy coding! :)

 Tweet about this on TwitterShare on LinkedInShare on Facebook