I’m thrilled RIA Services is out at last.
Developers who are familiar with Forms-over-Data, end-to-end, business application development at last have a Microsoft-sanctioned approach to building such applications in Silverlight.
They’re less inclined to roll-their own data management solution and more inclined to let someone else handle the plumbing.
That choice is not without problems. It’s unnerving to hand the keys over to a framework and say “you drive.” But let’s face it, your home-brew solution is just another framework too. It may be yours … which makes you feel all gnarly and in control. But it’s still a framework that someone is going to have to document, train, maintain, support, and grow … at the probable expense of delivering the end product demanded by the customer.
RIA Services has made it OK to delegate these challenging and time-wasting aspects of the application to a third party.
For me, the usual conversation has shifted from “Why do I need something like DevForce?” to “Why DevForce instead of RIA Services?”
Here’s how someone put that question on the RIA Services Forum.
DevForce or WCF RIA Services? Both seem to do more or less the same data abstraction for Silverlight, but which would be the better route to go in the end? The price tag for me is the winner with WCF RIA services, but this is not always the right choice. Any thoughts?
Colin Blair, MVP and RIA Services aficionado, invited me to respond to that forum post. Which I was happy to do :-).
You could read it there. But I’ll spare you the trip and re-post my response here.
I have much more to add… and I’ll elaborate in the coming weeks and months. Meanwhile, it’s a start.
Yes, RIA Services and DevForce share a common perspective: end-to-end application development, programming against a rich entity model backed (typically) by relational data with validation, concurrency, security, change management, unit-of-work rolled in.
DevForce has been in commercial release since 2002 (long before Silverlight) so it's been dipped rather thoroughly in the acid bath of real world experience.
It supports both 2-tier and n-tier applications (a config change) and all the typical .NET client technologies: Windows Forms, WPF, Silverlight, ASP Web Forms, ASP MVC. You can write one code base and use it across all of them ... not that that is always a great idea. We have versions for .NET 2.0, 3.5 and 4.0.
Let's assume, however, that you are only interested in Silverlight and you don't care about product maturity, track record, or any of that.
If it seems that DevForce and RIA Services are similar ... that's intentional. We have a common perspective and we want DevForce to align with RIA Services APIs and techniques as much as possible ... so that it's easy to move between the two communities.
But DevForce and RIA Services are not clones. We do many things differently and offer capabilities beyond the RIA Services baseline.
Our customers often cite some of the following dozen DevForce differences as their reasons for choosing DevForce:
1) Same model on server and client. The code you write on the server is the same as the code on the client (unless and except where you don't want it to be). Open the Employee class on either side ... it's identical. The physical class file resides on one side (typically a server, full .NET project) and you have a Silverlight model assembly that links to that file. Compilation produces different assemblies (.NET and Silverlight) whose class names, structures, and logic are effectively the same.
2) No code generation magic. We don't touch your code. We don't generate client code. No surprises.
3) Most DevForce applications use Entity Framework for Object Relational Mapping (ORM) and persistence operation (query, insert, update, delete).
DevForce generates its own (partial) classes from EF's EDMX using T4 templates; we don't need, use, or generate EF's own classes.
Our classes are serializable and designed to support RIA scenarios. We inscribe the UI-hint attributes (e.g., Display) and the obvious validation attributes (e.g., Required) into the generated classes. No separate metadata class files needed (keep reading)
4) You can override our code generation to introduce your own behaviors. You could take over the entire template but it's much easier to override one of the many code generation methods that target the moment of interest to you (e.g., property generation).
5) No service method pollution. In RIA Services you have CRUD methods for each type in your model. There could be 400 methods in a 100 entity model. We don't generate CRUD methods; like WCF Data Services, we manage CRUD operations dynamically. Of course you CAN write arbitrary service methods if you wish. You can intercept any Query to inspect, limit, adjust the query. You can intercept any Save to inspect, reject, add/subtract/modify the entities in the change set, or perform arbitrary operations (custom logging and auditing).
6) Iterative Development: In demos, you build your model and you're done. In reality, you will add, remove, and rename your properties, entities, and the relationships among them. over the long course of your application's lifespan. Such adjustments are trivial with EF-backed models; update the EF model, compile, and run.
Ok ... maybe you should test too and you made these changes because you wanted to introduce new capabilities. The point is that you'll program to those business concerns; you won't be updating a domain service file and fixing up satellite, entity-related class files.
7) Client-side LINQ. DevForce supports client-side composition of any LINQ to Entities query, including projections of all kinds, projections into anonymous types, aggregations, grouping and ordering, includes, polymorphic queries (query on a base type). There is NO query you have to compose on the server in a "domain service" method. You don't add OrderBy clauses on server query methods. It is almost unheard of for a DevForce application to have a server-side query method.
8) Client-side caching. Query results are cached as are entities you create, modify, delete ... and have not yet saved. RIA Services does this too.
But DevForce applies your LINQ queries BOTH to the server store and to the cache. Suppose you have queried for all Northwind employees; you change "Nancy Davolio" to "Sally Davolio" and you add a new employee named "Sam". Meanwhile, another user has saved a new employee named "Sherry". What is the result of a query for employees with first name beginning "S"? The DevForce answer includes "Sally (formerly Nancy)", "Sam" and "Sherry".
You can tell DevForce to query ONLY the cache or ONLY the server ... as appropriate.
It's trivial (and recommended) in DevForce for your Silverlight application to prepare the cache with entities you need for a particular user scenario as you enter that workflow. You then would default subsequent query execution to "CacheOnly", and "party on" as if you had an in-memory database. Yes, you can still make remote queries and asynchronously refresh all or part of the cache at will.
The key benefit: you can easily program the user experience in the synchronous style familiar to most business application developers and still exploit the responsiveness of asynchronous data access ... using the same queries.
9) Productivity and Testability. You don't need a database or server to build and test your application. You can populate the DevForce entity cache with test entities - entire object graphs - and run disconnected. You can serialize the cache to file (e.g., Isolated Storage) - in a single method - and restore that cache at will. I often build a development data cache file, include it as a resource, and launch my application "in test mode"; the cache fills with the dev data rather than having to hit the server, and I'm running with no web server at all. I can make and explore UI changes in a fraction of the time it would take if I had to spin up Entity Framework and a server. I can work with colleagues far away who don't have Entity Framework or the database ... because there is no dependence at all.
10) DevForce entity properties are implemented with "property interceptors" that enable you to inject custom behavior into the getters and setter. Without touching the Employee class I can add logic to automatically mask the Social Security number ... unless the employee is the current user or the user is an HR admin. I could inject logic into a setter to force values to upper case. I have complete, fine-grained control of the DevForce generated properties before and after the actual value access or mutation.
11) DevForce validation supports the same DataAnnotation validation attributes as RIA Services in addition to our own (richer) validation attributes. But you're not limited to attributes. You can add validation rules programmatically to the class and we'll discover them. You can access the list of validation rules for any type and manipulate that list, removing existing rules and adding other rules ... perhaps customer-specific rules determined by metadata. You can do this with logic entirely outside the entity class. And DevForce validation can be applied to any object, not just entities.
12) Navigation properties (Order.OrderDetails, Order.Customer) to related entities work even if the related entities are not in cache. DevForce fetches them asynchronously ... and can notify you when the data arrive. I would be wary of multiple, hidden trips to the database (the N+1 problem with lazy loading); you should consider eagerly loading these entities instead. But lazy loading has its place. Of course you can disable lazy loading of any property at any time.