Im trying to migrate a web api project (classic web.config project) there use PushStreamContent to the latest asp.net 5 web app (project.json).
My problem is that i can not get PushStreamContent to work.
When I use this api controller – a result will end up in a json format and not as a stream:
[Route("api/[controller]")]
public class EventsController : Controller
{
private static readonly ConcurrentQueue<StreamWriter> s_streamWriter = new ConcurrentQueue<StreamWriter>();
[HttpGet]
public HttpResponseMessage Get(HttpRequestMessage request)
{
HttpResponseMessage response = request.CreateResponse();
response.Content = new PushStreamContent(new Action<Stream, HttpContent, TransportContext>(WriteToStream), "text/event-stream");
return response;
}
private void WriteToStream(Stream outputStream, HttpContent headers, TransportContext context)
{
var streamWriter = new StreamWriter(outputStream) {AutoFlush = true};
s_streamWriter.Enqueue(streamWriter);
}
}
If I change the controller action to return a task and wrap PushStreamContent in a class MyPushStreamResult - Like this:
[HttpGet]
public async Task<IActionResult> Get(HttpRequestMessage request)
{
var stream = new PushStreamContent(new Action<Stream, HttpContent, TransportContext>(WriteToStream), "text/event-stream");
return new MyPushStreamResult(stream, "text/event-stream");
}
public class MyPushStreamResult : ActionResult
{
public string ContentType { get; private set; }
public PushStreamContent Stream { get; private set; }
public MyPushStreamResult(PushStreamContent stream, string contentType)
{
Stream = stream;
ContentType = contentType;
}
public override async Task ExecuteResultAsync(ActionContext context)
{
var response = context.HttpContext.Response;
response.ContentType = ContentType;
await Stream.CopyToAsync(response.Body);
}
}
A request to my controller action is now returning a stream, BUT the stream is not flushing before it close on serverside or contains a lot of data. When I push data to the PushStreamContent outputstream I flush after each text write, but I guess the flush is not on the response.Body stream.
What do i miss? Cannot find any samples with asp.net 5 structure.
HttpResponseMessage
is not treated specially in ASP.NET 5 unless you are using Microsoft.AspNet.Mvc.WebApiCompatShim
package. This package is not recommended if you can use the ASP.NET 5 features to do similar stuff and was created to support backward compatibility.
So since HttpResponseMessage
is not being considered special, its being rendered as json by the JsonOutuptFormatter
just like any other .NET object
Instead of PushStreamContent
, you currently have access to response stream directly via HttpContext.Response.Body
property, so you can just directly write to the stream.
Updated:PushStreamContent
in Web API allowed you to directly write to the response stream. This type was created(by Web API team and is not present as part of System.Net.Http
library where all other content types are) so that one could write directly to the stream, say for example, from a controller or filter etc. The alternative to PushStreamContent was StreamContent
which only allowed you to provide a Stream object and then the host layers 'copy' the data from the source stream(like 'pulling' data). Also PushStreamContent is nothing special by itself. One could write their own type which derives from HttpContent
.
To summarize, PushStreamContent
allowed writing to the response stream directly where as in ASP.NET 5 we have direct access to the stream and so you can write to it.
Updated:
At the very basic form (right, you could convert to actionresult for testability), the following should work.
[HttpGet]
public Task Get()
{
HttpContext.Response.ContentType = "text/event-stream";
var sourceStream = // get the source stream
return sourceStream.CopyToAsync(HttpContext.Response.Body);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With