6

Trying to move from OData v3 to OData v4. Why do I keep getting a 404 when trying to use OData Functions?

Web API Config:

ODataModelBuilder builder = new ODataConventionModelBuilder();
//etc
builder.EntitySet<LocalizableString>("LocalizableStringApi");
//etc
var getComparitiveTableFunction = builder.EntityType<LocalizableString>().Collection.Function("GetComparitiveTable");
getComparitiveTableFunction.Parameter<string>("cultureCode");
getComparitiveTableFunction.ReturnsCollection<ComparitiveLocalizableString>();
//etc
config.MapODataServiceRoute("OData_Kore_CMS", "odata/kore/cms", builder.GetEdmModel());

C# Code:

[EnableQuery(AllowedQueryOptions = AllowedQueryOptions.All)]
[HttpGet]
//[ODataRoute("Default.GetComparitiveTable(cultureCode={cultureCode})")] // Tried this, but gets errors and I noticed the function is in the OData model anyway without this, so should be fine.
public virtual IHttpActionResult GetComparitiveTable([FromODataUri] string cultureCode)
{
    // Implementation
    return Ok(query);
}

XML Returned from $metadata:

<Schema Namespace="Default">
    <Function Name="GetComparitiveTable" IsBound="true">
        <Parameter Name="bindingParameter" Type="Collection(Kore.Localization.Domain.LocalizableString)"/>
        <Parameter Name="cultureCode" Type="Edm.String" Unicode="false"/>
        <ReturnType Type="Collection(Kore.Localization.Models.ComparitiveLocalizableString)"/>
    </Function>
    ...

As you can see, it's in the schema / OData model... yet the following query does not work:

http://localhost:30863/odata/kore/cms/LocalizableStringApi/Default.GetComparitiveTable(cultureCode='en-US')

I have also tried the following:

http://localhost:30863/odata/kore/cms/LocalizableStringApi/GetComparitiveTable(cultureCode='en-US')
http://localhost:30863/odata/kore/cms/Default.GetComparitiveTable(cultureCode='en-US')
http://localhost:30863/odata/kore/cms/GetComparitiveTable(cultureCode='en-US')

All of the above result in a 404.

So... what am I doing wrong here?

Matt
  • 6,787
  • 11
  • 65
  • 112
  • Whoever downvoted, I would appreciate it if you would say why... – Matt Aug 18 '15 at 03:57
  • 2
    2 downvotes? Seriously guys.. if you have a problem with my post, have the decency to tell me what it is so I can correct it.. – Matt Aug 18 '15 at 04:13
  • I don't know who downvote :S .. what's your controller name ? – Fan Ouyang Aug 18 '15 at 04:15
  • Hi @FanOuyang. My controller name is `LocalizableStringApiController`. – Matt Aug 18 '15 at 04:16
  • @FanOuyang: In OData V3 I was using the code as an OData action and it was mostly fine but I had some problem that you showed me cannot be fixed with V3 (see: http://stackoverflow.com/questions/31822755/passing-parameters-to-an-odata-get-method-which-returns-a-collection/31823976?noredirect=1#comment51621266_31823976), so now I am trying to make it an OData function with V4... – Matt Aug 18 '15 at 04:20
  • I can't found what's wrong in your code, maybe you can share your project, FYI: http://odata.github.io/WebApi/#04-06-function-parameter-support – Fan Ouyang Aug 18 '15 at 04:21
  • @FanOuyang, thanks for being so helpful. Please check your inbox.. ;-) – Matt Aug 18 '15 at 04:31
  • Two questions related to my own function(s) not appearing when I moved from v3 to v4: Are you using `System.Web.OData`, or `System.Web.Http.OData`? The scaffolding will apply `System.Web.Http.OData`, but for v4 it should omit the `Http` Do you have more than one custom function? It has been nearly a year since I had trouble with multiple functions where only one function worked. I had to implement this answer http://stackoverflow.com/a/27226116/2069745 to allow multiple controllers with multiple functions. – Pynt Sep 14 '15 at 14:13
  • Possible duplicate of [Web API 2: OData 4: Actions returning 404](http://stackoverflow.com/questions/26071517/web-api-2-odata-4-actions-returning-404) – rdhainaut Sep 13 '16 at 08:51

4 Answers4

13

I solve a similar problem adding a trailing slash to the requested url.

  • This just saved my life. Thank you so much!! – arazzy Dec 16 '16 at 15:47
  • Oh wow that worked. Very annoying. Nothing about a trailing slash in the docs! https://learn.microsoft.com/en-us/aspnet/web-api/overview/odata-support-in-aspnet-web-api/odata-v4/odata-actions-and-functions – Patrick Borkowicz Jan 10 '18 at 16:22
7

I solved this by adding the following line in my web.config, under <system.webServer>:

<modules runAllManagedModulesForAllRequests="true">

This may cause performance issues though, if I remember correctly. So it's not ideal. Any better solutions are very welcome...

Matt
  • 6,787
  • 11
  • 65
  • 112
  • 2
    That's true, it's a performance issue (and a potential source of unexpected errors). Please see my answer for an alternative solution. – Sebastian Zaklada Jun 02 '16 at 09:10
3

You need a module that goes by the name of UrlRoutingModule-4.0 to be running through IIS. This solution causes all your registered HTTP modules to run on every request, not just managed requests (e.g. .aspx). This means modules will run on ever .jpg .gif .css .html .pdf etc.

So, a better solution would be to add the following in your web.config

<modules>
  <remove name="UrlRoutingModule-4.0" />
  <add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" preCondition="" />
</modules>

Source: http://www.britishdeveloper.co.uk/2010/06/dont-use-modules-runallmanagedmodulesfo.html

Sebastian Zaklada
  • 2,308
  • 1
  • 14
  • 25
2

This is a solution to prevent 404 Not Found error with OData functions / actions.

Benefits of this solution

Add theses lines in your web.config

<system.webServer>
    <handlers>
      <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
      <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
      <add name="ExtensionlessUrlHandler-Integrated-4.0Custom" path="/odata*" verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
    </handlers>
  </system.webServer>

Et Voilà :)

rdhainaut
  • 2,659
  • 1
  • 24
  • 34