Silverlight with Controller & WCF

I have received many questions on how to wire-up a Silverlight UI to the WCF back-end in a Layered Application. I noticed most Silverlight applications being taught or structured today, are not properly layered. Most are following the Fat-Client 2-tier architecture style with business logic embedded in the Silverlight UI and data being hosted on a server (accessed via WCF Data Services).

While this sort of architecture serves its purpose as an application, it does not promote centralize/shareable business logic in the back-end. UI technologies are very volatile. Therefore, when UI technology changes, we do not want it to impact our business logic.

The first challenge in building a layered Silverlight application is of course the mindset. Once that is taken care off, the next will be to understand the challenge in the separation of concerns. In a layered application, the UI is divided into 2 component types - the UI itself and a Controller component. Many Silverlight developers face a challenge here due to the async nature of Silverlight calls to WCF.

This is caused by the Controller component which is responsible to communicate with the back-end. The existence of the Controller component causes a "disconnection" between the service calls and the UI controls.

In this post, I will attempt to provide a simple solution to address that challenge. Here's the scenario - Assuming, I have a method called ListEmployeeExpenses that takes an EmployeeID and lists out all the expenses that belong to an Employee. This method is hosted in a WCF back-end. On my Silverlight page, I have a simple Button to invoke the method and a DataGrid to display the results.

This is how I would do it:

1. In the UI.Process project, create an EventArgs class to hold the results from the WCF call. Example, I create a DataPopulatedEventArgs class.

public class DataPopulatedEventArgs : EventArgs
{
    public T Result { getset; }
}

2. Next, create an Event and a method to raise the event in the Controller class.

public class ExpenseController
{
    public event EventHandler<EventArgs> DataPopulated;
    
    protected void OnDataPopulated(EventArgs args)
    {
        if (DataPopulated != null)
            DataPopulated(this, args);
    }
}

3. Now, let's put everything together in the method that calls to the WCF service. On the async completed event of the WCF service call, we create the EventArgs to hold the result and raise it with the DataPopulated event.

public void ListEmployeeExpenses(long employeeID)
{
    // Create proxy to WCF service.
    ExpenseServiceClient proxy = new ExpenseServiceClient();

    proxy.ListEmployeeExpensesCompleted += 
        delegate(object sender, ListEmployeeExpensesCompletedEventArgs e)
    {
        // Store the results from the call.
        var args = new DataPopulatedEventArgs<ObservableCollection<Expense>>();
        args.Result = e.Result;

        // Raise the event.
        OnDataPopulated(args);

        // Close the proxy.
        proxy.CloseAsync();

    };

    // Call the WCF method.
    proxy.ListEmployeeExpensesAsync(employeeID);
}

4. Finally, in our UI, we simply register to the DataPopulated event and bind the results to the UI Controls.
private void button1_Click(object sender, RoutedEventArgs e)
{
    // Create an instance of the controller.
    ExpenseController upc = new ExpenseController();

    // Register to the data populated event.
    upc.DataPopulated += delegate(object s, EventArgs args)
    {
        // Get the event argument.
        var dataArgs = 
            args as DataPopulatedEventArgs<ObservableCollection<Expense>>;

        // Bind to UI control.
        dataGrid1.ItemsSource = dataArgs.Result;
    };

    // Call the controller method.
    upc.ListEmployeeExpenses(6);
}
That's all to it! :) This is just one simple way to wire-up everything together. There are few other ways which I have experimented but this one seems to be the cleanest and have less code so far (not to mention easier to explain and maintain) ;)

Happy Layering your Silverlight apps!

No comments:

Post a Comment

Popular Post