Using the new client hooks in WCF Data Services Client
What are the Request and Response Pipeline configurations in WCF Data Services Client?In WCF Data Services 5.4 we added a new pattern to allow developers to hook into the client request and response pipelines. In the server, we have long had the concept of a processing pipeline. Developers can use the processing pipeline event to tweak how the server processes requests and responses. This concept has now been added to the client (though not as an event). The feature is exposed through the Configurations
property on the DataServiceContext
. On Configurations
there are two properties, called ResponsePipeline
and RequestPipeline
. The ResponsePipeline
contains configuration callbacks that influence reading to OData and materializing the results to CLR objects. The RequestPipeline
contains configuration callbacks that influence the writing of CLR objects to the wire. Developers can then build on top of the new public API and compose higher level functionality.
The explanation might be a bit abstract so let’s move look at a real world example. The code below will document how to remove a property that is unnecessary on the client or that causes materialization issues. Previously this was difficult to do, and impossible if the payload was returning the newer JSON format, but this scenario is now trivially possible with the new hooks. Below is a code snippet to remove a specific property:
This code is using the OnEntryRead
response configuration method to remove the property. Behind the scenes what is happening is the Microsoft.Data.ODataReader
calls reader.Read()
. As it reads though the items, depending on the ODataItem
type a call will be made to the all configuration callbacks of that type that are registered. A couple notes about this code:
- Since
ODataEntry.Properties
is anIEnumerable<ODataProperty>
and not anICollection<ODataProperty>
, we need to replace the entireIEnumerable
instead of just callingODataEntries.Properties.Remove()
. ResolveType
is used here to use theTypeName
and get theEntityType
, typically for a code generatedDataServiceContext
this method is automatically hooked up but if you are using aDataServiceContext
directly then delegate code will need to be written.
What if this scenario has to occur for other properties on the same type or properties on a different type? Let’s make some changes to make this code a bit more reusable.
Extension method for removing a property from an ODataEntry
:
Extension method for removing a property from the ODataEntry
on the selected type:
And now finally the code that the developer would write to invoke the method above and set the configuration up:
The original code is now broken down and is more reusable. Developers can use the RemoveProperties
extension above to remove any property from a type that is in the ODataEntry
payload. These extension methods can also be chained together.
The example above shows how to use OnEntryEnded
, but there are a number of other callbacks that can be used. Here is a complete list of configuration callbacks on the response pipeline:
All of the configuration callbacks above with the exception of OnEntityMaterialized
and OnMessageReaderSettingsCreate
are called when the ODataReader
is reading through the feed or entry. The OnMessageReaderSettingsCreate
callback is called just prior to when the ODataMessageWriter
is created and before any of the other callbacks are called. The OnEntityMaterialized
is called after a new entity has been converted from the given ODataEntry
. The callback allows developers to apply any fix-ups to an entity after it was converted.
Now let’s move on to a sample where we use a configuration on the RequestPipeline
to skip writing a property to the wire. Below is an example of an extension method that can remove the specified properties before it is written out:
As you can see we are following the same pattern as the extension method we wrote to RemoveProperties
for the ResponsePipeline
. In comparison to this extension method this function doesn’t require the type resolving func, so it’s a bit simpler. The type information is specified on the OnEntryEnding
args in the Entity
property. Again this example only touches on ODataEntryEnding
. Below is the complete list of configuration callbacks that can be used:
With the exception of OnMessageWriterSettingsCreated
, the other configuration callbacks are called when the ODataWriter
is writing information to the wire.
In conclusion, the request and response pipelines offer ways to configure the how payloads are read and written to the wire. Let us know any other questions you might have to leverage this feature.
Chris Robinson – OData Team
Comments
Anonymous
July 26, 2013
Well done guys, let's start writing samples post for new features! Much appreciated! M.Anonymous
July 31, 2013
Hi, it seems this cast will never be succesfull since the type is not a list: a.Entry.Properties as List<ODataProperty>Anonymous
August 20, 2013
Is there any possibility to create instance of entity object using Unity Container (from Enterprise Library)?Anonymous
September 07, 2013
Fedor, your question is perfect. I don't know why they didn't just put the object creation stage as part of the pipeline, instead of this "fix up" stuff. I've solved this though how I went about it I consider absolutely terrible: I wrapped the entire OData client library in a set of proxies. My custom context basically just holds a map of proxies to real entity instances, and when new instances appear it goes to my container to generate them.Anonymous
September 10, 2013
Excellent Post. Also visit www.msnetframework.com.Anonymous
September 30, 2013
Excellent Post. Also visit www.msnetframework.com