2

Let's say that there are two ways to post data to the same API endpoint, through a file or through he request body.

Is it possible to route to an action by the Accept header for the same resource?

By request body:

// Accept: application/json
[HttpPost]
public IActionResult PostText([FromBody]string text)
{
    ...
    return new HttpOkResult();
}

By file:

// Accept: application/x-www-form-urlencoded
[HttpPost]
public IActionResult PostFile(IFormFile file)
{
    ...
    return new HttpOkResult();
}
Dave New
  • 38,496
  • 59
  • 215
  • 394
  • have you checked: http://stackoverflow.com/questions/28573232/is-it-possible-to-select-an-action-with-attributerouting-in-net-mvc-based-on-th – ebram khalil Dec 24 '15 at 09:53

1 Answers1

4

Use Action Constraint for that.

Action Constraint

namespace WebApplication
{
    public class PostDataConstraint : ActionMethodSelectorAttribute
    {
        public override bool IsValidForRequest(RouteContext routeContext, ActionDescriptor action)
        {
            var httpContext = routeContext.HttpContext;
            var acceptHeader = //getting accept header from httpContext
            var currentActionName = action.DisplayName;

            if(actionName == "PostFile" and header == "application/x-www-form-urlencoded" ||
               actionName == "PostText" and header == "application/json")
            {
                return true
            }

            return false;
        }
    }
}

Actions:

// Accept: application/json
[HttpPost]
[PostData]
public IActionResult PostText([FromBody]string text)
{
    ...
    return new HttpOkResult();
}

// Accept: application/x-www-form-urlencoded
[PostData]
[HttpPost]
public IActionResult PostFile(IFormFile file)
{
    ...
    return new HttpOkResult();
}
Stas Boyarincev
  • 3,690
  • 23
  • 23
  • It would be better to just implement `IActionConstraint` instead of deriving from `ActionMethodSelectorAttribute` – Daniel J.G. Dec 24 '15 at 11:53
  • @DanielJ.G. can you please tell, why using IActionConstraint better? – Stas Boyarincev Dec 24 '15 at 12:02
  • 1
    Because `ActionMethodSelectorAttribute` is already an implementation of `IActionConstraint` which looks at the http method. What you need is a different implementation that looks at the accept header. So why would you inherit from a class when you want to replace the entire behavior that class provides? – Daniel J.G. Dec 24 '15 at 12:11
  • 1
    But i don't see anything tied to http methods in [implementation ActionMethodSelectorAttribute](https://github.com/aspnet/Mvc/blob/6.0.0-rc1/src/Microsoft.AspNet.Mvc.Core/ActionConstraints/ActionMethodSelectorAttribute.cs). And from description, this is: "Base class for attributes which can implement conditional logic to enable or disable an action for a given request." – Stas Boyarincev Dec 24 '15 at 12:25
  • 2
    Ah, my bad! I was wrongly assuming that was the class to filter actions based on the HTTP verb. – Daniel J.G. Dec 24 '15 at 12:56