The Elephant and the Silverlight

Thoughts and analysis of Silverlight for business applications

Page List

    Meet the DomainClient

    For those following along, I will be covering the Entity, EntityList, EntityContainer, DomainContext, and DomainService in the future and in that order, but for today I am jumping to the DomainClient. Roughly speaking, I am introducing each object in the reverse order of what you may expect. The point I am trying to make here is that RIA Services is more than just a bunch of meaningless plumbing designed to pump data from between the DomainService and the DomainDataSource. There is great power, great flexibility, and quite a bit of elegance to be found within RIA Services. Nowhere is this more apparent than with the DomainClient.

    Everything you thought you knew was wrong

    One of the early lessons that newcomers to RIA Services learns is that the DomainDataSource doesn’t actually do all the things that they think it does. The DomainDataSource doesn’t actually load data, the DomainDataSource doesn’t actually submit changes, and the DomainDataSource doesn’t actually store the entities. The DomainDataSource is a proxy that passes all of those commands to the DomainContext. Well, if you are reading this blog you are now a more advanced student of RIA Services so here is your next lesson: The DomainContext doesn’t do all the things you think it does. It doesn’t actually load data from the server and it doesn’t actually submit changes to the server; those jobs are actually done by the DomainClient. (It also isn’t really where the entities are stored, come back for the EntityContainer post for more info.)

    Power of Simplicity, Flexibility of Abstraction

    The DomainClient does three things: Query, Submit, and Invoke. Each of the three has a public Begin, Cancel,  and End function and each of those has a protected abstract version that has a name ending with Core. For example, there is both a public BeginQuery and a protected abstract BeginQueryCore. The DomainClient class itself is abstract and cannot be used directly; you must use one of the two provided implementations or create your own implementation

    Each public method of the DomainClient does an argument validity check, wraps the callback inside its own callback, in the case of a BeginSubmit converts the ChangeSet into a list of EntityOperation objects, and finally passes it all to the protected Core method. That is it, that is all that the DomainClient does. Everything else is up to the particular implementation of DomainClient.

    Notice I haven’t said anything about the DomainService; that is because the DomainClient and DomainContext are actually completely abstracted from the DomainService and whatever type of communication is going to be used to talk to that DomainService. In fact, your specific implementation of DomainClient may not even be talking to a DomainService at all. This is quite ironic considering that the DomainContext is usually generated by analyzing a compiled DomainService. Currently, the generated DomainContext that must of us deal with is hard coded to use the HttpDomainClient. The HttpDomainClient is a a one trick pony that only knows how to communicate with the DataServiceFactory (aka DataService.axd) but that will change when what is currently named the AtomDomainClient becomes the default implementation in the PDC release of RIA Services.

    Wilco Bauwer has a very cool demo showing how the AtomDomainClient can connect directly to an Azure service.  Without a DomainService the code generator doesn’t work so Wilco uses a few T4 templates to generate the Entities and DomainContext. Future versions of RIA Services, meaning after the initial release next year, are going to use T4 templates for all code generation. This will make it even easier going forward to use the RIA Services client with back ends other than the DomainService.

    Wrap-Up

    There are going to be several more posts (more code, less text) on the DomainClient before I move on in in the future, but I want to wrap up this post before all this text puts everyone to sleep. Some important thoughts I would like you to take from this article are:

    • The DomainClient is the client side object in RIA Services that actually performs does the Load, Submit, and Invoke actions that we ask the DomainContext to do.
    • The DomainClient is an abstract class that has no dependencies on how communications will be performed or what is being communicated with.
    • The DomainClient has no methods marked internal, this makes it really easy for us to implement.
    • The DomainClient is so simple that creating your own implementation is not difficult. It would be really easy to mock the DomainClient for unit tests.
    Detour

    I have come to the realization that I need to move on to the Entity and other, more interesting objects. The main problem is that I don’t want to cover the HttpDomainClient and the AtomDomainClient since both of them are temporary code but talking about the code in abstract is just…boring to write about. So, I am moving on. If anyone has any specific questions about the DomainClient and how it works let me know and I will get them answered.


    Permalink | Comments (9) | Post RSSRSS comment feed

    Comments

    Nikhil Kothari United States

    Thursday, September 03, 2009 11:37 PM

    Nikhil Kothari

    Colin,

    Excellent series! Besides the fact that I love seeing folks getting in-depth insight with what we've designed, I also love the clear writing style.

    Couple of links to share with you:
    - Using DomainClient to connect directly with the Bing Search API:
      www.nikhilk.net/BLinq-Silverlight-RIAServices.aspx

    - Using a MockDomainClient to unit test client code, while mocking the server:
      www.nikhilk.net/...rvices-ViewModel-Pattern-2.aspx

    Looking forward to future posts...

    ColinBlair United States

    Friday, September 04, 2009 6:41 AM

    ColinBlair

    @Nikhil- Thanks for the nice comments, BradA had sent me the Wilco link yesterday and since the blog entry itself was codeless I decided it matched better with this introduction. I was/am going to refer to your blog entries in the DomainClient wrap up post.

    Mike Graham United States

    Tuesday, October 13, 2009 10:59 AM

    Mike Graham

    I'm trying to migrate my ADO.Net Data Services test app to RIA Services

    The ADO.Net client lets me hook the client context 'SendingRequest' event, allowing me to add Http Headers in the event handler.  Then, the web service xxxWebDataService.svc.cs lets me override the 'CreateDataSource' method, allowing me to provide my own entity framework connection string (which I can fill in with Http Header fields I passed in).

    Can you point me in the direction of how to accomplish this in RIA Services?

    ColinBlair United States

    Tuesday, October 13, 2009 2:15 PM

    ColinBlair

    There are several threads on the RIA Services forum at silverlight.net that cover that, I don't have any handy links to them though. Sounds like a horribly insecure thing to do though, the client really shouldn't know anything about connection strings.

    Mike Graham United States

    Tuesday, October 13, 2009 2:44 PM

    Mike Graham

    Thanks for the reply...

    I'm just trying to get the credentials down to the service so the service can tack them on the database connect string.  What about passing them in an encrypted (via shared secret) token in the header?  do you think that would be ok?  

    Isn't that similar to what forms auth does anyway?  

    I want to be able to point my silverlight client at several different back end services (not necessarily at the same Url where the silverlight client came from).  not sure how else to send the credentials over the silverlight stack...

    ColinBlair United States

    Tuesday, October 13, 2009 4:48 PM

    ColinBlair

    The problem is that the client is not secure. You can't have a "shared secret" between the client and the server, that secret will be known by the user. I would suggest having seperate DomainServices at different URLs, each connecting to a single database. Passing in different DomainService URLs to the client shouldn't be a problem as long as each DomainService website it checking security rights. You can set the DomainService URL through the constructor of the DomainContext.

    Mike Graham United States

    Wednesday, October 14, 2009 4:19 AM

    Mike Graham

    Hi Colin...  I really appreciate your response...  I'm very new to RIA Services...

    I'm trying to expose data in a SQL Server database.  The database connection can function in Windows Auth mode and SQL Server Auth mode.  The SQL Server database uses the connection's 'suser_sname' property to filter the rows returned by SQL queries.  The database has a table with grants that indicate what rows a user is allowed to see and/or update.  This table is used by the views to filter out rows for which 'suser_sname' does not have the appropriate grant (row level security scheme).

    Windows Auth mode should work fine because the domain service will pick up the NT credentials from the client and pass them along via trusted connection to the database.  In this scenario, the connect string is the same for all clients.

    For SQL Server Auth mode however, the connection string must contain the user id and password.

    This is scenario I am trying to implement and the motivation for my questions Smile

    Brian United States

    Thursday, July 01, 2010 8:31 AM

    Brian

    Colin,

    I'm designing an application that will need to run disconnected, occasionally.  I am looking at RIA and I would like to utilize the RIA services.

    It look's like it might be feasible to build a custom DomainClient and have a local data switch that can construct a  DomainContext object for online mode or construct another one using a custom DomainClient.  This custom DomainClient would use the EntityCollection and just persist the new/changed objects to a local isolated storage queue.  Then, next time online mode is detected, this queue would sync the changes to the server.

    In this way,  the client (ViewModel) can use all the features of RIA (validation, pagination, change tracking, etc.) in either online/offline mode.

    Do you see any problems with this approach?

    -bri

    ColinBlair United States

    Tuesday, July 13, 2010 10:30 AM

    ColinBlair

    @Brian Using RIA Services Contrib  it is easy to save the contents of a DomainContext to isolated storage and then load it back into memory. Trying to modify the DomainClient to do that is difficult as the DomainContext expects the states of the entities to change once the submit completes. It makes verification and error handling very difficult. Saving the DomainContext using RIA Services Contrib is a lot less brittle.

    Add comment


    (Will show your Gravatar icon)

      Country flag

    Click to change captcha
    biuquote
    • Comment
    • Preview
    Loading