简体   繁体   中英

MVC WebApi Routing with field type specified in route

I have the following api definition

[RoutePrefix("api/lead/1.0")]
public class LeadController:ApiController
{
    [Route("/{id:integer}/request-td")]
    [HttpPost]
    public IHttpActionResult SubmitLead(int id, 
        FromBody]FormData FormData)
    {

    }
}

When my QA department is testing this code, they are calling

/api/lead/1.0/12345/request-td

with a valid body and everything passes

However if they change the id from an int to a string, /api/lead/1.0/invalidid/request-td

They are getting back an iis 404 message.

As a temp solution I have changed the id from an int to a string, and removed the definition from the route.

Within the controller is performing a TyParse to make sure that a valid integer has been passed in the url

However this solution is not very elegant for me

Is there any way so that i can leave the id field defined as an int, with the correct type defined in the route, trap the invalid api request, and then send back my own custom error. ie different http status code and message body

If I have the signature as an int, but with no variable definiton in the route,

[Route("/{id}/request-td")]
[HttpPost]
public IHttpActionResult SubmitLead(int id, 
        FromBody]FormData FormData)

It is sending back too much information as to why the request is invalid

What I have seen so far, is that you need to get the definitions created in the correct order in global.asax not how to trap invalid api requests and return my own response

If you want receive "string" or "int" as request parameter then you need to write multiple time your "Route" attribute to add it in routing map.

Following is solution to receive values.

[Route("{id:int}/request-td")]
[Route("{id:alpha}/request-td")]

This will accept both "string" and "int" request and don't 404 page.

Hope this code will help you.

I would actually create a custom attribute.

public class CheckArgumentTypeAttribute : ActionFilterAttribute
{
    private readonly string ActionArgumentName;

    public CheckArgumentIsPositiveAttribute(string actionArgumentName)
    {
        if (string.IsNullOrWhiteSpace(actionArgumentName)) throw new ArgumentException(nameof(actionArgumentName));
        ActionArgumentName = actionArgumentName;
    }

    public override void OnActionExecuting(HttpActionContext actionContext)
    {
        var keyValuePair = actionContext.ActionArguments.FirstOrDefault(x => x.Key.Equals(ActionArgumentName, StringComparison.OrdinalIgnoreCase));
        if (keyValuePair.Equals(default(KeyValuePair<string, object>)) || !int.TryParse(keyValuePair.Value, out in result))
        {
            actionContext.Response = new HttpResponseMessage(HttpStatusCode.BadRequest)
            {
                Content = new StringContent(JsonConvert.SerializeObject(new YourClass())), Encoding.UTF8, MimeTypes.Application.Json)
            };
        }
    }
}

Then I would decorate my action methods as [CheckArgumentType("id")] . It is possible to create dynamic error message based on the ActionArgumentName or to further extend this attribute.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM