Simple MVVM Toolkit: Ready for RIA Services

Part of Microsoft’s Silverlight strategy is to position it as a platform for building rich line of business applications.  One reason for this is the deployment story: in or out of the browser on Windows, Mac or Linux.  Another is the availability of WCF RIA Services, which eases n-tier application development for Silverlight by providing advanced features such as query composability, change-tracking and transactional batch updates, end-to-end data validation, better handling of async operations, application security with support for both authentication and authorization.  (For more information see my blog post and presentation of RIA Services.)

NOTE: You can obtain the code for this blog post from the SimpleMvvm-RiaServices sample project that’s part of the download for my Simple Mvvm Toolkit.

So how well does RIA Services play with MVVM?  Very nicely, I am happy to say.  In fact, you can easily use my Simple MVVM Toolkit to build a Silverlight app that uses RIA Services.  All you have to do is create a ServiceAgent that uses the generated DomainContext class to load and persist entities from the RIA Services web app.

Developing a Silverlight app that uses RIA Services is fairly straightforward.  You can start either with a plain vanilla Silverlight app by selecting the “Silverlight Application” Visual Studio project template, or you can choose the “Silverlight Business Application” template, which is based on the “Silverlight Navigation Application” template and has a few more bells and whistles (mainly user membership and authentication).  I suggest you start with a basic project template and then move on to the business application template when you want to explore features related to application security.

sl-app-dialog

After clicking OK you’ll be presented with another dialog in which you specify a web project to host your Silverlight app and if you wish to enable WCF RIA Services.  You should probably go ahead and check the box to enable RIA Services, but you can add a RIA Services link later on if you wish.

enable-ria

Now you have to decide where you want to get your data from.  Most of the time that would be from a database using the Entity Framework.  But to keep it simple we’ll just create some in-memory objects and expose them over RIA Services.  The important point to keep in mind here is that RIA Services is not in any way wedded to Entity Framework – you can use another ORM (such as NHibernate) or none at all.

Let’s say we create a Customer class with three properties: CustomerId, CustomerName and City.  Then for convenience we’ll add a factory method to return a List of them.  To play nice with RIA, you will need to add a [Key] attribute to one of the properties in Customer, such as CustomerId.

public class Customer
{
    [Key]
    public int CustomerId { get; set; }
    public string CustomerName { get; set; }
    public string City { get; set; }

    public static List<Customer> GetCustomers()
    {
        return new List<Customer>
        {
            new Customer { CustomerId = 1, 
                CustomerName = "Bill Gates", City = "Redmond" },
            new Customer { CustomerId = 2, 
                CustomerName = "Steve Jobs", City = "Cupertino" },
            new Customer { CustomerId = 3, 
                CustomerName = "Mark Zuckerberg", City = "Palo Alto" }
        };
    }
}

Next create a CustomerDomainService class using the Domain Service Class item template.

domain-service

Then add a GetCustomers method and return an IQueryable<Customer> by calling Customer.GetCustomers and invoking AsQueryable on the result.  IQueryable signifies that you are returning a query that can be further refined with things like filters or sorting.

[EnableClientAccess()]
public class CustomerDomainService : DomainService
{
    // Will surface as a method on the client DomainContext
    public IQueryable<Customer> GetCustomers()
    {
        return Customer.GetCustomers().AsQueryable<Customer>();
    }
}

When you build the project, RIA Services will project a CustomerDomainContext class on the client (it’s hiding inside the Generated_Code folder that’s visible only when you show all files).  There you have a GetCustomersQuery method that calls the GetCustomers service method and returns, you guessed it, an IQueryable<Customer>.

Now that you’ve done the RIA Services bit, it’s time to put in MVVM pieces in place.  For that you follow the instructions I’ve laid out in the Getting Started guide for the toolkit.  (The SimpleMvvm-RiaServices sample also has a readme file with step-by-step instructions.)  The key difference is that the ServiceAgent implementation will load entities from the query returned by CustomersDomainContext.GetCustomersQuery.

First create an ICustomerServiceAgent interface with a GetCustomers method.  Note that the method signature should reflect the asynchronous nature of services in Silverlight, with a callback parameter that returns either a sequence of customers or an exception.

public interface ICustomerServiceAgent
{
    void GetCustomers(Action<IEnumerable<Customer>, 
        Exception> completed);
}

The implementation looks like this.

public void GetCustomers(Action<IEnumerable<Customer>, 
    Exception> completed)
{
    // Load GetCustomersQuery
    EntityQuery<Customer> query = _domainContext.GetCustomersQuery();
    _domainContext.Load(query, loadOp =>
        {
            // Declare error and customers
            Exception error = null;
            IEnumerable<Customer> customers = null;

            // Set error or customers
            if (loadOp.HasError)
            {
                error = loadOp.Error;
            }
            else
            {
                customers = loadOp.Entities;
            }

            // Invoke completion callback
            completed(customers, error);
        }, null);
}

The code looks a little bit funny at first, because you have to call Load on an EntityQuery<Customer>, passing a callback method in which you harvest the result, which is an IEnumerable<Customer>.  The ViewModel simply invokes the ServiceAgent’s GetCustomers method, perhaps creating an ObservableCollection<Customer> for binding to a grid.

public void GetCustomers()
{
    serviceAgent.GetCustomers(GetCustomersCompleted);
}

private void GetCustomersCompleted(IEnumerable<Customer> result, 
    Exception error)
{
    // Notify view of an error
    if (error != null)
    {
        NotifyError("There was an error retrieving customers", error);
    }
    // Set Customers property
    else
    {
        this.Customers = new ObservableCollection<Customer>(result);
    }
}

If you have a DataGrid with an ItemsSource bound to the ViewModel Customers property, you should see the results displayed like so.

customers-grid

Now you have an Silverlight MVVM application that uses WCF RIA Services! The nice thing is that you can use the Simple MVVM Toolkit as is with RIA Services.  The ServiceAgent already abstracts away the task of retrieving entities, and the ViewModel doesn’t really care how it happens.  From the perspective of the ViewModel, RIA Services is simply an implementation detail. Nice.

About Tony Sneed

Sr. Software Solutions Architect, Hilti Global Application Software
This entry was posted in Technical and tagged , . Bookmark the permalink.

15 Responses to Simple MVVM Toolkit: Ready for RIA Services

  1. Rao says:

    Hi Tony your article is very nice, can you please let us know how to add a new customer in a detailview.

    Thanks Rao

    • Tony Sneed says:

      @Rao: Yes, I’m working on extending the main sample to use WCF RIA Services, and I will include CRUD operations there (Create Retrieve, Update, Delete). Stay tuned!

      Tony

  2. Oscar Agreda says:

    Thank You Tony..
    your contribution to MvvM are or incredible value.

    I was wondering if you have seen the John Papa , Kung Fu MvvM implementation, which is obvious good, but unfortunately way to complex and unrealistic to use in a real world to create a Business Application.
    but with your MvvM style of doing things or MvvM implementation, how will be a Tony way of having MvvM Designer or Mock data.

    Regards

    • Tony Sneed says:

      @Oscar: Thanks for turning my on to John’s PDC talk on Silvelright-MVVM. I’ll have a look and let you know what I think about it. In terms of designability (blendability) my toolkit supports that with an “IsInDesigner” property in the ViewModel base class. All you have to do is check it to see if you’re in design-mode and then supply design-time data. I have an example of this in the main sample app, but I plan to blog on this more in the future. In terms of testability with mock data, I have built-in support for injecting a mock service agent with MEF (Managed Extensibility Framework), and there’s a sample in the toolkit on how to do that. Check out this blog post for more into: https://blog.tonysneed.com/2011/03/08/keep-dependency-injection-simple-with-mef. I am adding enhanced support for testability and mocking in version 2 of the toolkit which will be coming out in the next couple of weeks. Cheers,

      Tony

  3. Martin Turner says:

    Great job with the Toolkit, Tony. I’m glad to see you are addressing RIA. I’m fairly new to MVVM, so some of the techniques are not 100% clear yet. I have been using the Toolkit with RIA for about 3 or 4 weeks and have run across a situation you may be able to shed some light upon. I have been using the RIA projected classes (or collections of them) as my model. I use a ViewModelBase and build the properties and methods I need. I did it exactly as you explain here, using the service agent to provide the methods to retrieve the data. Today I came across a situation where I want to associate a VM property with a model property, but since the model is generated by RIA I can’t inherit from ModelBase. Without creating a wrapper class, I can’t see an easy way to associate the properties. Do you have this figured out?

    Thanks,

    Marty

    • Tony Sneed says:

      @Martin: It turns out that my toolkit is really easy to use with RIA Services. 🙂 There’s no problem associating a ViewModel property with one or more properties in a model that is generated by RIA Services. The only constraint on the model type is that it implement INotifyPropertyChanged, which RIA Service entities do. In fact, most code-generated entities implement this interface to support two-way data binding. That includes classes generated when you add a WCF service reference. Don’t let the ModelBase class in the toolkit throw you off. This class is included only for scenarios where you are creating your own model classes from scratch (see the comment in the class source code).

      To call AssociateProperties, you just need to derive your ViewModel from ViewModelDetailBase, where TViewModel is the ViewModel type, and TModel is the model type, which could be the type of a RIA Services entity.

      Cheers,
      Tony

  4. Oscar Agreda says:

    @Tony
    yes, your MvvM is changing many developers life for the good.. Thank you.

    here is the John Papa, Kung Fu Implementation * he uses your toolkit, btw*
    http://johnpapa.net/silverlight/pdc10kungfu/

    and , is so good that even Ward Bell from Idea Blade, improved on it
    http://drc.ideablade.com/xwiki/bin/view/Documentation/code-sample-bookshelf

    very powerful Business Creations possible becasue of your work.

  5. Tony Sneed says:

    Update: Version 2 of the Simple Mvvm Toolkit now includes a full-fledged RIA Services sample. Just open up Part 2 of the Main sample. There you’ll find a sample that includes persistence of entities using RIA Services CRUD operations.

    Also, note that the toolkit installs a Visual Studio Project template for RIA Services. Just create a new project and select the SimpleMvvmRiaServices project template. Then follow instructions in the readme file.

  6. Nitin Sonawane says:

    Hi Tony,
    Please explain Unit testing for both SimpleMvvmToolkit & SimpleMvvmRIAServices through Screen Cast.
    Thanks & Regards
    Nitin Sonawane

  7. Nitin Sonawane says:

    Thank You Tony, for your professional and effective help.

    Thanks again!

    Regards,
    Nitin Sonawane

  8. Nitin Sonawane says:

    Hi Tony,
    I have one issue, I have put Required validation on ProductName attribute on NorthwindDomainService.metadata.cs. and rebuild the web project.
    The code generated file also get refresh, but when I add new product, it does not show required validation & blank product is inserted on database.
    Please tell me how i can put validation & please reply as soon as possible.
    If any screen cast for validation so please provide link.
    I am using following code
    public void AddProduct(Product item)
    {
    domainContext.Products.Add(item);

    domainContext.SubmitChanges(op =>
    {
    if (op.HasError)
    {
    MessageBox.Show(op.Error.Message);
    op.MarkErrorAsHandled();
    }

    }, null);
    }

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.