WCF RIA Services Presentation Model Explained
Earlier this week we released the Beta version of WCF RIA Services for Visual Studio 2008 and the preview version for VS2010 Beta 2. There were a lot of great features added to it from our July CTP.
Here is a quick list of all the features:-
WCF Integration
Compositional hierarchy
Better error handling
Better support for DomainDataSource
Presentation Model
You can get details for most of them from https://silverlight.net/riaservices.
One of the features that I got to work on was the Presentation Model.
So what is presentation model in WCF RIA Services?
Exposing DAL types back to client is not a good idea in many ways. The system can go through many changes and can move away from a particular backend to another. This change will require the client to be updated which can be costly. Application developers also have the desire to control what the entity looks like on the client. To address some of these concerns application developers have been adapting the Data Transfer Objects pattern but that does not fit well with RIA services as we have a notion of Domain Object Model where the user can write custom Business Logic. Enters WCF RIA Services presenttion model.
During the design phase of the feature, we were looking to enable four main scenarios:-
- Provide a pattern to create PM types from DAL Types in query methods
- Provide a pattern to create DAL Types from PM Type translation in CUD/Custom methods
- Provide a way to flow back store generated values back to the client
- Provide a way to propagate errors from DAL Types to the client
In this post I will try to cover up on how you can achieve the top three scenarios, I will follow up with a more detailed post on how to propagate errors back to the client.
In this blog post I will be using the following DAL Types:-
DAL_Customer
DAL_CustomerPreferences
DAL_CustomerProfile
I will create the following PresentationModel type and project to the client:-
In order to create a Presentation Model type you will need to create a new POCO(Plain OLD CLR Object) type in the server project.
Add this type to your server project.
public class PM_Customer
{
[Key]
public int CustomerID { get; set; }
public string Email { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string FavoriteColor { get; set; }
public string SomeOtherPreference { get; set; }
public string City { get; set; }
public string State { get; set; }
public int Zip { get; set; }
}
Projecting Presentation Model type to the client
Converting DAL type to presentation model types will be a typical scenario for query methods. An application developer can use projection to compose his presentation model type. The code for querying presentation model type would look like:-
public IQueryable<PM_Customer> GetCustomers()
{
return from c in this.Context.DAL_CustomerSet
select new PM_Customer()
{
CustomerID = c.CustomerID,
Email = c.EmailAddress,
City = c.CustomerProfile.City,
FavoriteColor = c.CustomerPreferences.FavoriteColor,
FirstName = c.FirstName,
LastName = c.LastName,
SomeOtherPreference = c.CustomerPreferences.SomeOtherPreference,
State = c.CustomerProfile.State,
Zip = c.CustomerProfile.ZipCode
};
}
Updating DAL types from Presentation Model types
Converting presentation model type to DAL types will be a typical scenario for update or custom methods. An application developer can use projection to compose his presentation model type. The code for updating presentation model type would look like:-
[Update]
public void UpdateCustomer(PM_Customer customer)
{
DAL_Customer dalCustomer = this.Context.DAL_CustomerSet.Where(c => c.CustomerID == customer.CustomerID).FirstOrDefault();
DAL_CustomerPreferences dalPreferences = this.Context.DAL_CustomerPreferencesSet.Where(c => c.CustomerID == customer.CustomerID).FirstOrDefault();
DAL_CustomerProfile dalProfile = this.Context.DAL_CustomerProfileSet.Where(c => c.CustomerID == customer.CustomerID).FirstOrDefault();
// Custom logic to copy data from PM type to DAL Type
this.MyMerge(customer, dalCustomer);
this.MyMerge(customer, dalPreferences);
this.MyMerge(customer, dalProfile);
}
In this example MyMerge is a custom function that I wrote which copies values from my presentation model type to my DAL Type. You can choose to do the merge in place.
Updating Presentation Model types after submit changes.
Many databases design have fields that are store generated value. E.G. timestamps, ids etc. To flow back these values to the client a developer would need to do the following.
[Update]
public void UpdateCustomer(PM_Customer customer)
{
DAL_Customer dalCustomer = this.Context.DAL_CustomerSet.Where(c => c.CustomerID == customer.CustomerID).FirstOrDefault();
DAL_CustomerPreferences dalPreferences = this.Context.DAL_CustomerPreferencesSet.Where(c => c.CustomerID == customer.CustomerID).FirstOrDefault();
DAL_CustomerProfile dalProfile = this.Context.DAL_CustomerProfileSet.Where(c => c.CustomerID == customer.CustomerID).FirstOrDefault();
this.MyMerge(customer, dalCustomer);
this.MyMerge(customer, dalPreferences);
this.MyMerge(customer, dalProfile);
this.ChangeSet.Associate(customer, dalCustomer, MapDALCustomerToPMCustomer );
this .ChangeSet.Associate(customer, dalPrefernces, MapDALCustomerToPMCustomer );
this .ChangeSet.Associate(customer, dalProfile, MapDALCustomerToPMCustomer );
}
The change set will now have a new function called the Associate which will take in instances of PM Type and DAL Types. Once the data is submitted to the database the MapDALCustomerToPMCustomer function will be called with the updated instances.
private void MapDALCustomerToPMCustomer(PM_Customer pmCustomer, DAL_Customer dalCustomer)
{
pmCustomer.CustomerID = dalCustomer.CustomerId;
}
I could set up transform function for each of my DAL Types and flow back the value in to my Presentation Model type and then to the client.
This post should get you started on presentation model type. I will follow up with a post on how to flow back errors to the client.
Comments
Anonymous
December 01, 2009
Great post.... thanks. hope to see some samples on Presentation Model as well.. cheersAnonymous
September 29, 2010
Good post. I've tried to add a complex class to my server side, but the complex type is not generated on the the server side. Is this the convention, or am I doing something wrong? Sample class, where the Children property will is not re-generated on the Client side: public class Task { [Key] public string TaskName { get; set; } public DateTime StartDate { get; set; } public DateTime EndDate { get; set; } public double PercentComplete { get; set; } public string Resources { get; set; } public List<Task> Children { get; set; } }Anonymous
January 31, 2011
@LarsM1 / Complex types are not supported in WCF RIA Services 1.0. I've heard that they'll be supported on SP1. As of current there's SP1 beta available.