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
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
Configuration
Modules
Pipeline...
- Pipeline contributors
- Well-known contributors
- PipelineContinuation members
Resources
Handlers
Binding...
- Object binders
- The default resource binder?
- ChangeSet<T> support?
Codecs
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.
Because OpenRasta supports a dynamic type system, in which the type of an object may not be an actual CLR Type (but could in fact be a DLR object, a script or nearly any other type system), it provides an IType interface with which you can inspect what object members (properties, methods, etc) exist on said IType.
As the DataContractJsonSerializer can only create objects backed by a CLR Type, we first try to see if the IType interface can return us a CLR Type. If we can cast the destinationType parameter to INativeMember, then it's ok to hydrate the object as it's a CLR Type the DataContractJsonSerializer can use. If not, we will return Missing.Value to indicate we couldn't deserialize anything 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!
