Posts Tagged ‘ Asynchronous ’

MVVM Enabling Database Driven Silverlight Applications

One of the more exciting projects we are working on here at Affirma is a line-of-business solution for a client that includes talking to a SQL Server backend.  This was a great opportunity to put our own MVVM framework to the test in developing a data-driven Silverlight client that would increase productivity and visibility for our customer.

There are a number of different topics from our lessons learned that could be covered in our blog, and I will definitely cover as many as possible in the future, but for now I just wanted to highlight how we were able to put together a group of technologies in a very quick timeframe to provide great value to our customers.

If you are unfamiliar with MVVM, don’t fret!  You can read this quick overview from Joel Wetzel on the topic to get a quick understanding, but for now just think of it as a group of patterns and practices wrapped into a framework that allows us to build testable and reusable components with great flexibility.  It’s also a topic we will cover in blog posts in the future.

For this project, we used the following technologies:

  • Microsoft SQL Server 2008
  • Silverlight 4 (including the Toolkit)
  • Silverlight Unit Testing Framework
  • Windows Communication Foundation
  • DevExpress Silverlight Controls
  • .NET 4.0, ASP.NET 3.5/4.0, RhinoMocks, nUnit, MSTest, and others

The requirement from our customer was to provide an interface for their managers to modify and insert business data in monthly batches that would then report up to business operations for accounting and other purposes.  The managers were also familiar with WPF clients and so Silverlight seemed like a great choice for their intranet needs.  To understand how all these pieces fit together, here is a pretty little architecture diagram.

Now for the tricky part.  Silverlight runs on the client UI thread and cannot talk directly to SQL or other server code that requires a network connection.  So how is this accomplished?  With a little asynchronous, anonymous delegate gravy!!

using System;
using System.Collections.Generic;
using Affirma.Silverlight.Services;

namespace SilverlightLOB.DomainServices
{
    public interface IDomainService : IClientService
    {
        void Add(BusinessObject businessObject, Action<IResult<bool>> action);
        void GetItemsFor(Store store, Action<IResult<IEnumerable<BusinessObject>>> action);
    }

    public class DomainService  : IDomainService
    {
        public void Add(BusinessObject businessObject, Action<IResult<bool>> action)
        {
			// our web service proxy
            var client = new DataServiceClient();

            client.AddCompleted +=
                (obj, args) =>
                {
                    if (args.Error != null)
                        Logging.Log.Debug("Error in Add - " + args.Error.Message);

                    action.Invoke(new SimpleServiceResult { Error = args.Error });
                };

            client.AddAsync(businessObject);
        }

        public void GetItemsFor(Store store, Action<IResult<IEnumerable<BusinessObject>>> action)
        {
            var client = new DataServiceClient();

            client.GetItemsForCompleted +=
                (obj, args) =>
                {
                    if (args.Error != null)
                        Logging.Log.Debug("Error in GetItemsFor - " + args.Error.Message);

                    var result = new EnumerableServiceResult<BusinessObject> {Error = args.Error};
                    if (result.Success)
                        result.Value = args.Result;

                    action.Invoke(result);
                };

            client.GetItemsForAsync(store);
        }
    }
}

Easy!  This domain service lives on the client UI thread and will execute asynchronous requests to our WCF service, and invoke the result back onto our UI thread thanks to the provided callback.  This means the Silverlight client UI can continue to execute requests and other user interactions while the service requests process and returns a value.  From our view model, we can easily wire up to this domain service and execute the appropriate asynchronous method.

public ICommand AddCommand
{
	return ConstructCommand(() => AddCommand, AddHandler);
}

void AddHandler()
{
	_service.Add(ObjectToInsert,
		result => {
			if (result.Success) MessageBox.Show("Success!");
		};
}