In part 3 I showed how to access a simple RIA service from Silverlight, but it wasn't too interesting as it didn't even return an object of a class (just a double). In this post I'll show how to extend the service to return an instance of a user class. For simplicity I'll still implement this in the RIA web project and in later posts we'll use another library.
Creating a class for use in RIA services is as easy as creating a new class and adding a few data annotations. In the case of SocialBus, the primary data type is a 'User', so I'll add a simple user class to the project and add a couple of useful properties:
This class itself isn't very useful for RIA services. As a matter of fact if we tried to use it in a service API the system would throw an exception complaining that there is not a key defined for the class. This is imporant in RIA services, even with POCO, as the class needs to have this attribute assigned using data annotations. So, I'll add this by including the System.ComponentModel.DataAnnotations namespace, and the [Key] attribute on the ID property:
What is interesting is that if you compile the solution, there is still no additional code generated. The code generator is smart enough to know that even though I annotated this class, that no domain service uses the class and therefore code is not needed.
Now I need to modify the domain service to return User object. This is a typical use case in SocialBus, that given an ID the client would like to get User object for that ID. For right now to keep it simple I will just add a single GetUser method that takes no parameters and returns a canned instance (this will get much more complicated later):
I won't show the generated code for the service, but the generator has added a User class to the generated code:
Notice all the niceties here. DataContract, DataMember and Key attributes; fully formed properties that handle all of the entity types of operations (on this, on that, ...); all automatic.
To use the object on the client, the Silverlight code changes to be as follows:
Notice that there are some subtle differences here than in the last example. First, notice that the GetUser method in out domain service generates a method named 'GetUserQuery'. This is because since it the method is returning and entity, it appends Query to the client side method name. This is to clue you into the second difference, in that this method returns an EntityQuery<User> object instead of an InvokeOperation instance, because this is actually constructing an entity query object that is both lazy loaded and can be used in a LINQ clause.
The third difference is that to get the object it is needed to pass the query to the Load method of the domain context object. This will actually invoke the service call asynchronously, and it is then possible to set the Completed event handler to a method that is executed when the call completed.
The final difference(s) are that the first parameter to the callback is of type LoadOperation<T>, and that to get the result values it is needed to access the 'Entities' property of this object, and in this case I get the first object and assign it to the data context of the user control.
For reference, here is the XAML for this control to show how the data binding is specified:
That's it for this post. The next post will show how to use a POCO in another library other than the .web project created by the RIA wizard.
I started playing around today with ADO.NET Data Services, and all the examples I can find use the Northwind database. I never noticed it until now, but Northwind is not installed automatically any more. And it also was not easy to find the database online.
I did find a script to do this at this site. Thanks Jon!
And for good measure, you can get the AdventureWorks database files here on CodePlex.