-
Notifications
You must be signed in to change notification settings - Fork 527
ThrowResponseAlreadyStartedException while setting StatusCode in a Controller method #2667
Comments
Set the status code before writing. Writing the response will start it. That’s what the rrror message is trying to say. Maybe it’s not clear enough. |
You have to set the status code prior to writing to the body Switch the last two lines Response.ContentType = "application/octet-stream";
Response.StatusCode = (int) HttpStatusCode.OK;
Response.Body.Write(someData, 0, someData.Length); |
Maybe go async as well 😉 await Response.Body.WriteAsync(someData, 0, someData.Length); |
Thing is in this specific case, I need to write to the body first, then the StatusCode depends on something else. |
and by the way, if I return the data on the method return like this: I get this in the debug console:
But I've added this and no change.... services.AddMvc(options =>
{
options.OutputFormatters.Add(new StreamOutputFormatter());
}) |
@benaadams WriteAsync doesn't change anything... I'll try to take a look at the implem behind but so far I don't understand the logic behind this. Why can't I set the body's content then set the Status Code? |
The response body isn’t buffered m. When you write it will be written (with headers and the start line) to the client. |
@nockawa the headers; of which status code is one, occur in the output before the response body, so they can't be written after the body is written. You could buffer the output before sending it if you expect that the status code could change while processing the request; then set the status code, followed by the buffered response. e.g. new up and write to a then var memStream = new MemoryStream();
// Write data buffering it
memStream.Write(someData, 0, someData.Length);
// Set headers
Response.ContentType = "application/octet-stream";
Response.StatusCode = (int) HttpStatusCode.OK;
Response.ContentLength = memStream.Length; // might as well...
// Write buffered data to body
await memStream.CopyToAsync(Response.Body); |
@benaadams yes, it totally makes sense, I thought about this afterward. Initially, I thought it wouldn't matter because I was in a Controller and not a middleware, but afterward I realized it was the only way to achieve great performances to process everything in order. @davidfowl is that normal that I can't return a Because the whole initial 'issue' is because of this. I initially wanted to mark the response content as octet-stream, set the Status Code and return a |
Seems like an mvc question. You’d need to show the original code you wrote. There’s nothing special here at the kestrel level. |
Do you want me to post an issue on the corefx repo? In the meantime, here's the code: [Route("cell/{constructId}/{x}/{y}/{z}/{h}/version")]
[HttpGet]
public async Task<ActionResult<byte[]>> GetCellHashAndVersion(ulong constructId, long x, long y, long z, byte h)
{
// Return the Cell Model, we should always get on, whether the cell is new or not
var cell = await _service.GetCellAsync(constructId, x, y, z, h);
// Setup the response
Response.ContentType = "application/octet-stream";
using (var ms = new MemoryStream(2048))
{
cell.ToPBCellVersion(ms);
return Ok(ms.ToArray());
}
} Doing this display this warning message :
With a Status Code of 406 (I believe this is due to the OutputFormatter not willing to deal with |
@nockawa for future reference MVC issues go here (https://github.com/aspnet/Mvc). Seems like MVC doesn't support that content type, the StreamOutputFormatter is for Streams, not public class HomeController : Controller
{
[HttpGet("/bin")]
[Produces("application/octet-stream")]
public byte[] GetBin()
{
return Encoding.UTF8.GetBytes("Hello World");
}
[HttpGet("/bin2")]
public Task GetBinRaw()
{
Response.ContentType = "application/octet-stream";
var buffer = Encoding.UTF8.GetBytes("Hello World");
return Response.Body.WriteAsync(buffer, 0, buffer.Length);
}
[HttpGet("/bin3")]
[Produces("application/octet-stream")]
public Stream GetBinStream()
{
return new MemoryStream(Encoding.UTF8.GetBytes("Hello World"));
}
} Seems like MVC just doesn't support returning a /cc @rynowak for more info |
@nockawa if you want to avoid allocations, you can write directly to the response stream. |
@davidfowl thanks for all the help, I think I'll manage from there. |
Agreed. File an issue on MVC. I'm not sure why we don't support |
that's what I'm doing right now! :) I just make sure I give all the details I can |
My use case is pretty simple, I have a method from an asp.net core 2.1 controller that is call for a given
post
request.All I want to do is write some binary data in the
Response.Body
and set theResponse.StatusCode
.No matter what I try it throws a
ThrowResponseAlreadyStartedException
stating:StatusCode cannot be set because the response has already started.
All I want to do is something like this:
Maybe I'm not using the right way to write binary data in the Response's body but that's the only one I came up with. Changing the signature of my method to return
Task<ActionResult<byte[]>>
won't do the trick to return binary data.The text was updated successfully, but these errors were encountered: