The Aspen progress – Silverlight 4, Net 4, WCF RIA Services ref. project
It was a while since I wrote a blog post, the reason are many, first preparation for the SDC2010 conference where I talked about WCF RIA Services, then 2 sessions at Microsoft TechDays 2010 where I talked about Web Form vs MVC and building business application with Silverlight 4, MVVM and WCF RIA Services.. and then bought a new car and also have bean on the Microsoft Visual Studio 2010 Ultimate tour and one week vacation in Italy. So a busy time. This blog post will only mention some of the latest updates we have made to the project.
Data Model and Domain Model changes
We still uses POCOs but we have removed the Code First feature because it’s not part of the EF 4.0 RTM. Instead Dag König have added the support of using T4 templates. So we create our entities out from our Data Model by using T4 POCO templates. You can find the template “AspenPocogeneration.tt” in the project “Fdd.Aspen.DomainModel” and under the folder “Entities”.
“Defensive programming/argument validations”
Before we used methods to check if the user of the code passes in a correct value to our methods etc, now we have replaces it with Code Contract. The following is an example where we have for example used Code Contract:
public BaseRepository(IObjectContext objectContext) { Contract.Requires(objectContext != null); Contract.Ensures(_objectContext != null); Contract.Ensures(_objectSet != null); _objectContext = objectContext; _objectSet = _objectContext.CreateObjectSet<TEntity>(); }
First we Requires that the objectContext attribute can’t be null, if it’s not null we will ensure the the private fields _objectContext and _objectSet will not be null. Code Contract is all about setting up a contract “if you give me this, I promise that you will get this.”. So by using pre-condition “Requires” we can check if the user of the code passes in the correct value we expected to get, then we use post-condition “Ensures” to make sure we fulfill our part of the contract. We also use Contract Invariant, to make sure the object is in a good state.
[ContractInvariantMethod] private void ObjectInvariant() { Contract.Invariant(_objectContext != null); Contract.Invariant(_objectSet != null); }
We haven’t upgraded all our code to use Code Contract yet, but while we working with a old class we will do the changes, every new class will use Code Contract.
ViewModel and the Client Side Data Channel
At the moment there are no changes made to the client-side and ViewModel. We will not use a 3ed party framework or Prism etc, we will try to use most of the things shipped with the RTM version of Silverlight 4 and VS2010. I haven’t mention anything about the client-side in a blog post yet even if there are some test code added to try out some infrastructure stuffs. To make it easy to do the testing we will work with an abstraction of the server call. At the moment we call it a DataChannel but some people also call it “Repository” for the client-side. The name here is not so important.
public class ListMemberViewModelDataChannel : IListMemberViewModelDataChannel { MemberDomainContext _memberDomainContext = new MemberDomainContext(); public void GetAllMembersAsync(Action<IEnumerable<MemberPM>> getAllMembersCompletedCallBack) { _memberDomainContext.Load<MemberPM>( _memberDomainContext.GetMembersQuery(), loadOperation => { getAllMembersCompletedCallBack(loadOperation.Entities); } , null); } public void Save() { _memberDomainContext.Save(); } }
The ListMemberViewModelDataChannel is the “DataChannel” for the ListMemberViewModel, it have the responsibility to handle all communication to the server-layer on the server-side. The DataChannel will use WCF RIA Services, and one DataChannel will be create for one View, and one DomainService will be used for one View. The reason why we use a “DataChannel”, is to make it easy to do testing against our ViewModel and also if we don’t want to use WCF RIA Services, we can simply implement a DataChannel that will use WCF.
The following is an example of a ViewModel that uses a DataChannel:
public class ListMemberViewModel : BaseViewModel { private ObservableCollection<MemberPM> _members = null; private IListMemberViewModelDataChannel _listMemberViewService; private bool _isBusy = false; public ListMemberViewModel(IListMemberViewModelDataChannel listMemberViewService) { Contract.Requires(listMemberViewService != null); Contract.Ensures(_listMemberViewService != null); this._listMemberViewService = listMemberViewService; this.IsBusy = true; this._listMemberViewService.GetAllMembersAsync(GetAllMembersCompleted); } private void GetAllMembersCompleted(IEnumerable<MemberPM> result) { this.Members = new ObservableCollection<MemberPM>(result); this.IsBusy = false; } public bool IsBusy { get { return _isBusy; } private set { _isBusy = value; base.NotifyPropertyChanged("IsBusy"); } } public ObservableCollection<MemberPM> Members { get { return _members; } private set { _members = value; base.NotifyPropertyChanged("Members"); } } }
On the server-side in our DomainServices we don’t expose our DomainModel’s Domain entities, instead we create a “Presentation Model”, a model more suitable for presentation purpose. They will be part of the ViewModel, and thanks to the WCF RIA Services uses of the INotifyDataErrorInfo interface, we can use the “Presentation Model” as part of the ViewModel (it’s a ViewModel more or less in the way it’s implemented but with not operation added to it). We haven’t added the infrastructure for location our ViewModels and bind them to the Views yet, we are thinking about using MEF or Unity 2.0, or maybe combine both of them. At the moment we use simply hardcode the dependencies and do the injection manually in the View’s code-behind:
public MainPage() { InitializeComponent(); var listMemberViewModel = new ListMemberViewModel(new ListMemberViewModelDataChannel()); this.DataContext = listMemberViewModel; }
This will be changed, I’m thinking about using convention to locate the ViewModel for the View.
If you want to know when I post a new blog post, you can follow me on twitter: http://www.twitter.com/fredrikn