ODataLib's message formatting component produces and consumes OData messages. It consists of several smaller components which work together to achieve this goal.

Messages

ODataLib itself doesn't contain any code to work with network stacks. Instead it abstracts the messages into interfaces. These interfaces are used to access the HTTP headers and the content of the message.

Request message
A request message is abstracted through the IODataRequestMessage. ODataLib can both read and write the request message, but typical implementation of this interface will only implement one direction. For example an OData client would only implement the ability to write a request message but not to read one.

Response message
A response message is abstracted through the IODataResponseMessage. Again both reading and writing is possible on such a message.

Note that there's no prescribed way to get a response for a request if used on the client. The actual implementation of the request message would typically provide such functionality on its own.

OData object model

ODataLib defines a set of classes to interact with the payload of an OData message. The main groups of classes are:
  • Feeds use ODataFeed, entries use ODataEntry and navigation links use ODataNavigationLink
  • Properties are represented as ODataProperty
  • Primitive values are represented as their respective CLR value. So for example a string is a System.String and a 32-bit integer is a System.Int32.
  • Other atomic values are represented as value classes ODataComplexValue and ODataCollectionValue.
  • Several other payload kinds have their own specialized classes. For example ODataWorkspace, ODataEntityRefereceLink and so on.

The library assumes that one entry fits into a memory, but a collection of entries does not. So you will not find a list of entries on a feed. Instead entries in a feed are accessed by iterating over them through a reader. This approach is used in several places (feeds, batch, top-level collections, parameters) and in such places the payload is read using readers (ODataReader, ODataBatchReader, ...) or written using writers (ODataWriter, ODataBatchWriter, ...)

Almost every class in the OData object model derives from the ODataAnnotatable base class and allows for storing custom annotations. These are use by ODataLib itself in some cases, but can also be used by the user code to store additional pieces of information on the OM.

The OData object model classes are then used by the readers to report the results of reading an OData message and by the writers to specify the content of the OData message to produce.

Reading OData messages

To read either a request or response message, create an instance of the ODataMessageReader class. In order to read the payload the caller must know which payload kind to read. This is either known up front or can be determined by calling DetectPayloadKind.

The caller calls the appropriate reading method. Some of them will read the payload in one call, for example ReadProperty or ReadServiceDocument, others will create a reader, for example CreateODataFeedReader or CreateODataBatchReader.

The readers (for example ODataReader) are used by calling the Read method in a loop. Each call will move the reader to the next item in the payload and that item will be reported through the various properties and methods on the reader.

It is important to Dispose the message reader at the end of reading.

Writing OData messages

To write an OData message, create an instance of the ODataMessageWriter class and then call one of the writing method on it.

Some of the methods will write the entire payload immediately (for example WriteProperty), while other will return a writer used to produce the payload (for example CreateODataFeedWriter).

The writers (for example ODataWriter) are used by calling write methods on them in an ordered sequence and they produce the desired payload.

It is important to Dispose the message writer at the end of writing.

Models

Every OData service defines an EDM model which describes the metadata for the service. This model is usually served to the clients as the response to the $metadata endpoint. ODataLib uses another library, EdmLib, to provide the object model for working with EDM models and to read or write the XML (CSDL, EDMX) representation of the model.

Each model is represented as an instance of the IEdmModel interface. This interface has methods (and extension methods defined by the EdmLib library) to access the types, entity sets and other pieces of it. Almost every element in the model can be annotated with a custom annotation.

ODataLib defines several custom annotations and uses them to store OData specific information in the model. For example the OData version information and the Entity Property Mappings are stored this way. ODataLib then usually defines helper extension methods to access this information.

Both ODataMessageReader and ODataMessageWriter take a model parameter. If it is specified, the model will be used to validate the payload being read or written. Validation, for example, verifies that a property specified on an entry is declared by the model and that its value type matches the one in the model.

Some formats and or operations on the readers and writers actually require the model in order to work at all. We strongly recommend to specify the model every time.

Last edited Aug 1, 2012 at 5:33 PM by ArloBelshee, version 1

Comments

No comments yet.