Aspnetcore: Returning HTML using Produces("text/html") causes 406 response

Created on 15 Aug 2017  路  18Comments  路  Source: dotnet/aspnetcore

After upgrading to ASP.NET Core 2.0, [Produces("text/html")] doesn't seem to work anymore. I am returning a string in my action using Ok(str) with that attribute specified.

area-mvc enhancement

Most helpful comment

The StringOutputFormatter used to ignore content types entirely and it no longer does this - it will only output text/plain. If you want it to output strings as text/html then you can add that as well.

options.OutputFormatters.OfType<StringOutputFormatter>().Single().SupportedMediaTypes.Add("text/html");

Personally I would just use Content(...) for this. You have the HTML text, and the content type already decided. This doesn't rely on serialization nor on content negotiation.

All 18 comments

@mohd-akram can you show what your action method looks like? And what kind of request is being sent to the server?

Using dotnet new mvc and modifying HomeController:

[Produces("text/html")]
public IActionResult Index()
{
    return Ok("hello");
}

Using Chrome:

Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding:gzip, deflate, br
Accept-Language:en-US,en;q=0.8
Cache-Control:no-cache
Connection:keep-alive
Cookie:_ga=GA1.1.255538139.1497605335
Host:localhost:5000
Pragma:no-cache
Upgrade-Insecure-Requests:1
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3138.0 Safari/537.36

In console:

warn: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1]
      No output formatter was found for content type 'text/html' to write the response

@mohd-akram thanks for the info!

@rynowak / @dougbu - ideas on this? Does the OkResult somehow not participate in con-neg?

@Eilon what formatter is registered for text/html by default? AFAIK, none...

Oh right text/html, I totally missed that - was thinking plaintext... yeah probably nothing is registered.

@mohd-akram are you saying this worked in 1.x?

Yeah. The docs seem to support this.

I've added this for now:

public class HtmlOutputFormatter : StringOutputFormatter
{
    public HtmlOutputFormatter()
    {
        SupportedMediaTypes.Add("text/html");
    }
}
services.AddMvc(options => options.OutputFormatters.Add(new HtmlOutputFormatter()));

Yes this looks like a regression. I reproduced it working with 1.1 and then failing after an upgrade.

This was an intentional change https://github.com/aspnet/Mvc/issues/4945

We used to have a formatter that would just barf out any string that you gave it. It caused a lot of confusion every time it kicked into action.

This is what ContentResult does. If you know ahead of time what content type and have the content in a string, just use that.

It feels like there is a middle ground here i.e. respecting Produces and returning 406 otherwise?

The StringOutputFormatter used to ignore content types entirely and it no longer does this - it will only output text/plain. If you want it to output strings as text/html then you can add that as well.

options.OutputFormatters.OfType<StringOutputFormatter>().Single().SupportedMediaTypes.Add("text/html");

Personally I would just use Content(...) for this. You have the HTML text, and the content type already decided. This doesn't rely on serialization nor on content negotiation.

That's perfect, thanks! Yeah, but I can't specify a status code (easily) that way. I prefer using Ok, BadRequest, NotFound, etc.

Should we add a status code to to content? Or is the issue mostly that you like the semantically meaningful names like Ok, BadRequest?

Mostly the semantic names, but I still think adding a status code to Content (and View) would be helpful.

For the particular scenario that started this issue, we recommend using the workaround listed by adding the supported MIME type(s) to the existing formatter.

What we are considering is adding new action result type (or factory helpers), plus making setting the status code easier on existing action result types.

Putting this on the Backlog for future consideration.

I ran into this issue today after upgrading from 1.1 to 2.0. In my particular scenario my API is a 'Gateway' for a number of microservices. In a number of instances after receiving a response from the downstream microservice the controllers were returning this response using a StatusCodeResult, retaining the status code from the result of the call to the downstream services.

After upgrading to 2.0 I found that any response from a downstream service which contained JSON was now being wrapped in additional quotes when being returned to the client of the gateway API, producing invalid JSON as the end result. I assume this is a result of the Json output formatter now being applied to this in 2.0 and being unable to deserialize the content correctly, whereas in 1.x the StringOutputFormatter would have been applied.

For now I have used the workaround that was suggested and this is working fine. I would like to move to returning ContentResult, but at present it seems this always produces a 200 result. The ability to provide a status code when creating a ContentResult using Content() has been mentioned in this thread, that would be a great help.

I also encountered this "No output formatter was found for content type 'text/html' to write the response" error while I tried to return html from my controller.
But in my case I have a Steam with data. What I tried at first is just copying my stream into Response.Body:

HttpContext.Response.GetTypedHeaders().ContentType = new MediaTypeHeaderValue(mediaType);
stream.CopyTo(HttpContext.Response.Body);
return Ok();

It produces the mentioned error.
The suggested workaround is to return ContentResult. Ok, but for this I'll have to copy my stream into string:

var content = new StreamReader(stream).ReadToEnd();
return Content(content , formatInfo.ContentType.MediaType);

I'd like to avoid double memory allocation.

Could please suggest how should I act in such a case?

This is not something we plan to change.

Was this page helpful?
0 / 5 - 0 ratings