The State of Data Access in Silverlight


SilverlightI've said much about my opinion of Silverlight data access. Currently this is Web Services, WCF Data Services and WCF RIA Services. Let's talk about Data Services and RIA Services and how they are related:

WCF Data Services

Data Services are a good story in Silverlight, but only as of version 2.0 of the protocol. For those users of version 1.0, using Data Services was painful as automatic tracking did not exist yet. Data Services can create not only the data contract classes, but a context object that will do tracking and batching for you.  The basic story of how Data Services works is that it takes a context object from a LINQ provider and exposes all the IQueryable endpoints as REST resources that can be queried. This works well in creating a place to execute queries and post/put/delete changes. While Data Services' URI API is another skill that could be learned, the Silverlight (and .NET) client library allows you to just issue LINQ queries to the data service.  In addition, the ability to create client-designed graphs (e.g. embed relationships for eager loading) and navigate relationships to the server presents a good API for a data-centric application today.

The method for connecting to a data service is via a "Add Service Reference..." which means that it is easy to have data services projects that are outside a particular solution file. This is critical for when you are building very large projects.

One of my favorite things about Data Services today is the ability to create tracked projections from the Silverlight client:

var qry = from g in ctx.Games
          where g.ReleaseDate <= cutoffDate
          orderby g.ReleaseDate
          select new 
         {
           Name = g.Name,
           Id = g.Id,
           ReleaseDate = g.ReleaseDate
         };

This projection (which minimizes the data being sent over the wire from a Games entity), can be tracked like any other entity. This is a big boon for Silverlight clients where we want to reduce the surface area of the data being sent over the wire.

WCF Data Services' standard wire protocol is OData (which is a variant of ATOM). This means that tools like PivotTable, code-name Dallas and others can co-mingle data with other systems that are supporting OData like SharePoint, WebSphere, OpenGovernment project and SQL Azure table storage.

Some of the problems with Data Services include the fact that Service Operations are not part of the Silverlight proxy (and are not completely supported by the client library); any validation attributes of model information (like string length) are left on the client; and having to wrap your collections as DataServiceCollections to support tracking.

While I think Data Services still represents a major case for Silverlight usage, it still has a way to go before I am completely satisfied.

WCF RIA Services

WCF RIA Services takes a different approach to data access the resembles a mix of Data Services and Web Services. In RIA Services a server project is set up to expose data across the wire, but instead of Data Services' approach of exposing queryable end-points, it creates methods on the server which can be executed to retrieve, update, insert and delete data. These methods can be crafted to take specific parameters which takes some of the responsibility for what to query out of the hands of the developer (which may be fine in some cases). RIA Services does take model constraints and validation attributes and generate them in the client, which is a big win.  Also, RIA Services is like Data Services in that you can still do basic sorting, filtering and paging via the service.

The way that RIA Services is wired up to a project (via a Shared Code folder that is generated as the server-side project changes) is sexy, but for large projects the need to keep the RIA Services' project in the same solution (or use a project file hack to get it working) becomes an issue.

RIA Services is really built for the RIA Services' DomainContext to be the center of the application (which you can see when you look at demos utilizing their Data Source object that automatically wires up data as XAML elements). While you can write a loosely coupled application, it takes planning and is not the natural design of the API.

Other issue I have is with the design of the Load API where the attempt is made to hide the asynchronicity of the call.  The problem is that when errors happen on the load operation, it is hard to capture the error (other than letting it be cause as a top-level exception) so that most users will need to provide a callback which is just like having a full asynchronous operation. No better than before but the principle of least surprise isn't followed.

Finally, in comparison with Data Services, RIA Services has a lot of the same features but is missing the ability to do projections, client-defined eager loading and loading properties (e.g. relationships).

What does all this mean?

 So here we sit as Silverlight developers and we are being asked by Microsoft to choose of the three major options for data access. The problem is that none of them are perfect by any stretch of the imagination. I would think that Data Services and RIA Services are both great solutions but they are both missing features the others have.  In some ways the generation of these two projects has caused a lot of confusion as to which is the prescribed method for doing data access in Silverlight. It reminds me of the Entity Framework vs. LINQ to SQL debacle.

But where do we go from here?  I'd like to implore Microsoft to fast-track the work needed to provide parity in these products. That means build the underpinnings of both projects from the same underlying platform. That way the features of each platform could be included in the other. The features do not become the discrimator but instead it is the style of data access.  We want and need the missing features on both platforms:

  • "Add Service Reference..." Linkage to support large development projects.
  • Exposure and code-generation of any EDMX constraints and Validation attributes.
  • Projection and tracked minimizing projection support.
  • Full eager loading and navigation support.
  • Operations and Endpoints have the same level of support in the generated code.
  • Obvious and simple communication APIs to prevent the library from surprising us with error propagation.

...One More Thing

I also have the request that for the next development cycle that we provide secondary methods for communicating validation information than just validation attributes.  Validation attributes cause our server-side POCO classes to be not really POCO (since they have to have a reference to the validation assembly).  As well as most cases require us to use the painful and hacky MetadataClass method of creating a class to *only* hold these attributes. You don't have to get rid of the attributes, just let us feed them to the model in other ways (open the hooks, we'll decide how to communicate it; whether it be a DSL, XML file, database, etc.).

Your Job

As a reader of this blog, I'd like to ask you a favor.  Respond to this blog entry. I want to make sure my frustration with the two data access stacks is not just my annoyance but is causing confusion and pain to you my readers. If you agree, just comment (it can be just saying "I agree") so I can make sure the Data team at Microsoft understands how it impacts Silverlight (and others) development efforts.  Thanks!

 



Shawn
Shawn Wildermuth
Author, Teacher, and Coach




My Courses

Wilder Minds Training
Vue.js by Example (New Lower Price)
Bootstrap 4 by Example (New Lower Price)
Intro to Font Awesome 5 (Free Course)
Pluralsight
Building an API with ASP.NET Core (New Course)
Building a Web App with ASP.NET Core, MVC6, EF Core, Bootstrap and Angular (updated for 2.2)
Less: Getting Started (New)
Using Visual Studio Code for ASP.NET Core Projects
Implementing ASP.NET Web API

Application Name WilderBlog Environment Name Production
Application Ver v4.0.30319 Runtime Framework x86
App Path D:\home\site\wwwroot\ Runtime Version .NET Core 4.6.27514.02
Operating System Microsoft Windows 10.0.14393 Runtime Arch X86