A different view of the .Net RIA Services

Some of you have probably heard about the Microsoft .Net RIA Services, if not you can find some info here. In this post I will show you a different view of the .Net RIA Services, how it can be used to create a RESTfull Service, or at least try ;)

REST Services is about “nouns” (resources, like friends, customers etc) with few “verbs” for example create, read, update and destroy. We can easily create a “resource”, where the resource can be in different kind of formats like JSON, XAML, RSS etc. It’s more or less up to us what kind of formats we want to use. If we take a look at Twitter, the REST API they use can return a resource in different formats. When we create the resource, we need to create the response value (A Response value is the value returned from a REST API, it’s a resource in a specific format). If we want to get all of our Followers by using one of the Twitter’s REST API, we simply use the following URL: http://twitter.com/statuses/followers.xml the .xml at the end specify the resource “followers” format. The response value is something like this:

<?xml version="1.0" encoding="UTF-8" ?> 
<users type="array">
   <user>
     <id>1111111</id> 
     <name>John Doe</name> 
     <location>Stockholm</location> 
     <description /> 
     <profile_image_url></profile_image_url> 
     ...

   </user>

   ...

</users>

The resource is something the developers of the API have decided. If we want to use the .NET RIA Services we can simply define the resource of the response value like a simple POCO class. Like this:

public partial class User
{
    [Key]
    public string ID { get; set; }

    public string Name { get; set; }

    public string Description { get; set; }
}


Note: The KeyAttribute is needed to specify a way to specify a property which will work as an identity for the “entity”.
When using the .Net RIA Services the the classes we can create are referred as a Entity in a model. So we create a “model” more or less, but don’t see the User class as an entity in a Model, instead as a resource used by a specific REST API.

By default .NET RIA Services will “serialize” the above class to a JSON format similar to this:

{
   "__type":"User:http://schemas.datacontract.org/2004/07/SilverlightApplication8.Web.DataModel",
   "ID":"1",
   "Name":"John Doe",
   "Description":"John Doe\u0027s description"
}


Remember that this post is a different view of the .Net RIA Services, so once again try to see the POCO as a simple resource, not as an object which we will distribute (We all know that we shouldn’t distribute objects).

Now when the resource is created, we can simply create a “fake” object which will return a list of it.

public class UserDataService
{
    public IEnumerable<User> Users
    {
       get
       {
           return new List<User>()
                  {
                      new User()
                      {
                          ID = "1",
                          Name = "John Doe",
                          Description = "John Doe's description"
                      },
                      new User()
                      {
                          ID = "2",
                          Name = "Jane Doe",
                          Description = "Jane Doe's description"
                      }
                  };
        }
    }
}


Note: I couldn’t find a good name for this class, it looks like its a some kind of data access class but it isn’t. It’s more like taking a existing model and transform it to a resource.

The next step is to create our REST API, in this case we can for example call it Followers, the same name as Twitter uses to get Followers. We can for example use ASP.NET MVC or a normal WebForm as a REST Service to get our resource.

The following is a REST Service where ASP.NET MVC is used with a Controller named UserController with and an Action method called Followers.


public class UserController : Controller
{
    public ActionResult Followers()
    {
        var userDataService = new UserDataService();

        return View(userDataService.Users);
    }
}


Followers.aspx


<%@ Page Language="C#" 
         Inherits="System.Web.Mvc.ViewPage<List<Models.User>>" %> 
<users type="array"> 
    <% foreach (var user in ViewData.Model) { %>
        <user> 
            <id><%= Html.Encode(user.ID)%></id> 
            <name><%= Html.Encode(user.Name)%></name> 
            <description><%= Html.Encode(user.Description)%></description> 
        </user>
    <% } %> 
    </user> 
</users>

We can get the Followers by simply use the following URL:   /User/Followers">http://<servername>/User/Followers

To call the REST Service and it’s API, we can for example use the Silverlight’s WebClient class. We can also use the XDocument to get the data out from the resource:

public MainPage()
{
     InitializeComponent();

     var wc = new WebClient();

     wc.OpenReadCompleted += wc_OpenReadCompleted;
     wc.OpenReadAsync(new Uri("/User/Followers", UriKind.Relative));
}

void wc_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
    XDocument xmlUsers = XDocument.Load(e.Result);

    var users = from user in xmlUsers.Descendants("user")
                select new
                       {
                         ID = (string)user.Element("ID").Value,
                         Name = (string)user.Element("Name").Value,
                         Description = (string)user.Element("Description").Value
                       }; 

}


If we use the above solution we need to do some plumbing. We first need to do a request to our URL to get the followers, then we need to read from the XML and get the values and map it to a type (if we want to work with a typed result). In this case wouldn’t it be nice to avoid some plumbing and instead use a solution where we simply use a typed API (not a string), and also get the result as typed classes with properties?

Instead of doing all the plumbing, we can use the .Net RIA Services to create a REST Service. To create and implement our REST Service and API, we create a DomainService. A DomainService within the .NET RIA Services is a class where we add our CURD API and we can also add shared domain methods etc. To create a DoaminService we create a new class which will inherits from the .NET RIA Service’s DomainService base class. We will also add our Followers API to the DomainService:


[EnableClientAccess()]
public class UserService : DomainService
{
    private UserDataService _userDataService = new UserDataService();

    [Query(PreserveName=true)]
    public IEnumerable<User> Followers()
    {
        return this._userDataService.Users;
    }
}


Note: The EnableClientAccessAttribute is only used to make sure .NET RIA Services creates a client-side proxy for our DomainService, this proxy is called a DomainContext. The QueryAttribute with the property PreserverName, will make sure the generated DomainContext for the DomainService will preserver the name Followers. Normally we should add a method called “GetFollowers”, and the .NET RIA Services code generation will generate a method for the DomainContext called “LoadFollowers”.

The Followers method will use the UserDataService’s Users method to get all the followers and return them.

When we build our solution, the .NET RIA Services will generate a DomainContext for our Silverlight app, a proxy class which will make it easier for us to “call” the DominService. The generated DomainContext will communicate to the service through an AXD called DomainService.axd using REST. After we have created our DomainService, we can if we wants to, do a direct call to the DomainService.axd and use it as a REST Service:

http://<servername>/DataService.axd/SilverlightApplication8-Web-DataModel-UserService/Followers

When we enter the above URL we will get a response value in a JSON format like this:

{
    "__type":"DataServiceResult:DomainServices",
    "IsDomainServiceException":false,
    "Results":
        [
            {
                "__type":"User:http://schemas.datacontract.org/2004/07/SilverlightApplication8.Web.DataModel",
                "ID":"1",
                "Name":"John Doe",
                "Description":"John Doe\u0027s description"
            },
            {
                "__type":"User:http://schemas.datacontract.org/2004/07/SilverlightApplication8.Web.DataModel",
                "ID":"2",
                "Name":"Jane Doe",
                "Description":"Jane Doe\u0027s description"}
        ],
    "TotalCount":-2
}

Note: The DomainService.axd will by default using the JavaScriptSerializer.

The DomainSevice.axd will take the first “parameter” “SilverlightApplication8-Web-DataModel-UserService”  and replace “-“ to “.” to get the DomainService to instantiate. In this case it will be the UserService. It will then call a method with the same name as the last “parameter” of the URL, in this case “Followers” and use the JavaScriptSerializer to serialize the result of the Followers method.

By using a class we create our resource. We have used the .NET RIA Services to create a REST Service with the API Followers to return a list of Users. We can then use the DomainService.axd to call our REST API. To make it simple for us to call the REST API and get a list of Users, we can now use the generated client-side proxy class (DomainContext) in our Silverlight project. It will give us a typed API and also a typed resource. So we don’t need to use the WebClient or a JSON Serializer on the client-side, the generated DomainContext for our DominService, will handle that for us. The following code is the code-behind file of the MainPage.xaml in a Silverlight app:


public partial class MainPage : UserControl
{
    UserContext _uc = new UserContext();

    public MainPage()
    {
        InitializeComponent();

        myGrid.ItemsSource = _uc.Users;
        _uc.Followers();

    }
}

To make a call to the Followers API, we simply instantiate the generated DomainContext class “UserContext” and make a call to the Followers API. Every “entity/resource” we creates and returns from the DomainService will be added to the DomainContext as properties. So to get the User class after we make a call to the Followers method, we can use the Users property. When we call the Followers method, an asynchronous call to the DomainService will be made. The DomainContext will use REST behind the scene and call the DomainService.axd.

Wouldn’t it be nice if we could instead of getting a whole list of Users, make it possible to define a query which will only returns the Users we want based on a criteria? It’s possible, and that is really cool:


public MainPage()
{
    InitializeComponent();

    myGrid.ItemsSource = _uc.Users;
    _uc.Followers(_uc.Users.AsQueryable<User>().Where( c => c.ID == "1") , null);
}


By default all “Query” methods added to the DomainService, takes a IQueryable as an argument. So we can pass a query as an argument. So now we can use the DomainContext as a proxy to call a RESTful Service and also define a query.

In this post, I wanted to give you a “different” view of .NET RIA Services, more or less to make sure you know how it works behind the scene, and also how it can be used to define a resource and a RESTful Service, because behind the scene .NET RIA Services uses REST.

2 Comments

  • Normen, this is just want I was looking for.

    Basically, I don't pass my 'EF' or 'L2S' or 'NHibernate' objects to my UX (Silverlight in this case)

    I'd rather use RIA.NET to pass my 'DTO' objects back and forth, using RIA.NET to facilitate that then map those objects back to my 'EF' objects for database saves, etc...

    Thanks for writeup.

  • it was a nice explanation. Thanks

Comments have been disabled for this content.