Kalanamith
Kalanamith

Reputation: 20668

How to have a Route which points to two different controller end points which accepts different arguments in WEB Api 2

How to have a Route which points to two different controller end points which accepts different arguments in WEB Api 2 I have two different end points declared in controller and as for the REST perspective I have to use the alpha/{aplhaid}/beta format for both the end points ,

            [Authorize]
            [HttpPost]
            [Route("alpha/{aplhaid}/beta")]
            public async Task<HttpResponseMessage> CreateAlpha(Beta beta, string projectId, [FromHeader] RevisionHeaderModel revision)

            [Authorize]
            [HttpPost]
            [Route("alpha/{aplhaid}/beta")]
            public async Task<HttpResponseMessage> CreateAlpha(List<Beta> betas, string projectId, [FromHeader] RevisionHeaderModel revision)

Is it possible to use the same router with different parameters which points to 2 different end points in Web API 2?

Upvotes: 2

Views: 264

Answers (3)

smoksnes
smoksnes

Reputation: 10851

If you really need to have the same route and the same ActionName, you could do it with an IHttpActionSelector.

public class CustomActionSelector : ApiControllerActionSelector, IHttpActionSelector
{
    public new HttpActionDescriptor SelectAction(HttpControllerContext controllerContext)
    {
        var context = HttpContext.Current;

        // Read the content. Probably a better way of doing it?
        var stream = new StreamReader(context.Request.InputStream);
        var input = stream.ReadToEnd();

        var array = new JavaScriptSerializer().Deserialize<List<string>>(input);
        if (array != null)
        {
            // It's an array
            //TODO: Choose action.
        }
        else
        {
            // It's not an array
            //TODO: Choose action.
        }

        // Default.
        var action = base.SelectAction(controllerContext);
        return action;
    }

    public override ILookup<string, HttpActionDescriptor> GetActionMapping(HttpControllerDescriptor controllerDescriptor)
    {
        var lookup = base.GetActionMapping(controllerDescriptor);
        return lookup;
    }
}

In your WebApiConfig:

    config.Services.Replace(
        typeof(IHttpActionSelector),
        new CustomActionSelector());

Example for your an Controller:

public class FooController: ApiController
{
    [HttpPost]
    public string Post(string id)
    {
        return "String";
    }

    [HttpPost]
    public string Post(List<string> id)
    {
        return "some list";
    }
}

The solution has some big downsides, if you ask me. First of, you should look for a solution for using this CustomActionSelector only when needed. Not for all controllers as it will create an overhead for each request.

I think you should reconsider why you really need two have to identical routes. I think readability will be suffering if the same route accepts different arguments. But that's just my opinion.

I would use different routes instead.

Upvotes: 2

isxaker
isxaker

Reputation: 9496

Overload web api action method based on parameter type is not well supported. But what about attribute based routing ?

You can find out a good example here

Route constraints let you restrict how the parameters in the route template are matched. The general syntax is "{parameter:constraint}". For example:

[Route("users/{id:int}"]
public User GetUserById(int id) { ... }

[Route("users/{name}"]
public User GetUserByName(string name) { ... }

And I think this link must be helpful

Upvotes: 2

Lőrincz P&#233;ter
Lőrincz P&#233;ter

Reputation: 160

Use one route and call the other controller inside from the first controller.

Upvotes: 1

Related Questions