Routing Conventions In OData v4 Using Web API 2
Introduction
Developing OData Web API service is pretty simple but mostly we get a "404 - Not Found" error due to routing issue and it makes debugging difficult. When user is requesting OData URL, the request is mapped with controller name and action name. This request mapping is based on HTTP methods (GET, POST, PUT, DELETE, and PATCH) and URI.
There are two types of routing conventions supported by OData using Web API.
- Built-in Routing Conventions
- Custom Routing Conventions
Built-in Routing Conventions
OData URI mainly contains three parts:
- Service Root
- Resource path
- Query option
Resource path is a very important part in URI. The Resource path may have many parts like Entity set name (Controller name), entity key, related entity (navigation property) etc. As we know, the controller name is always derived from the entity set and it is root of the resource path. In above mention example, web API looks for "TestDataController". The Action name is decided from the path segment along with EDM (entity data model).
We have two choices for action name: HTTP method name (example- GET, POST, etc.) and HTTP method name +Entity set name (example: GetTestData,PostTestData, etc.)
Following table contains the List of action name based URI supported by OData.
Following are rules to define method signatures:
- Action should have parameter name as "key" if path contains key.
- Action should have parameter name as "relatedKey" if path contains key of navigation property.
- FromODataUri attribute used to get key and relatedKey parameter from URI.
- Parameter type must be entity type for PUT and POST request.
- Parameter type must be Delta<T> where T is entity type for PATCH request.
- SelectController: It returns the name of the controller.
- SelectAction: It returns the name of the action.
- namespaceWebAPITest
- {
- usingSystem.Linq;
- usingSystem.Net.Http;
- usingSystem.Web.Http.Controllers;
- usingSystem.Web.OData.Routing;
- usingSystem.Web.OData.Routing.Conventions;
- publicclassCustomConvention: EntitySetRoutingConvention
- {
- publicoverridestringSelectAction(ODataPathodataPath, HttpControllerContext context, ILookup < string, HttpActionDescriptor > actionMap)
- {
- if (context.Request.Method == HttpMethod.Get && odataPath.PathTemplate == "~/entityset/key/navigation/key")
- {
- NavigationPathSegmentnavigationSegment = odataPath.Segments[2] asNavigationPathSegment;
- varnavigationProperty = navigationSegment.NavigationProperty;
- //Create Action name
- stringactionName = "Get" + navigationProperty.Name;
- if (actionMap.Contains(actionName))
- {
- // Add keys to route data, so they will bind to action parameters.
- KeyValuePathSegmentkeyValueSegment = odataPath.Segments[1] asKeyValuePathSegment;
- context.RouteData.Values[ODataRouteConstants.Key] = keyValueSegment.Value;
- KeyValuePathSegmentrelatedKeySegment = odataPath.Segments[3] asKeyValuePathSegment;
- context.RouteData.Values[ODataRouteConstants.RelatedKey] = relatedKeySegment.Value;
- returnactionName;
- }
- }
- // Not a match.
- returnnull;
- }
- }
- }
- namespaceWebAPITest
- {
- usingMicrosoft.OData.Edm;
- usingSystem.Web.Http;
- usingSystem.Web.OData.Batch;
- usingSystem.Web.OData.Builder;
- usingSystem.Web.OData.Extensions;
- usingSystem.Web.OData.Routing;
- usingSystem.Web.OData.Routing.Conventions;
- publicstaticclassWebApiConfig
- {
- publicstaticvoid Register(HttpConfigurationconfig)
- {
- var conventions = ODataRoutingConventions.CreateDefault();
- // Insert the custom convention at the start of the collection.
- conventions.Insert(0, newCustomConvention());
- config.MapODataServiceRoute("odata", null,
- GetEdmModel(), newDefaultODataPathHandler(), conventions,
- newDefaultODataBatchHandler(GlobalConfiguration.DefaultServer));
- config.EnsureInitialized();
- }
- privatestaticIEdmModelGetEdmModel()
- {
- ODataConventionModelBuilder builder = newODataConventionModelBuilder();
- builder.Namespace = "WebAPITest";
- builder.ContainerName = "DefaultContainer";
- builder.EntitySet < Department > ("Department");
- //
- builder.EntitySet < Employee > ("Employee");
- varedmModel = builder.GetEdmModel();
- returnedmModel;
- }
- }
- }
- publicIHttpActionResultGetEmployees(int key, intrelatedKey)
- {
- var result = DAL.GetDepartments().Where(p => p.Id == key).FirstOrDefault().Employees.Where(q => q.Id == relatedKey).FirstOrDefault();
- return Ok(result);
- }
Summary
OData v4 provides many built-in routing conventions and we can also create our custom routing conventions which are not supported by built-in routing.
0 Comments