原文来自: http://odata.github.io/WebApi/
1. INTRODUCTION
-
1.1 Preface
About
This document aims to provide organized content about how to build a OData V4 service using ASP.NET Web API for OData. It’s more than just a getting started guidance and is more systematic than the samples.
Version
This is the first version of this document written in April, 2015.
Targetted audience
This document fits best the readers who has a relative good knowledge of OData (e.g. knowing the OData primitive and structured types, knowing the basic OData URL conventions, knowing the basic OData features such as operations, queries and so on) and would like to explore how some advanced scenarios can be implemented using Web API for OData.
Beginners to OData or Web API for OData can also leverage this document as a structured way to learn. But it’s strongly recommended to read the Getting Started tutorials on OData.org to get a grasp of OData concepts before reading this doc.
This document also assumes that the readers know how to create projects in Visual Studio and know how to install packages using the Nuget Package Manager. It also assumes they have knowledge in C# programming and are not unfamiliar with concepts like classes, properties, methods, and so on.
Structure of this document
This document starts with a tutorial about how a simplest OData V4 service can be written using ASP.NET Web API for OData. Then it steps into the section about how OData models can be built in different ways. After that, OData routing is introduced in details followed by a description of OData feature implementation. Finally, it talks about security and customization of the OData V4 service.
Resources and references
-
1.2 Write a simple OData V4 service
Let’s get started by creating a simple OData V4 service. It has one entity set Products
, one entity typeProduct
.Product
has two propertiesID
andName
, withID
being an integer andName
being a string. The service is read only. The only data clients can get besides the service document and metadata document, is theProducts
entity set.a. Create the Visual Studio project
In Visual Studio, create a new C# project from the ASP.NET Web Application template. Name the project “ODataService”.
In the New Project dialog, select the Empty template. Under “Add folders and core references…”, click Web API. Click OK.
b. Install the OData packages
In the Nuget Package Manager, install
Microsoft.AspNet.OData
and all it’s dependencies.c. Add a model class
Add a C# class to the Models folder:
d. Add a controller class
Add a C# class to the Controllers folder:
In the controller, we defined a
List<Product>
object which has one product element. It’s considered as a in-memory storage of the data of the OData service.We also defined a
Get
method that returns the list of products. The method refers to the handling of HTTP GET requests. We’ll cover that in the sections about routing.e. Configure the OData Endpoint
Open the file App_Start/WebApiConfig.cs. Replace the existing
Register
method with the following code:f. Start the OData service
Start the OData service by running the project and open a browser to consume it. You should be able to get access to the service document at
http://host/service/
in whichhttp://host/service/
is the root path of your service. The metadata document can be accessed atGET http://host/service/$metadata
and the products atGET http://host/service/Products
.
2. DEFINING THE MODEL
-
2.1 Introduction to the model builders
The data model is the basis of an OData service. OData service uses an abstract data model called Entity Data Model (EDM) to describe the exposed data in the service. OData client can issue a GET request to the root URL of the OData service with $metadata
to get an XML representation of the service’s data model. In Microsoft ASP.NET Web API 2.2 for OData v4.0, to build a data model for OData service is to create anIEdmModel
object. There are three ways to build an EDM model in Web API OData:- Explicit Edm Model Builder
- Implicit, non-convention model builder or fluent API
- Implicit, convention model builder.
2.1.1 Build Edm Model
Let’s see the difference between them.
Explicit model builder
To build an Edm model explicitly is to create an
IEdmModel
object by directly using APIs in ODatalib. The basic code structure to build an Edm model explicitly is shown as:The Edm Model built by this way is called un-typed (or typeless, week type) Edm model. Owing that there is no corresponding CLR classes.
Non-convention model builder
To build an Edm model using non-convention model builder is to create an
IEdmModel
object by directly call fluent APIs ofODataModelBuilder
. The developer should take all responsibility to add all Edm types, operations, associations, etc into the data model one by one. The basic code structure of this way is shown as:Convention model builder
To build an Edm model using convention model builder is to create an
IEdmModel
object by a set of conventions. Such conventions are pre-defined rules in Web API OData to help model builder to identify Edm types, keys, association etc automatically, and build them into the final Edm model.ODataConventionModelBuilder
wrappers these conventions and apply them to the Edm model when building. The basic code structure of this way is shown as:Basically, it’s recommended to use convention model builder to build Edm model for its simplicity and convenience. However, if user wants to make more control on the model building, or he doesn’t have the corresponding CLR classes, the non-convention model builder and the explicitly method are also very useful.
2.1.2 Edm Model Sample
We’ll build an Edm model using the above three methods in the following sections respectively. Each section is designed to walk you through every required aspect to build such Edm model. First of all, let’s have a brief view about the Edm model we will build. This is a Customer-Order business model, in which three entity types, two complex types and one enum type are included. Here’s the detail information about each types:
• Customer is served as an entity type with three properties.
• VipCustomer is an entity type derived from Customer. It includes one more property:
• Order is another entity type with two properties.
• Address & SubAddress are served as complex types, while SubAddress is derived from Address.
• Color is served as an Enum Type.
Here’s the class heritance:
-
2.2 Build Edm Model Explicitly
As mentioned in previous section, to build Edm model explicitly is to create an IEdmModel
object directly using ODatalib API. The Edm model built by this method is called type-less model, or week type model, or just un-typed model.Let’s see how to build the Customer-Order business model.Enum Type
We can use
EdmEnumType
to define an Enum typeColor
as:It will generate the below metadata document:
Complex Type
Basic Complex Type
We can use
EdmComplexType
to define a complex typeAddress
as:It will generate the below metadata document:
Derived Complex type
We can set the base type in construct to define a derived complex type
SubAddress
as:It will generate the below metadata document:
Other Complex Types
We can call the following construct to set a complex type whether it is abstract or open.
For example:
It will generate the below metadata document:
Entity Type
Basic Entity Type
We can use
EdmEntityType
to define two entity typesCustomer
&Order
as:It will generate the below metadata document:
Derived Entity type
We can set the base type in construct to define a derived entity type
VipCustomer
as:It will generate the below metadata document:
Other Entity Types
We can call the following construct to set an entity type whether it is abstract or open.
For example:
It will generate the below metadata document:
Default Entity Container
Each model MUST define at most one entity container, in which entity sets, singletons and operation imports are defined. For example:
It will generate the below metadata document:
Singleton
We can also add singleton into entity container. For example:
It will generate the below metadata document:
Navigation Property
Now, we can add navigation property to Customer. For example:
It will generate the below metadata document:
First, it will add a new item in the entity type as:
Second, it will add a new item in the entity container for Customers entity set as:
Function
Let’s define two functions. One is bound, the other is unbound as:
It will generate the below metadata document:
Action
Let’s define two actions. One is bound, the other is unbound as:
It will generate the below metadata document:
Function Import
Unbound function can be called through function import. The following codes are used to build a function import:
It will generate the below metadata document:
Action Import
Unbound actioin can be called through action import. The following codes are used to build an action import:
It will generate the below metadata document:
Summary
Let’s put all codes together:
And the final XML will be:
-
2.3 Non-convention model builder
To build an Edm model using non-convention model builder is to create an IEdmModel
object by directly call fluent APIs ofODataModelBuilder
. The developer should take all responsibility to add all Edm types, operations, associations, etc into the data model one by one. Let’s see how to build the Ccustomer-Order* business model byODataModelBuilder
.CLR Models
Non-convention model builder is based on CLR classes to build the Edm Model. The Customer-Order business CLR classes are present in abstract section.
Enum Type
The following codes are used to add an Enum type
Color
:It will generate the below metadata document:
Complex Type
Basic Complex Type
The following codes are used to add a complex type
Address
:It will generate the below metadata document:
Derived Complex type
The following codes are used to add a derived complex type
SubAddress
:It will generate the below metadata document:
Abstract Complex type
The following codes are used to add an abstract complex type:
It will generate the below metadata document:
Open Complex type
In order to build an open complex type, you should change the CLR class by adding an
IDictionary<string, object>
property, the property name can be any name. For example:Then you can build the open complex type by call
HasDynamicProperties()
:It will generate the below metadata document:
You can find that the complex type
Address
only has two properties, while it hasOpenType="true"
attribute.Entity Type
Basic Entity Type
The following codes are used to add two entity types
Customer
&Order
:It will generate the below metadata document:
Abstract Open type
The following codes are used to add an abstract entity type:
It will generate the below metadata document:
Open Entity type
In order to build an open entity type, you should change the CLR class by adding an
IDictionary<string, object>
property, while the property name can be any name. For example:Then you can build the open entity type as:
It will generate the below metadata document:
You can find that the entity type
Customer
only has three properties, while it hasOpenType="true"
attribute.Entity Container
Non-convention model builder will build the default entity container automatically. However, you should build your own entity sets as:
It will generate the below metadata document:
Besides, you can call
Singleton<T>()
to add singleton into entity container.Function
It’s very simple to build function (bound & unbound) in Web API OData. The following codes define two functions. The first is bind to
Customer
, the second is unbound.It will generate the below metadata document:
Besides, Web API OData will automatically add function imports for all unbound functions. So, the metadata document should has:
Action
Same as function, it’s also very simple to build action (bound & unbound) in Web API OData. The following codes define two actions. The first is bind to collection of
Customer
, the second is unbound.It will generate the below metadata document:
Same as function, Web API OData will automatically add action imports for all unbound actions. So, the metadata document should has:
Summary
Let’s put all codes together:
And the final XML will be:
-
2.4 Convention model builder
In the previous two sections, we walk you through the required aspects to build an Edm model by directly using ODatalib or leveraging ODataModelBuilder
fluent API in WebApi OData.Obvious, there are many codes you should add to develop a simple Customer-Order business model. However, Web API OData also provides a simple method by usingODataConventionModelBuilder
to do the same thing. It’s called convention model builder and can extremely reduce your workload.Convention model builder uses a set of pre-defined rules (called conventions) to help model builder identify Edm types, keys, associations, relationships, etc automatically, and build them into the final Edm data model.In this section, we will go through all conventions used in convention model builder. First, let’s see how to build the Edm model using
ODataConventionModelBuilder
.CLR Models
We also use the Customer-Order business model presented in abstract section.
Build the Edm Model
The following codes can add all related entity types, complex types, enum type and the corresponding entity sets into the Edm model:
It will generate the below metadata document:
Note: We omit the function/action building because it’s same as non-convention model builder.
Conventions
Wow, how the convention model builder do that! Actually, convention model builder uses a set of pre-defined rules (called conventions) to achieve this. If you open the source code for
ODataConventionModelBuilder
, You can find the following codes at the beginning of theODataConventionModelBuilder
class:Where lists the conventions wrapped in convention model builder. However, in
ODataConventionModelBuilder
, there are some conventions which can’t be clearly listed. Let’s walk you through these conventions one by one with some relevant attributes & annotations to illustrate the convention model builder.Type Inheritance Identify Convention
Rule: Only derived types can be walked.
For example:
By using convention builder:
It will generate the below entity type in the resulted EDM document:
If you change the model builder as:
It will generate the below entity type in the resulted EDM document:
There is no
Base
entity type existed.Abstract type convention
Rule: The Edm type will be marked as abstract if the class is abstract.
The result is :
Entity key convention
Rule: If one and only one property’s name is ‘Id’ or ‘
<entity class name>
Id’ (case insensitive), it becomes entity key property.The result is:
Key attribute
Rule: The [
KeyAttribute
] specifies key property, it forces a property without ‘id’ to be Key property. It’ll suppress the entity key convention.The result is:
ComplexType Attribute Convention
Rule-1: Create a class without any ‘id’ or ‘id’ or [`KeyAttribute`] property, like
Rule-2: Add [ComplexType] attribute to a model class: it will remove ‘id’ or ‘id’ or [Key] properties, the model class will have no entity key, thus becomes a complex type.
Then, the above two types wil be built as
Complex Type
.DataContract & DataMember
Rule: If using DataContract or DataMember, only property with [DataMember] attribute will be added into Edm model.
The resulted EDM document is:
You can also change name-space and property name in EDM document. For example, if the above DataContract attribute is added with NameSpace:
The result will become:
NotMapped Attribute Convention
Rule: [NotMapped] deselects the property to be serialized or deserialized, so to some extent, it can be seen as the converse of DataContract & DataMember.
For example, the above if
Trip
class is changed to the below, it generates exactly the same Trip Entity in EDM document, that is, no ‘SharedId’ property.The result is:
Required Attribute Convention
Rule: The property with [Required] attribute will be non-nullable.
Then the result has
Nullable=”false”
forName
property:ConcurrencyCheck Attribute Convention
Rule: It can mark one or more properties for doing optimistic concurrency check on entity updates.
The expected result should be like the below:
Timestamp Attribute Convention
Rule: It’s same as [ConcurrencyCheck].
The expected result should be like the below:
IgnoreDataMember Attribute Convention
Rule: It has the same effect as
[NotMapped]
attribute. It is able to revert the[DataMember]
attribute on the property when the model class doesn’t have[DataContract]
attribute.NonFilterable & NotFilterable Attribute Convention
Rule: Property marked with [NonFilterable] or [NotFilterable] will not support
$filter
query option.Then, if you issue an query option as:
~/odata/Customers?$filter=Title eq 'abc'
You will get the following exception:
NotSortable & Unsortable Attribute Convention
Rule: Property marked with [NotSortable] or [Unsortable] will not support
$orderby
query option.Then, if you issue an query option as: `~/odata/Customers?$orderby=Title
You will get the following exception:
NotNavigable Attribute Convention
Rule: Property marked with [NotNavigable] will not support
$select
query option.Then, if you issue an query option as: `~/odata/Customers?$select=address
You will get the following exception:
NotExpandable Attribute Convention
Rule: Property marked with [NotExpandable] will not support
$expand
query option.Then, if you issue an query option as: `~/odata/Customers?$expand=Orders
You will get the following exception:
NotCountable Attribute Convention
Rule: Property marked with [NotCountable] will not support
$count
query option.Then, if you issue an query option as: `~/odata/Customers(1)/Addresses?$count=true
You will get the following exception:
ForeignKey Attribute Convention
Rule: Property marked with [ForeignKey] will be used to build referential constraint.
You will get the following result:
[ForeignKey] can also put on dependent property. for example:
It’ll get the same result.
ActionOnDelete Attribute Convention
Rule: Property marked with [ActionOnDelete] will be used to build referential constraint action on delete.
You will get the following result:
ForeignKeyDiscovery Convention
Rule: A convention used to discover foreign key properties if there is no any foreign key configured on the navigation property. The basic rule to discover the foreign key is: with the same property type and follow up the naming convention. The naming convention is: 1. The “Principal class name + principal key name” equals the dependent property name For example: Customer (Id) <–> Order (CustomerId) 2. or the “Principal key name” equals the dependent property name. For example: Customer (CustomerId) <–> Order (CustomerId)
You will get the following result:
-
2.5 Summary
In this chapter, we describe the three methods used to build the Edm model in Web API OData and walk you through every required aspect to build a simple Customer-Order Edm model. It’s recommended to use convention model builder to build Edm model for its simplicity and convenience. However, if user wants to make more control on the model building, or he doesn’t have the corresponding CLR classes, the non-convention model builder and the explicitly method are also very useful.
3. ROUTING
-
3.1 Introduction Routing
In Web API, Routing is how it matches a request URI to an action in a controller. The Routing of Web API OData is derived from Web API Routing and do more extensions. In Web API OData, an OData controller (not API controller) is severed as the request handler to handle HTTP requests, while the public methods (called action methods) in the controller are invoked to execute the business logic. So, when the client issues a request to OData service, the Web API OData framework will map the request to an action in the OData controller. Such mapping is based on pre-registered Routes in global configuration. Register the Web API OData Routes
In Web API, developer can use the following codes to register a Web API route into routing table:
While, Web API OData re-uses the Web API routing table to register the Web OData Routes. However it provides its own extension method called
MapODataServiceRoute
to register the OData route.MapODataServiceRoute
has many versions, here’s the basic usage:With these codes, we register an OData route named “myRoute”, uses “odata” as prefix and by calling
GetEdmModel()
to set up the Edm model.After registering the Web OData routes, we define an OData route template in the routing table. The route template has the following syntax:
Now, the Web API OData framework can handle the HTTP request. It tries to match the request Uri against one of the route templates in the routing table. Basically, the following URIs match the odata route:
Where, Customers is the entity set names.
However, the following URI does not match the odata route, because it doesn’t match “odata” prefix segment:
Routing Convention
Once the odata route is found, Web API OData will parse the request Uri to get the path segments. Web API OData first uses the ODatalib to parse the request Uri to get the ODL path segments, then convert the ODL path segments to Web API OData path segments. Once the Uri Parse is finished, Web API OData will try to find the corresponding OData controller and action. The process to find controller and action are the main part of Routing Convention. Basically, there are two parts of Routing Convention:
- Convention RoutingIt is also called built-in routing conventions. It uses a set of pre-defined rules to find controller and action.
- Attribute RoutingIt uses two Attributes to find controller and action. One is
ODataRoutePrefixAttribute
, the other isODataRouteAttribute
.
-
3.2 Built-in routing conventions
When Web API gets an OData request, it maps the request to a controller name and an action name. The mapping is based on the HTTP method and the URI. For example, GET /odata/Products(1)
maps toProductsController.GetProduct
.This article describe the built-in OData routing conventions. These conventions are designed specifically for OData endpoints, and they replace the default Web API routing system. (The replacement happens when you call MapODataRoute.)Built-in Routing Conventions
Before describe the OData routing conventions in Web API, it’s helpful to understand OData URIs. An OData URI consists of:
- The service root
- The odata path
- Query options
For example:
http://example.com/odata/Products(1)/Supplier?$top=2
- The service root : http://example.com/odata
- The odata path : Products(1)/Supplier
- Query options : ?$top=2
For OData routing, the important part is the OData path. The OData path is divided into segments, each segments are seperated with ‘/’.
[For example],
Products(1)/Supplier
has three segments:- Products refers to an entity set named “Products”.
- 1 is an entity key, selecting a single entity from the set.
- Supplier is a navigation property that selects a related entity.
So this path picks out the supplier of product 1.
OData path segments do not always correspond to URI segments. For example, “1” is considered a key path segment.
Controller Names. The controller name is always derived from the entity set at the root of the OData path. For example, if the OData path is
Products(1)/Supplier
, Web API looks for a controller named ProductsController.So, the controller convention is: [entityset name] + “Controller”, derived from
ODataController
Action Names. Action names are derived from the path segments plus the entity data model (EDM), as listed in the following tables. In some cases, you have two choices for the action name. For example, “Get” or “GetProducts”.
Querying Entities
Creating, Updating, and Deleting Entities
Operation on Navigation Property
Querying, Creating and Deleting Links
Properties
Request Example URI Action Name Example Action GET /entityset(key)/property /Products(1)/Name GetPropertyFromEntityType or GetProperty GetNameFromProduct GET /entityset(key)/cast/property /Products(1)/Models.Book/Author GetPropertyFromEntityType or GetProperty GetTitleFromBook Actions
Action only supports the POST request method, and the parameters are sent using the request body. In controller, each action is using an
ODataActionParameters
to accept the parameters’ value:Functions
Functions only supports the GET request method.
Method Signatures
Here are some rules for the method signatures:
- If the path contains a key, the action should have a parameter named key.
- If the path contains a key into a navigation property, the action should have a parameter named relatedKey.
- POST and PUT requests take a parameter of the entity type.
- PATCH requests take a parameter of type Delta, where T is the entity type.
For reference, here is an example that shows method signatures for most built-in OData routing convention.
Update form Routing Conventions in OData V3.0
-
3.3 Attribute Routing
Same as Web API, Web API OData supports a new type of routing called attribute routing. It uses two Attributes to find controller and action. One is ODataPrefixAttribute
, the other isODataRouteAttribute
.You can use attribute routing to define more complex routes and put more control over the routing. Most important, it can extend the coverage of convention routing. For example, you can easily use attribute routing to route the following Uri:In Web API OData, attribute routing is combined with convention routing by default.
Enabling Attribute Routing
ODataRoutingConventions
provides two methods to register routing conventions:As the name implies, the first one creates a mutable list of the default OData routing conventions with attribute routing enabled, while the second one only includes convention routing.
In fact, when you call the basic
MapODataServiceRoute
, it enables the attribute routing by default as:However, you can call other version of
MapODataServiceRoute
to custom your own routing conventions. For example:ODataRouteAttribute
ODataRouteAttribute
is an attribute that can, and only can be placed on an action of an OData controller to specify the OData URLs that the action handles.Here is an example of an action defined using an
ODataRouteAttribute
:With this attribute, Web API OData tries to match the request Uri with
Customers({id})/Address/City
routing template toGetCityOfACustomer()
function inMyController
. For example, the following request Uri will invokeGetCityOfACustomer
:For the above request Uri,
id
in the function will have1
,2
and301
value.However, for the following request Uri, it can’t match to `GetCityOfACustomer()’:
Web API OData supports to put multiple
ODataRouteAttribute
on the same OData action. For example,ODataRoutePrefixAttribute
ODataRoutePrefixAttribute
is an attribute that can, and only can be placed on an OData controller to specify the prefix that will be used for all actions of that controller.ODataRoutePrefixAttribute
is used to reduce the routing template inODataRouteAttribute
if all routing template in the controller start with the same prefix. For example:Then you can use
ODataRoutePrefixAttribute
attribute on the controller to set a common prefix.Now, Web API OData supports to put multiple
ODataRoutePrefixAttribute
on the same OData controller. For example,Route template
The route template is the route combined with
ODataRoutePrefixAttribute
andODataRouteAttribute
. So, for the following example:The
GetAddress
matches toCustomers({id})/Address
route template. It’s called key template because there’s a template{id}
. So far in Web API OData, it supports two kind of templates:- key template, for example:
- function parameter template, for example:
Web API OData team also works to add the third template, that is the dynamic property template. It’s planed to ship in next release.
You can refer to this blog for attribute routing in Web API 2.
-
3.4 Custom routing convention
It’s easy to custom your own routing convention to override the default Web API OData routing convention. Let’s see how to target it. Property access routing convention
From built-in routing convention section, we know that users should add many actions for every property access.
For example, if the client issues the following property access request Uris:
Service should have the following actions in
CustomersController
to handle:If
Customer
has hundreds of properties, users should add hundres of similar functions inCustomersController
. It’s boring and we can create our own routing convention to override it.Custom routing convention
We can create our own routing convention class by implementing the
IODataRoutingConvention
. However, if you don’t want to change the behaviour to find the controller, the new added routing convention class can derive from `NavigationSourceRoutingConvention’.Let’s build a sample property access routing convention class derived from
NavigationSourceRoutingConvention
.Where, we routes the following path templates to a certain action named
GetProperty
.Enable customized routing convention
The following sample codes are used to enable the customized routing convention:
Where, we insert our own routing convention at the starting position to override the default Web API OData property access routing convention.
Add actions
In the
CustomersController
, only one method namedGetProperty
should be added.Samples
Let’s have some request Uri samples to test:
a)
The result is:
b)
The result is:
c)
The result is:
4. ODATA FEATURES
-
4.1 DateTime support
This sample will introduce how to support DateTime type in Web API OData V4. Build DateTime Type
OData V4 doesn’t include DateTime as primitive type. Web API OData V4 uses DateTimeOffset to represent the DateTime. For example, if user defines a model as:
The metadata document for Customer entity type will be:
Time Zone Configuration
By Default, converting between DateTimeOffset and DateTime will lose the Time Zone information. Therefore, Web API provides a API to config the Time Zone information on server side. For example:
$filter DateTime
Since Web API OData 5.6, it supports to filter on DateTime type. For example:
$orderby DateTime
Since Web API OData 5.6, it supports to orderby on DateTime type. For example:
Thanks.
-
4.2 Referential constraint
The following sample codes can be used for Web API OData V3 & V4 with a little bit function name changing. Define Referential Constraint Using Attribute
There is an attribute named “ForeignKeyAttribute” which can be place on:
1.the foreign key property and specify the associated navigation property name, for example:
2.a navigation property and specify the associated foreign key name, for example:
Where, Customer has two keys.
Now, you can build the Edm Model by convention model builder as:
Define Referential Constraint Using Convention
If user doesn’t add any referential constraint, Web API will try to help user to discovery the foreign key automatically. There are two conventions as follows: 1.With same property type and same type name plus key name. For example:
Where, Customer type name “Customer” plus key name “Id” equals the property “CustomerId” in the Order.
2.With same property type and same property name. For example:
Where, Property (key) “CustomerId” in the Customer equals the property “CustomerId” in the Order.
Now, you can build the Edm Model using convention model builder same as above section.
Define Referential Constraint Programmatically
You can call the new added Public APIs (HasRequired, HasOptional) to define the referential constraint when defining a navigation property. For example:
It also supports to define multiple referential constraints, for example:
Define Nullable Referential Constraint Using Convention
Currently, it doesn’t suppport to define nullable referential constraint from attribute and convention method. However, you can do it by Programmatically by calling
HasOptional()
method:For example:
Then you can get the following result:
Where,
CategoryId
is nullable while navigation propertySupplier
is nullable too.Thanks.
-
4.3 Nested $filter in $expand
OData Web API v5.5 supports nested $filter in $expand, e.g.: .../Customers?$expand=Orders($filter=Id eq 10)
POCO classes:Map route, e.g., in
WebApiConfig.cs
:Controller:
Request:
http://localhost:port_number/orest/Customers?$expand=Orders($filter=Id eq 10)
Response:
-
4.4 Edm.Date and Edm.TimeOfDay
This sample introduces how to use the Edm.Date
&Edm.TimeOfDay
supported in Web API OData V5.5.Build Edm Model
ODL V6.8 introduces two new primitive types. One is
Edm.Date
, the other isEdm.TimeOfDay
. Besides, it also introduces two new struct types to represent the CLR types of Edm.Date and Edm.TimeOfDay. So, developers can use the new CLR struct types to define their CLR model. For example, if user defines a model as:The metadata document for Customer entity type will be:
Build-in Functions
Along with the
Edm.Date
&Edm.TimeOfDay
, new date and time related built-in functions are supported in Web API OData V5.5.Here’s the list:
- Date
- Edm.Int32 year(Edm.Date)
- Edm.Int32 month(Edm.Date)
- Edm.Int32 day(Edm.Date)
- TimeOfDay
- Edm.Int32 hour(Edm.TimeOfDay)
- Edm.Int32 minute(Edm.TimeOfDay)
- Edm.Int32 second(Edm.TimeOfDay)
- Edm.Decimal fractionalseconds(Edm.TimeOfDay)
- DateTimeOffset
- Edm.Decimal fractionalseconds(Edm.DateTimeOffset)
- Edm.Date date(Edm.DateTimeOffset)
- Edm.TimeOfDay time(Edm.DateTimeOffset)
Query examples
Let’s show some query request examples:
- Date
- ~/odata/Customers?$filter=year(Publish) eq 2015
- ~/odata/Customers?$filter=month(Publish) ne 11
- ~/odata/Customers?$filter=day(Publish) lt 8
- TimeOfDay
- ~/odata/Customers?$filter=hour(CheckTime) eq 2
- ~/odata/Customers?$filter=minute(CheckTime) ge 11
- ~/odata/Customers?$filter=second(CheckTime) lt 18
- ~/odata/Customers?$filter=fractionalseconds(CheckTime) eq 0.04
- DateTimeOffset
- ~/odata/Customers?$filter=fractionalseconds(Birthday) lt 0.04
- ~/odata/Customers?$filter=date(Birthday) lt 2015-03-23
- ~/odata/Customers?$filter=time(Birthday) eq 03:04:05.90100
Thanks.
- Date
-
4.5 Abstract entity types
Since Web API OData V5.5-beta, it is allowed to: - define abstract entity types without keys.
- define abstract type (entity & complex) without any properties.
- define derived entity types with their own keys.
Let’s see some examples:
Entity type example:
The CLR model is shown as below:
We can use the following codes to build Edm Model:
Then, we can get the metadata document for Animal as:
Note: 1. Animal is an abstract entity type without any keys and any properties 2. Dog & Pig are two sub entity types derived from Animal with own keys.
However, it’s obvious that abstract entity type without keys can’t be used to define any navigation sources (entity set or singleton). So, if you try to:
you will get the following exception:
Complex type example
Let’s see a complex example. The CLR model is shown as below:
We can use the following codes to build Edm Model:
Then, we can get the metadata document for Graph as:
Where, Graph is an abstract complex type without any properties.
Thanks.
-
4.6 Function parameter support
Since Web API OData V5.5-beta, it supports the following types as function parameter: - Primitive
- Enum
- Complex
- Entity
- Entity Reference
- Collection of above
Let’s see how to build and use the above types in function.
CLR Model
First of all, we create the following CLR classes as our model:
Build Edm Model
Now, we can build the Edm Model as:
where, BuildFunction() is a helper function in which functions can be built.
Primitive and Collection of Primitive parameter
Configuration
In BuildFunction(), we can configure a function with
Primitive
and collection ofPrimitive
parameters:Routing
In the
CustomersController
, add the following method:Request Samples
We can invoke the function as:
Enum and Collection of Enum parameter
Configuration
In BuildFunction(), we can configure a function with
Enum
and collection ofEnum
parameters:Routing
In the
CustomersController
, add the following method :Request Samples
We can invoke the Enum function as:
Complex and Collection of Complex parameter
Configuration
In BuildFunction(), we can configure a function with
Complex
and collection ofComplex
parameters:Routing
In the
CustomersController
, add the following method :Request Samples
We can invoke the complex function as:
Entity and Collection of Entity parameter
Configuration
In BuildFunction(), we can configure a function with
Entity
and collection ofEntity
parameters:It’s better to call
EntityParameter<T>
andCollectionEntityParameter<T>
to define entity and collection of entity parameter.Routing
In the
CustomersController
, add the following method :Request Samples
We can invoke the entity function as:
However, only parameter alias is supported for entity.
Entity Reference and collection of Entity Reference parameter
In fact, we can’t build a function with entity reference as parameter. However, we can call the function with entity parameter using entity reference value. So, without any change for the
EntityFunction
, we can call as:FromODataUri
‘[FromODataUri]’ is mandatory for complex, entity and all collection. However, it is optional for Primitive & Enum. But for string primitive type, the value will contain single quotes without ‘[FromODataUri]’.
Thanks.
For un-typed scenario, please refer to untyped page.
-
4.7 Action parameter support
Since Web API OData V5.5-beta, it supports the following types as action parameter: - Primitive
- Enum
- Complex
- Entity
- Collection of above
Let’s see how to build and use the above types in action.
CLR Model
Re-use the CLR models in function sample.
Build Edm Model
Same as build Edm Model in function sample, but change the helper function as BuildAction().
Primitive and Collection of Primitive parameter
Configuration
In BuildAction(), we can configure an action with
Primitive
and collection ofPrimitive
parameters:Routing
In the
CustomersController
, add the following method:Request Samples
We can invoke the action by issuing a Post on
~/odata/Customers/Default.PrimitiveAction
with the following request body:Enum and Collection of Enum parameter
Configuration
In BuildAction(), we can configure an action with
Enum
and collection ofEnum
parameters:Routing
In the
CustomersController
, add the following method :Request Samples
We can invoke the action by issuing a Post on
~/odata/Customers/Default.EnumAction
with the following request body:Complex and Collection of Complex parameter
Configuration
In BuildAction(), we can configure an action with
Complex
and collection ofComplex
parameters:Routing
In the
CustomersController
, add the following method :Request Samples
We can invoke the action by issuing a Post on
~/odata/Customers/Default.ComplexAction
with the following request body:Entity and Collection of Entity parameter
Configuration
In BuildAction(), we can configure an action with
Entity
and collection ofEntity
parameters:It’s better to call
EntityParameter<T>
andCollectionEntityParameter<T>
to define entity and collection of entity parameter.Routing
In the
CustomersController
, add the following method :Request Samples
We can invoke the action by issuing a Post on
~/odata/Customers/Default.EntityAction
with the following request body:Know issues
- It doesn’t work if “null” value in the collection of entity in the payload. See detail in #100.
- It doesn’t work if anything else follows up the collection of entity in the payload. See detail in #65
Null value
If you invoke an action with a ‘null’ action parameter value, please don’t add the parameter (for example,
"p1":null
) in the payload and leave it un-specified. However, for collection, you should always specify it even the collection is an empty collection (for example,"p1":[]
).Thanks.
For un-typed scenario, please refer to untyped page.
-
4.8 Operation paramters in untyped scenarios
In this page, we introduce the Function/Action parameter in untyped scenario. For CLR typed scenarios, please refer to Function page and Action page. Build Edm Model
Let’s build the Edm Model from scratch:
Here’s the metadata document for this Edm Model:
Controller & Routing
Let’s add the following methods into
CustomersController
:Request Samples
Now, We can invoke the function with the entity and collection of entity parameter as:
Also, We can invoke the action by issuing a Post on
~/odata/Customers(1)/NS.EntityAction
with the following request body:For other request samples, please refer to Function page and Action page.
Unbound function/action
Unbound function and action are similiar with bound function and action in the request format. But only attribute routing can be used for unbound function/action routing.
Thanks.
-
4.9 Query by dynamic properties
Since Web API OData V5.5, it supports filter, select and orderby on dynamic properties.Let’s see a sample about this feature. CLR Model
First of all, we create the following CLR classes as our model:
Build Edm Model
Now, we can build the Edm Model as:
Use filter, orferby, select on dynamic property
Routing
In the
SimpleOpenCustomersController
, add the following method:Request Samples
We can query like:
-
4.10 Open type in untyped scenarios
Since Web API OData V5.5, it supports open type and dynamic property on un-type scenario, dynamic properties can be: - Primitive Type
- Enum Type
- Complex Type
- Collection of above
Let’s see a sample about this feature.
Build un-type Edm Model
Now, we can build the Edm Model as:
If the dynamic property is not primitive type, you should declare it in model like the code above.
GET an untyped open entity with dynamic property
Routing
In the
UntypedSimpleOpenCustomersController
, add the following method:Request Samples
We can get the entity as:
POST an untyped open entity with dynamic property
Routing
In the
UntypedSimpleOpenCustomersController
, add the following method :Request Samples
You should declare the type of dynamic properties in request body. Payload:
Url:
The type of dynamic properties in un-type scenario
EdmEntityObject (Collection)
Represent an entity.
EdmComplexObject (Collection)
Represent an complex property.
EdmEnumObject (Collection)
Represent an enum property.
-
4.11 Query Options
OData defines parameters that can be used to modify an OData query, samples can be found at supporting-odata-query-options and using-select-expand-value. -
4.12 Batch Support
Batch requests allow grouping multiple operations into a single HTTP request payload and the service will return a single HTTP response with the response to all operations in the requests. This way, the client can optimize calls to the server and improve the scalability of its service.Please refer to OData Protocol for more detail about batch, and Batch in ODL for batch in ODL client. Enable Batch in Web API OData Service
It is very easy to enable batch in an OData service which is built by Web API OData.
Add Batch Handler
As above, we only need to create a new batch handler and pass it when mapping routing for OData service. Batch will be enabled.
For testing, we can POST a request with batch body to the baseurl/$batch:
POST http://localhost:14409/odata/$batch HTTP/1.1 User-Agent: Fiddler Host: localhost:14409 Content-Length: 1244 Content-Type: multipart/mixed;boundary=batch_d3bcb804-ee77-4921-9a45-761f98d32029 --batch_d3bcb804-ee77-4921-9a45-761f98d32029 Content-Type: application/http Content-Transfer-Encoding: binary GET http://localhost:14409/odata/Products(0) HTTP/1.1 OData-Version: 4.0 OData-MaxVersion: 4.0 Accept: application/json;odata.metadata=minimal Accept-Charset: UTF-8 User-Agent: Microsoft ADO.NET Data Services --batch_d3bcb804-ee77-4921-9a45-761f98d32029 Content-Type: multipart/mixed;boundary=changeset_77162fcd-b8da-41ac-a9f8-9357efbbd --changeset_77162fcd-b8da-41ac-a9f8-9357efbbd Content-Type: application/http Content-Transfer-Encoding: binary Content-ID: 1 DELETE http://localhost:14409/odata/Products(0) HTTP/1.1 OData-Version: 4.0 OData-MaxVersion: 4.0 Accept: application/json;odata.metadata=minimal Accept-Charset: UTF-8 User-Agent: Microsoft ADO.NET Data Services --changeset_77162fcd-b8da-41ac-a9f8-9357efbbd-- --batch_d3bcb804-ee77-4921-9a45-761f98d32029 Content-Type: application/http Content-Transfer-Encoding: binary GET http://localhost:14409/odata/Products HTTP/1.1 OData-Version: 4.0 OData-MaxVersion: 4.0 Accept: application/json;odata.metadata=minimal Accept-Charset: UTF-8 User-Agent: Microsoft ADO.NET Data Services --batch_d3bcb804-ee77-4921-9a45-761f98d32029--
And the response should be:
HTTP/1.1 200 OK Cache-Control: no-cache Pragma: no-cache Content-Type: multipart/mixed; boundary=batchresponse_5667121d-ca2f-458d-9bae-172f04cdd411 Expires: -1 Server: Microsoft-IIS/8.0 OData-Version: 4.0 X-AspNet-Version: 4.0.30319 X-SourceFiles: =?UTF-8?B?YzpcdXNlcnNcbGlhbndcZG9jdW1lbnRzXHZpc3VhbCBzdHVkaW8gMjAxM1xQcm9qZWN0c1xUZXN0V2ViQVBJUmVsZWFzZVxUZXN0V2ViQVBJUmVsZWFzZVxvZGF0YVwkYmF0Y2g=?= X-Powered-By: ASP.NET Date: Wed, 06 May 2015 07:34:29 GMT Content-Length: 1449 --batchresponse_5667121d-ca2f-458d-9bae-172f04cdd411 Content-Type: application/http Content-Transfer-Encoding: binary HTTP/1.1 200 OK Content-Type: application/json; odata.metadata=minimal; charset=utf-8 OData-Version: 4.0 { "@odata.context":"http://localhost:14409/odata/$metadata#Products/$entity","ID":0,"Name":"0Name" } --batchresponse_5667121d-ca2f-458d-9bae-172f04cdd411 Content-Type: multipart/mixed; boundary=changesetresponse_e2f20275-a425-404a-8f01-c9818aa63610 --changesetresponse_e2f20275-a425-404a-8f01-c9818aa63610 Content-Type: application/http Content-Transfer-Encoding: binary Content-ID: 1 HTTP/1.1 204 No Content --changesetresponse_e2f20275-a425-404a-8f01-c9818aa63610-- --batchresponse_5667121d-ca2f-458d-9bae-172f04cdd411 Content-Type: application/http Content-Transfer-Encoding: binary HTTP/1.1 200 OK Content-Type: application/json; odata.metadata=minimal; charset=utf-8 OData-Version: 4.0 { "@odata.context":"http://localhost:14409/odata/$metadata#Products","value":[ { "ID":1,"Name":"1Name" },{ "ID":2,"Name":"2Name" },{ "ID":3,"Name":"3Name" },{ "ID":4,"Name":"4Name" },{ "ID":5,"Name":"5Name" },{ "ID":6,"Name":"6Name" },{ "ID":7,"Name":"7Name" },{ "ID":8,"Name":"8Name" },{ "ID":9,"Name":"9Name" } ] } --batchresponse_5667121d-ca2f-458d-9bae-172f04cdd411--
Setting Batch Quotas
DefaultODataBatchHandler contains some configuration, which can be set by customers, to customize the handler. For example, the following code will only allow a maximum of 8 requests per batch and 5 operations per ChangeSet.
Enable/Disable continue-on-error in Batch Request
We can handle the behavior upon encountering a request within the batch that returns an error by preference
odata.continue-on-error
.Preference
odata.continue-on-error
: The odata.continue-on-error preference on a batch request is used to request that, upon encountering a request within the batch that returns an error, the service return the error for that request and continue processing additional requests within the batch. If not specified, upon encountering an error the service MUST return the error within the batch and stop processing additional requests within the batch.Enable Preference
odata.continue-on-error
Preference
odata.continue-on-error
makes no sense by default, and service returns the error for that request and continue processing additional requests within the batch as default behavior.First we should enable
odata.continue-on-error
by callingEnableContinueOnErrorHeader()
inHttpConfiguration
.Request Without Preference
odata.continue-on-error
For testing, we can POST a batch request without Preference
odata.continue-on-error
:POST http://localhost:9001/DefaultBatch/$batch HTTP/1.1 Accept: multipart/mixed Content-Type: multipart/mixed; boundary=batch_abbe2e6f-e45b-4458-9555-5fc70e3aebe0 Host: localhost:9001 Content-Length: 633 Expect: 100-continue Connection: Keep-Alive --batch_abbe2e6f-e45b-4458-9555-5fc70e3aebe0 Content-Type: application/http Content-Transfer-Encoding: binary GET http://localhost:9001/DefaultBatch/DefaultBatchCustomer(0) HTTP/1.1 --batch_abbe2e6f-e45b-4458-9555-5fc70e3aebe0 Content-Type: application/http Content-Transfer-Encoding: binary GET http://localhost:9001/DefaultBatch/DefaultBatchCustomerfoo HTTP/1.1 --batch_abbe2e6f-e45b-4458-9555-5fc70e3aebe0 Content-Type: application/http Content-Transfer-Encoding: binary GET http://localhost:9001/DefaultBatch/DefaultBatchCustomer(1) HTTP/1.1 --batch_abbe2e6f-e45b-4458-9555-5fc70e3aebe0--
The response should be:
HTTP/1.1 200 OK Content-Length: 820 Content-Type: multipart/mixed; boundary=batchresponse_b49114d7-62f7-450a-8064-e27ef9562eda Server: Microsoft-HTTPAPI/2.0 OData-Version: 4.0 Date: Wed, 12 Aug 2015 02:23:10 GMT --batchresponse_b49114d7-62f7-450a-8064-e27ef9562eda Content-Type: application/http Content-Transfer-Encoding: binary HTTP/1.1 200 OK Content-Type: application/json; odata.metadata=minimal; odata.streaming=true OData-Version: 4.0 { "@odata.context":"http://localhost:9001/DefaultBatch/$metadata#DefaultBatchCustomer/$entity","Id":0,"Name":"Name 0" } --batchresponse_b49114d7-62f7-450a-8064-e27ef9562eda Content-Type: application/http Content-Transfer-Encoding: binary HTTP/1.1 404 Not Found Content-Type: application/json; charset=utf-8 {"Message":"No HTTP resource was found that matches the request URI 'http://localhost:9001/DefaultBatch/DefaultBatchCustomerfoo'.","MessageDetail":"No route data was found for this request."} --batchresponse_b49114d7-62f7-450a-8064-e27ef9562eda--
Service returned error and stop processing.
Request With Preference
odata.continue-on-error
Now POST a batch request with Preference
odata.continue-on-error
:POST http://localhost:9001/DefaultBatch/$batch HTTP/1.1 Accept: multipart/mixed prefer: odata.continue-on-error Content-Type: multipart/mixed; boundary=batch_abbe2e6f-e45b-4458-9555-5fc70e3aebe0 Host: localhost:9001 Content-Length: 633 Expect: 100-continue Connection: Keep-Alive --batch_abbe2e6f-e45b-4458-9555-5fc70e3aebe0 Content-Type: application/http Content-Transfer-Encoding: binary GET http://localhost:9001/DefaultBatch/DefaultBatchCustomer(0) HTTP/1.1 --batch_abbe2e6f-e45b-4458-9555-5fc70e3aebe0 Content-Type: application/http Content-Transfer-Encoding: binary GET http://localhost:9001/DefaultBatch/DefaultBatchCustomerfoo HTTP/1.1 --batch_abbe2e6f-e45b-4458-9555-5fc70e3aebe0 Content-Type: application/http Content-Transfer-Encoding: binary GET http://localhost:9001/DefaultBatch/DefaultBatchCustomer(1) HTTP/1.1 --batch_abbe2e6f-e45b-4458-9555-5fc70e3aebe0--
Service returns the error for that request and continue processing additional requests within the batch:
HTTP/1.1 200 OK Content-Length: 1190 Content-Type: multipart/mixed; boundary=batchresponse_60fec4c2-3ce7-4900-a05a-93f180629a11 Server: Microsoft-HTTPAPI/2.0 OData-Version: 4.0 Date: Wed, 12 Aug 2015 02:27:45 GMT --batchresponse_60fec4c2-3ce7-4900-a05a-93f180629a11 Content-Type: application/http Content-Transfer-Encoding: binary HTTP/1.1 200 OK Content-Type: application/json; odata.metadata=minimal; odata.streaming=true OData-Version: 4.0 { "@odata.context":"http://localhost:9001/DefaultBatch/$metadata#DefaultBatchCustomer/$entity","Id":0,"Name":"Name 0" } --batchresponse_60fec4c2-3ce7-4900-a05a-93f180629a11 Content-Type: application/http Content-Transfer-Encoding: binary HTTP/1.1 404 Not Found Content-Type: application/json; charset=utf-8 {"Message":"No HTTP resource was found that matches the request URI 'http://localhost:9001/DefaultBatch/DefaultBatchCustomerfoo'.","MessageDetail":"No route data was found for this request."} --batchresponse_60fec4c2-3ce7-4900-a05a-93f180629a11 Content-Type: application/http Content-Transfer-Encoding: binary HTTP/1.1 200 OK Content-Type: application/json; odata.metadata=minimal; odata.streaming=true OData-Version: 4.0 { "@odata.context":"http://localhost:9001/DefaultBatch/$metadata#DefaultBatchCustomer/$entity","Id":1,"Name":"Name 1" } --batchresponse_60fec4c2-3ce7-4900-a05a-93f180629a11--
-
4.13 Delta Feed Support
Serialization Support for Delta Feed
This sample will introduce how to create a Delta Feed which is serialized into a Delta Response in Web API OData V4.
Similar to
EdmEntityObjectCollection
, Web API OData V5.6 now has anEdmChangedObjectCollection
to represent a collection of objects which can be a part of the Delta Feed. A delta response can contain new/changed entities, deleted entities, new links or deleted links.WebAPI OData V4 now has
EdmDeltaEntityObject
,EdmDeltaDeletedEntityObject
,EdmDeltaLink
andEdmDeltaDeletedLink
respectively for the objects that can be a part of the Delta response. All the above objects implement theIEdmChangedObject
interface, while theEdmChangedObjectCollection
is a collection ofIEdmChangedObject
.For example, if user defines a model as:
The
EdmChangedObjectCollection
collection for Customer entity will be created as follows:Changed or Modified objects are added as
EdmDeltaEntityObject
s:Deleted objects are added as
EdmDeltaDeletedObject
s:Delta Link is added corresponding to a $expand in the initial request, these are added as
EdmDeltaLink
s:Deleted Links is added for each deleted link that corresponds to a $expand path in the initial request, these are added as
EdmDeltaDeletedLink
s:Sample for Delta Feed
Let’s create a controller to return a Delta Feed:
Now, user can issue a GET request as:
The corresponding payload will has the following contents:
-
4.14 Capabilities vocabulary support
Web API OData supports some query limitations, for example: - NonFilterable / NotFilterable – $filter
- NotCountable – $count
- NotExpandable – $expand
- NotNavigable – $select
- NotSortable / Unsortable – $orderby
However, the corresponding annotations cannot be exposed in metadata document. This sample introduces the capabilities vocabulary support in Web API OData V5.7, which will enable capabilites vocabulary annotations in metadata document. The related sample codes can be found here.
Build Edm Model
Let’s define a model with query limitations:
Where,
Address
is a normal complex type,Color
is an enum type andOrder
is a normal entity type. You can find their definitions in the sample codes.Based on the above CLR classes, we can build the Edm model as:
Expose annotations
Now, you can query the metadata document for capabilites vocabulary annotation as:
Thanks.
-
4.15 AutoExpand attribute
In OData WebApi 5.7, we can put AutoExpand
attribute on navigation property to make it automatically expand withoutexpand
query option, or can put this attribute on class to make all Navigation Property on this class automatically expand.Model
Result
If you call return Product in response, Category will automatically expand and Customer will expand too. It works the same if you put
[AutoExpand]
on Class if you have more navigation properties to expand. -
4.16 Ignore query option
In OData WebApi 5.7, we can ignore some query options when calling ODataQueryOption
ApplyTo
method, this is helpful when your odata service is integrate with other service that may already applied those query options.Customize
Controller
Result
Then your queryOption won’t apply Top and Skip.
-
4.17 Alternate keys
Alternate keys is supported in Web API OData V5.7. For detail information about alternate keys, please refer to hereThe related sample codes can be found here Enable Alternate key
Users can enable alternate key in the global configuration.
Model builder
So far, an Edm model with alternate keys can be built by ODL APIs.
So, SSN is an alternate key.
Routing for alternate key
In OData controller, Users can use the attribute routing to route the alternate key. The Uri template is similiar to function parameter. For example:
-
4.18 Add NextPageLink and $count for collection property
In OData WebApi V5.7, it supports to add the NextPageLink and $count for collection property. Enable NextPageLink and $count
It’s easy to enable the NextPageLink and $count for collection property in controller. Users can only put the [EnableQuery(PageSize=x)] on the action of the controller. For example:
Sample Requests & Response
Request: GET http://localhost/Customers(5)/Colors?$count=true
Response content:
-
4.19 Prefer odata.include-annotations
Since OData WebApi V5.6, it supports odata.include-annotations. odata.include-annotations
It supports the following four templates:
- odata.include-annotations=”*” // all annotations
- odata.include-annotations=”-*” // no annotations
- odata.include-annotations=”display.*” // only annotations under “display” namespace
- odata.include-annotations=”display.subject” // only annotation with term name “display.subject”
Let’s have examples:
odata.include-annotations=*
We can use the following codes to request all annotations:
The response will have all annotations:
odata.include-annotations=Entry.*
We can use the following codes to request specify annotations:
The response will only have annotations in “Entry” namespace:
-
4.20 Prefer odata.continue-on-error
Since OData Web API V5.7, it supports odata.continue-on-error. Enable odata.continue-on-error
Users should call the following API to enable continue on error:
Prefer odata.continue-on-error
We can use the following codes to prefer continue on error
The response will have all responses, includes the error responses.
-
4.21 Set namespace for operations in model builder
Since OData Web API V5.7, it allows to set a custom namespace for individual function and action in model builder. Set namespace for function and action in model builder
The setting works for ODataConventionModelBuilder as well.
-
4.22 Use HttpRequestMessage Extension Methods
HttpRequestMessage provides set of exention methods. For services that don’t use LINQ or ODataQueryOptions.ApplyTo(), those extention methods can offer lots of help. ODataProperties
OData methods and properties can be GET/SET through ODataProperties, including:
Model The EDM model associated with the request.
Path The ODataPath of the request.
PathHandler Return DefaultODataPathHandler by default.
RouteName The Route name for generating OData links.
SelectExpandClause The parsed the OData SelectExpandClause of the request.
NextLink Next page link of the results, can be set through GetNextPageLink.
For example, we may need generate service root when querying ref link of a navigation property.
GetNextPageLink
Create a link for the next page of results, can be used as the value of
@odata.nextLink
. For example, the request Url ishttp://localhost/Customers/?$select=Name
.Then the nextlink generated is
http://localhost/Customers/?$select=Name&$skip=10
.GetETag
Get the etag for the given request.
CreateErrorResponse
Create a HttpResponseMessage to represent an error.
Then payload would be like:
{ "error":{ "code":"36", "message":"Bad stuff", "innererror":{ "message":"Exception message", "type":"", "stacktrace":"" } }
-
4.23 OData Simplified Uri convention
OData v4 Web API 5.8 RC intruduces a new OData Simplefied Uri convention that supports key-as-segment and default OData Uri convention side-by-side. To enable the ODataSimplified Uri convention, in
WebApiConfig.cs
: -
4.24 MaxExpansionDepth in EnableQueryAttribute
Since Web API OData V5.9.1, it corrected the behavior of MaxExpansionDepth of EnableQueryAtrribute. MaxExpansionDepth means the max expansion depth for the $expand query option.When MaxExpansionDepth value is 0, it means the check is disabled, but if you use $level=max at the same time, the expand depth will be a default value : 2
, to avoid the dead loop.Let’s see some samples about this behavior.$expand=Manager($levels=max)
will be the same as$expand=Manager($expand=Manager)
$expand=Manager($levels=3)
will be the same as$expand=Manager($expand=Manager($expand=Manager))
Related Issue #731.
-
4.25 Bind Custom UriFunctions to CLR Methods
Since Web API OData V5.9.0, it supports to bind the custom UriFunctions to CLR methods now, so user can add,modify or override the existing pre defined built-in functions.Let’s see how to use this feature. Then you can use filter function like
$filter=padright(ProductName, 5) eq 'Abcd'
.Related Issue #612.
5. SECURITY
-
5.1 Basic authentication over HTTPS
We’re often asked by people if OData APIs can be secured. The name “Open Data Protocol” and the way we evangelize it (by focusing on how open a protocol it is and how it provides interoperability) may give people the impression that OData APIs doesn’t work with authentication and authorization.The fact is that using OData is orthogonal to authentication and authorization. That is to say, you may secure an OData API in any way you can secure a generic RESTful API. We write this post to demonstrate it. The authentication methods we use in this post is the basic authentication over HTTPS. The service library we use is ASP.NET Web API for OData V4.0. Secure an OData Web API using basic authentication over HTTPS
OData Protocol Version 4.0 has the following specification in section 12.1 Authentication:
OData Services requiring authentication SHOULD consider supporting basic authentication as specified in [RFC2617] over HTTPS for the highest level of interoperability with generic clients. They MAY support other authentication methods.
Supporting basic authentication over HTTPS is relatively easy for OData Web API. Suppose you already have a working OData service project. In this post, we implemented an OData API which has only one entity type Product and exposes only one entity set Products. In order to secure Products, the following steps needs to be taken:
1. Create a custom
AuthorizeAttribute
for the basic authenticationAdd a class to your project as follows:
In this sample we name the attribute
HttpBasicAuthorizeAttribute
. It derives fromSystem.Web.Http.AuthorizeAttribute
. We override two of its methods:OnAuthorization
andHandleUnauthorizedRequest
.In
OnAuthorization
, we first get the base64-encoded value of the headerAuthorization
and decode it. Then we apply our custom authentication logic to verify if the decoded value is a valid one. In this sample, we compare the decoded value to “Parry:123456”. As is specified in [RFC2617], this value indicates that the username is “Parry” and password is “123456”. InHandleUnauthorizedRequest
, we handle unauthorized request by responding with HTTP status code401 Unauthorized
.2. Decorate the controller with the custom
AuthorizeAttribute
We decorate our
ProductsController
withHttpBasicAuthorizeAttribute
:3. Enable HTTPS
In the project properties window, enable the SSL and remember the SSL URL:
4. Create a custom
AuthorizationFilterAttribute
for HTTPSAdd a class to your project as follows:
In this sample we name this class
RequireHttpsAttribute
. It derives fromSystem.Web.Http.Filters.AuthorizationFilterAttribute
and overrides itsOnAuthorization
method by responding with HTTP status code403 HTTPS Required
.5. Decorate the controller with the custom
AuthorizationFilterAttribute
We further decorate our
ProductsController
withRequireHttpsAttribute
:6. Testing
We run the project to test it. When run for the first time, you’ll be asked to create a self-signed certificate. Follow the instruction to create the certificate and proceed.
In the above steps, we’ve secured the OData API by allowing only HTTPS connections to the Products and responding with data only to requests that has a correct Authorization header value (the base64-encoded value of “Parry:123456”: UGFycnk6MTIzNDU2). Our HTTP service endpoint is
http://localhost:53277/
and our HTTPS endpoint ishttps://localhost:43300/
.First of all, we send a
GET
request tohttp://localhost:53277/Products
, and the service responds with an empty payload and the status code403 HTTPS Required
.Then we send the request over HTTPS to
https://localhost:43300/Products
. Since the basic authentication info needs to be provided. The service responds with an empty payload and the status code401 Unauthorized
.Finally, we set the value of the
Authorization
header to “Basic UGFycnk6MTIzNDU2” and send it over HTTPS to the same address again. The service now responds with the correct data.Summary
In this post we demoed how an OData API can be secured by basic authentication over HTTPS. You may additionally add authorization logic to the API by further customizing the
HttpBasicAuthorizeAttribute
class we created. Furthermore, you may also use other authentication methods such as OAuth2 to secure your OData API. More information can be found at: http://www.asp.net/web-api/overview/security.
6. CUSTOMIZATION
-
6.1 Custom URL parsing
Let’s show how to extend the default OData Uri Parser behavior: Basic Case Insensitive Support
User can configure as below to support basic case-insensitive parser behavior.
Note: Case insensitive flag enables both for metadata and key-words, not only on path segment, but also on query option.
For example:
- ~/odata/$metaDaTa
- ~/odata/cusTomers …
Unqualified function/action call
User can configure as below to support basic unqualified function/action call.
For example:
Original call: * ~/odata/Customers(112)/Default.GetOrdersCount(factor=1)
Now, you can call as: * ~/odata/Customers(112)/GetOrdersCount(factor=1)
Since Web API OData 5.6, it enables unqualified function in attribut routing. So, Users can add the unqualified function template. For example:
Enum prefix free
User can configure as below to support basic string as enum parser behavior.
For example:
Origin call:
Now, you can call as:
Advance Usage
User can configure as below to support case insensitive & unqualified function call & Enum Prefix free:
Thanks.
-
6.2 Relax version constraints
For both Web API OData V3 and V4, a flag IsRelaxedMatch
is introduced to relax the version constraint. WithIsRelaxedMatch = true
, ODataVersionConstraint will allow OData request to contain both V3 and V4 max version headers (V3:MaxDataServiceVersion
, V4:OData-MaxVersion
). Otherwise, the service will return response with status code 400. The default value ofIsRelaxdMatch
is false.To set this flag, API HasRelaxedODataVersionConstraint() under ODataRoute can be used as following:
-
6.3 Customize OData Formatter
This page illustrates how to use sensibility points in the ODataFormatter and plugin custom OData serializers/deserializers, gives a sample extends the ODataFormatter to add support of OData instance annotations.Let’s see this sample. CLR Model
First of all, we create the following CLR classes as our model:
If I search for documents by sending the search query, in the result, I’d like have a score for the match for each document, as the score is dependent on the in coming query, it cannot be modeled as a property on response’s document, it should be modeled as an annotation on the document. Let’s do that.
Build Edm Model
Now, we can build a pretty simple Edm Model as:
Customize OData Formatter
A custom entity serializer
This entity serializer is to add the score annotation (org.northwind.search.score) to document entries.
A custom serializer provider
This serializer provider is to inject the AnnotationEntitySerializer.
Setup configuration with customized ODataFormatter
Create the formatters with the custom serializer provider and use them in the configuration.
Controller Samples
You should add a score to result documents.
Request Samples
Add prefer header and send request.
Response Samples
Annotation is supported in newest night build, 5.6.0-beta1.
Conclusion
The sample has a custom entity type serializer, AnnotatingEntitySerializer, that adds the instance annotation to ODataEntry by overriding the CreateEntry method. It defines a custom ODataSerializerProvider to provide AnnotatingEntitySerializer instead of ODataEntityTypeSerializer. Then creates the OData formatters using this serializer provider and uses those formatters in the configuration.
-
6.4 Custom Stream Entity
Since Web API OData V5.7, it supports to customize entity as stream. Fluent API
Users can call fluent API to configure the stream entity. For example,
Convention model builder
Users can put [MediaType] attribute on a CLR class to configure the stream entity. For example,
7. RELEASE NOTES
-
7.1 OData Web API 5.4 Beta
The NuGet packages for OData Web API 5.4 beta are now available on the NuGet gallery. Download this release
You can install or update the NuGet packages for OData Web API 5.4 beta using the Package Manager Console:
PM> Install-Package Microsoft.AspNet.OData -Version 5.4.0-beta -Pre PM> Install-Package Microsoft.AspNet.WebApi.OData -Version 5.4.0-beta -Pre
What’s in this release?
This release primarily includes new features for OData (v4 and v3) Web API as summarized below:
- Referential constraint (v4, v3) #37
- Relax flag for version constraint (v4, v3): By default requests with both v3 and v4 max version headers will no longer fail. #191
- DateTime support (v4) #136
- Case-insensitive support (v4) #11
- StoreGeneratedPattern annotation (v3) #189
- ConcurrencyMode annotation and ETag (v3) #190
- Bug fixes
V4 package has a dependency on ODataLib 6.9.
Questions and feedback
You can submit questions related to this release, any issues you encounter and feature suggestions for future releases on our GitHub site.
-
7.2 OData Web API 5.4 RC
The NuGet packages for OData Web API 5.4 RC are now available on the NuGet gallery. Download this release
You can install or update the NuGet packages for OData Web API 5.4 RC using the Package Manager Console:
PM> Install-Package Microsoft.AspNet.OData -Version 5.4.0-rc -Pre PM> Install-Package Microsoft.AspNet.WebApi.OData -Version 5.4.0-rc -Pre
What’s in this release?
This release primarily includes new features for OData (v4 and v3) Web API as summarized below:
- Referential constraint (v4, v3) #37
- Relax flag for version constraint (v4, v3): By default requests with both v3 and v4 max version headers will no longer fail. #191
- DateTime support (v4) #136
- Case-insensitive support (v4) #11
- StoreGeneratedPattern annotation (v3) #189
- ConcurrencyMode annotation and ETag (v3) #190
- Bug fixes: CodePlex & GitHub
V4 package has a dependency on ODataLib 6.9.
Questions and feedback
You can submit questions related to this release, any issues you encounter and feature suggestions for future releases on our GitHub site.
-
7.3 OData Web API 5.4
The NuGet packages for OData Web API 5.4 are now available on the NuGet gallery. Download this release
You can install or update the NuGet packages for OData Web API 5.4 using the Package Manager Console:
What’s in this release?
This release primarily includes new features for OData (v4 and v3) Web API as summarized below:
- Referential constraint (v4, v3) #37
- Relax flag for version constraint (v4, v3): By default requests with both v3 and v4 max version headers will no longer fail. #191
- DateTime support (v4) #136
- Case-insensitive support (v4) #11
- StoreGeneratedPattern annotation (v3) #189
- ConcurrencyMode annotation and ETag (v3) #190
- Bug fixes: CodePlex & GitHub
V4 package has a dependency on ODataLib 6.9.
Questions and feedback
You can submit questions related to this release, any issues you encounter and feature suggestions for future releases on our GitHub site.
-
7.4 OData Web API 5.5
The NuGet packages for OData Web API 5.5 are now available on the NuGet gallery. Download this release
You can install or update the NuGet packages for OData Web API 5.5 using the Package Manager Console:
What’s in this release?
This release primarily includes new features for OData v4 Web API as summarized below:
- Abstract entity type without keys or properties #182
- Complex type, Entity reference, Entity, and collection as function/action parameters #7
- Edm.Date & Edm.TimeOfDay support #156
- Open type and dynamic property on un-type scenario #171
- Nested $filter in $expand #127
- Pull requests
- Update SelectExpandQueryOption.cs #213 by Jordi Scharloo
- Add support for OpenPathSegment #222 by Brad Cleaver
- Allow multiple ODataRoutePrefix attributes #228 by Brad Cleaver
- Fix for issue #248 where a single instance function is queried using $select #249 by Hans van Bakel
- Support dynamic properties in $filter, $orderby and $select #250 by Hans van Bakel
- Bug fixes
- EnableCaseInsensitive doesn’t work right when $top #214
- DateTime doesn’t work for ETag #224
- Get parameter alias from ParameterAliasNodes by ODataLib parser #143
- DeleteRef fails if a navigation property is a derived type and there is no corresponding entity set #231
- Cannot parse Enum function parameter when its EdmType is nullable #110
- GetClrType() doesn’t work for nullable enum #241
- Enum prefix free doesn’t work for function parameter #243
- FromODataUri attribute not work for a function’s string parameter #223
- Nested $expand with $levels=max does not have correct expansion depth #148
- Enum keys not recognized by ODataConventionModelBuilder #139
In this release, we moved the license from Microsoft OpenTech + Apache to Microsoft + MIT.
v4 package has a dependency on ODataLib 6.10.
Questions and feedback
You can submit questions related to this release, any issues you encounter and feature suggestions for future releases on our GitHub site.
-
7.5 OData Web API 5.5.1
The NuGet packages for OData Web API 5.5.1 are now available on the NuGet gallery. Download this release
You can install or update the NuGet packages for OData Web API 5.5.1 using the Package Manager Console:
What’s in this release?
- Fix the issue: $count segment doesn’t work in 5.5 with EF #290
-
7.6 OData Web API 5.6 beta1
The NuGet packages for OData Web API 5.6 beta1 are now available on the NuGet gallery. Download this release
You can install or update the NuGet packages for OData Web API 5.6 beta1 using the Package Manager Console:
PM> Install-Package Microsoft.AspNet.OData -Version 5.6-beta1 -Pre
What’s in this release?
- Convention and Attribute Routing for Dynamic Property #319
- Support the odata.include-annotations. #90
- Support UnqualifiedNameCall in attribute routing. #280
- DateTime $filter and $orderby support. #293
Bug fix
#300: Function Date() doesn’t work with Linq To Entity.
-
7.7 OData Web API 5.6
The NuGet packages for OData Web API v5.6 are available on the NuGet gallery. Download this release
You can install or update the NuGet packages for OData Web API v5.6 using the Package Manager Console:
PM> Install-Package Microsoft.AspNet.OData -Version 5.6.0
What’s in this release?
New Features:
- GitHub Issue #71, Pull request #287 by hotchandanisagar : Add support for Delta Feed serialization in Web API OData.
- Pull request #280 by OData team : Support UnqualifiedNameCall in ODataRoute attribute.
- GitHub Issue #293, Pull request #297 by OData team : DateTime $filter and $orderby EF support.
- GitHub Issue #319 : Convention and Attribute Routing for Dynamic Property. This built upon a previous pull request #222 by Brad Cleaver: Add support for OpenPathSegment
Bug Fixes:
- GitHub Issue #300 : date() and time() function doesn’t work with EF.
- GitHub Issue #317, Pull request #340 by OData team : Support nullable referential constraint with conventional model builder.
- GitHub Issue #331, Pull request #336 by OData team : Support nullable enum prefix free in $filter.
- GitHub Issue #281, Pull request #341 by OData team : OData serialization cannot serializer the derived complex types.
- GitHub Issue #330, Pull request #350 by OData team : Dynamic property name is null use convention routing.
- GitHub Issue #214, Pull request #343 by OData team : Issue about Web API model validation.
- GitHub Issue #294, Pull request #323, #332 by OData team : Formatting
<see>true</see>
,<see langword="null"/>
issue in xml comments about true, false, and null.
OData Web API v5.6 package has a dependency on ODataLib 6.11.
Questions and feedback
You and your team are warmly welcomed to try out this new version if you are interested in the new features and fixes above. You are also welcomed to contribute your code to OData Web API repository. For any feature request, issue or idea please feel free to reach out to us at GitHub Issues.
-
7.8 OData Web API 6.0.0 alpha1
The NuGet packages for OData Web API v6.0.0 alpha1 are now available on the myget. Configure package source
You can configure the NuGet package source for OData Web API v6.0.0 preview releases in the Package Manager Settings:
Download this release
You can install or update the NuGet packages for OData Web API v6.0.0 alpha1 using the Package Manager Console:
PM> Install-Package Microsoft.AspNet.OData -Version 6.0.0-alpha1 -Pre
What’s in this release?
This release contains the first preview of the next version of OData Web API which is built on ASP.NET 5 and MVC 6. This preview includes the basic support of:
- Querying service metadata
- Querying entity sets
- CRUD of single entity
- Querying structural or navigation property
- $filter query option
OData Web API v6.0.0 alpha1 package has a dependency on ODataLib 6.12.
Where’s the sample service?
You can take a look at a basic sample service built by this library.
Now the sample service can support (but not limit to) the following requests:
- Metadata.
GET http://localhost:9091/odata/$metadata
- EntitySet.
GET http://localhost:9091/odata/Products
- Entity.
GET http://localhost:9091/odata/Products(1)
- Structural property.
GET http://localhost:9091/odata/Customers(1)/FirstName
- Navigation property.
GET http://localhost:9091/odata/Customers(1)/Products
- $filter.
GET http://localhost:9091/odata/Products?$filter=ProductId%20gt%201
- Create.
POST http://localhost:9091/odata/Products
- Delete.
DELETE http://localhost:9091/odata/Products(2)
- Full update.
PUT http://localhost:9091/odata/Products(2)
Where’s the source code?
You can view the source code of this library at our OData Web API repository. We warmly welcome any feedback, proposition and contribution from you!
-
7.9 OData Web API 5.7 beta
The NuGet packages for OData Web API v5.7 beta are available on the NuGet gallery. Download this release
You can install or update the NuGet packages for OData Web API v5.7 using the Package Manager Console:
PM> Install-Package Microsoft.AspNet.OData -Version 5.7.0-beta -Pre
What’s in this release?
New Features:
- Pull request #322 by chinese007, #407 by OData team : Add the NextPageLink and Count for collection property.
- GitHub Issue #149, Pull request #379 by OData team : Expose HasStream for EntityType configuration.
- GitHub Issue #377, Pull request #384 by Bruce Johnston : Making ODataQueryOptions.GetNextPageLink public.
- GitHub Issue #310, Pull request #399 by OData team : Cannot ignore some query options like $skip.
- GitHub Issue #98, #107, #258, Pull request #405 by OData team : Add capabilities vocabulary annotation support
- Pull request #419 by Abhishek Kumar : Adding support for alternate key Uri resolver.
- GitHub Issue #408, Pull request #426 by OData team : Handling of preference header ‘continue-on-error’ in user request.
- GitHub Issue #311, Pull request #428 by OData team : Auto expand navigation property.
- GitHub Issue #304, Pull request #444 by OData team : Support setting namespaces for operations in ODataConventionModelBuilder.
Bug Fixes:
- GitHub Issue #334, Pull request #335 by Matt Johnson : Time zone conversions are not DST aware.
- GitHub Issue #195, Pull request #372 by Brad Cleaver : Navigation link generation for contained navigations.
- GitHub Issue #376, Pull request #386 by OData team : $orderby with duplicate property in odata v4 failed.
- GitHub Issue #387, Pull request #391 by OData team : Can’t get untyped enum property.
- GitHub Issue #401, Pull request #402 by CrazyViper : DateTime min and max value serialization problem.
- GitHub Issue #398, Pull request #430 by OData team : Change IsRelaxedMatch’s default value to True.
OData Web API v5.7-bata package has a dependency on ODataLib 6.13.
Questions and feedback
You and your team are warmly welcomed to try out this new version if you are interested in the new features and fixes above. You are also welcomed to contribute your code to OData Web API repository. For any feature request, issue or idea please feel free to reach out to us at GitHub Issues.
-
7.10 OData Web API 5.7 rc
The NuGet packages for OData Web API v5.7 rc are available on the NuGet gallery. Download this release
You can install or update the NuGet packages for OData Web API v5.7 using the Package Manager Console:
PM> Install-Package Microsoft.AspNet.OData -Version 5.7.0-rc -Pre
What’s in this release?
New Features:
- Pull request #322 by chinese007, #407 by OData team : Add the NextPageLink and Count for collection property.
- GitHub Issue #149, Pull request #379 by OData team : Expose HasStream for EntityType configuration.
- GitHub Issue #377, Pull request #384 by Bruce Johnston : Making ODataQueryOptions.GetNextPageLink public.
- GitHub Issue #310, Pull request #399 by OData team : Cannot ignore some query options like $skip.
- GitHub Issue #98, #107, #258, Pull request #405 by OData team : Add capabilities vocabulary annotation support
- Pull request #419 by Abhishek Kumar : Adding support for alternate key Uri resolver.
- GitHub Issue #408, Pull request #426 by OData team : Handling of preference header ‘continue-on-error’ in user request.
- GitHub Issue #311, Pull request #428 by OData team : Auto expand navigation property.
- GitHub Issue #304, Pull request #444 by OData team : Support setting namespaces for operations in ODataConventionModelBuilder.
Bug Fixes:
- GitHub Issue #398, Pull request #430 by OData team : Change IsRelaxedMatch’s default value to True.
- Pull request #407 by OData team : Add the NextPageLink & $Count for collection property
- GitHub Issue #334, Pull request #335 by Matt Johnson : Time zone conversions are not DST aware
- GitHub Issue #376, Pull request #386 by OData team : $orderby with duplicate property in odata v4 failed.
- GitHub Issue #401, Pull request #402 by CrazyViper : DateTime min and max value serialization problem.
- GitHub Issue #387, Pull request #393 by OData team : Can’t get untyped enum property.
OData Web API v5.7-rc package has a dependency on ODataLib 6.13.
Questions and feedback
You and your team are warmly welcomed to try out this new version if you are interested in the new features and fixes above. You are also welcomed to contribute your code to OData Web API repository. For any feature request, issue or idea please feel free to reach out to us at GitHub Issues.
-
7.11 OData Web API 5.7
The NuGet packages for OData Web API v5.7 are available on the NuGet gallery. Download this release
You can install or update the NuGet packages for OData Web API v5.7 using the Package Manager Console:
PM> Install-Package Microsoft.AspNet.OData -Version 5.7.0
What’s in this release?
New Features:
- Pull request #322 by chinese007, #407 by OData team : Add the NextPageLink and Count for collection property.
- GitHub Issue #149, Pull request #379 by OData team : Expose HasStream for EntityType configuration.
- GitHub Issue #377, Pull request #384 by Bruce Johnston : Making ODataQueryOptions.GetNextPageLink public.
- GitHub Issue #310, Pull request #399 by OData team : Cannot ignore some query options like $skip.
- GitHub Issue #98, #107, #258, Pull request #405 by OData team : Add capabilities vocabulary annotation support
- Pull request #419 by Abhishek Kumar : Adding support for alternate key Uri resolver.
- GitHub Issue #408, Pull request #426 by OData team : Handling of preference header ‘continue-on-error’ in user request.
- GitHub Issue #311, Pull request #428 by OData team : Auto expand navigation property.
- GitHub Issue #304, Pull request #444 by OData team : Support setting namespaces for operations in ODataConventionModelBuilder.
Bug Fixes:
- GitHub Issue #334, Pull request #335 by Matt Johnson : Time zone conversions are not DST aware.
- GitHub Issue #195, Pull request #372 by Brad Cleaver : Navigation link generation for contained navigations.
- GitHub Issue #376, Pull request #386 by OData team : $orderby with duplicate property in odata v4 failed.
- GitHub Issue #387, Pull request #391 by OData team : Can’t get untyped enum property.
- GitHub Issue #401, Pull request #402 by CrazyViper : DateTime min and max value serialization problem.
- GitHub Issue #398, Pull request #430 by OData team : Change IsRelaxedMatch’s default value to True.
- GitHub Issue #442, Pull request #453 by Ilchert : Checking propetry for null changed from Or to OrElse
- GitHub Issue #447, Pull request #457 by OData team : Keep default behavior for batch error handling.
- GitHub Issue #459, Pull request #474 by OData team : Add concurrency annotation support.
OData Web API v5.7 package has a dependency on ODataLib 6.13.
Questions and feedback
You and your team are warmly welcomed to try out this new version if you are interested in the new features and fixes above. You are also welcomed to contribute your code to OData Web API repository. For any feature request, issue or idea please feel free to reach out to us at GitHub Issues.
-
7.12 OData Web API 5.8 beta
The NuGet packages for OData Web API v5.8 beta are available on the NuGet gallery. Download this release
You can install or update the NuGet packages for OData Web API v5.8 using the Package Manager Console:
PM> Install-Package Microsoft.AspNet.OData -Version 5.8.0-beta -Pre
What’s in this release?
Improvements and fixes:
- Fixed typographical error, changed availabe to available in README. PR #519 by orthographic-pedant
[ConcurrencyCheck]
attribute doesn’t work with EF. Issue #522, PR #529- Manually using ODataQueryOptions.Validate and setting SelectExpandQueryOption.LevelsMaxLiteralExpansionDepth. Issue #516, PR #524
- CultureInfo property can’t be serialized. Issue #427, PR #542
- Web API does not support Edm.Date literal in $filter when the property is Edm.Date [Nullable=True] and the backend is EF. Issue #482, PR #541
- Add swagger model APIs. Issue #302, PR #520
- Add operationId for Swagger json generation. Issue #302, PR #552
- ETag can’t work for double type. Issue #475, PR #549
- Expand query option contain $count don’t work. Issue #349, PR #553
- EditLink is wrong in 5.7. Issue #543, PR #554
- $count is evaluated prematurely at the call queryOptions.ApplyTo. Issue #1, PR #562
- Unnecessary casts in expression when querying properties of the base class for the inheritor. Issue #560, PR #556 by Yuriy Soldatkin
OData Web API v5.8-beta package has a dependency on ODataLib 6.13.
Questions and feedback
You and your team are warmly welcomed to try out this new version if you are interested in the new features and fixes above. You are also welcomed to contribute your code to OData Web API repository. For any feature request, issue or idea please feel free to reach out to us at GitHub Issues.
-
7.13 OData Web API 5.8 rc
The NuGet packages for OData v4 Web API 5.8 RC are available on the NuGet gallery. Download this release
You can install or update the NuGet packages for OData Web API v5.8 using the Package Manager Console:
PM> Install-Package Microsoft.AspNet.OData -Pre
What’s in this release?
Improvements and fixes:
- Fixed typographical error, changed availabe to available in README. PR #519 by orthographic-pedant
[ConcurrencyCheck]
attribute doesn’t work with EF. Issue #522, PR #529- Manually using ODataQueryOptions.Validate and setting SelectExpandQueryOption.LevelsMaxLiteralExpansionDepth. Issue #516, PR #524
- CultureInfo property can’t be serialized. Issue #427, PR #542
- Add operationId for Swagger json generation. Issue #302, PR #552
- ETag can’t work for double type. Issue #475, PR #549
- EditLink is wrong in 5.7. Issue #543, PR #554
- $count is evaluated prematurely at the call queryOptions.ApplyTo. Issue #1, PR #562
- Unnecessary casts in expression when querying properties of the base class for the inheritor. Issue #560, PR #556 by Yuriy Soldatkin
- Regression about the complex inheritance build. Issue #575, PR #577
- ProcedureConfiguration API to support types known at runtime. PR #580 by Yogev Mizrahi
- Array of enum doesn’t work for convention model builder. Issue #581, PR #582
New Features:
- Web API does not support Edm.Date literal in $filter when the property is Edm.Date [Nullable=True] and the backend is EF. Issue #482, PR #541
- Add swagger model APIs. Issue #302, PR #520
- Expand query option contain $count don’t work. Issue #349, PR #553
- Added UrlConventions configuration in DefaultODataPathHandler that supports ODataSimplified Uri convention. PR #599 by Gan Quan
- Make other nested query options in to work. Issue #557, PR #569
- Added config options SerializeNullCollectionsAsEmpty and DoNotSerializeNullCollections. Issue #490, PR #583 by nickkin-msft
- Enable to serialize the null dynamic propery by config. Issue #313, PR #573
OData Web API v5.8 RC package has a dependency on OData v4 Lib 6.14.
Questions and feedback
You and your team are warmly welcomed to try out this new version if you are interested in the new features and fixes above. You are also welcomed to contribute your code to OData Web API repository. For any feature request, issue or idea please feel free to reach out to us at GitHub Issues.
-
7.14 OData Web API 5.8
The NuGet packages for OData v4 Web API 5.8 are available on the NuGet gallery. Download this release
You can install or update the NuGet packages for OData Web API v5.8 using the Package Manager Console:
PM> Install-Package Microsoft.AspNet.OData
What’s in this release?
Improvements and fixes:
- Fixed typographical error, changed availabe to available in README. PR #519 by orthographic-pedant
[ConcurrencyCheck]
attribute doesn’t work with EF. Issue #522, PR #529- Manually using ODataQueryOptions.Validate and setting SelectExpandQueryOption.LevelsMaxLiteralExpansionDepth. Issue #516, PR #524
- CultureInfo property can’t be serialized. Issue #427, PR #542
- Add operationId for Swagger json generation. Issue #302, PR #552
- ETag can’t work for double type. Issue #475, PR #549
- EditLink is wrong in 5.7. Issue #543, PR #554
- $count is evaluated prematurely at the call queryOptions.ApplyTo. Issue #1, PR #562
- Unnecessary casts in expression when querying properties of the base class for the inheritor. Issue #560, PR #556 by Yuriy Soldatkin
- Regression about the complex inheritance build. Issue #575, PR #577
- ProcedureConfiguration API to support types known at runtime. PR #580 by Yogev Mizrahi
- Array of enum doesn’t work for convention model builder. Issue #581, PR #582
New Features:
- Web API does not support Edm.Date literal in $filter when the property is Edm.Date [Nullable=True] and the backend is EF. Issue #482, PR #541
- Add swagger model APIs. Issue #302, PR #520
- Expand query option contain $count don’t work. Issue #349, PR #553
- Added UrlConventions configuration in DefaultODataPathHandler that supports ODataSimplified Uri convention. PR #599 by Gan Quan
- Make other nested query options in to work. Issue #557, PR #569
- Added config options SerializeNullCollectionsAsEmpty and DoNotSerializeNullCollections. Issue #490, PR #583 by nickkin-msft
- Enable to serialize the null dynamic propery by config. Issue #313, PR #573
OData Web API v5.8 package has a dependency on OData v4 Lib 6.14.
Questions and feedback
You and your team are warmly welcomed to try out this new version if you are interested in the new features and fixes above. You are also welcomed to contribute your code to OData Web API repository. For any feature request, issue or idea please feel free to reach out to us at GitHub Issues.
-
7.15 OData Web API 5.9
The NuGet packages for OData v4 Web API 5.9 are available on the NuGet gallery. Download this release
You can install or update the NuGet packages for OData Web API v5.9 beta using the Package Manager Console:
PM> Install-Package Microsoft.AspNet.OData
What’s in this release?
Improvements and fixes:
- Support Pass Null to EntitySet during Feed Serialization. Issue #617, PR #621
- DataContractAttribute, etc don’t work for enum type. Issue #640
- Provide an extensibility hook for consumers of ODataMediaTypeFormatter to customize base address of service root in OData uris. Issue #644, PR #645 by Jack Freelander
- Using object key for null check in expression. Issue #559, PR #584 by Yuriy Soldatkin
New Features:
- Support PATCH to a complex type. Issue #135, PR #623
- Added basic support for aggregations spec. Issue #70, PR #594 by Konstantin Kosinsky
- Support Edm.Date. Issue #118, PR #600
- Support “isof” query built-in function. Issue #185, PR #646
- Advertise action/function in feed payload. Issue #637, PR #642
- Bind Uri Functions to CLR methods. Issue #612, PR #613
OData Web API v5.9 package has a dependency on OData v4 Lib 6.15.
Questions and feedback
You and your team are warmly welcomed to try out this new version if you are interested in the new features and fixes above. You are also welcomed to contribute your code to OData Web API repository. For any feature request, issue or idea please feel free to reach out to us at GitHub Issues.
-
7.16 OData Web API 5.9.1
The NuGet packages for OData v4 Web API 5.9.1 are available on the NuGet gallery. Download this release
You can install or update the NuGet packages for OData Web API v5.9.1 using the Package Manager Console:
PM> Install-Package Microsoft.AspNet.OData
What’s in this release?
Improvements and fixes:
- POST with GeographyPoint throws object must implement IConvertable. Issue #718
- Model binding broken with enum keys. Issue #724
- Update enum property doesn’t work. Issue #742
- Delta<T> should avoid static properties. Issue #137
- MaxExpansionDepth of 0 is not work. Issue #731
- EnumMember support without value. Issue #697
- Make IsIfNoneMatch public. Issue #764
New Features:
- ETagMessageHandler is not supporting typeless entities. Issue #172
OData Web API v5.9.1 package has a dependency on OData v4 Lib 6.15.
Questions and feedback
You and your team are warmly welcomed to try out this new version if you are interested in the new features and fixes above. You are also welcomed to contribute your code to OData Web API repository. For any feature request, issue or idea please feel free to reach out to us at GitHub Issues.
-
7.17 OData Web API 6.0.0-beta
The NuGet packages for OData v4 Web API 6.0.0-beta are available on the NuGet gallery. Download this release
You can install or update the NuGet packages for OData Web API v6.0.0-beta using the Package Manager Console:
PM> Install-Package Microsoft.AspNet.OData -Pre
What’s in this release?
Breaking Changes:
- Unify the entity and complex (collection) type serialization/deserialization, See [ odata issue #504 ]
- Rename
ODataFeed
toODataResourceSet
- Rename
ODataEntry
toODataResource
- Rename
ODataNavigationLink
toODataNestedResourceInfo
- Rename
ODataPayloadKind.Entry
toODataPayloadKind.Resource
- Rename
ODataPayloadKind.Feed
toODataPayloadKind.ResourceSet
- Rename
ODataEntityTypeSerializer
toODataResourceSerializer
- Rename
ODataFeedSerializer
toODataResourceSetSerizlier
- Rename
ODataEntityDeserializer
toODataResourceDeserializer
- Rename
ODataFeedDeserializer
toODataResourceSetDeserializer
- Remove
ODataComplexValue
- Remove
ODataComplexSerializer/ODataComplexTypeDeserializer
- Rename
- Issue #745 Support dependency injection (DI).
- Integrate with the very popular DI framework Microsoft.Extensions.DependencyInjection.
- Enable extremely easy customization of many services in Web API OData using DI.
- Simplify APIs by removing redundant parameters and properties that have corresponding services registered in DI.
- Issue #681 Using ODL path segment classes directly.
- Remove all path segment classes defined in Web API OData.
- Using the ODL path segment classes and template classes
- Issue #693 Support new model bound attributes.
- New attribute classes, ( for example
FilterAttribute
,OrderbyAttribute
, etc ) used to enhance query options validation.
- New attribute classes, ( for example
- Support complex type with navigation property.
HasMany(), HasRequired(), HasOptional
can be used on complex type to add navigation property.- Support navigation property on complex type in convention model builder.
- Remove
INavigationSourceConfiguration
andDeclaringEntityType
property
- Support multiple navigation property bindings for a single navigation property by using different paths, see [ odata issue #629 ]
- New
BindingPathConfiguration<T>
class used to add binding path - New
NavigationPropertyBindingOption
used to control binding in model builder.
- New
- Issue #764 public
IsIfNoneMatch
property - Issue #797 public Convert APIs in ODataModelBinderProvider.
- Issue #172 ETagMessageHandler is not supporting typeless entities.
- Issue #652 Some changes in Delta for complex/entity type delta.
Migration ODL changes:
- Simplified ODL namespaces, see [ odata issue #491 ]
- Rename ODataUrlConvention to ODataUrlKeyDelimiter, see [ [odata issue #571] (https://github.com/OData/Odata.net/issues/571) ]
- Rename ODataUrlConvention to ODataUrlKeyDelimiter.
- Use ODataUrlKeyDelimiter.Slash instead of ODataUrlConvention.Simplified or ODataUrlConvention.KeyAsSegment
- Use ODataUrlKeyDelimiter.Parentheses instead of ODataUrlConvention.Default
- Change SerializationTypeNameAnnotation to ODataTypeAnnotation, see [ odata issue #614 ]
- Change Enum member value type from IEdmPrimitiveValue to a more specific type, see [ odata issue #544 ]
- Adjust query node kinds in Uri Parser in order to support navigation under complex. see [ odata issue #643 ]
- Add SingleComplexNode and CollectionComplexNode to specifically represent complex type node.
- Add SingleResourceNode as the base class of SingleEntityNode and SingleComplexNode, etc.
- Rename CsdlXXX to SchemaXXX, and EdmxXXX to CsdlXXX, see [ odata issue #632 ]
- CsdlReader/Writer to SchemaReader/Writer;
- EdmxReader/Writer to CsdlReader/Writer;
- EdmxReaderSettings to CsdlReaderSettings;
- EdmxTarget to CsdlTarget
- Remove Edm.ConcurrencyMode attribute. see [ odata issue #564 ]
- Remove
odata.null
in ODL. It’s developer’s responsibility to check whether the return object is null or not.
Improvements & Fixes:
- Issue #719 ODataSwaggerConverter throws exception on composite key.
- Issue #711 Using same enum twice in a model causes null reference exception.
- Issue #697 EnumMember attribute without value.
- Issue #726 Aggregation failed in Restier.
- Issue #706 Change substringof to contained builtin function.
- Issue #722 URI template parser doesn’t work correctly if key is of an enum type, see [ odata issue #556 ]
- Issue #630 Orderby with duplicate properties.
Here can find the OData V4 7.0.0 breaking changes docs and tutorials.
Questions and feedback
You and your team are warmly welcomed to try out this new version if you are interested in the new features and fixes above. You are also welcomed to contribute your code to OData Web API repository. For any feature request, issue or idea please feel free to reach out to us at GitHub Issues.
- Unify the entity and complex (collection) type serialization/deserialization, See [ odata issue #504 ]
-
7.18 OData Web API 6.0.0
The NuGet packages for OData v4 Web API 6.0.0 are available on the NuGet gallery. Download this release
You can install or update the NuGet packages for OData Web API v6.0.0 using the Package Manager Console:
PM> Install-Package Microsoft.AspNet.OData
What’s in this release?
Breaking Changes:
- Unify the entity and complex (collection) type serialization/deserialization, See [ odata issue #504 ]
- Rename
ODataFeed
toODataResourceSet
- Rename
ODataEntry
toODataResource
- Rename
ODataNavigationLink
toODataNestedResourceInfo
- Rename
ODataPayloadKind.Entry
toODataPayloadKind.Resource
- Rename
ODataPayloadKind.Feed
toODataPayloadKind.ResourceSet
- Rename
ODataEntityTypeSerializer
toODataResourceSerializer
- Rename
ODataFeedSerializer
toODataResourceSetSerizlier
- Rename
ODataEntityDeserializer
toODataResourceDeserializer
- Rename
ODataFeedDeserializer
toODataResourceSetDeserializer
- Remove
ODataComplexValue
- Remove
ODataComplexSerializer/ODataComplexTypeDeserializer
- Rename
- Issue #745 Support dependency injection (DI).
- Integrate with the very popular DI framework Microsoft.Extensions.DependencyInjection.
- Enable extremely easy customization of many services in Web API OData using DI.
- Simplify APIs by removing redundant parameters and properties that have corresponding services registered in DI.
- Issue #681 Using ODL path segment classes directly.
- Remove all path segment classes defined in Web API OData.
- Using the ODL path segment classes and template classes
- Issue #693 Support new model bound attributes.
- New attribute classes, ( for example
FilterAttribute
,OrderbyAttribute
, etc ) used to enhance query options validation. - Query options are disallowed by default, see detail in document.
- New attribute classes, ( for example
- Support complex type with navigation property.
HasMany(), HasRequired(), HasOptional
can be used on complex type to add navigation property.- Support navigation property on complex type in convention model builder.
- Remove
INavigationSourceConfiguration
andDeclaringEntityType
property
- Support multiple navigation property bindings for a single navigation property by using different paths, see [ odata issue #629 ]
- New
BindingPathConfiguration<T>
class used to add binding path - New
NavigationPropertyBindingOption
used to control binding in model builder.
- New
- Issue #764 public
IsIfNoneMatch
property - Issue #797 public Convert APIs in ODataModelBinderProvider.
- Issue #172 ETagMessageHandler is not supporting typeless entities.
- Issue #652 Some changes in Delta for complex/entity type delta.
Migration ODL changes:
- Simplified ODL namespaces, see [ odata issue #491 ]
- Rename ODataUrlConvention to ODataUrlKeyDelimiter, see [ [odata issue #571] (https://github.com/OData/Odata.net/issues/571) ]
- Rename ODataUrlConvention to ODataUrlKeyDelimiter.
- Use ODataUrlKeyDelimiter.Slash instead of ODataUrlConvention.Simplified or ODataUrlConvention.KeyAsSegment
- Use ODataUrlKeyDelimiter.Parentheses instead of ODataUrlConvention.Default
- Change SerializationTypeNameAnnotation to ODataTypeAnnotation, see [ odata issue #614 ]
- Change Enum member value type from IEdmPrimitiveValue to a more specific type, see [ odata issue #544 ]
- Adjust query node kinds in Uri Parser in order to support navigation under complex. see [ odata issue #643 ]
- Add SingleComplexNode and CollectionComplexNode to specifically represent complex type node.
- Add SingleResourceNode as the base class of SingleEntityNode and SingleComplexNode, etc.
- Rename CsdlXXX to SchemaXXX, and EdmxXXX to CsdlXXX, see [ odata issue #632 ]
- CsdlReader/Writer to SchemaReader/Writer;
- EdmxReader/Writer to CsdlReader/Writer;
- EdmxReaderSettings to CsdlReaderSettings;
- EdmxTarget to CsdlTarget
- Remove Edm.ConcurrencyMode attribute. see [ odata issue #564 ]
- Remove
odata.null
in ODL. It’s developer’s responsibility to check whether the return object is null or not.
Improvements & Fixes:
- Issue #719 ODataSwaggerConverter throws exception on composite key.
- Issue #711 Using same enum twice in a model causes null reference exception.
- Issue #697 EnumMember attribute without value.
- Issue #726 Aggregation failed in Restier.
- Issue #706 Change substringof to contained builtin function.
- Issue #722 URI template parser doesn’t work correctly if key is of an enum type, see [ odata issue #556 ]
- Issue #630 Orderby with duplicate properties.
- Issue #578 The $skip and $top query options throw ODataException if overflows. Pull Request #801 by Tijmen van der Burgt.
- Issue #418 Ignore non-odata query parameters when building parameter. Pull Request #748 by Michael Petito.
- Issue #750 Provide a option to disable AutoExpand when $select is present.
Here can find the OData V4 7.0.0 breaking changes docs and tutorials.
Questions and feedback
You and your team are warmly welcomed to try out this new version if you are interested in the new features and fixes above. You are also welcomed to contribute your code to OData Web API repository. For any feature request, issue or idea please feel free to reach out to us at GitHub Issues.
- Unify the entity and complex (collection) type serialization/deserialization, See [ odata issue #504 ]
8. V1-3 SPECIFIC FEATURES
-
8.1 ConcurrencyMode and ETag
In OData V3 protocol, concurrencyMode is a special facet that can be applied to any primitive Entity Data Model (EDM) type. Possible values are None
, which is the default, andFixed
. When used on an EntityType property,ConcurrencyMode
specifies that the value of that declared property should be used for optimistic concurrency checks. In the metadata, concurrencyMode will be shown as following:There are two approaches to set concurrencyMode for a primitive property: Using ConcurrencyCheck attribute:
Using API call
9. TEST
-
9.1 Unit Test and E2E Test
In OData WebApi, there are unit test, e2e test for V3 and V4, those test cases are to ensure the feature and bug fix, also to make sure not break old functionality. Unit Test
Every class in OData WebApi has it’s own unit test class, for example: OData/src/System.Web.OData/OData/Builder/ActionLinkBuilder.cs ‘s test class is OData/test/UnitTest/System.Web.OData.Test/OData/Builder/ActionLinkBuilderTests.cs.
You can find that the structural under
System.Web.OData
folder andSystem.Web.OData.Test
folder are the same, also for V3System.Web.Http.OData.Test
, so if your pull request contains any class add/change, you should add/change(this change here means add test cases) unit test file.How To Add Unit Test
- Try to avoid other dependency use moq.
- Make sure you add/change the right class(V4 or V3 or both).
- Can add functinal test for complicate scenario, but E2E test cases are better.
E2E Test
E2E test are complete test for user scenarios, always begin with client request and end with server response. If your unit test in pull request can’t cover all scenario well or you have a big pull request, please add E2E test for it.
How To Add E2E Test
- Add test cases in exist test class that related to your pull request.
- Add new folder and test class for your own scenario.
- If the test has any kind of state that is preserved between request, it should be the only test defined in the test class to avoid conflicts when executed along other tests.
- Try to test with both in memory data and DB data.
- Keep test folder, class style with exist test folder, class.
Test Sample
10. OTHERS
-
10.1 How To Debug
If you want to debug OData Lib, WebAPI, Restier source, open DEBUG
->Options and Settings
in VS, configure below things inGeneral
tab:- Uncheck
Enable Just My Code (Managed only)
. - Uncheck
Enable .NET Framework source stepping
. - UnCheck
Require source files to exactly match the original version
. - Check
Enable source server support
.
Setup your symbol source in
Symbols
tab:- Check
Microsoft Symbol Servers
. - Add location: http://srv.symbolsource.org/pdb/Public (For preview/public releases in nuget.org).
- Add location: http://srv.symbolsource.org/pdb/MyGet (For nightly build, and preview releases in myget.org).
- Set the cache symbols directory in your, the path should be as short as it can be.
Turn on the CLR first change exception to do a quick debug, open
DEBUG
->Exceptions
in VS, check theCommon Language Runtime Exceptions
. - Uncheck
-
10.2 Work around for SingleResult.Create an empty result
When SingleResult.Create takes in a query that returns an empty result, a SerializationException is being thrown.Let’s see a work-around about this issue. NullEntityTypeSerializer
First of all, we define the NullEntityTypeSerializer to handle null value:
NullSerializerProvider
Now, we can define a NullSerializerProvider, we need to avoid the situation of function,action call:
Formatters
Add NullSerializerProvider in ODataMediaTypeFormatters:
11. TOOLS
-
11.1 OData V4 Web API Scaffolding
Install Visual Studio Extension
The installer of OData V4 Web API Scaffolding can be downloaded from Visual Studio Gallery: Microsoft Web API OData V4 Scaffolding. Double click vsix to install, the extension supports the VS2013 and VS2015, now.
Generate Controller Code With Scaffolding
The scaffolding is used to generate controller code for model class. Two kinds of scaffolders are provided: for model without entity framework(Microsoft OData v4 Web API Controller) and model using entity framework(Microsoft OData v4 Web API Controller Using Entity Framework).
Scaffolder for model without entity framework:
Before using scaffolding, you need to create a web api project and add model classes, the following is a sample:
Then, you can right click “Controller” folder in solution explorer, select “Add” -> “Controller”. “Microsoft OData v4 Web API Controller” will be in the scaffolder list, as following:
Select scaffoler item, then choose a model class you want to generate the controller. You can also select the “Using Async” if your data need to be got in Async call.
After click “Add”, the controller will be genereted and added into your project. Meanwhile, all reference needed, including OData Lib and OData Web API, will be added into the project, too.
Scaffolder for model using entity framework:
If want to use entity framework as provider in service, no matter whether derived class of DbContext contained in project, when right click “Controller” folder in solution explorer, select “Add” -> “Controller” -> “Microsoft OData v4 Web API Controller Using Entity Framework” as scaffolder:
Then you will see as following:
Please select the existing Model (need build before scaffolding). You can select the existing data context class or add a new one:
After click “Add”, the controller will be genereted and added into your project, new data context class will be added if needed. Meanwhile, all reference needed, including OData Lib and OData Web API, will be added into the project, too.
Change WebApiConfig.cs File
After generating the controller code, you may need to add some code in WebApiConfig.cs to generate model. Actually the code needed are in the comment of generated controller:
Just need to copy/paste the code to WebApiConfig.cs.
Add the Code to retrieve Data
As Scaffolding only genreate the frameowrk of controller code, data retrieve part should also be added into controller generated. Here, we write a simple in-memory data source and return all of them when call “GetProducts” method:
Add in ProductsController:
private static List<Product> products = new List<Product>() { new Product() {Id = 1, Name = "Test1"}, };
Add in GetProducts Method:
return Ok(products);
12. DESIGN
-
12.1 Edm.Date and Edm.TimeOfDay with EF
Problem
The Transact-SQL has date (Format: YYYY-MM-DD) type, but there isn’t a CLR type representing date type. Entity Framework (EF) only supports to use
System.DateTime
CLR type to map the date type.OData V4 lib provides a CLR
struct Date
type and the corresponding primitive type kind Edm.Date. Web API OData V4 supports it. However, EF doesn’t recognize this CLR type, and it can’t mapstruct Date
directly to date type.So, this doc describes the solution about how to support Edm.Date type with Entity Framework. Meanwhile, this doc also covers the Edm.TimeOfDay type with EF.
Scopes
It should support to map the type between date type in Database and Edm.Date type through the CLR
System.DateTime
type. The map is shown in the following figure:So, it should provide the below functionalities for the developer:
- Can configure the
System.DateTime
/System.TimeSpan
property to Edm.Date/ Edm.TimeOfDay. - Can serialize the date/ time value in the DB as Edm.Date /Edm.TimeOfDay value format.
- Can de-serialize the Edm.Date/Edm.TimeOfDay value as date/ time value into DB.
- Can do query option on the date/ time value.
Most important, EF doesn’t support the primitive collection. So, Collection of date is not in the scope. The developer can use navigation property to work around.
Detail Design
Date & Time type in SQL DB
Below is the date & time type mapping between DB and .NET:
So, From .NET view, only
System.DateTime
is used to represent the date value, meanwhile onlySystem.TimeSpan
is used to represent the time value.Date & time mapping with EF
In EF Code First, the developer can use two methodologies to map
System.DateTime
property to date column in DB:1 Data Annotation
The users can use the Column Data Annotation to modify the data type of columns. For example:
“date” is case-insensitive.
2 Fluent API
HasColumnName
is the Fluent API used to specify a column data type for a property. For example:For time type, it implicitly maps the
System.TimeSpan
to represent the time value. However, you can use string literal “time” in DataAnnotation or fluent API explicitly.CLR Date Type in ODL
OData Library defines one
struct
to hold the value of Edm.Date (Format: YYYY-MM-DD).Where, Edm.Date is the corresponding primitive type Kind.
OData Library also defines one struct to hold the value of Edm.TimeOfDay (Format: HH:MM:SS. fractionalSeconds, where fractionalSeconds =1*12DIGIT).
Where, Edm.TimeOfDay is the corresponding primitive type Kind.
Configure Date & Time in Web API by Fluent API
By default, Web API has the following mapping between CLR types and Edm types:
We should provide a methodology to map
System.DateTime
to Edm.Date type, andSystem.TimeSpan
to Edm.TimeOfDay type as follows:Extension methods
We will add the following extension methods to re-configure
System.DateTime
&System.TimeSpan
property:For example, the developer can use the above extension methods as follows:
Configure Date & Time in Web API by Data Annotation
We should recognize the Column Data annotation. So, we will add a convention class as follows:
In this class, it will identify the Column attribute applied to
System.DateTime
orSystem.TimeSpan
property, and callAsDate(…)
orAsTimeOfDay()
extension methods to add a Date or TimeOfDay mapped property. Be caution, EF supports the TypeName case-insensitive.After insert the instance of ColumnAttributeEdmPropertyConvention into the conventions in the convention model builder:
For example, the developer can do as follows to build the Edm model:
Now, the developer can call as follows to build the Edm model:
Serialize
System.DateTime
value to Edm.DateWe should modify
ODataEntityTypeSerializer
andODataComplexTypeSerializer
to identify whether or not theSystem.DataTime
is serialized to Edm.Date. So, we should add a function inODataPrimitiveSerializer
:System.TimeSpan
value to Edm.TimeOfDayAdd the following codes into the above function:
Top level property
If the end user want to query the top level property, for example:
The developer must take responsibility to convert the value into its corresponding type.
De-serialize
Edm.Date to System.DateTime value
It’s easy to add the following code in
EdmPrimitiveHelpers
to convertstruct Date
toSystem.DateTime
:Edm.TimeOfDay to System.TimeSpan value
Add codes in
EdmPrimitiveHelpers
to convertstruct TimeOfDay
toSystem.TimeSpan
:Query options on Date & Time
We should to support the following scenarios:
Fortunately, Web API supports the most scenarios already, however, we should make some codes changes in
FilterBinder
class to make TimeOfDay scenario to work.Example
We re-use the Customer model in the Scope. We use the Lambda expression to build the Edm Model as:
Here’s the metadata document:
We can query:
GET ~/Customers
We can do filter:
~/Customers?$filter=Birthday eq 2017-12-31
Thanks.
- Can configure the
13. 6.X FEATURES
-
13.1 Model Bound Attributes
Since Web API OData V6.0.0 which depends on OData Lib 7.0.0, we add a new feature named ModelBoundAttribute, use this feature, we can control the query setting through those attributes to make our service more secure and even control the query result by set page size, automatic select, automatic expand.Let’s see how to use this feature. Global Query Setting
Now the default setting for WebAPI OData is : client can’t apply
$count
,$orderby
,$select
,$top
,$expand
,$filter
in the query, query likelocalhostodataCustomers?$orderby=Name
will failed as BadRequest, because all properties are not sort-able by default, this is a breaking change in 6.0.0, if we want to use the default behavior that all query option are enabled in 5.x version, we can configure the HttpConfigration to enable the query option we want like this:Page Attribute
Pagination settings correlate to OData’s @odata.nextLink (server-side pagination) and
?$top=5&$skip=5
(client-side pagination). We can set the PageSize to control the server-side pagination, and MaxTop to control the maximum value for$top
, by default client can’t use$top
as we said in theGlobal Query Setting
section, every query option is disabled, if you set thePage
Attribute, by default it will enable the$top
with no-limit maximum value, or you can set the MaxTop like:In the model above, we defined the page setting for Customer and Orders navigation property in Customer and Customers navigation property in Order, let’s explain the usage of them one by one.
Page Attribute on Entity Type
The first page attribute on Customer type, means the query setting when we query the Customer type, like
localhostodataCustomers
, the max value for$top
is 5 and page size of returned customers is 1.For example:
The query like
localhostodataCustomers?$top=10
will failed with BadRequest : The limit of ‘5’ for Top query has been exceeded.The page size is 1 if you request
localhostodataCustomers
.Page Attribute on Navigation Property
And what about the page attribute in Order type’s navigation property Customers? it means the query setting when we query the Customers navigation property in Order type. Now we get a query setting for Customer type and a query setting for Customers navigation property in Order type, how do we merge these two settings? The answer is: currently the property’s query setting always override the type’s query setting, if there is no query setting on property, it will inherent query setting from it’s type.
For example:
The query like
localhostodataOrders?$expand=Customers($top=10)
will works because the setting is no limit.The result of
localhostodataOrders?$expand=Customers
won’t have paging because the setting didn’t set the page size.So for the attribute on Orders navigation property in Customer type, the page size and maximum value of
$top
setting will have effect when we request likelocalhostodataCustomers?$expand=Orders
orlocalhostodataCustomers(1)Orders
as long as we are query the Orders property on Customer type.Count Attribute
Count settings correlate to OData’s
?$count=true
(items + count). We can set the entity type or property is countable or not like:In the model above, we can tell that the Order is not countable(maybe the number is very large) but Orders property in Customer is countable.
About the priority of attribute on property and type, please refer to
Page Attribute
section.So you can have those examples:
Query
localhostodataOrders?$count=true
will failed with BadRequest that orders can’t used for$count
Query
localhostodataCustomers?$expand=Orders($count=true)
will worksQuery
localhostodataCustomers(1)/Orders?$count=true
works too.OrderBy Attribute
Ordering settings correlate to OData’s
$orderby
query option. We can specify which property is sort-able very easy and we can also define very complex rule by use attribute on property and on type. For example:Multiple Attribute
We can see that the we can have multiple OrderBy attributes, how are they merged? The answer is the Attribute on a class with a constrained set of properties gets high priority, the order of their appear time doesn’t matter.
OrderBy Attribute on EntityType and ComplexType
Let’s go through those attributes to understand the settings, the first attribute means we can specify the single navigation property
AutoExpandOrder
and single complex propertyAddress
when we query Customer type, like querylocalhostodataCustomers?$orderby=Address/xxx
orlocalhostodataCustomers?$orderby=AutoExpandOrder/xxx
. And how do we control which property under AutoExandOrder is sort-able?For the AutoExpandOrder property, we add OrderBy Attribute on Order type, the first attribute means
Name
is not sort-able, the second attribute means all the property is sort-able, so for the Order type, properties exceptName
are sort-able.For example:
Query
localhostodataCustomers?$orderby=Name
will failed with BadRequest that Name is not sort-able.Query
localhostodataCustomers?$orderby=AutoExpandOrder/Price
works.Query
localhostodataCustomers?$orderby=AutoExpandOrder/Name
will failed with BadRequest that Name is not sort-able.OrderBy Attribute on Property
About the priority of attribute on property and type, please refer to
Page Attribute
section. We have OrderBy attribute on Address property, it means all properties are sort-able when we query Customer, and for Orders property, it means onlyId
is sort-able when we query Orders property under Customer.For example:
Query
localhostodataCustomers?$orderby=Address/Name
works.Query
localhostodataCustomers?$expand=Orders($orderby=Id)
works.Query
localhostodataCustomers?$expand=Orders($orderby=Price)
will failed with BadRequest that Price is not sort-able.Filter Attribute
Filtering settings correlate to OData’s
$filter
query option. For now we only support to specify which property can be filter just like what we do in OrderBy Attribute, we can simply replace orderby with filter in the example above, so please refer toOrderBy Attribute
section.Select Attribute
Search settings correlate to OData’s
$search
query option. We can specify which property can be selected, which property is automatic selected when there is no$select
in the query.Automatic Select
Automatic select mean we will add
$select
in the query depends on the select attribute.If we have a User class, and we don’t want to expose some property to client, like secrete property, so client query
localhostodataUsers?$select=Secrete
will failed and querylocalhostodataUsers?
won’t return Secrete property, how can we achieve that with Select Attribute?The first attribute means all the property will be automatic select when there is no
$select
in the query, the second attribute means the property Secrete is not select-able. For example, requestlocalhostodataUsers
will have the same response withlocalhostodataUsers?$select=Id,Name
Automatic Select on Derived Type
If the target type of our request have some derived types which have automatic select property, then these property will show in the response if there is no
$select
query option, for example, requestlocalhostodataUsers
will have the same response withlocalhostodataUsers?$select=Id,Name,SpecialUser/SpecialName
if the SpecinalName property in automatic select.Select Attribute on Navigation Property
About the priority of attribute on property and type, please refer to
Page Attribute
section. About the multiple attribute, please refer toMultiple Attribute
section. We also support Select attribute on navigation property, to control the expand scenario and property access scenario, like if we want client can only selectId
andName
from Customer’s navigation property Order.Expand Attribute
Expansion settings correlate to OData’s
$expand
query option. We can specify which property can be expanded, which property is automatic expanded and we can specify the max depth of the expand property. Currently we support Expand attribute on entity type and navigation property, the using scenario is quite like Select Attribute and other attributes, you can just refer to those sections.Automatic Expand
Automatic expand mean it will always expand that navigation property, it’s like automatic select, we will add a $expand in the query, so it will expand even if there is a
$select
which does not contain automatic epxand property.Model Bound Fluent APIs
We also provide all fluent APIs to configure above attributes if you can’t modify the class by adding attributes, it’s very straight forward and simple to use:
The example shows class with attributes and build model using the model bound fluent APIs if we can’t modify the class. These two approaches are getting two same models. About the multiple attribute, model bound fluent APIs are the same, the model bound fluent API with a constrained set of properties wins. For example:
builder.EntityType<Customer>().Expand().Expand("Friend", SelectExpandType.Disabled)
, Friend can’t be expanded, even we putExpand()
in the end. If there is a setting with same property, the last one wins, for example:.Expand(8, "Friend").Expand(1, "Friend")
, the max depth will be 1.Overall Query Setting Precedence
Query settings can be placed in many places, with the following precedence from lowest to highest: System Default(not query-able by default), Global Configuration, Model Bound Attribute, Fluent API.
Controller Level Query Setting
If we only want to control the setting in one API call, like the
Get()
method inCustomerController
, we can simply use the Settings in EnableQueryAttribute, like:The model bound attribute and the settings in EnableQueryAttribute are working separately, so the query violent one of them will fail the request.
More test case with more complex scenario can be find at here.
You can participate into discussions and ask questions about this feature at our GitHub issues, your feedback is very important for us.
-
13.2 Complex Type with Navigation Property
Since Web API OData V6.0.0 beta, It supports to configure navigation property on complex type.Let’s have an example to illustrate how to configure navigation property on complex type: CLR Model
We use the following CRL classes as the CLR model:
Where:
- Address is a complex type.
- City is an entity type.
Add navigation properties
The following APIs are used to add navigation properties for complex type:
So, we can do as:
We can get the following result:
<ComplexType Name="Address"> <NavigationProperty Name="CityInfo" Type="ModelLibrary.City" Nullable="false" />" <NavigationProperty Name="Cities" Type="Collection(NS.City)" />" </ComplexType> <EntityType Name="City"> <Key> <PropertyRef Name="Id" /> </Key> <Property Name="Id" Type="Edm.Int32" Nullable="false" /> </EntityType>
Add navigation properties in convention model builder
Convention model builder will automatically map the class type properties in complex type as navigation properties if the declaring type of such navigation property has key defined.
So, as the above example, we can use the following codes to define a convention model:
As result, We can get the following result:
<edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx"> <edmx:DataServices> <Schema Namespace="ModelLibrary" xmlns="http://docs.oasis-open.org/odata/ns/edm"> <ComplexType Name="Address"> <NavigationProperty Name="CityInfo" Type="ModelLibrary.City" /> <NavigationProperty Name="Cities" Type="Collection(ModelLibrary.City)" /> </ComplexType> <EntityType Name="City"> <Key> <PropertyRef Name="Id" /> </Key> <Property Name="Id" Type="Edm.Int32" Nullable="false" /> </EntityType> </Schema> <Schema Namespace="Default" xmlns="http://docs.oasis-open.org/odata/ns/edm"> <EntityContainer Name="Container" /> </Schema> </edmx:DataServices> </edmx:Edmx>
-
13.3 Multiple Navigation property binding path
Since Web API OData V6.0.0 beta, It supports to configure multiple navigation property binding paths. Original navigation property binding
The following APIs are used to add navigation property binding in model builder.
1. HasManyBinding() 2. HasRequiredBinding() 3. HasOptionalBinding()
So, we can do as:
We can get the following result:
<EntityContainer Name="Container"> <EntitySet Name="Customers" EntityType="System.Web.OData.Builder.Cusomter"> <NavigationPropertyBinding Path="Orders" Target="Orders" /> <NavigationPropertyBinding Path="SingleOrder" Target="SingleOrders" /> </EntitySet> <EntitySet Name="Orders" EntityType="System.Web.OData.Builder.Order" /> <EntitySet Name="SingleOrders" EntityType="System.Web.OData.Builder.Order" /> </EntityContainer>
Where, the binding path is straight-forward, just as the navigation property name. Before 6.0.0, it doesn’t support to:
- Add the complex property into binding path
- Add the type cast into binding path
Multiple navigation property binding path in model builder
In Web API OData V6.0.0 beta, we add a new generic type class to configure the multiple binding path:
In this class, it provides the following APIs to add binding path:
It also provides the following APIs to bind the navigation property with multiple binding path to a targe navigation source.
So, the normal navigation property binding configuration flow is:
- Call
Binding
fromNavigationSourceConfiguration{TEntityType}
to get an instance of BindingPathConfiguration{TEntityType} - Call
HasManyPath()/HasSinglePath
from BindingPathConfiguration{TEntityType}` to add a binding path - Repeat step-2 if necessary
- Call
HasManyBinding()/HasRequiredBinding()/HasOptionalBinding()
to add the target navigation source.
Here’s an example:
Example
Let’s have the following CLR classes as the model:
Entity types
Complex types
Add navigation property binding:
So, we can get the following target binding:
<Schema Namespace="Default" xmlns="http://docs.oasis-open.org/odata/ns/edm"> <EntityContainer Name="Container"> <EntitySet Name="Customers" EntityType="System.Web.OData.Builder.Cusomter"> <NavigationPropertyBinding Path="Pet/System.Web.OData.Builder.Human/HumanAddress/SubCity" Target="HumanCities" /> <NavigationPropertyBinding Path="Pet/System.Web.OData.Builder.Horse/HorseAddress/SubCity" Target="HorseCities" /> <NavigationPropertyBinding Path="Pet/System.Web.OData.Builder.Horse/HorseAddresses/SubCity" Target="HorseCities" /> <NavigationPropertyBinding Path="System.Web.OData.Builder.VipCustomer/VipLocations/System.Web.OData.Builder.UsAddress/SubCity" Target="B" /> <NavigationPropertyBinding Path="System.Web.OData.Builder.VipCustomer/VipLocations/City" Target="A" /> </EntitySet> <EntitySet Name="A" EntityType="System.Web.OData.Builder.City" /> <EntitySet Name="B" EntityType="System.Web.OData.Builder.City" /> <EntitySet Name="HumanCities" EntityType="System.Web.OData.Builder.City" /> <EntitySet Name="HorseCities" EntityType="System.Web.OData.Builder.City" /> </EntityContainer> </Schema>
Where: As example shown:
- It supports single property with multiple binding path.
- It supports collection property with mutliple binding path.
- It also supports mulitple binding path with inheritance type.
Besides, the
HasManyPath()/HasSinglePath()
has onverload methods to configure the containment binding path.Multiple navigation property binding path in convention model builder
In convention model builder, it will automatically traverl all property binding paths to add a binding for the navigation proeprty.
There’s an unit test that you can refer to.
-
13.4 Dependency Injection Support
Since Web API OData V6.0.0 beta, we have integrated with the popular dependency injection (DI) framework Microsoft.Extensions.DependencyInjection. By means of DI, we can significantly improve the extensibility of Web API OData as well as simplify the APIs exposed to the developers. Meanwhile, we have incorporated DI support throughout the whole OData stack (including ODataLib, Web API OData and RESTier) thus the three layers can consistently share services and custom implementations via the unified DI container in an OData service. For example, if you register an ODataPayloadValueConverter
in a RESTier API class, the low-level ODataLib will be aware of that and use it automatically because they share the same DI container.For the fundamentals of DI support in OData stacks, please refer to this docs from ODataLib. After understanding that, we can now take a look at how Web API OData implements the container, takes use of it and injects it into ODataLib.Implement the Container Builder
By default, if you don’t provide a custom container builder, Web API OData will use the
DefaultContainerBuilder
which implementsIContainerBuilder
from ODataLib. The default implementation is based on the Microsoft DI framework introduced above and what it does is just delegating the builder operations to the underlyingServiceCollection
.But if you want to use a different DI framework (e.g., Autofac) or make some customizations to the default behavior, you will need to either implement your own container builder from
IContainerBuilder
or inherit from theDefaultContainerBuilder
. For the former one, please refer to the docs from ODataLib. For the latter one, here is a simple example to illustrate how to customize the default container builder.After implementing the container builder, you need to register that container builder in
HttpConfiguration
to tell Web API OData that you want to use your custom one. Please note that you MUST callUseCustomContainerBuilder
BEFOREMapODataServiceRoute
andEnableDependencyInjection
because the root container will be actually created in these two methods. Setting the container builder factory after its creation is meaningless. Of course, if you wish to keep the default container builder implementation,UseCustomContainerBuilder
doesn’t need to be called at all.Register the Required Services
Basic APIs to register the services have already been documented here. Here we mainly focus on the APIs from Web API OData that help to register the services into the container builder. The key API to register the required services for an OData service is an overload of
MapODataServiceRoute
which takes aconfigureAction
to configure the container builder (i.e., register the services).Theoretically you can register any service within the
configureAction
but there are two mandatory services that you are required to register: theIEdmModel
and a collection ofIRoutingConvention
. Without them, the OData service you build will NOT work correctly. Here is an example of calling the API where a custom batch handlerMyBatchHandler
is registered. You are free to register any other service you like to thebuilder
.You might also find that we still preserve the previous overloads of
MapODataServiceRoute
which take batch handlers, path handlers, HTTP message handlers, etc. They are basically wrapping the first overload that takes aconfigureAction
. The reason why we keep them is that we want to give the users convenience to create OData services and bearings to the APIs they are familiar with.Once you have called any of the
MapODataServiceRoute
overloads, the dependency injection for that OData route is enabled and an associated root container is created. As we internally maintain a dictionary to map the route name to its corresponding root container (1-1 mapping), multiple OData routes (i.e., callingMapODataServiceRoute
multiple times) are still working great and the services registered in different containers (or routes) will not impact each other. That said, if you want a custom batch handler to work in the two OData routes, register them twice.Enable Dependency Injection for HTTP Routes
It’s also possible that you don’t want to create OData routes but just HTTP routes. The dependency injection support will NOT be enabled right after you call
MapHttpRoute
. In this case, you have to callEnableDependencyInjection
to enable the dependency injection support for ALL HTTP routes. Please note that all the HTTP routes share the SAME root container which is of course different from the one of any OData route. That said callingEnableDependencyInjection
has nothing to do withMapODataServiceRoute
.Please also note that the order of
MapHttpRoute
andEnableDependencyInjection
doesn’t matter because they have no dependency on each other.Manage and Access the Request Container
Given a root container, we can create scoped containers from it, which is also known as request containers. Mostly you don’t need to manage the creation and destruction of request containers yourself but there are some rare cases you have to touch them. Say you want to implement your custom batch handler, you have the full control of the multi-part batch request. You parse and split it into several batch parts (or sub requests) then you will be responsible for creating and destroying the request containers for the parts. They are implemented as extension methods to
HttpRequestMessage
inHttpRequestMessageExtensions
.To create the request container, you need to call the following extension method on a request. If you are creating the request container for a request that comes from an HTTP route, just pass
null
for therouteName
.To delete the request container from a request, you need to call the following extension method on a request. The parameter
dispose
indicates whether to dispose that request container after deleting it from the request. Disposing a request container means that all the scoped and transient services within that container will also be disposed if they implementIDisposable
.To get the request container associated with that request, simply call the following extension method on a request. Note that you don’t need to provide the route name to get the request container because the container itself has already been stored in the request properties during
CreateRequestContainer
. There is also a little trick inGetRequestContainer
that if you have never calledCreateRequestContainer
on the request but directly callGetRequestContainer
, it will try to create the request container for all the HTTP routes and return that container. Thus the return value ofGetRequestContainer
should never benull
.Please DO pay attention to the lifetime of the services. DON’T forget to delete and dispose the request container if you create it yourself. And scoped services will be disposed after the request completes.
Services Available in Web API OData
Currently services Available in Web API OData include:
IODataPathHandler
whose default implementation isDefaultODataPathHandler
and lifetime isSingleton
.XXXQueryValidator
whose lifetime are allSingleton
.ODataXXXSerializer
andODataXXXDeserializer
whose lifetime are allSingleton
. But please note that they are ONLY effective whenDefaultODataSerializerProvider
andDefaultODataDeserializerProvider
are present. Custom serializer and deserializer providers are NOT guaranteed to call those serializers and deserializers from the DI container.ODataSerializerProvider
andODataDeserializerProvider
whose implementation types areDefaultODataSerializerProvider
andDefaultODataDeserializerProvider
respectively and lifetime are allSingleton
. Please note that you might lose all the default serializers and deserializers registered in the DI container if you don’t call into the default providers in your own providers.IAssembliesResolver
whose implementation type is the default one from ASP.NET Web API.FilterBinder
whose implementation type isTransient
because eachEnableQueryAttribute
instance will create its ownFilterBinder
. Override it if you want to customize the process of binding a $filter syntax tree.
Services Avaliable in OData Lib
Services in OData Lib also can be injected through Web API OData.
-
13.5 Use ODL path classes
Since Web API OData V6.0.0 beta, Web API OData uses the ODL path classes directly.In Web API OData V5.x, there are a lot of path segment classes defined to wrapper the corresponding path segment classes defined in ODL. for example: Where,
- Some segments are just used to wrapper the corresponding segments defined in ODL, such as BatchPathSegment.
- Some segments are used to do some conversions, such as BoundFunctionPathSegment, KeyValuePathSegment.
However, ODL defines the same segments and Web API OData needn’t to do such conversion. So, all segment classes defined in Web API OData are removed in v6.x.
Web API OData will directly use the path segment classes defined in ODL as follows:
-
13.6 Key value binding
Since Web API OData V6.0.0 beta, Web API OData supports the composite key convention binding.Let’s have an example: Where, Customer is an entity type with three properties. We will make all these trhee properties as the composite keys for Customer entity type.
So, we can do:
Before Web API OData V6.x, key segment convention routing only supports the single key convention binding, just use the key as the parameter name.
In Web API OData V6.x, we use the following convention for the composite key parameter name, but leave the key for single key parameter.
Therefore, for StringProp key property, the action parameter name should be keyStringProp.
Let’s see how the contoller action looks like:
Now, you can issue a request:
The result is:
Be noted, this rule also applys to the navigation property key convention binding.
-
13.7 Merge complex & entity value serialize/deserialize
You can refer the detail in: complex type and entity type in ODL 7.0 doc.In Web API OData 6.x, we do the following to support the merge of complex type and entity type: - Rename ODataFeed to ODataResourceSet
- Rename ODataEntry to ODataResource
- Rename ODataNavigationLink to ODataNestedResourceInfo
- Rename ODataPayloadKind.Entry to ODataPayloadKind.Resource
- Rename ODataPayloadKind.Feed to ODataPayloadKind.ResourceSet
- Rename ODataEntityTypeSerializer to ODataResourceSerializer
- Rename ODataFeedSerializer to ODataResourceSetSerizlier
- Rename ODataEntityDeserializer to ODataResourceDeserializer
- Rename ODataFeedDeserializer to ODataResourceSetDeserializer
- Remove ODataComplexValue
- Remove ODataComplexSerializer/ODataComplexTypeDeserializer
So, for any complex value, it will use ODataResourceSerializer and ODataResourceDeserializer to read and write. for any complex collection value, it will use ODataResourceSetSerializer and ODataResourceSetDeserializer to read and write.