Ria Services under the hood Part 1 – Service Operations

We’ve been using Ria Services at work for a LOB application written in Silverlight 3.  Ria Services is still pretty new, and when you use it, you find little quirks that don’t immediately make sense.  Some of the behavior prompted my curiosity, so I busted open Reflector and Fiddler to dig a little deeper, and thought I’d publish these findings for anyone who’s curious.  I’ll probably do this in bite-size chunks; hence the “Part #” post naming convention.  The focus is mainly on the serialization, marshalling, and service handling behaviors and does not address application services like security or the validation benefits of Ria Services.  To keep things simple, we use straight POCO and won’t muddy the waters by bringing in an ORM like the Entity Framework (which we are using at “The Company” with moderate success).  You can find all the code for this post (and other Ria Services posts) up on my space on sky drive here.   Just ignore the other pieces of code beyond the “EchoString” service operation for now.  Those other methods will be covered in future posts.

Here’s our simple service operation for our DomainService:

[ServiceOperation]
public string EchoString(string input)
{
  return input + “” + DateTime.Now.ToString();
}


And here is the Silverlight client consuming it:

    DomainService1 _ds = new DomainService1();

    private void Button_Click(object sender, RoutedEventArgs e)
    {
      _ds.EchoString("jason calling",
        (InvokeOperation<string> invokeOperation) =>
      {
        MessageBox.Show(invokeOperation.Value);
      },null);
      
    }

When the client makes this call, what’s happening under the hood?  To answer that question, you can inspect the generated code that Ria Services places in your Silverlight client.  You can find that code by clicking the “Show all Files” option within Solution Explorer, and you’ll see a “Generated_Code” folder, containing the generated code projected from your DomainService in your web project.  There will be several classes in this file including DomainService1.  Check out the default constructor and you’ll notice this default constructor:

 /// <summary>
 /// Default constructor.
 /// </summary>
 public DomainService1() : 
         this(new HttpDomainClient(new Uri("DataService.axd/SilverlightApplication1-Web-DomainService1/", System.UriKind.Relative)))
 {
 }


The HttpDomainClient is what our client-side domain service uses to conduct the HTTP calls.  The server-side handler (DataService.axd) is registered in your website’s list of HttpHandlers in the web.config (see below), and that’s the guy receiving the HTTP calls (and ultimately getting those calls to your server side Domain Service object):



<
httpHandlers>

(others omitted for brevity)…

<addpath="DataService.axd" verb="GET,POST" type="System.Web.Ria.DataServiceFactory, System.Web.Ria, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"

  validate="false" />

</
httpHandlers>


Referring back to our “EchoString” Service Operation, here’s what’s going on in the generated client-side DomainService1 class (note that last call):

public InvokeOperation<string> EchoString(string input, Action<InvokeOperation<string>> callback, object userState)
{
    Dictionary<string, object> parameters = new Dictionary<string, object>();
    parameters.Add("input", input);
    return base.InvokeServiceOperation<string>("EchoString", parameters, callback, userState);
}

When we bust open the System.Windows.Ria.Data.DomainContext (which our DomainService1 derives from) in Reflector and look into that InvokeServiceOperation, we’ll note that [after validation work is conducted], a call to the DomainClient’s BeginInvoke method is called.  This passes through the DomainClient base, where some housekeeping is done, then onto the HttpDomainClient.BeginInvokeCore method.  Inside this method, a System.Net.HttpWebRequest object is created and setup for an HTTP Post (since this is a “ServiceOperation”), with content type set to “text/json”.  The parameters, callback info, and user state are all packed up and sent through as well.  So, now we’re heading to the server over the wire as json, so here’s what the request looks like through Fiddler:

———————————————————————————————————————————

POST /ClientBin/DataService.axd/SilverlightApplication1-Web-DomainService1/EchoString HTTP/1.1

Accept: */*

Content-Length: 17

Content-Type: text/json

Accept-Encoding: gzip, deflate

User-Agent: (omitted for brevity)

Host: localhost.:53937

Connection: Keep-Alive

Pragma: no-cache

["jason calling"]

———————————————————————————————————————————

Recall the “System.Web.Ria.DataServiceFactory”  assignment from the web.config entry containing the HttpHandler entry.  That guy splits out the portion of the HTTP path after the handler (the “SilverlightApplication1-Web-DomainService1” bit from the info above), replaces the dashes with dots, and uses reflection to snag an instance of that type (our server side DomainService1 guy).   A statically-cached map of the public instance service methods are created (or retrieved on subsequent requests) for the object, which will be used to execute the methods.  Methods are wrapped into classes that derive from DomainOperationEntry which provides additional information about the "Domain Operation” such as Authorization and the DomainOperation type (Query, Insert, Update, Delete, Custom, ServiceOperation, or Resolve).  The method name to execute is the 2nd part of the HTTP Path (the “EchoString” in this case).  Some checking is conducted to determine what type DomainOperationType (note the difference here of “DomainOperationType” which is a a more coarse categorization containing only three choices of “Query”, “ServiceOperation”, and “Submit”) will be executing.  Generally, HTTP “GET” is used for Query DomainOperationTypes whereas HTTP “POST” is used for ServiceOperation(s) and Submit.  Finally, a System.Web.Ria.DataService object is created, initialized with the DomainOperationEntry it will be working with, and is returned by the DataServiceFactory.  At this point, the DataService’s IHttpHandler.ProcessRequest(HttpContext) method is executed as part of the standard HttpPipeline in asp.net.  Method parameters are deserialized as json using the JavascriptSerializer.  Security checks are conducted to ensure the method is permitted, parameter types are resolved, validation is run [again] on the server, and the method is invoked on our DomainService1 object.  The response from our DomainService1 object is returned back out from the DomainService base class, and out through the DataService[.axd] serialized through the JavascriptSerializer (as json). 

For our example “EchoString” method, here is the raw HTTP response:

———————————————————————————————————————————

Server: ASP.NET Development Server/9.0.0.0

Date: Sat, 26 Sep 2009 21:18:21 GMT

X-AspNet-Version: 2.0.50727

Cache-Control: no-cache

Pragma: no-cache

Expires: -1

Content-Type: text/json; charset=utf-8

Content-Length: 128

Connection: Close

{"__type":"DataServiceResult:DomainServices","IsDomainServiceException":false,"ReturnValue":"jason calling 9/26/2009 5:18:21 PM"}

———————————————————————————————————————————

Summary

So, we’ve seen that Ria Services is handling a number of things for us behind the scenes, including serialization on the client, deserialization on the server, and routing the calls to the method counterparts on our DomainService object on the server.  These are things you can also do with other technologies such as WCF or plain old .asmx web services, but doing so requires creating those services, and maintaining service references to those in the client.  Ria services also does bring other goodness like the validation and application services like security to the table which is pretty sweet as well.  In the next post, we’ll look closer at Query Domain operations and see how those look under the hood and on the wire.

4 thoughts on “Ria Services under the hood Part 1 – Service Operations

  1. Pingback: Ria Services under the hood Part 2 – Query Operations « Jason Harper’s blog

  2. Pingback: Ria Services under the hood Part 3 – The CUD in CRUD « Jason Harper’s blog

Leave a reply to Klinger Cancel reply