TracNav
OpenRasta's Documentation...
- Release Notes
- FAQs
Downloading/Building OpenRasta...
- Download from source
- Download the binaries
- Run the test suite
- .NET versions support
Using OpenRasta...
- Configuration how-tos
What you need to know about dependency injection...
- Using Castle as the IoC container
- Using Ninject as the IoC container
Tutorials...
- Building your first OpenRasta website
- Creating views with no code-behind
- Writing handlers
- Using model binders?
- Implementing a Codec
- Extending OpenRasta with a Contributor
WebForms...
- Using multiple views for a resource
- Linking a URI to a static WebForm
Deployment...
- Installing OpenRasta on IIS
- Files required for production deployment?
Building web-sites with OpenRasta...
- Supporting clients that only know GET and POST
Reference...
Hosting...
- Root dependencies?
- Available dependencies
Configuration...
- ResourceSpace.Has
- ResourceSpace.Uses
Modules...
- SharpView
Pipeline...
- Pipeline contributors
- Well-known contributors
- PipelineContinuation members
Resources...
- Linking to resources
Handlers...
- Handler method selection
- Defined OperationResults
Binding...
- Object binders
- The default resource binder?
- ChangeSet<T> support?
Codecs...
- The Webforms Codec
- The XmlSerializer codec
- The JsonDataContract codec
- The XmlDataContract codec
Building Codecs...
- Building a media type reader
- Building a media type writer
- MediaType attribute
- Implementing configuration for ICodec
- Supporting binders and ChangeSet<> in a codec?
About Codecs
A codec's raison d'etre is to take Resources (POCOs) and either write (enCOde) them to a stream or read (DECode) them from a stream. In OpenRasta, this means implementing one or both of IMediaTypeWriter and IMediaTypeReader.
Most of the time, writing a codec isn't too complex. You only have to look at the source for OpenRasta's own JsonDataContractCodec or XmlSerializerCodec to see this. In both of these examples, the codec is taking an existing .NET serialization mechanism and simply writing the tiny amount of OpenRasta plumbing necessary to make it work.
Let's take a look at the JsonDataContractCodec source code to see how it implements reading and writing resources to the JSON format using existing .NET classes. The whole class isn't too big, so we might as well take a look at the whole thing, then break it down bit by bit:
[MediaType("application/json;q=0.5", "json")] public class JsonDataContractCodec : IMediaTypeReader, IMediaTypeWriter { public object Configuration { get; set; } public object ReadFrom(IHttpEntity request, IType destinationType, string paramName) { if (destinationType is INativeMember) return new DataContractJsonSerializer(((INativeMember)destinationType).NativeType).ReadObject(request.Stream); return Missing.Value; } public void WriteTo(object entity, IHttpEntity response, string[] parameters) { if (entity == null) return; DataContractJsonSerializer serializer = new DataContractJsonSerializer(entity.GetType()); serializer.WriteObject(response.Stream, entity); } }
The MediaType attribute
Let's start at the top with the MediaType attribute. This is the place where you specify some good defaults for the media type - its mime type, its quality rating and what extension it will use if you're using the ContentTypeExtensionUriDecorator?. Specifying these defaults here lets you avoid cluttering your fluent configuration later with repeated directives such as .ForMediaType("application/json").
The Configuration implementation
Both IMediaTypeWriter and IMediaTypeReader inherit the responsibility to implement ICodec, which has a single Configuration {get; set;} member. We have no special configuration requirements for the codec (in fact, most codecs don't) so it's sufficient for us to supply this property. We won't use it here.
The IMediaTypeReader.ReadFrom method
public object ReadFrom(IHttpEntity request, IType destinationType, string paramName) { if (destinationType is INativeMember) return new DataContractJsonSerializer(((INativeMember)destinationType).NativeType).ReadObject(request.Stream); return Missing.Value; }
This method is going to take some input from request a stream and hydrate it to a type we know about. First, though, we need to check that we can hydrate the type at all. OpenRasta has provided us with an IType interface here for this purpose. If we can cast the destinationType parameter to INativeMember, then it's ok to hydrate as it's a type OpenRasta knows about. If not, we will return Missing.Value to indicate we couldn't deserialize the type from the request stream. Once we know we can serialize the type, we do so with the .NET DataContractJsonSerializer.ReadObject method - using the IHttpEntity.Stream that's available to us through the request parameter. That's it - we're done!
The IMediaTypeWriter.WriteTo method
public void WriteTo(object entity, IHttpEntity response, string[] parameters) { if (entity == null) return; DataContractJsonSerializer serializer = new DataContractJsonSerializer(entity.GetType()); serializer.WriteObject(response.Stream, entity); }
This method takes an object (entity) and (provided it's not null) uses the DataContractJsonSerializer again to write it to the response stream (which we can access through response.Stream here). There's not much more to say here - once again, we're done!
