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.
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.
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.