OData v4 Custom Function
Per the model builder, the function GetByExternalKey is a bound function. According to the OData Protocol v4, a bound function is invoked through the namespace or alias qualified named, so you need to add more in the route attribute:
[HttpGet]
[ODataRoute("Orders({id})/Your.Namespace.GetByExternalKey(key={key})")]
public IHttpActionResult GetByExternalKey(long key)
{
return Ok(from o in db.Orders
where//SpecialCrazyStuff is done
select o);
}
If you don't know the namespace, just add below to the method GetModel():
builder.Namespace = typeof(Order).Namespace;
And replace "Your.Namespace" with the namespace of the type Order.
Here are 2 samples related to your question, just for your reference: https://aspnet.codeplex.com/SourceControl/latest#Samples/WebApi/OData/v4/ODataFunctionSample/
Admin
Updated on June 18, 2022Comments
-
Admin almost 2 years
I'm trying to create a custom function in an OData v4 Web API solution. I need to return a collection of "Orders" based on unique logic that can't be handled natively by OData. I cannot seem to figure out how to create this custom function without destroying the entire OData service layer. When I decorate the Controller method with an ODataRoute attribute it all goes to hell. Any basic request produces the same error. Can someone please take a look at the code below and see if you notice something that I must be missing?
WebApiConfig.cs
public static class WebApiConfig { public static void Register(HttpConfiguration config) { config.MapHttpAttributeRoutes(); config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); config.MapODataServiceRoute("odata", "odata", model: GetModel()); } public static Microsoft.OData.Edm.IEdmModel GetModel() { ODataModelBuilder builder = new ODataConventionModelBuilder(); builder.EntitySet<Account>("Accounts"); builder.EntitySet<Email>("Emails"); builder.EntitySet<PhoneNumber>("PhoneNumbers"); builder.EntitySet<Account>("Accounts"); builder.EntitySet<Address>("Addresses"); builder.EntitySet<Order>("Orders"); builder.EntitySet<OrderDetail>("OrderDetails"); var orders = builder.EntityType<Order>(); var function = orders.Function("GetByExternalKey"); function.Parameter<long>("key"); function.ReturnsCollectionFromEntitySet<Order>("Orders"); return builder.GetEdmModel(); } }
OrdersController.cs
public class OrdersController : ODataController { private SomeContext db = new SomeContext(); ...Other Stuff... [HttpGet] [ODataRoute("GetByExternalKey(key={key})")] public IHttpActionResult GetByExternalKey(long key) { return Ok(from o in db.Orders where //SpecialCrazyStuff is done select o); } } }
When issuing ANY request against the OData layer I receive the following error response.
The path template 'GetByExternalKey(key={key})' on the action 'GetByExternalKey' in controller 'Orders' is not a valid OData path template. Resource not found for the segment 'GetByExternalKey'.