This post is part of a series about WCF extensibility points. For a list of all previous posts and planned future ones, go to the index page.
And we’re again taking a small detour over the normal flow of the series covering the “proper” WCF extensibility points. This time, we’ll talk about how you can use (almost) all the extensibility points seen before to configure the endpoint used by a WCF RIA Service. WCF RIA Services is a framework which allows easy creation of n-tiered rich internet applications using Silverlight, by coordinating the application logic between the middle tier and the presentation tier. As the name suggests, WCF RIA Services use WCF as the communication framework underneath, by exposing endpoints which are consumed by a “transparent” proxy on the Silverlight application – unlike on “normal” WCF scenarios, if you create an application using the WCF RIA Services, there’s no need to explicitly create a proxy to the service to access it in a typed way – anytime a change is made in a domain service class in the service, that change is automatically propagated to the client so it can be used right away. Domain service is the term used to describe services a service written using the WCF RIA Services framework.
Since WCF RIA Services use WCF, it’s possible to use all of the applicable extensibility points in the server to configure the endpoint which is used by the framework. This post is about how to get to the endpoint from the WCF RIA Services framework, so that you can use all the extensions which have already been covered in this series. Notice that this is quite an advanced scenario, requiring not only that you use WCF RIA Services in the first place, but also that the existing endpoint types not being enough (which is not common), but since I’ve answered a similar question in the Silverlight forum for WCF, I decided to include it here in case other people run into this same scenario.
The “entry point” to the WCF world in the WCF RIA Service is the DomainServiceEndpointFactory class. The goal of the class is to, given a description for the domain service, return one (or more) WCF endpoints which will be used by the client to communicate with that tier. We’ll cover it as we did other “normal” extensibility points of WCF.
There are a few public domain service endpoint factories, both in the “main” framework and in the "WCF RIA Services Toolkit”, an “out-of-band” release of improvements for the framework.
The first factory is the default one used by the framework. The second one can be enabled in the Silverlight Business Application VS template, while the ones from the toolkit need to be enabled manually by editing the web.config on the web application.
The DomainServiceEndpointFactory class has essentially one method which needs to be overriden: CreateEndpoints. Given the description of the domain service, and the instance of the service host (which is an instance of the DomainServiceHost class, itself a subclass of the WCF ServiceHost class). Usually only one endpoint is returned by each factory, but it’s possible to have one factory return multiple endpoints.
Custom domain service endpoint factories are added by adding a reference under the <system.serviceModel> / <domainServices> / <endpoint> element of the configuration file. The “pox binary” endpoint is added by default, any other endpoints need to be added based on the assembly-qualified name class which inherits from DomainServiceEndpointFactory.
This one came from the Silverlight forums for WCF (Accessing Web Services with Silverlight). A user had a simple service which was consumed not only by the Silverlight client, but also by a third-party application which used the application/x-www-form-urlencoded content-type. I don’t know whether the 3rd party was able to change the content type or not, but the user wanted to know whether it was possible to be supported on a domain service. Well, domain services are built on top of WCF, and this scenario is listed on this post, so of course this can be done .
First of all, this is really not a common scenario. In most cases, clients can use the JSON endpoint to communicate to domain service. You can call all CRUD operations, and also [Invoke] operations using that endpoint which works quite well from JavaScript. You can find a good overview of the JSON endpoint for WCF RIA Services in Joseph Connoly’s blog (part 1, part 2). But in this case apparently the client couldn’t be changed, so we can create our own endpoint factory which supports that media type as well.
First, as usual, a scenario. You can start by creating a new “Silverlight Business Application” on Visual Studio (or Visual Web Developer Express), which will give a basic template for such an application, with a login feature. For this sample we’ll ignore the authentication part, as it’s not relevant to this post. Let’s then create a contact list, which will be exposed in a domain service. I’ll create a “POCO” domain service instead of the usual, database-backed, one, to make this sample simpler to run, but the idea works for all domain services.
And we can now create a domain service to expose it to the client. The contact repository, used below, is a simple in-memory representation of the contacts. And that’s a good point to insert the usual disclaimer: this is a sample for illustrating the topic of this post, this is not production-ready code. I tested it for a few operations and it worked, but I cannot guarantee that it will work for all scenarios – please let me know if you find a bug. The “repository” is an in-memory list of the objects which is definitely not what a real scenario would use. Also, as usual, I’ve kept the error checking to a minimum, which needs to happen in a real application.
We can also add “invoke” operations to domain services, which may or may not have any side effects in the domain context. We’ll add one of those operations, which we’ll use to invoke with both the “normal” JSON input, and with the modified forms-urlencoded data. The [CanReceiveFormsUrlEncodedInput] is a tagging attribute which we defined to let the inspector to know that it should try to handle this case.
Now for the actual code which does the trick. There are quite a few ways we can go about it. We can build a custom message formatter which understands the form-urlencoded data and converts it to the appropriate parameters in the operation. That could work, but I don’t know if the formatter used by the domain service does anything else – it’s possible that it does. What I ended up doing instead was to use a message inspector to do a translation between the forms-urlencoded format and the JSON which should be sent to the JSON endpoint in the first place.
So, let’s start with the endpoint factory. Since we’ll just do a translation, I’ll create a class which inherits from the JsonEndpointFactory class itself. Then, when it’s asked to create the endpoints, it first gets the endpoints from the base class, then inserts the “translator” before the other behaviors in the main endpoint. The behavior itself does nothing more than add an inspector, which will do the bulk of the work.
The inspector will look at the request headers of the message, trying to find any with the forms encoding. If the incoming message is such one, it will then look at the last part of the request URI (which represents the operation name), and then find that operation in the endpoint description. If that operation exists, and it’s marked with the attribute that allows such input to be sent, we start the conversion process.
The translation starts by getting the data in binary format (after all, no mapper is registered for the application/x-www-form-urlencoded content type, so it will be mapped to raw / binary), and using the ParseQueryString(String) method from the HttpUtility class to convert between the input and a collection of name/value pairs. Later, we start creating the equivalent JSON, and with that in hand, we create a new message, copying the headers and properties from the original one. One property which we need to change is the WebBodyFormatMessageProperty, to tell the WCF pipeline that it’s now dealing with JSON data.
The conversion between the name/value collection and the JSON is fairly straightforward. For simple operations (i.e., those taking primitive parameter types, such as strings, bools and numbers) we can just create a JSON object mapping each name/value pair as a member of that object. We can even map those non-strings parameters as JSON strings, since the JSON deserializer used by WCF is smart enough to deserialize JSON strings representing numbers (or bools) into the appropriate type. However, I thought we could go further, that we could also support simple complex types as well, such as the Contact we showed before. For that, we need to map the name value pairs not as parameters themselves, but as members of the contact object. To implement that, I used a simple wrapping technique that if there is a single parameter in the operation, and the parameter name isn’t present in the name/value pairs, then we’ll wrap the values in another JSON object, and have that as a member whose name is the same as the operation parameter. In the Contact case, for example, it will map an input such as Name=John+Doe&Age=33&Telephone=415-555-1234 into the JSON {“contact”:{“Name”:”John Doe”,”Age”:”33”,”Telephone”:”415-555-1234”}}.
And that’s it. Now we need to create a HTML page to test that. Since I haven’t worked with the JSON endpoint too much, I first tried using a simple JSON request just to make sure that everything was ok, before going with the simple HTML form (which uses the form-urlencoded content type). The form has two buttons, one which uses a JavaScript code (JSON-ifying the input prior to sending to the service), and another which is “pure” HTML. The JSON one will format the entry appropriately, then after submitting the data, will redirect to the main Silverlight page, which will display the added contact. The HTML post button will just submit the data. But the HTML post expects to receive a HTML page back, so I edited the [Invoke] operation to redirect to the page at the server side (see code in the gallery).
And that’s it. Granted, it’s not a very common scenario, but it just shows how to get into the world of WCF extensibility from within a WCF RIA Service.
[Code in this post]
[Back to the index]