3

I'm trying to get ASP.NET Core 2 MVC to route the action based on the HTTP verb via the following code in Startup.cs:

        app.UseMvc(routes =>
        {
            routes.MapRoute(
                name: "post",
                template: "api/{controller}/{id?}",
                defaults: new { action = "Post" },
                constraints: new RouteValueDictionary(new { httpMethod = new HttpMethodRouteConstraint("POST") })
            );
            routes.MapRoute(
                name: "delete",
                template: "api/{controller}/{id?}",
                defaults: new { action = "Delete" },
                constraints: new RouteValueDictionary(new { httpMethod = new HttpMethodRouteConstraint("DELETE") })
            );
            routes.MapRoute(
                name: "default",
                template: "api/{controller}/{action=Get}/{id?}");
        });

I.e.,

  • If the client calls GET http://example.com/api/foo, that runs the Get() method on my FooController : Controller class.
  • If they call GET http://example.com/api/foo/123, that runs the Get(int id) method on my FooController : Controller class.
  • If they call POST http://example.com/api/foo, that runs the Post([FromBody] T postedItem) method on my FooController<T> : Controller class.
  • If they call POST http://example.com/api/foo/123, that runs the Post(int id, [FromBody] T postedItem) method on my FooController<T> : Controller class.
  • If they call DELETE http://example.com/api/foo/123, that runs the Delete(int id) method on my FooController : Controller

When I run the project, it doesn't seem to run any of my controllers. I have some Razor pages that respond but all of the controller-based routes just return 404. Not even the default route seems to work.

I've been using https://github.com/ardalis/AspNetCoreRouteDebugger to try and help me narrow the issue down but I'm still not finding the problem. It shows the methods on the controllers as available actions but doesn't list any of the names, templates or constraints added via MapRoute. I'd be glad to know of any other helpful tools as well.

FWIW, I'm trying to use the same verb constraints as here: https://github.com/aspnet/Routing/blob/2.0.1/src/Microsoft.AspNetCore.Routing/RequestDelegateRouteBuilderExtensions.cs#L252-L268

steamer25
  • 9,278
  • 1
  • 33
  • 38
  • What is `FooController`? You can't route directly to a generic controller, as Core has no way to provide the type during construction. You can use it as a base controller, but you'd have to route to something that "implements" the type, i.e. `BarController : FooControlller`. – Chris Pratt Dec 28 '17 at 11:30
  • @ChrisPratt: That's a bit of pseudo-code intended to convey that the various controllers will expect different POST body schemas and receive [FromBody] arguments of respective types. I'm definitely okay with putting concrete types as the method param--it's just that each class will have the same method name but expect a different concrete type. P.S. I love your movie (maybe you really are Chris Pratt?): https://www.youtube.com/embed/kj802AGE9Bg?start=22&end=25 – steamer25 Dec 28 '17 at 15:52

1 Answers1

1

So I don't recall exactly what the problem turned out to be but the meta-solution is that you can debug routing problems by increasing the log level from "Information" to "Debug". E.g., via appsettings.json:

{
  "Logging": {
    "Debug": {
      "LogLevel": {
        "Default": "Debug"
      }
    },
    "Console": {
      "LogLevel": {
        "Default": "Debug"
      }
    }
  }
}

...then you'll get messages like this in e.g., the Application Output pane of Visual Studio:

[40m[37mdbug[39m[22m[49m: Microsoft.AspNetCore.Routing.RouteConstraintMatcher[1]
      Route value '(null)' with key 'httpMethod' did not match the constraint 'Microsoft.AspNetCore.Routing.Constraints.HttpMethodRouteConstraint'.
Microsoft.AspNetCore.Routing.RouteConstraintMatcher:Debug: Route value '(null)' with key 'httpMethod' did not match the constraint 'Microsoft.AspNetCore.Routing.Constraints.HttpMethodRouteConstraint'.
[40m[37mdbug[39m[22m[49m: Microsoft.AspNetCore.Routing.RouteBase[1]
      Request successfully matched the route with name 'get' and template 'api/{controller}/{id?}'.
Microsoft.AspNetCore.Routing.RouteBase:Debug: Request successfully matched the route with name 'get' and template 'api/{controller}/{id?}'.
[40m[37mdbug[39m[22m[49m: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1]
      Executing action Contoso.Media.ServiceHost.Controllers.MediaController.Get (Contoso.Media.ServiceHost)
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Debug: Executing action Contoso.Media.ServiceHost.Controllers.MediaController.Get (Contoso.Media.ServiceHost)
steamer25
  • 9,278
  • 1
  • 33
  • 38