OData v4 Custom Function

2,367 views
Skip to first unread message

Rudy Wilkinson Jr

unread,
Aug 12, 2014, 10:35:01 AM8/12/14
to odata-di...@googlegroups.com

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.  Can someone please take a look at the code below and see if you notice something that I must be missing?



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();
 
    }
 
}


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using DataAccessLibrary;
using DataAccessLibrary.Models;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Net;
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.OData;
using System.Web.OData.Routing;
 
namespace Service.Controllers
{
    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); }
    }
}


http://localhost:50987/odata/Accounts
<Error>
<Message>An error has occurred.</Message>
<ExceptionMessage>
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'.
</ExceptionMessage>
<ExceptionType>System.InvalidOperationException</ExceptionType>
<StackTrace>
at System.Web.OData.Routing.Conventions.AttributeRoutingConvention.GetODataPathTemplate(String prefix, String pathTemplate, HttpActionDescriptor action) at System.Web.OData.Routing.Conventions.AttributeRoutingConvention.<>c__DisplayClass11.<GetODataPathTemplates>b__e(ODataRouteAttribute route) at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext() at System.Linq.Enumerable.WhereEnumerableIterator`1.MoveNext() at System.Web.OData.Routing.Conventions.AttributeRoutingConvention.BuildAttributeMappings(IEnumerable`1 controllers) at System.Web.OData.Routing.Conventions.AttributeRoutingConvention.<>c__DisplayClass2.<>c__DisplayClass4.<.ctor>b__1() at System.Web.OData.Routing.Conventions.AttributeRoutingConvention.get_AttributeMappings() at System.Web.OData.Routing.Conventions.AttributeRoutingConvention.SelectController(ODataPath odataPath, HttpRequestMessage request) at System.Web.OData.Routing.ODataPathRouteConstraint.SelectControllerName(ODataPath path, HttpRequestMessage request) at System.Web.OData.Routing.ODataPathRouteConstraint.Match(HttpRequestMessage request, IHttpRoute route, String parameterName, IDictionary`2 values, HttpRouteDirection routeDirection) at System.Web.Http.Routing.HttpRoute.ProcessConstraint(HttpRequestMessage request, Object constraint, String parameterName, HttpRouteValueDictionary values, HttpRouteDirection routeDirection) at System.Web.Http.Routing.HttpRoute.ProcessConstraints(HttpRequestMessage request, HttpRouteValueDictionary values, HttpRouteDirection routeDirection) at System.Web.Http.Routing.HttpRoute.GetRouteData(String virtualPathRoot, HttpRequestMessage request) at System.Web.Http.WebHost.Routing.HttpWebRoute.GetRouteData(HttpContextBase httpContext)
</StackTrace>
</Error>

Yi Ding

unread,
Aug 12, 2014, 10:49:32 AM8/12/14
to Rudy Wilkinson Jr, odata-di...@googlegroups.com
At the first site it seems like a collision of OData controller method name with the conventional name defined in the Web API OData routing convention. Could you try change the name of the function to something like "RetrieveByExternalKey" or "AquireByExternalKey"?


发件人: Rudy Wilkinson Jr
发送时间: ‎2014/‎8/‎12 22:35
收件人: odata-di...@googlegroups.com
主题: [OData Discussion] OData v4 Custom Function

--
You received this message because you are subscribed to the Google Groups "OData Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to odata-discussi...@googlegroups.com.
To post to this group, send email to odata-di...@googlegroups.com.
Visit this group at http://groups.google.com/group/odata-discussion.
To view this discussion on the web visit https://groups.google.com/d/msgid/odata-discussion/888142b7-a6cf-4bec-9afe-6ccec3ae5f6c%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Rudy Wilkinson Jr

unread,
Aug 12, 2014, 10:56:25 AM8/12/14
to Yi Ding, odata-di...@googlegroups.com
Updated the following:

        var orders = builder.EntityType<Order
>();
        var function = orders.Function("RetrieveByExternalKey");
        function.Parameter<long>("key");
        function.ReturnsCollectionFromEntitySet<Order>("Orders");

        [HttpGet]
        [ODataRoute("RetrieveByExternalKey(key={key})")]
public IHttpActionResult RetrieveByExternalKey(long key)

{     return Ok(from o in db.Orders               where //SpecialCrazyStuff is done               select o); }

Result is same error as before:
<Error>
<Message>An error has occurred.</Message>
<ExceptionMessage>
The path template 'RetrieveByExternalKey(key={key})' on the action 'RetrieveByExternalKey' in controller 'Orders' is not a valid OData path template. Resource not found for the segment 'RetrieveByExternalKey'.
</ExceptionMessage>
<ExceptionType>System.InvalidOperationException</ExceptionType>
<StackTrace>
at System.Web.OData.Routing.Conventions.AttributeRoutingConvention.GetODataPathTemplate(String prefix, String pathTemplate, HttpActionDescriptor action) at System.Web.OData.Routing.Conventions.AttributeRoutingConvention.<>c__DisplayClass11.<GetODataPathTemplates>b__e(ODataRouteAttribute route) at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext() at System.Linq.Enumerable.WhereEnumerableIterator`1.MoveNext() at System.Web.OData.Routing.Conventions.AttributeRoutingConvention.BuildAttributeMappings(IEnumerable`1 controllers) at System.Web.OData.Routing.Conventions.AttributeRoutingConvention.<>c__DisplayClass2.<>c__DisplayClass4.<.ctor>b__1() at System.Web.OData.Routing.Conventions.AttributeRoutingConvention.get_AttributeMappings() at System.Web.OData.Routing.Conventions.AttributeRoutingConvention.SelectController(ODataPath odataPath, HttpRequestMessage request) at System.Web.OData.Routing.ODataPathRouteConstraint.SelectControllerName(ODataPath path, HttpRequestMessage request) at System.Web.OData.Routing.ODataPathRouteConstraint.Match(HttpRequestMessage request, IHttpRoute route, String parameterName, IDictionary`2 values, HttpRouteDirection routeDirection) at System.Web.Http.Routing.HttpRoute.ProcessConstraint(HttpRequestMessage request, Object constraint, String parameterName, HttpRouteValueDictionary values, HttpRouteDirection routeDirection) at System.Web.Http.Routing.HttpRoute.ProcessConstraints(HttpRequestMessage request, HttpRouteValueDictionary values, HttpRouteDirection routeDirection) at System.Web.Http.Routing.HttpRoute.GetRouteData(String virtualPathRoot, HttpRequestMessage request) at System.Web.Http.WebHost.Routing.HttpWebRoute.GetRouteData(HttpContextBase httpContext)
</StackTrace>
</Error>
--
Rudy Wilkinson
rudyw...@gmail.com

Mark Stafford

unread,
Aug 12, 2014, 11:06:29 AM8/12/14
to Rudy Wilkinson Jr, Yi Ding, odata-di...@googlegroups.com

Hi Rudy,

 

It seems like this would be a great question to post on StackOverflow. There are Web API OData team members consistently looking at that site to provide answers to problems and it’s the place most .NET developers use to find answers – and someone may have the same question as you so putting it out there helps the community in the best possible way. Would you mind posting the question there and closing the loop here with a link to the question?

 

And one question for you while I have your attention. J This particular mailing list is loosely intended to be for general protocol questions and questions about odata.org or the sample services (e.g., the thread started by Bruno). We also have been thinking about setting up stack-specific mailing lists so that this mailing list can stay focused on OData itself, not a stack. Do you think that’s a good idea? Would you make use of something like odata-net-stacks if it existed as a mailing list?

 

Thanks,

Mark

Rudy Wilkinson Jr

unread,
Aug 12, 2014, 11:28:52 AM8/12/14
to odata-di...@googlegroups.com, rudyw...@gmail.com, yid...@microsoft.com, mast...@microsoft.com

--

To post to this group, send email to odata-d...@googlegroups.com.



 

--
Rudy Wilkinson
rudyw...@gmail.com

--
You received this message because you are subscribed to the Google Groups "OData Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to odata-discussi...@googlegroups.com.

To post to this group, send email to odata-d...@googlegroups.com.
Visit this group at <a href="http://grou

...
Reply all
Reply to author
Forward
0 new messages