A few weeks back I wrote about getting RIA services to work with POCO. It was a long post, so long that it was 5 posts. In the weeks since, I spent some time trying to use POCO/RIA in some work that I was doing for a client, and I started to develop some strong feelings about why bother with all of this extra work to just get things to work with RIA instead of just using WCF/Data Contracts/DTOs. I'm still trying to be able to articulate these feelings, but figure I'll give it a shot right now.
First, it was a lot of work to get the POCO to work with RIA, at least compared to just creating a class that is annotated with DataContact/DataMember attributes. The former took me 5 posts just to describe how it works. The latter takes maybe a minute to build an end to end solution.
But that's not all.
Second, a lot of what RIA (excuse me WCF RIA) does is autogenerate code to do different things, such as generating client side objects that know how to track changes and do automatic validation. I'm left to wonder about the former, but do by that the automatic validation code is useful, but I'm not sure its worth the effort getting POCO to work over using validation libraries such as EL.
The issue with tracking changes I think is the sticking point, as I don't see what value there is in POCO, as it is inherently tied to using entities on the server side (read Entity Framework). Without the mapping back to entities in the client side, is it adding any value? I don't see that it is.
This also leads to the generation of service methods for which I can see as nothing but CRUD operations. Again in a POCO world, is CRUD really necessary? If I'm not using a database, and not modelling my objects off of entities generated from the database, do I really need CRUD methods auto generated by convention? And to be honest, it was really hard to just get a single POCO object returned with RIA.
So what I think this boils down to is without a database, and then additionally without EF, I don't see the advantage.
And now one more kicker. The system I was building wanted to try and use RIA, but we were not connecting to a database, so hence the POCO route. Instead of a database, we are connecting with a backend system via EMS messages bridged over JMS into services in Oracle. This throws this whole thing into the world of asyncronous messaging. WCF RIA services are inherently tied to syncronous operations, since they pretty much are generated to do syncronous communications to the database and return the result. The EMS method we looked at had to be asyncronous (it's the nature of the environment I'm working in, not that EMS can't be syncronous - the back end Oracle app could not do this syncronously).
So, the method to get objects would need to either block waiting to a response message on EMS, or return directly without any data. In the latter case, there is really no use for RIA; why do all this magic if I can't get the data to be managed during the RIA services call? Well, none that I can see. In the case of blocking waiting for a response, sure I can program that, but it is going to inherently reduce scalability of the solution. And it kind of defeats one of the things I really like about Silverlight - the asyncronous nature of calls to the client. The Silverlight client will still do the call asyncronously which is great, but with my having to program syncronous blocks on the server it just seems to defeat the purpose. I would rather go totally asyncronous and gain all the scalability possible, even at the expense of having to use callbacks from the server to the silverlight client for when response messages arrive back on EMS.
So, I guess this would lead to some rules about when to use / not use WCF RIA. I'll take a try at them...
When not to use:
- You are not using a database.
- You need asyncronous communications with a third tier
- You are using something other than Silvelright for a client
When to use:
- You don't have a database, or are doing async communications with a third tier, but feel the automatic generation and use of validation rules is worth the effort
- You are building forms-like CRUD apps against your database model
I also have concerns about how portable this is to non-Silverlight clients. For example, I can't use the RIA objects in WPF, and I wonder how this would integrate to web or AJAX clients; sure the classes can't be used, but can you use the web services that are exposed? My guess (as I haven't tried it yet) is that you can't, at least easily.
I'd really like to hear your comments on this. Every time I look at RIA services I really want to like it, and I'd like to be able to feel like it has broader value, so please let me know your experiences.
65014566-3505-44b6-b6ba-ce698f8180bd|1|5.0
In part 4 of this series I showed how to declare a POCO for use in RIA services, and how to use the object on the client. In this post, I'll show how to use a class in another project/assembly. Honestly, it's not very difficult at all.
As part of the SocialBus solution, I already has a User class defined in another project (SocialBus.Model). This is a pretty straightforward class as-is:

A user in SocialBus is just a SocialBus specific user id, and a ServiceInfo object. The ServiceInfo object is what is of real interest in SocialBus, as it will contains users and messages from various social networks (Twitter, Yammer, ...) that are mapped to this SocialBus user with the specified ID. But for purposes of this example, it is only needed to be concerned with this User class.
To RIA enable this class, all I need to do as before is annotate the class, and all that is needed for now is to add a Key attribute:

This class is now ready to be used in the RIA services library. All that is needed to be done is to add a reference to SocialBus.Model to SocialBus.RIA.Web, and to change the domain service to return an instance of this User class:

Now this service is very contrived and not of much use, but this is just for showing this example. In another series of posts I will discuss connecting the domain service to LINQ to SQL, Twitter and Yammer; returning collections of objects; but like I said that's for another time.
The differences in this service model are really just in the using for the SocialBus.Model namespace, and in returning and instance of that object. The client only changes slightly (besides there are no e-mail and username properties) is that I needed to add a 'using SocialBus.Model;' line.
That's it for this series. There's a lot more that can be covered, but like I said those will be for another series of posts (that I'll do soon).
c16efd58-696b-4c08-9139-f71dd9f0acb5|1|5.0
In
part 2 I showed how to create a domain service and get the code generated for that service (heck that was automatic). In this post I'll show how to call that service from Silverlight.
In the the first post I added a reference to the Silverlight project to the Silverlight.RIA project, which will allow the Silverlight application to use those classes. I modify the MainPage.XAML to have a TextBox named 'result' and modify the MainPage.XAML.cs file to be as follows to call the service and display the result:

What's going on here? We'll, there is a whole new syntax to these calls, which I will explain briefly.
On lines 14 and 15 I add two namespaces as they are needed for the InvokeOperation (System.Windows.Ria), and the SocialBus.RIA.Web is the namespace in our RIA web project that contains the domain service.
The domain service we created is implemented by the SocialBusDomainContext class. It has a bunch of methods for managing entities, as well as the method I added to the class, 'Add'. To call the service, I create a new instance of this class, and call the 'Add' method. As is the case in Silverlight, all calls are asynchronous, so to capture the result a delegate is assigned to the method calls return value's (which is an InvokeOperation object) Completed event handler. I choose to use the lamba syntax for this, and the method is actually passed the InvokeOperation object and an EventArgs object. I cast the 's' parameter to InvokeOperation<double> (the generic is important), get the return Value, convert it to a string and assign it to the text box on the UI.
Sure, there is a lot more detail that can be covered here, such as error/exception handling and such, but this show the basics of calling the service and using the result. In the next post, I'll show how to create a POCO and pass it to the client.
dccac8dc-b7a6-4b51-868b-f14f55b5e963|0|.0
In part 1 of this series of posts I covered adding a new WCF RIA Services Class Library to your solution. In this post, I'm going to cover creating a domain service and getting the code generated for the domain service. Note that in this post I'm not even going to create a new POCO - I'll keep it even simpler. In follow up posts I'll show how to use POCO and an POCO in an existing library.
To add a domain service for that will eventualy serve POCO objects, and hence create a web service to implement it, I add a new items called 'Domain Service Class' to the SocialBus.RIA.Web project:

When you press add on this dialog, you will then be presented with the 'Add New Domain Service Class' dialog. The purpose of this dialog is to allow you to select a data context (or object context) from you solution for the derive the domain service. Normally this adds a lot of smarts to the domain service for managing entities exposed by providers like the Entity Framework. Since we are using POCO, we can just select 'OK':

This adds a file named 'SocialBusDomainService.cs' to the project, and it looks like the following:

There's not a whole lot to this class, but I'll shortly be adding methods to provide functionality to clients.
One thing that I'm going to do right now is add a quick Silverlight application to the solution for showing how to use these classes; right now we have no place to use these so we need to do that now. So, in the RIA folder I add a new Silverlight application (named SocialBus.RIA.TestClient) and I already had a web project in the solution (named SocialBus.Web) so I serve up the Silverlight app from that project.
I also make sure to 'Enable .NET RIA Services' on the dialog that pops up:

Two things now need to be done. I need to add references for the RIA projects to both the new Silverlight client, and to SocialBus.web web site. So, in the new Silverlight project I a reference to SocialBus.RIA, and to the SocialBus.Web I add a reference to SocialBus.RIA.Web. What this does is allow the Silverlight app to use the code generated by VS.NET / RIA, and the reference to SocialBus.Web extends that solution to know how to serve up the domain services declared sin SovialBus.RIA.Web.
Before proceeding, a useful thing to do is to select 'Project -> Show All Files' from the main menu when the SocialBus.RIA project is selected. RIA auto-generates code into a hidden folder anmed in that solution, and this lets you see that folder and the code files:

Right now there is not folder or files files as no code has been generated, even if you compile the solution. This is because the domain service is empty at this point, and the code generation extensions see this and don't generate anything. As a matter of fact, there is also a warning to this fact emitted by the compiler:

To get some code generated, I'll add a real simple method to the domain service. I don't think this scenario is written anywhere, as every example seems based upon entities, and CRUD operations. What I'm going to do is just add a method that adds two doubles and returns the result:

I'll be honest, I'm not sure this is even supposed to work as I can't find any info that supports it. But it does. Compile the solution and you now see code generated:

Cool!
Double click the generated file to examine the generated code. The at this point contains one class, SocialBusDomainContext, which is the class we will use in the Silveright project to call the domain service (partially shown here):

Note the 'Add' method which is generated to match the add method of the domain service we created. There are actually two versions with different signatures that are created (to give different ways of calling the service):

One thing I want to point out at this point. How is this code generation triggered, and how does it know what code to look at? Open the properties for the SocialBus.RIA project, and it shows the following:

The .NET RIA Services link specifies a project, that when this project is compiled, that will be examined for domain services and entities, and for those identified code will be generated.
One more thing. Because I'm using a Silverlight RIA Class Library and my own web site (not one auto generated by the wizard), the web.config on my site must be modified to know how to serve the RIA service from the domain service class. Getting this to work requires adding three entries to web.config:

There's is still some magic in all of this on how the service is exposed, but that's a story for another post.
Okay, I think that's enough for this post. In the next post I'll show how to call this service from Silverlight.
7741eea4-f6d1-4572-abc8-82e17470833d|0|.0
Now that it's post PDC09 I've decided to take some time to migrate some of the code that I have in my SocialBus project from standard WCF and DTO's over to RIA services. The SocialBus project is something I've been working on as an evolution of back end of the TweetZenn client I was building before. What it will provide is a unified interface to various social networks; right now that being just Twitter and Yammer.
Up to now I've built it with standard WCF services. This always had a problem that bugs me to now end. In the solution I have "Model" classes for the domain, and the service calls return those model objects to the client. The problem is that to use the service in Silverlight, the proxy generator builds new classes based off of the WSDL from the service. These classes look the same from the perspective of properties, but they are:
- In a different namespace
- Lose any methods to perform manipulations of the data in the objects
What this is in all actuality is an implementation of the Data Transfer Object pattern implemented by visual studio. It's problematic for the reasons mentioned above, as well as if you build any libraries that use the model objects, the objects you have in the client are actually not the objects in the library, and it won't work.
A typical scenario to solve this is the following:
- Cross-compile the model code in Silverlight, and
- Project the DTO objects into the silveright versions of the model objects
Well, this works fine, but it's a real pain in the butt. Every model object's .cs flle has to be added as a link into a Silverlght project. First, this is real fun with the Silverlight and non-silverlight libraries get out of sync because you forgot to add a link to a new class. Second, you are doing all these projects. Sure, LINQ makes it real easy, but why can't I just use my object as I defined it the first time!?!?
Well, WCF RIA services is supposed to solve all of this. I've played with it a bit in the last week and decided to really start using it. Note, I tried the CTP and had too much trouble with it, but those issues seem to be solved. So, I'm going to stick it in a real project now and give you some tips on how to use it.
Now, this may not be the most elegant way of doing it. It's what I'm doing to learn more. Also, I am using POCO, which is for the most part very sparsely documented and not in a manner of how I want to use it. Finally, yes, I use LINQ to SQL on the backend, and I could just move to LINK to EF and use RIA to move the entities to the client. However, this has issues to me that are not obvious yet in this solution; so yes, I could do it and things would be easier for purposes of this demonstration, but it is not in the long run so I'm just going to use LINQ to SQL for that database access and project them into the domain model POCO objects for passing back by RIA (also note that client side I am not planning to need any entity tracking, so that lack of functionality also makes EF an amount of overkill).
To start out, the solution looks like this:

What we need to do is add a WCF RIA Services Class Libary to the solution (I'm putting it in a solution folder named 'RIA' - which is already shown):

This creates two projects in the solution:

The Class1.cs files are not needed so I will delete them as I'm going to use an existing C# library instead of adding new classes to these projects. This is one area in existing documentation that is not clear as it always mentions to add new classes to these projects. What if I have existing classes in another assembly and I don't want to duplicate effort (Dont Repeat Yourself - DRY)? Well it's okay as it works fine and I'll show an example of it.
Anyway, what are the purposes of these two projects?
The project that ends in '.Web' is where we will place our RIA domain service(s), which will eventually be exposed as WCF services (I'd say web services, which used to be true, but there are other potentials now too). This project can be linked into your web project for you Silverlight app and the service(s) defined by the domain service classes will be exposed from that web site. Also, in most examples on the web, you also put your domain objects in this solution. Since I've got them declared already, we'll only be putting domain services in here.
The other project is where the RIA services extensions in Visual Studio will auto generate code for Silverlight based applications, which includes both service proxies, as well as Silverlight based versions of your domain objects. This code generation is done by the extensions by examining the attributes on classes in this solution (and it turns out any referenced assemblies) post compile.
This is really convenient for the following reasons:
- You don't have to manually create the proxies through add service reference,
- You never have to regenerate proxies when changing the service interface (the code is always regenerated),
- The domain objects are in the same namespace as you gave them in wither the .web file, or in our case the assembly that we already have written, and
- The signature of the Silverlight objects will be the same, and given the correct use of RIA attributes, will also have any methods that you define for client side business logic.
Well, I'm thinking I'll break this into a number of parts as it appears this will be involved. In the next post, I'll write about how to create and consume a really basic domain service thereby showing how RIA makes this all work.
70243032-00f1-4c87-80fa-c22f2b134bdd|2|5.0