ODataLib's message formatting component produces and consumes OData messages. It consists of several smaller components which work together to achieve this goal.
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.
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.
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
- 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
, ...) or written using writers (ODataWriter
Almost every class in the OData object model derives from the
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
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
The caller calls the appropriate reading method. Some of them will read the payload in one call, for example
, others will create a reader, for example
The readers (for example ODataReader
) are used by calling the
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
), while other will return a writer used to produce the payload (for example
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.
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
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.
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.