Jure
Jure

Reputation: 1176

MVC WebApi advanced custom routing

I'm struggling with this for some time now. I've searched all over the internet, didn't find any solution.

I'd like to create a webapi project with somewhat custom routing. Using VS 2019, project is of type ASP.NET WebApi on .NET Core 2.2. Routing should be like this:

Basic application must reside on url similar to "https://my.server.com/myapi". URLs which will be called are in form "https://my.server.com/myapi/{InstanceName}/{CommandName}?{customParams}"

I have one controller defined in my project and I would like to redirect all requests to that controller, where instanceName could be parameter of all the methods contained in a controller, so I would get a value for that parameter. CommandName is basicly the same as "action" RouteData by MVC principles. As you can see there is no controller specified, since all is handled by one controller.

So far I've tried setup routing like this:

Startup.cs

app.UseMvc(routes =>
{
    routes.MapRoute(
        name: "MyRoute",
        template: "{instance}/{action}",
        defaults: new { controller = "MyController" });
    });
}

MyController.cs

[Route("/")]
[ApiController]
public class MyController : ControllerBase
{
    [HttpGet("{instance}/info")]
    public JsonResult Info(string instance, InfoCommand model)
    {
        // Just return serialized model for now.
        var result = new JsonResult(model);

        return result;
    }
}

But this does not work. I get 415 response from (I think) web server when I call for example

https://my.server.com/myapi/MYINSTANCE/info?param1=value1&param2=value2

While debugging from VS this URL looks like this:

https://localhost:12345/MYINSTANCE/info?param1=value1&param2=value2

but I think it shouldn't matter for routing.

In best case scenario (putting [Route("{instance}")] above controller and [HttpGet("info")] above Info method) I get 404 response, which is also what I do not want.

I've even tried creating my own ControllerFactory, but that didn't work either (changing controller inside ControllerFactory's create method and adding another parameter to RouteData).

How to setup routing like that? Is it even possible? I would still like to use all other MVC features (model binding, proper routing, auth features, etc.), it's just this routing I cannot figure it out.

Upvotes: 0

Views: 91

Answers (1)

pfx
pfx

Reputation: 23314

Your attempt resulting a in 415 Unsupported Media Type error was your best one.
You were only missing the FromQuery as shown below.

The error indicates that the complex type InfoCommand could not be resolved.
You must specify that it must be parsed from the querystring.

Note that the route defined via MapRoute doesn't have effect, since you are using attribute-based routing; it's only one or the other.

[Route("/")]
[ApiController]
public class MyController : ControllerBase
{
    [HttpGet("{instance}/info")]
    public JsonResult Info(string instance, [FromQuery] InfoCommand model)
    {
        var result = new JsonResult(model);
        return result;
    }
}

public class InfoCommand
{
    public InfoCommand()
    {}

    public string Param1 { get; set; }
    public string Param2 { get; set; }
}

Upvotes: 2

Related Questions