You’ve decided to create a new business application (meaning some n-tier application) using Silverlight as the frontend. Is Silverlight the best choice? That’s a debate for another post… Anyway, now it comes to deciding on a data access strategy, which one do you choose? Well this is one of those things where there is no clear winner. To make a choice, Shawn Wildermuth has a great post on the “State of Data Access in Silverlight 4.” Looking at his awesome chart comparing plain WCF, WCF Data Services, and WCF RIA Services, you’ll see that some of the things on the “Cons” side for all of the approaches could be a deal breaker. So which one should you choose? Let me take you through a deliberation that I was involved in recently when forced to make this decision. There is no right answer here (as with most interesting topics), but I would be interested in your feelings on the topic. Let’s get started…
Given the three strategies that Shawn had identified, we had pretty much focused on just WCF Data Services and WCF RIA Services. Plain old WCF services are useful for a lot of things, but they aren’t very flexible on their own. Things like client-side shaping, sorting, filtering or paging are rough, plus I don’t see the value in writing boilerplate service code for CRUD operations. I suppose you could use something like a T4 template for that, but for “standard” web services the thing I really don’t like is SOAP. I won’t wax poetic about how REST makes so much more sense than SOAP, but if you are interested, you should check out RESTful .NET: Build and Consume RESTful Web Services with .NET 3.5 by Jon Flanders, it’s a fantastic book. Sure, you could have a standard WCF Service using REST instead of SOAP, but I don’t believe that you can generate a proxy against a WCF REST service (I don’t mind WebClient/HttpWebRequest code). That isn’t a deal breaker, but it is when writing a lot of code against a lot of objects. We decided that standard WCF just wasn’t the easiest option for the lion’s share of the work.
So that leaves us with WCF Data Services or WCF RIA Services. For a previous project we had discounted using WCF RIA Services for the majority of the data access (though, we did use it for user roles and such). Trying to go into a new project with an open mind, we thought we should dig a little deeper into RIA, after all, it “seems” to be the approach that you should use for a business application as you’ll see.
WCF RIA Services Overview
So you’re building a “Business Application,” right? Well I guess a good place to start would be File » New Project » Silverlight Business Application, right? Well this assumes some things, like that you want to use things like Silverlight Navigation (yes, please), controls for user login and registration (partially ok, but we’re using Windows Authentication and don’t need registration code), and it assumes that you want to use RIA Services (maybe, but you wouldn’t be reading this post if this was clear-cut answer). I like the concept of RIA Services very much, but the implementation has some fundamental flaws. Let’s start with a couple of pros that RIA provides where I see real value:
Who likes validation code? Hmmm, no hands raised? RIA’s validation seems fantastic (at least on paper; I haven’t tried all of them in practice). Having validation code that is shared between the client and server is cool and it’s a nice addition to Silverlight. This is really the single compelling reason behind using RIA Services for me.
Sometimes there is a disconnect between your entity model and the code you want to expose to the client. For example, let’s say you have a Person object that has a First and Last Name. Well, you want to expose a property called DisplayName to the client, which joins the First and Last Name. With RIA, the DisplayName property can be added on the server and Silverlight will see it. With something like WCF Data Services, you would need to augment the Person class on the Silverlight side, where the server knows nothing about this property (Is that a big deal in this example? Not really).
Shawn’s post lists more than discussed here, but those two really stand out as useful to me. I want to embrace WCF RIA Services, but a few of the cons really rub me the wrong way.
Model and Service Disconnect
Referring to Shawn’s post, the very first con is “Entity Changes Don’t Cascade to Contract.” What does this mean? Let’s say you are incrementally building an app for managing products. You start with a very simple model with only one entity exposed, “Product.” You add the Products to your model, and you expose this over RIA Services using the wizard (listed as a pro on Shawn’s post, but wizards aren’t always a blessing as you’ll see). Anyway, so far so good. You continue your development, and you find out you need to add a “Category” entity to your model. Assuming you’re using Entity Framework, you update your model from the database (good tooling), and then you try to expose the entity over your RIA Service. Ummm… You try clicking and right-clicking all over looking for something like “Update RIA Service from Model” only to find that it doesn’t exist.
Having a disconnect between the model and the service is a giant red flag for errors on a team. Your model can end up looking totally different than the objects you are passing over the wire, resulting in all sorts of fun errors. There are workarounds for the issue, for example using a partial service class for each entity, or manually copying and pasting code from a temporary service into your actual service. You can get over the con of not having tooling, but neither option is really great (IMHO).
No Eager Loading Support
I was most shocked to find this out, since the proxies for WCF Data Services and WCF RIA Services look similar. With RIA, when you are in Silverlight (say a ViewModel or Repository) you cannot dictate what data you want. Let’s say you have a Person object, and each Person has 1 to many Address objects. On the client, you want to get and display a property found on the Address object (like City or something). Well, the client can’t eager load the Person’s Addresses. With WCF Data Services, you can add an .Expand(“Address”) to your query that you send in order to eagerly load the Address for a Person. This doesn’t exist with RIA though. The workaround is to perform an .Include(“Address”) in your service method that gets the list of People. However, this really isn’t a workaround. As a consumer of a service (Silverlight or otherwise), I want to be able to dictate what I need, not have the server force the “worst case scenario” down to me. Of course you could have two methods, like GetPeople() and GetPeopleWithAddresses(), etc., but yuck.
This isn’t listed in Shawn’s list, but I’ve bumped into issues with the “Generated Code” folder in my Silverlight projects. WCF RIA Services generates it’s client-side code when you build your solution. This is super fragile. What is wrong with Service References? I’d like to have the option to break my client when I feel like it (Update Service Reference), but I don’t get the choice with RIA. Build your solution, and boom all the changes are pulled down whether you are ready or not.
WCF Data Services Overview
Full disclosure, I LOVE WCF Data Services. Does it have some shortcomings? Sure, but it’s quite amazing. I have been using WCF Data Services through all of it’s names (code-name Astoria, ADO.NET Data Services, and now WCF Data Services). I’ve used it before the output was known as OData, etc. In short, I’m a huge fan of the strategy. My love of WCF Data Services comes from the fact that they are REST based and can be consumed by just about anything (shameless plug for ruby_odata; more info here). I also like the simplicity of exposing your data model over HTTP. IQueryable
Having used WCF Data Services for so long, I’m pretty familiar with the good and the bad. The only two things that are lacking are the two “pros” found in the WCF RIA Services discussion found above. Really though, WCF Data Services serve all spaces and isn’t specific to “Silverlight” or RIA Applications. You can do validations with WCF Data Services just fine (e.g. QueryInterceptors and ChangeInterceptors), but these are limited to the server. It makes perfect sense though. How could the WCF Data Services team integrate client and server validation into one when the range of clients is so broad? The wide reach of WCF Data Services is what makes them so useful.
After deliberating for hours, we decided to stick with WCF Data Services for the lion’s share of our development. This decision was made simply because none of the WCF Data Services cons were deal-breakers for us, while the cons with WCF RIA Services were harder to swallow. Again, that doesn’t mean we aren’t going to use pieces here and there (like RIA for roles and such), but we felt we needed a “default direction.” What are your feelings on this?