asp.net core mvc HttpContext.Response.Body.WriteAsync(byte[],0,length) auto write hex length string to stream

bluesky zhang 21 Reputation points
2021-02-24T09:03:53.557+00:00

in asp.net core mvc i use HttpContext.Response.Body.WriteAsync(byte[],0,length) send data,but it auto write hex length string to stream at start

Developer technologies | ASP.NET | ASP.NET Core
0 comments No comments
{count} votes

Accepted answer
  1. Michael Taylor 60,161 Reputation points
    2021-02-26T15:11:38.35+00:00

    The data looks correct to me. You are not sending a series of responses, you are sending a single response. Every X seconds you send the next set of data. How the network breaks this up is completely up to it. You might be expecting that each time you delay it sends the previous response but that isn't how the response system works. Normally the response is buffered so it won't potentially send anything until the response is entirely written. That, of course, wouldn't work here.

    To force the response to go out you have to disable buffering. Even then you need to also flush the response but note that the response could have already been sent out. That isn't an issue because the protocol can handle that.

    In the MjpegStreamContent class that sends the image disable buffering before sending the content.

    public async Task ExecuteResultAsync ( ActionContext context )
    {
    
        //Disable buffering on this response so it sends it out before it is done
        var responseFeature = context.HttpContext.Features.Get<IHttpResponseBodyFeature>();
        responseFeature.DisableBuffering();
    
        context.HttpContext.Response.ContentType = _contentType;
    
        var outputStream = context.HttpContext.Response.Body;
        var cancellationToken = context.HttpContext.RequestAborted;
        ...
    

    Then flush the response after the writes, just to have some control.

    await outputStream.WriteAsync(headerData, 0, headerData.Length, cancellationToken);
    await outputStream.WriteAsync(imageBytes, 0, imageBytes.Length, cancellationToken);
    await outputStream.WriteAsync(_newLine, 0, _newLine.Length, cancellationToken);
    await outputStream.FlushAsync();
    

    Note that browsers may behave differently when sending this kind of response so test in all browsers you need to support. I tried this in Chrome and it works correctly. Every couple of seconds an image is loaded. But I don't have a camera so I just wrote out the current time.

    1 person found this answer helpful.

1 additional answer

Sort by: Most helpful
  1. Michael Taylor 60,161 Reputation points
    2021-02-24T15:31:52.613+00:00

    Is there any particular reason why you are manually generating a response rather than using the defacto approach of using (or creating) an ActionResult that does this for you? That tends to solve problems people have with improperly trying to write to the response. In your case the thing that comes to mind is that there is already data written to the response and, in fact, WriteAsync isn't doing that.

    Body is a Stream and WriteAsync won't prefix the length. BTW your code is not even valid as byte[] is a type declaration, not an argument. Nevertheless either that data was already written earlier in the process or the response body is set to a custom HttpContent that uses a custom Stream that length prefixes byte arrays. The latter would pretty much break streams so it is highly unlikely. However if you were to simply use a standard (or custom) ActionResult then I suspect the problem will go away. For example the ByteArrayContent can be used to write a byte array as a response without the need for the low level writing that you're trying to do here.


Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.