public async Task ExecuteResultAsync(HttpContext context) { foreach (var item in this) { if (item.Stream != null) { var content = new StreamContent(item.Stream); if (item.ContentType != null) { content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(item.ContentType); } if (item.FileName != null) { var contentDisposition = new ContentDispositionHeaderValue("attachment"); contentDisposition.FileName = item.FileName; content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment"); content.Headers.ContentDisposition.FileName = contentDisposition.FileName; content.Headers.ContentDisposition.FileNameStar = contentDisposition.FileNameStar; } this.content.Add(content); } } // Don't set ContentLength, Transfer-Encoding: Chunked is set // automatically by kestrel and simulates an unknown number of body elements //context.Response.ContentLength = content.Headers.ContentLength; context.Response.ContentType = content.Headers.ContentType.ToString(); var str = await content.ReadAsStringAsync(); var sw = new StreamWriter(context.Response.Body); var multipartBoundary = this.content.Headers.ContentType.Parameters .First(p => p.Name == "boundary").Value.Trim('"'); var parts = str.Split(multipartBoundary + "\r\n"); for (var i = 0; i < parts.Length; i++) { var part = parts[i]; await sw.WriteAsync(part); if (i < parts.Length - 1) { await sw.WriteAsync(multipartBoundary + "\r\n"); } await sw.FlushAsync(); if (i < parts.Length - 1) { // Artificial delay to simulate asynchronous processing and response await Task.Delay(TimeSpan.FromSeconds(2)); } } await sw.DisposeAsync(); }
static void Main(string[] args) { Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseUrls("http://*****:*****@"{ ""Name"": ""Arthur"" }"); await sw.DisposeAsync(); part1.Seek(0, SeekOrigin.Begin); var part2 = new MemoryStream(); sw = new StreamWriter(part2, leaveOpen: true); await sw.WriteAsync(@"{ ""Name"": ""Candace"" }"); await sw.DisposeAsync(); part2.Seek(0, SeekOrigin.Begin); var part3 = new MemoryStream(); sw = new StreamWriter(part3, leaveOpen: true); await sw.WriteAsync(@"{ ""Name"": ""Timothy"" }"); await sw.DisposeAsync(); part3.Seek(0, SeekOrigin.Begin); var result = new MultipartResult(); result.Add(new MultipartContent { ContentType = "application/xml", FileName = "part1.xml", Stream = part1 }); result.Add(new MultipartContent { ContentType = "application/xml", FileName = "part2.xml", Stream = part2 }); result.Add(new MultipartContent { ContentType = "application/xml", FileName = "part3.xml", Stream = part3 }); await result.ExecuteResultAsync(context); }); }); }); }) .Build().Run(); }