Using instructions in a task

In the ASP.NET web API controller, I want to return an image. To stream images I need a MemoryStream . Normally, I would wrap it in a using statement to make sure that it is correctly configured afterwards. However, since this runs asynchronously in Task , this does not work:

 public class ImagesController : ApiController { private HttpContent GetPngBitmap(Stream stream) { var pngBitmapEncoder = new PngBitmapEncoder(); pngBitmapEncoder.Save(stream); stream.Seek(0, SeekOrigin.Begin); return new StreamContent(stream); } // GET api/images public Task<HttpResponseMessage> Get(string id, string path) { //do stuff return Task.Factory.StartNew(() => { var stream = new MemoryStream(); //as it asynchronous we can't use a using statement here! { var response = new HttpResponseMessage(HttpStatusCode.OK) { Content = GetPngBitmap(stream) }; response.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("image/png"); return response; } //how can I dispose stream??? }); } } 
+6
source share
5 answers
  • MemoryStream is one of the classes that implements IDisposable , because their base class does. MemoryStream does not contain any resources (other than managed memory), so it is actually optional to dispose of it.
  • HttpResponseMessage is one-time. This means that when the entire response is sent, this object is deleted. For this, the contained HttpContent , which in the case of StreamContent provides the underlying Stream . Therefore, even if you have a Stream that needs to be deleted, you do not have to worry about it in this case.
+5
source

It may sound naive, but can you just dispose of it at the end of the assignment?

 var stream = new MemoryStream(); //use the stream... stream.Dispose(); 

edit: or "Close ()", same thing in a MemoryStream.

-2
source

use "using", then it will be automatically installed.

 public class ImagesController : ApiController { // GET api/images public Task<HttpResponseMessage> Get(string id, string path) { //do stuff return Task.Factory.StartNew(() => { using( stream = new MemoryStream()) //as it asynchronous we can't use a using statement here! { { var response = new HttpResponseMessage(HttpStatusCode.OK) { Content = GetPngBitmap(stream) }; response.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("image/png"); return response; } //how can I dispose stream??? } }); } } 
-2
source

Perhaps return a Tuple<HttpResponseMessage, Stream> and attach a continue task to get rid of Stream ?

 public Task<Tuple<HttpResponseMessage,Stream>> Get(string id, string path) { //do stuff return Task.Factory.StartNew(() => { var stream = new MemoryStream(); { var response = new HttpResponseMessage(HttpStatusCode.OK) { Content = GetPngBitmap(stream) }; response.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("image/png"); return Tuple.Create(response, stream); } }) .ContinueWith(t => t.Result.Item2.Close()); } 
-2
source

You can do it like this. This will execute your initialRun first, and after the asynchronous call, return and it will continue with.

  Task<System.IO.MemoryStream> initialRun = new Task<System.IO.MemoryStream>(() => { System.IO.MemoryStream stream = new System.IO.MemoryStream(); // use stream return stream; }); initialRun.ContinueWith(new Action<Task<System.IO.MemoryStream>>((stream) => { stream.Dispose(); }), TaskScheduler.FromCurrentSynchronizationContext()); initialRun.Start(); 
-2
source

Source: https://habr.com/ru/post/959028/


All Articles