Architecting Silverlight 4 with RIA Services, MEF and MVVM - Part 1

Url: http://wildermuth.com/downloads/riaxboxgames.zip

Architecture

Recently I blogged about Brad Abrams' PDC RIA Services Talk and complained about the data source functionality. While the drag-n-drop ability in RIA Services is interesting, I believe that it may be a bad approach for all but the smallest of projects (or one-off projects). In that comments of that article, I promised to show you how I would architect a Silverlight solution with RIA Services. 

The outcome of that work is a sample that I will cover in a series of blog posts (starting with this one) to explain not only how i'd use RIA Services in Silverlight 4, but also how to solve some of the basic difficulties with those types of architectures. I will be covering how I integrated the Managed Extensibility Framework (MEF) and Laurent Bugnion's MVVM Light Framework to stitch together a loosely coupled Silverlight applciation.  But let's start with RIA Services.

At the core, RIA Services is a way of manipulating data across an Internet connection. While it provides other services like shared code and communication of validation attributes, I am going to focus on its use as a data provider for Silverlight 4.

Like I've discussed in articles, the Silverlight Tour and in blog posts, I have been recommending the Model-View-ViewModel pattern for separating concerns in Silverlight. This is especially true for data-driven or line-of-business applications.  If you are building widgets or video players, this pattern may be more work than necessary.  But for larger applications, this pattern allows us to separate the layers and test each of the layers in isolation. This provides a bedrock of testable code and regression testing that makes our software predictably written. So let's look at some code.

As I mentioned in my MVVM Article in MSDN Magazine, I believe the Model is best expressed as a set of operations that retrieve data. It may be temping to simply use the data context itself as the model.  The reason that using the data context means we would need to mock the entire data context surface area to use it for testing. Additionally, creating a custom model allows us to isolate what transport layer we're using so we can change it or even have several data providers specifying data for our model.  For example, in the example application, I am isolating the RIA Services' data context inside the model like so:

public class GamesModel : IGamesModel
{
  public void GetGamesByGenreAsync(string genre) // ...

  public void SaveGamesAsync() // ...

  XBoxDomainContext _ctx;

  public event EventHandler<GameResultsArgs> GetGamesComplete;
  public event EventHandler<ResultsArgs> SaveGamesComplete;
}

Because the model is for Silverlight 4, the methods that retreive data are asynchronous (and the event handlers make retrieving the results (or errors) simple. Because the model is implementing an interface (IGamesModel) we can mock the model as necessary to test other parts of the system (primarily ViewModels).

Notice in the model, I have both retrieval (GetGamesByGenreAsync) and updating (SaveGamesAsync). One of my basic ideas here is that the model is not only a conduit but also where the state for changed objects are held. In that way, by the model holding onto the data context, it can keep tracked entities around so when save is called, we don't need to tell it what entities...it already knows what has been changed (though we may need an AddGame and DeleteGame method on the model if we wanted to support new and deleted objects). 

But why does this work?  It works because data binding in Silverlight 4 is powerful. When we pass the objects through to the ViewModel (and ultimately to the View), any changes that happen are going to notify anyone who cares because of the INotifyPropertyChanged interface. One of the listening parties to the INotifyPropertyChanged interface is the data context itself. That's how it knows when an object  has changed. So when we create a view model (I am using Laurent Bugnion's MVVM Light's ViewModelBase as the base class for my view models), we can expose a bindable surface for the view to use, like so:

public class GameListViewModel : MyViewModelBase, IGameListViewModel
{
  IGamesModel _model;

  public GameListViewModel(IGamesModel theModel)
  {
    _model = theModel;

    _model.GetGamesComplete += 
      new EventHandler<GameResultsArgs>(_model_GetGamesComplete);

  }
  
  private ObservableCollection<Game> _games;

  public ObservableCollection<Game> Games
  {
    get { return _games; }
    private set
    {
      if (value != _games)
      {
        _games = value;
        RaisePropertyChanged("Games");
      }
    }
  }
    
  // ...
}

You should see here in the viewmodel that I am accepting the interface for the model (so the viewmodel can be tested in isolation). Also, note that the ViewModels also use an interface so they can be mocked but testing Views in isolation is not an easy task so far. I do this by habit for the days when it will be possible. One trick to make this easier, is to just write the View or ViewModel class first then extract the interface (using the VS refactoring tools or another 3rd party tool like refactor.

Because the view model is responsible for creating a bindable interface for the view, we can expose the games as an ObservableCollection so that changes are correctly monitored by the bindings.   In this case take the Games I exposed in the viewmodel and directly bind it to a ListBox so the user can specify specific games as shown below:

<ListBox ItemsSource="{Binding Games}"
         DisplayMemberPath="Name"
         x:Name="theList"
         VerticalAlignment="Stretch" />

For individual games, we expose them directly from the selected index item (which I'll explain in Part 3 of this series) by binding to the CurrentGame element of the editor's own viewmodel:

<StackPanel DataContext="{Binding CurrentGame}">
  <TextBlock>Name</TextBlock>
  <TextBox Text="{Binding Name, Mode=TwoWay, 
                  TargetNullValue='(None)', 
                  ValidatesOnExceptions=True, 
                  NotifyOnValidationError=True}" />
  <TextBlock>Description</TextBlock>
  <TextBox Text="{Binding Description, Mode=TwoWay, 
                  TargetNullValue='(None)', 
                  ValidatesOnExceptions=True, 
                  NotifyOnValidationError=True}"
           AcceptsReturn="True"
           TextWrapping="Wrap"
           VerticalScrollBarVisibility="Auto"
           Height="100" />
  <TextBlock>Price</TextBlock>
  <TextBox Text="{Binding Price, Mode=TwoWay, 
                  TargetNullValue='(None)', 
                  StringFormat=c, 
                  ValidatesOnExceptions=True, 
                  NotifyOnValidationError=True}" />
  <TextBlock>Release Date</TextBlock>
  <my:DatePicker SelectedDate="{Binding ReleaseDate, Mode=TwoWay, 
                                ValidatesOnExceptions=True, 
                                NotifyOnValidationError=True}" />
  <dat:ValidationSummary />
</StackPanel>

Since these are going to be the actual games from RIA Services, we can use the Validation Summary and the binding properties for exposing our validation attributes. This might seem like a tightly bound contract between the exposed elements in RIA Services and the data bindings but I contend that its not.  These bindings simply say that it should deal with any validation necessary. The fact that the RIA Services' implementations do validation using validation attributes is just a side affect.

At this point you should see some simple patterns for creating multiple-views and viewmodels while wrapping RIA Services without ever using the DataSource control. In the next part of this series I will show you how we'll use MEF to link the views, viewmodels and the model while allowing us to test and compose our application. You can see the demonstration code here:

http://wildermuth.com/downloads/riaxboxgames.zip

 

Comments

Gravatar

Colin Blair Tuesday, December 15, 2009

The one part I would disagree with is your use of ObservableCollection. I suggest exposing IEnumerable<Game> from the model instead of ObservableCollection<Game>. This would allow you to directly return EntitySets or EntityCollections from the DomainContext through your Model. For situations where I want to expose a subset of the EntitySet I have been using the PagedCollectionView.

Gravatar

Aaron Tuesday, December 15, 2009

Thanks Shawn, good stuff here. Looking forward to pt. 2.

Gravatar

Shawn Wildermuth Tuesday, December 15, 2009

Colin,

Good point about IEnumerable<T>, I like the solution you suggested.

Gravatar

Fallon Massey Tuesday, December 15, 2009

Shawn, you may not be a Wall Street Fat Cat, but you're still doing God's work(lol).

This is great stuff, and I look forward to the following articles in this series. BTW, I've had similar concerns, and I am a heavy user of both MEF and MVVM Light(had to get my bias out there).

Gravatar

geokaps Tuesday, December 15, 2009

Thanks Shawn. Looking forward to the MEF integration post. Also, this post led me to discovering the MVVM Light Toolkit - wow, very cool.

Gravatar

Zoltan Arvai Tuesday, December 15, 2009

Actually I agree with Colin. By using OC u immediatly loose change tracking which you'll probably need. Ienumerable and pagedcollectionview seems to be okay( too bad dataform has issues with add support for those two.) btw i have a question. You have a dataform with a combobox inside among others. How do you fill up ur combobox dynamically when u have the vm demonstrated anove?

Gravatar

Shawn Wildermuth Tuesday, December 15, 2009

Zoltan,

The OC doesn't make you lose change tracking (only change tracking for add/remove which i will likely need). I don't have any dataforms. Its all just XAML. I am not yet filling the combo box from RIA, i'll probably add that by the last blog in the series. It would be exposed off the menuviewmodel and just be a call into the model.

Gravatar

Colin Blair Tuesday, December 15, 2009

Shawn,

Your point on Zoltan on the lack of add/remove change tracking reminded me of another point. If you are going to expose an ObservableCollection then you should wrap it in a ReadOnlyObservableCollection to make sure that the lack of add/remove support is enforced.

Gravatar

Fredrik Normén Wednesday, December 16, 2009

I notice that you are exposing your DAL types directly to the ViewModel, and also bind it to the View. In this case you will have several dependencies to the DAL model in different tiers and layers. A simple changes on the server-side model can lead to changes in several places. In this case I should use DTO instead of exposing DAL types, the DTO will be designed in a way that only data the View is needed it passed to the View. The DomainService will use the Transform pattern to transform the DAL or domain entities to DTOs.

Gravatar

Shawn Wildermuth Wednesday, December 16, 2009

Fredrik,

I considered this for this example. Generally only the shape of the types are changing and since data binding is loose, I think the dependency is ok. Though I could see using DTO's in several places (e.g. in the server-side DomainService). The fact that the EF model is a 1-to-1 model should be ignored as all the RIA is doing is exposing the EF model. I think that separation from the database to entities is where i'd do it. I have never been a big fan of DTO's but I do see benefit in the isolation in some cases, just not the majority case. But thanks for the input.

Gravatar

Fredrik Normén Wednesday, December 16, 2009

Everything depends on how large your app is, how the user will use the data etc. When you create the EF model, do you for example have the View in mind, and also what data the View is needed? If so, in a small app there is often no problems of exposing DAL types. Most RIA will also need business logic on the server-side, in this case the Domain Service is just a service-layer and should not expose business domain entities or DAL types, they are often not designed for presentation in mind. In some cases it can also be good to transform the DTO to another "presentation model" in the presentation layer and expose the new model from the ViewModel. By doing so, optimization or some specific changes to server-side model or DTO can be done without affecting the View, and will decrease number of changes, but can also lead to more changes. So there is not Silver bullet. I talked to a customer today after my RIA talk, he exposes domain entities. They have a major problem right now, they pass to much data over the wire because the models aren't designed with presentation in mind. They now notice the need of using DTO for data projection and also minimizing the data passed to the client side.

Gravatar

Shawn Wildermuth Wednesday, December 16, 2009

Fredrik,

This model of what you expose over the wire is specifically why I very commonly use WDS instead. Projections in v2 allows me to create DTO's on the fly and not confuse the entities with the view requirements...but that's a different discussion.

Gravatar

Ward Bell Wednesday, December 16, 2009

You are too kind, Shawn. The "purist" argument for "screen DTOs" and against exposing entities to view binding is YAGNI and misguided. It actually makes code harder to read, harder to write, more brittle, and more expensive.

It obliges you "on principle" to write anemic DTO classes and mapping code in anticipation of trouble that most likely never arrives ... as if the DTOs and mapping were cost and maintenance free.

It invites premature optimization (e.g., unsubstantiated concern about retrieving more entity data than is actually needed ) without considering the accompanying complexities (e.g., changes to entities not propagated to their projections) that bloat the application with code and mistakes.

As Shawn observes, the view has no idea what it is binding to. If the entity has more properties than are displayed, so what? When you produce a measurable degradation in response, I'll listen.

Additive changes to the entity are harmless to the view. Deleting a property is harmless too ... unless the property is displayed in which case you have the multiple maintenance burdens of adjusting the DTO, mapping, and entity. The notion that the view is impervious to a substantive change to the entity or the backing table(s) defies experience and common sense.

Finally, if the need arises to replace binding to the entity with binding to a ViewModel that wraps/reshapes the entity ... if you discover that the entity is unsuitable for presentation (which occurs < 5% of the time), you can introduce the "DTO" with no impact on the view or surrounding code. In other words, it is an easy, low impact refactoring that can and should wait.

Time to call B.S. on the mania for mapping to "screen DTOs". You do that when you have a proven need ... and not before.

Gravatar

Shawn Wildermuth Wednesday, December 16, 2009

As usual Ward, you're my hero ;)

Gravatar

Michael Iantosca Wednesday, December 16, 2009

I couldn't agree more with Ward Bell's comment. Why introduce all of that code before you have to. Keep it simple as long as you can and the refactored when you have to, if you ever have to

Gravatar

Francois Germain Wednesday, December 16, 2009

I was reading the comments and could not agree more with Ward. The presentation model should only be introduced in specific cases, especially when using RIA Services.

If you're going to do this by hand, you might as well just map your presentation Model to your DAL with nHibernate and create your own WCF comm. layer and forget all about RIA.

Be careful with the presentation model and only use it in specific cases or this is really not going to gain you anything.

Gravatar

Fredrik Normén Wednesday, December 16, 2009

It's based on the app your are building.. there is no Silver bullet, no one have ever stated that DTO should always be used. But they will often fit well in enterprise apps. If you don't agree, you don't have to. This is based on my 13 years of writing distributed enterprise apps, and maybe I just didn't had the luck to be in the perfect enterprise project ;)

Gravatar

David Thursday, December 17, 2009

Why did you choose MVVM Light over the many other available toolkits? Do you use MVVM Light in your commercial engagements?

Gravatar

Rob Thursday, December 17, 2009

I third what Ward says: don't try too hard to be a purist until - at least until you really need to.

On that note, Shawn, if it's so easy to generate an interface from your viewmodel "just in case", then why are you doing it before you "need" it?

It seems easier to me to bind to a concrete viewmodel, and anyway, XAML bindings are usually not strongly typed anyway (ie, you can substitute any object of the same shape, even without a common base class)

If I was unit testing a view I would probably still prefer to mock out my model than my viewmodel, otherwise all you're testing is Microsoft's binding code.

Gravatar

Shawn Wildermuth Thursday, December 17, 2009

Rob,

Your points about the VM interface are on the money. You're right though the MEF implementation might reveal a little about why I did it that way, though you don't need an interface for that.

As far as mocking, I think both need to be mockable (mock the Model to test the VM, mock the VM (with the mocked model under it) to test the View.

Gravatar

Shawn Wildermuth Thursday, December 17, 2009

David,

No reason except I wanted to get familiar with MVVM Light (and Laurent is a smart guy so I figured it was worthing looking at). As I've mentioned at conference talks, a toolkit will help you, there isn't one 'go-to' toolkit right now. SilverlightFX is interesting, MVVM Light is nice and small, etc. You should look at them and match your requirements. At this point there is a new MVVM library on codeplex about every 3 1/2 hours, so instead of looking at them all, I am looking at a couple and I like Laurent's.

Gravatar

Rob Friday, December 18, 2009

I third what Ward says: don't try too hard to be a purist until - at least until you really need to.

On that note, Shawn, if it's so easy to generate an interface from your viewmodel "just in case", then why are you doing it before you "need" it?

It seems easier to me to bind to a concrete viewmodel, and anyway, XAML bindings are usually not strongly typed anyway (ie, you can substitute any object of the same shape, even without a common base class)

If I was unit testing a view I would probably still prefer to mock out my model than my viewmodel, otherwise all you're testing is Microsoft's binding code.

Gravatar

Ryan Riley Saturday, December 19, 2009

@Shawn:
Great post! I'm excited to see what more is in store!

@Ward:
I don't know what sorts of simple demo apps you are building, but using connected entities straight from LINQ to SQL has bitten us hard so many times on the app I'm working on now, that I would happily take the relatively small amount of complexity of using "anemic" DTO's. (Btw, DTO's are by definition "anemic", so I'm not certain what you were trying to say there.) I suppose this is yet another case of YMMV, but immediately discounting the need for DTO's is ridiculous.

Gravatar

Shawn Wildermuth Saturday, December 19, 2009

Ryan,

I generally think that using DTO's in every case isn't necessary. Anyway, its in Silverlight so you're getting data copies anyway (sure the interface is tied to the original objects). But RIA will let you expose your DTO's if you prefer...not a big deal in any case.

Gravatar

Fredrik Normén Sunday, December 20, 2009

About DTO, some developers are used to simple dataform apps and don't have experience in building large enterprise distributes apps, or are still stuck with the old dataform binding thinking. Every enterprise pattern has its purpose to solve problems, so they aren't there to just make people angry ;) Why does WCF use DataContracts and why did DCOM fail, just a thought. It has to do with the distribution. There is a reason why well known architects say "Don't distribute objects", "Data Transfer Object are concepts to make remote architectures work". Read the following, it will be of great interest for everyone I think:
http://martinfowler.com/bliki/FirstLaw.html

http://www.ddj.com/architect/184414966.

Note: The use of DTO is based on the apps we are bulding, and in some cases they may be not needed at all.

Gravatar

Aaron Wednesday, February 03, 2010

Sean, is there a reason why you left out adding functionality? It seems that everyone in demoland is doing this, and I'm beginning to suspect it's because getting WCF RIA to perform the most trivial of tasks (especially when adding new objects on the client) is like pulling teeth.

For example, if I instantiate a new class that inherits from Entity, its .HasChanges property should be true after a change has been made, no? That's certainly what one would hope for.

Also, validation is not immediate. You actually have to attempt to persist the object and have it invalidated on the server before you can display to the client that the bound object is invalid. Yes, I know there are hackish solutions out there to grab the bindings and invalidate them, but again, hackish.

Another issue is that instantiating new objects inheriting from Entity may have a different EntityState than others. WTF?!

Something else I noticed is that the Entity classes are incapable of tracking their dirty state properly. For example, change a bound object's property, change it back to the way it was. The object things it's still dirty (this would be on an object that was loaded from the service).

And getting paging to work with the datapager in conjunction with lazy loading pages and MVVM? Forget about it. Might as well write your own pager.

Sorry for the rant, it just seems to me that RIA is nowhere near production ready. Things that you would think should just work don't. These are very trivial things too, I don't think I'm asking for too much. Perhaps I should post this elsewhere and use CSLA SL. It's a bit more work, but at least I know it works!

On a lighter note, thanks for all of your efforts though, it's truly appreciated :)

Gravatar

elguapo@guapo.com Sunday, April 18, 2010

DTOs are garbage. I find the original comment about using DTOs to minimize changes when a database change is made, to be quite humorous. If you introduce DTOs you simply have MORE changes to make, not LESS


Gravatar

Jay Sunday, September 05, 2010

I have been working with SL4/MVVM/RIA Services. I am very impressed with the work you did and how quickly you are able to show developing applications in a de-coupled and clean way. I learned MEF in practice right from your example and it hardly took any time for me. Credit goes to you. I also like they way you made it clear - few key advantages with MEF compared to other Unity etc options. Great work and thanks for sharing your ideas/code and helping us to develop more cleaner solutions/software.

Gravatar

Joe Wednesday, October 13, 2010

could you provide a simple set of steps that you used to set up your projects and create the basic shell of the application? seeing the finished result is very useful as a reference, but it's hard to reverse engineer the process by which you created it.

Gravatar

Nk54.fr Tuesday, October 26, 2010

Nice stuff ! Funny how you're solution get a lot of project :)

Why do you put some ResourceDictionnary in Common/Themes project and in client too ?

Why Data project isn't on Data.Web one ?

Gravatar

Nk54.fr Tuesday, October 26, 2010

Nice stuff ! Funny how you're solution gets a lot of project :)

Why do you put some ResourceDictionnary in Common/Themes project and in client too ?

Why Data project isn't on Data.Web one ?

Gravatar

Niek Thursday, November 18, 2010

Shawn,

As far as I can see all the layers and concerns are already separated.

* XAML == View
* DomainService ~ ViewModel
* DataContext == Model

(put the ~ there because as a developer you also have the choice to re-use services over multiple views, and combine multiple services in a single view, as well as create a service for a specific view)

The RIA services layer also already serializes objects over the wire to be reconstructed on the other side (in a way the view already works with DTO's). And if you so wish you can simply do projections into new view specific DTO's too.

Your testability argument makes no sense to me. To test your model code in isolation you would still need to mock the data context that is being injected.

In the large scale enterprise applications I have been involved in aggregations over multiple data contexts happen fairly often. If this has to be done more than once the code is extracted into a separate class. Whether you consider this a model or a view model is really not too interesting.

What am I missing?

Gravatar

Tony Friday, December 10, 2010

Hello Shawn. Thank you for this Code. I have a question. After i downloaded your source code, i noticed that the project RIAXBoxGames.Client.Common is the one linking to the WCF RIA Service (RiaXBoxGames.Data). I thought it would be RiaXBoxGames.Client the one doing that. Is there any reason for this? Isn't .Client the one consuming this services?

Thank you

Gravatar

Steve Saturday, January 15, 2011

First off great article. I am trying to follow the pattern you set up but I keep getting a 404 error trying to access the WCF service. I can access a service created with the standard RIA setup but once I separate the model into a separate web project and funnel that through the Common silverlight project I get the 404 error. I am simply debugging the app and getting this problem. Any ideas?

Gravatar

Andrew Thursday, March 10, 2011

Hi Shawn,

Like Joe, I too would be interested in knowing how you created the solution...particularly, how did you set up the RIA Services link? I only get the web project in the drop down, never my domain class library project.

Andrew

Gravatar

Shawn Wildermuth Friday, March 11, 2011

Andrew/Joe,

When I do it, I get the RIA Services created in the Library project. But the link is from the server LIbrary project to the Silverlight Library project (not the main SL project). HTH

Gravatar

Andrew Friday, March 11, 2011

Hi Shawn,

Like Joe, I too would be interested in knowing how you created the solution...particularly, how did you set up the RIA Services link? I only get the web project in the drop down, never my domain class library project.

Andrew

Gravatar

Andrew Friday, March 11, 2011

Thanks for the reply, Shawn, I tried it with a class library and that seemed to work. So how does Visual Studio go about populating the RIA Services drop down? Is it looking for a project with an Entity Model, or with a Domain Service?

Andrew

Gravatar

Lina Manjarres Monday, May 23, 2011

Thanks Shawn for all the help I have recieved from you.
I would like to kno if it is a good idea to use RIA Services. I am startin my app, and I am using MVVM and MEF. Thanks a lot!!

Gravatar

Lina Manjarres Monday, May 23, 2011

Thanks Shawn for all the help I have recieved from you.
I would like to kno if it is a good idea to use RIA Services. I am startin my app, and I am using MVVM and MEF. Thanks a lot!!

Gravatar

ibrahim Wednesday, October 17, 2012

good work!


Leave a Comment

*
*
*