Blowing off the dust

Its been a very long time since I last blogged. Many things have happened over the last year or two that has stopped me from keeping my blog active and its decayed as a result ;-(. I had been freelancing just over a year ago and the long days and lots of travel got me out of the routine. Bundled up with family time, martial arts and my xbox, my blogging time become non-existent. But now, i have a bit more time in my life and i hope to get a few new fresh posts out. I have had requests for source code for some of my older posts and i can only say sorry as i haven’t kept the code so i can’t email it, sorry.

Advertisements

Using WCF Async pattern with Silverlight 3

Introduction

I haven’t blogged lately over the last 6 months. Main reason being Silverlight 3, I have been using most of my time consuming myself with Silverlight 3 and related technologies, plus working on to many projects and holding down a fulltime job. My focus is about developing line of business applications that involves communicating with distributed services rather than very pretty UIs. The obvious technology is WCF for communicated with backend services from silverlight (or any UI in the .net world).

One of the many golden rules with UI development is not lock up the UI while running long running processes and this includes communicated with backend services. Not locking the UI is nothing new, multi-threaded applications have been around for years and years. So what is this post about, its about using WCF asynchronously. Specifically with Silverlight, but the UI could be WPF (or winforms with some subtle differences).

The approach

Add service reference

The easier way to achieve asynchronous communication with WCF and Silverlight is to use “Add service reference” (ASR) in visual studio. Although this works and takes about a minute to do. The wizard generates a load of code for you, based on your service and data contracts, that you would be mad to modify it. If you are in control of the services then you might want to reuse the messages types. This is possible with the ASR. When you are prototyping/spiking ASR is a good choice. So what’s my issue:

  • Control, while building an application with WCF, silverlight i came to this point frequently where i needed to manipulate the data being fetched from a service before displaying in the UI.
  • TDD and IOC. both are very much part of me and while using TDD with IOC i have to go out of my way to support this with the generated code from IOC.
  • The code started to smell. I was wrapping the called to xxxClient generated for a service from ASR. It was not a pleasant smell.
  • When you look at the generated code and know WCF well enough, you realise that you have much more code then what is required. Its not big thing, but it increasing the size of the XAP file downloaded on the client.

Channel Factory

A simple object that is core to the client communication process. When you are in control of the services and UI its a best choice because to can reuse the same types. If you have never used the Channel factory, its a generic class that you use with your service contract (the interface) and you call a method called “CreateChannel” that returns you an instance of your service contract as a proxy. You can when call operations on the proxy like a regular object instance.

The Design goal

While I have been working on a project will Silverlight that communicates with backend services, I wanted to apply a pattern that i could use consistently for all communication with the services. All of my services followed the “Request/response” pattern and worked synchronously and i am perfectly happy to keep them this way.

From the silverlight end, i want to make a service request and receive the response without locking up the UI thread. Once I have the response back from the service, then I might place the results in the UI, so I needed to marshal this back on the UI thread.  In the past I have used the “AsyncCallback” delegate to accomplish this and I needed the same approach here. To add to my problem, i wanted to apply a pattern that does not involve writing loads of code, especially framework code.

The Async Pattern

In WCF, the operation contract attribute contains a boolean property called “AsyncPattern”. While looking into how to use this, i discovered that have to change your service contract to:

  • Return “IAsyncResult”.
  • Prefix the Operation with “Begin”
  • Add two additional parameters to the operation, being the callback (asyncCallback and state object)
  • Add another method to the interface that complies with the “AsyncCallback” delegate  with the same name as my operation but prefixed with “End” instead of “Begin” and does not have any WCF attributes.

My first thought to this was how would my service implementation change to suit this interface. I was put off my this, I liked my standard service contract that returned my specific Response object and took a specific Request object.

So my original interface:

    public interface ICompanyService
    {
        [OperationContract]
        FetchCompanyResponse GetAllCompanies();

        [OperationContract]
        FetchContactsResponse FetchContacts(FetchContactsRequest request);

        [OperationContract]
        SaveResponse Save(SaveCompanyRequest request);
    }

Would change to this:

    public interface ICompanyService
    {
        [OperationContract(AsyncPattern = true)]
        IAsyncResult BeginGetAllCompanies(AsyncCallback callback, object state);
        FetchCompanyResponse EndGetAllCompanies(IAsyncResult result);

        [OperationContract(AsyncPattern = true)]
        IAsyncResult BeginFetchContacts(FetchContactsRequest request, AsyncCallback callback, object state);
        FetchContactsResponse EndFetchContacts(IAsyncResult result);

        [OperationContract(AsyncPattern = true)]
        IAsyncResult BeginSave(SaveCompanyRequest request, AsyncCallback callback, object state);
        SaveResponse EndSave(IAsyncResult result);
    }

What was not clear to me and I never found out on the web was that I could keep my original service contract and service implementation as it was and create another interface local to silverlight that uses the async pattern. My WCF configuration (endpoint) was still configured to use my original contract.

Communicating with WCF from within Silverlight

So, interact with your service(s) from within silverlight, you use the channel factory. You use the async version of your service contract. The following code shows how interact with the service by creating a request object, constructing a call back method that handles the response to marshals the execution back to the UI thread.

    public class CompanyRepository : DependencyObject, ICompanyRepository
    {
        public ObservableCollection<Company> GetAllCompanies()
        {
            ObservableCollection<Company> companies = new ObservableCollection<Company>();

            ICompanyService companyService = GetCompanyService();

            AsyncCallback asyncCallback = (result =>
            {
                FetchCompanyResponse response = ((ICompanyService)result.AsyncState).EndGetAllCompanies(result);

                CompanyMapper mapper = new CompanyMapper();

                var query = from companyInfo in response.Companies
                            select mapper.MapTo(companyInfo);

                Action method = () => query.ToList().ForEach(x => companies.Add(x));

                Dispatcher.BeginInvoke(method);
            });

            companyService.BeginGetAllCompanies(asyncCallback, companyService);

            return companies;
        }

        public ObservableCollection<Contact> GetContactsByCompany(Company company)
        {
            if (company == null)
            {
                throw new ArgumentNullException("company");
            }

            ObservableCollection<Contact> contacts = new ObservableCollection<Contact>();

            ICompanyService companyService = GetCompanyService();

            AsyncCallback asyncCallback = (result =>
            {
                FetchContactsResponse response = ((ICompanyService)result.AsyncState).EndFetchContacts(result);

                ContactMapper mapper = new ContactMapper();

                Action method = () =>
                {
                    mapper.MapTo(response.Contacts).ForEach(x => contacts.Add(x));
                };

                Dispatcher.BeginInvoke(method);
            });

            FetchContactsRequest request = new FetchContactsRequest { CompanyId = company.Id };

            companyService.BeginFetchContacts(request, asyncCallback, companyService);

            return contacts;
        }

        public void Save(Company company)
        {
            if (company == null)
            {
                throw new ArgumentNullException("company");
            }

            ICompanyService companyService = GetCompanyService();

            AsyncCallback asyncCallback = (result =>
            {
                SaveResponse response = ((ICompanyService)result.AsyncState).EndSave(result);

                Action method = () =>
                {
                    if (response.WasSuccessful)
                    {
                        // Do whatever
                    }
                    else
                    {
                        // Show some validation message, etc etc. not relavant for this example
                    }
                };

                Dispatcher.BeginInvoke(method);
            });

            SaveCompanyRequest request = new SaveCompanyRequest
            {
                Company = new CompanyMapper().MapFrom(company)
            };

            companyService.BeginSave(request, asyncCallback, companyService);
        }

        private ICompanyService GetCompanyService()
        {
            return new ChannelFactory("SomeEndpointThatMatchsTheConfig").CreateChannel();
        }
    }

Its a little lambda-tastic, but you don’t have to use lambdas and could use methods instead (actually if my code grows, i might make the method a class instead with defined methods.. may a future post to follow up on). The Company, Contact, message types (request/response) and mapper objects aren’t relavant to this subject, so no need to show the code.

The pattern is the key issue, I get a proxy from the “GetCompanyService” method using the Channel factory. For the “Get” methods, I create return types (observable collections) and return them at the end of method. At runtime when the main method is called, the return type (observable collections) is new’ed up and returned to the calling code.

In my project, i using the MVVM pattern, so the the return type for these methods are exposed as a public properties on my viewmodel. My view is bound to be view model via xaml. So the view loads straight away, when the async call is complete the reference is changes on the return type and my view automatically shows the results.

The code between the return type declaration and the return statement is the callback code which is going to be executed when the service responds. The first thing that happens in the callback to the get the response object from the service call by calling the “End..” method using the asyncState property on the IAsyncResult interface which is what the variable “result” just happens to be. The asyncState property is returning the reference of the proxy that is passed in, in the “begin…” call. This is all part of the standard pattern when using Asynchronous callbacks.

Once I have the response from the service, although its not relevant to this, i map the results into types that are local to the silverlight application. Where i have a collection as the return type, i am adding my newly mapped object to the return type reference, inside another method. this little method is invoked by the “Dispatcher” object, which will execute the method on the UI thread. My class inherits from “DependencyObject” so that i can use the Dispatcher. My class also implements an interface which again isn’t relevant to this subject.

This works for me very well and i have many service calls happening at once with some of my rich/complex UI’s and (although in a dev environment) the performance is very good.