简体   繁体   中英

Swagger UI sends multiple headers bound to a single action parameter as a single json object, rather than as multiple headers

I enabled Swagger in my asp.net core 3.1 API by following the usual MS docs. https://docs.microsoft.com/en-us/aspnet/core/tutorials/getting-started-with-swashbuckle?view=aspnetcore-3.1&tabs=visual-studio It works fine.

The following controller works great in Postman. myBody has its Body1 and Body2 fields bound from the POST request's json body. myHeader has its Header1 and Header2 bound from the request's two "Header1" and "Header2" headers.

namespace MyApi.Controllers
{
    [ApiController]
    [Route("test")]
    public class TestController : ControllerBase
    {
        [HttpPost]
        [ProducesResponseType(StatusCodes.Status200OK)]
        public ActionResult Post(
            [FromHeader] MyHeaders myHeaders,
            MyBody myBody)
        {
            return Ok();
        }
    }

    public class MyHeaders
    {
        [FromHeader]
        public string Header1 { get; set; }

        [FromHeader]
        public string Header2 { get; set; }
    }

    public class MyBody
    {
        public string Body1 { get; set; }

        public string Body2 { get; set; }
    }
}

However Swagger UI only passes 1 json object for the two headers: [swagger ui][1]

And it generates a corresponding curl command: curl -X POST "https://localhost:5001/test" -H "accept: */*" -H "myHeaders: header1,string,header2,string" -H "Content-Type: application/json" -d "{\\"body1\\":\\"string\\",\\"body2\\":\\"string\\"}"

The problem is the -H "myHeaders: header1,string,header2,string" portion. Model binding sets myHeaders.Header1 and .Header2 to null, as expected, because the header is named "myHeaders". Replacing the portion with **-H "Header1: cat" -H "Header2: dog" works correctly.

Asp.net is clever enough to map separate headers into a single action parameter by matching their names. But how can I get Swagger have multiple headers the UI, so its curl command works? I know I could replace [FromHeader] MyHeaders myHeaders with [FromHeader] string Header1, [FromHeader] string Header2 , but I want to avoid that. There will be dozens of actions that all receive the same set of headers.

Solution is given in Yura's answer in How to use [FromHeader] attribute with custom model binding in Asp.Net Core 2.2 It is to change [FromHeader] MyHeaders myHeaders to [FromQuery] MyHeaders myHeaders . This gets Swagger UI working, even though the FromQuery seems to be contradicted by the FromHeader attribute on Header1 and Header2.

The fixed code is:

public class TestController : ControllerBase
{
    [HttpPost]
    [ProducesResponseType(StatusCodes.Status200OK)]
    public ActionResult Post(
        [FromQuery] MyHeaders myHeaders, // FromHeader is changed to FromQuery
        MyBody myBody)
    {
        return Ok();
    }
}

public class MyHeaders // unchanged
{
    [FromHeader]
    public string Header1 { get; set; }

    [FromHeader]
    public string Header2 { get; set; }
}

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