Home > Software engineering >  ASP.NET Core 6 - Use URI's extension to get Accept header value
ASP.NET Core 6 - Use URI's extension to get Accept header value

Time:09-23

I'm migrating an application from NancyFx to Kestrel in ASP.NET Core 6.

In Nancy, you could specify the Accept value in the URI. For example, these Uris:

  • http://localhost:5000/my/resource.json
  • http://localhost:5000/my/resource.protobuf
  • http://localhost:5000/my/resource.xml

Would be the equivalent of setting the Accepts header to application/json, application/protobuf or application/xml respectively.

Does this exist in Kestrel? I remember finding one example, long ago, of regex-ing the route and doing it somewhat manually. But

  1. I can't find that post again, and
  2. If I have to do that, I'm not sure I want to :)

Is there a way to configure this behavior in ASP.NET Core 6?

The object returned from my handler in the controller is already capable of being serialized to json/xml/whatever. I just need to check the URI to set the content-type of the response so the correct formatter will be invoked.

At the moment, I have a client that will speak to both Nancy and Kestrel and it was written to use the URI to get the type. I'm fine to rewrite/update the client so it will use the Accept header. But getting the URI method to work will make the initial integration easier and a refactor to use the headers can come next.

CodePudding user response:

I created a very simple middleware that reads the accept value from the query string and sets the Accept header to the request:

public class AcceptHeaderFromQueryString
{
    private readonly RequestDelegate _next;

    public AcceptHeaderFromQueryString(RequestDelegate next)
    {
        _next = next;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        var accept = context.Request.Query["accept"];

        if (!string.IsNullOrEmpty(accept))
        {
            context.Request.Headers.Accept = accept;
        }

        await _next(context);
    }
}

Register the middleware:

app.UseMiddleware<AcceptHeaderFromQueryString>();

I added [Produces(MediaTypeNames.Application.Json, MediaTypeNames.Application.Xml)] attribute to my api controller action (this step is not required):

[HttpGet]
[Produces(MediaTypeNames.Application.Json, MediaTypeNames.Application.Xml)]
public IEnumerable<WeatherForecast> Get()
{
    return Enumerable.Range(1, 5).Select(index => new WeatherForecast
    {
        Date = DateTime.Now.AddDays(index),
        TemperatureC = Random.Shared.Next(-20, 55),
        Summary = Summaries[Random.Shared.Next(Summaries.Length)]
    })
    .ToArray();
}

Finally I added support for xml serialization in Program.cs:

builder.Services.AddControllers()
    .AddXmlDataContractSerializerFormatters();

Then I tried these urls and they both gave appropriate response:

https://localhost:7258/weatherforecast?accept=application/json

https://localhost:7258/weatherforecast?accept=application/xml

CodePudding user response:

You possibly want the [Consumes] attribute. This allows you to specify a controller action that only gets called from a route of the specified content type.

Obviously this is not using the Accepts header but the content type of the request.

  • Related