I'm looking to properly configure System.Web.Handlers.TransferRequestHandler
path
attribute to handle both routes to WebApi REST actions and ODataController custom function in an ASP.NET WebApi 2 project.
My web.config
file handlers are configured as follow in order to support custom ODataController functions call (see my related question here) :
<handlers>
<clear/>
<remove name="ExtensionlessUrlHandler-Integrated-4.0"/>
<remove name="OPTIONSVerbHandler"/>
<remove name="TRACEVerbHandler"/>
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="/*" verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0"/>
</handlers>
</system.webServer>
Note that the path is set to /*
and it works well when accessing custom OData functions on our ODataControllers
Nevertheless we also have an ApiController and when we access it, IIS doesn't properly handle the request and fails with the following details :
HTTP Error 500.0 - Internal Server Error
Internal Server ErrorDetailed Error Information:
Module ManagedPipelineHandler
Notification ExecuteRequestHandler
Handler ExtensionlessUrlHandler-Integrated-4.0
Error Code 0x800703e9
If I set the TransferRequestHandler
path
to *.
as suggested here the WebApi request get properly resolved however the ODataController request ends up not beeing found with HTTP 400 :
HTTP Error 404.4 - Not Found
The resource you are looking for does not have a handler associated with it.Detailed Error Information:
Module IIS Web Core
Notification MapRequestHandler
Handler Not yet determined
Error Code 0x80070002
How can I properly configure it to handle both cases ?
++++ Edit : ++++
For the sake of clarity here is the queries I use to tests my controllers :
http://localhost:xxxx/myProject/odata/SomeModels/MyNamespace.MyCustomFunction(parameterA=123,parameterB=123)
http://localhost:xxxx/myProject/odata/SomeModels
http://localhost:xxxx/myProject/api/SomeOtherModel?parameterC=123
My web api controller :
public class SomeOtherModelsController : ApiController
{
public IHttpActionResult Get(int parameterC)
{
// ...
return Ok(/* some result */);
}
[HttpPost]
public IHttpActionResult Post(SomeOtherModel model)
{
// ...
return Ok(/* some result */);
}
}
My odata controller:
public class SomeModelController : ODataController
{
[EnableQuery]
public IHttpActionResult Get()
{
// ...
return Ok(/* some result*/);
}
[HttpGet]
[EnableQuery]
public IHttpActionResult MyCustomFunction(int parameterA, int parameterB)
{
// ...
return Ok(/* some result */);
}
[HttpGet]
[EnableQuery]
public IHttpActionResult AnotherCustomFunction()
{
// ...
return Ok(/* some result */);
}
}
Here is the web api configuration:
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
and the odata configuration :
var builder = new ODataConventionModelBuilder
{
Namespace = "MyNamespace"
};
builder.EntitySet<SomeModelModel>("SomeModels");
var anotherCustomFunction = builder.EntityType<SomeModelModel>().Collection.Function("AnotherCustomFunction");
anotherCustomFunction.Returns<SomeResultValue>();
var myCustomFunction = builder.EntityType<SomeModel>().Collection.Function("MyCustomFunction");
myCustomFunction.Parameter<int>("parameterA");
myCustomFunction.Parameter<int>("parameterB");
myCustomFunction.ReturnsFromEntitySet<SomeModelModel>("SomeModels");
A possible solution, as proposed here, is to add <modules runAllManagedModulesForAllRequests="true" />
to <system.webServer>
in the web.config
file :
<system.webServer>
<modules runAllManagedModulesForAllRequests="true" />
</system.webServer>
It turns out that adding this module makes the presence of System.Web.Handlers.TransferRequestHandler
handler unnecessary.
Therefore the following system.webServer configuration is sufficient to handle both api query and custom OData function queries :
<system.webServer>
<modules runAllManagedModulesForAllRequests="true" />
<handlers>
<remove name="OPTIONSVerbHandler"/>
<remove name="TRACEVerbHandler"/>
</handlers>
</system.webServer>
Nevertheless, I'm not confortable with this solution as I don't know exactlly what could be the effects of <modules runAllManagedModulesForAllRequests="true" />
.
Starting from my previous answer, I've created a new model (AnotherModel) and a new ApiController (AnotherModelsController)
AnotherModel.cs
namespace DemoOdataFunction.Models
{
public class AnotherModel
{
public int Id { get; set; }
public int MyInt { get; set; }
public string MyString { get; set; }
}
}
AnotherModelsController.cs
namespace DemoOdataFunction.Controllers
{
public class AnotherModelsController : ApiController
{
public IHttpActionResult Get(int parameterC)
{
// ...
return Ok();
}
public IHttpActionResult Get()
{
// ...
return Ok("Ok");
}
[HttpPost]
public IHttpActionResult Post(AnotherModel model)
{
// ...
return Ok();
}
}
}
Without any other changes both Api and OData controller works.
GET
http://localhost:4186/api/AnotherModels?parameterC=1
GET
http://localhost:4186/api/AnotherModels
Post
http://localhost:4186/api/AnotherModels
{
"Id" : 1,
"MyInt" : 2,
"MyString" : "Hello"
}
GET
http://localhost:4186/odata/TestModels/MyNamespace.MyFunction(parA=1,parB=2)
I've also tried changing the "path" setting of web.config to * but that's fine. I suggest you create a new project from scratch and compare it with yours.
User contributions licensed under CC BY-SA 3.0