Asp.net-Core
如何在 ASP.NET Core 中間件中直接將響應主體設置為文件流?
下面用於在 ASP.NET Core 中間件中寫入文件流的範常式式碼
Response.Body不起作用(發出空響應):public Task Invoke(HttpContext context) { context.Response.ContentType = "text/plain"; using (var fs = new FileStream("/valid-path-to-file-on-server.txt", FileMode.Open) using (var sr = new StreamReader(fs)) { context.Response.Body = sr.BaseStream; } return Task.CompletedTask; }任何想法這種直接設置的方法可能有什麼問題
context.Response.Body?注意:管道中的任何下一個中間件都將被跳過,不再進行進一步處理。
更新(另一個例子):一個簡單的
MemoryStream分配也不起作用(空響應):context.Response.Body = new MemoryStream(Encoding.UTF8.GetBytes(DateTime.Now.ToString()));
- 不,你永遠不能直接這樣做。
請注意,這
context.Response.Body是對對象 (HttpResponseStream)的引用,該對像在中可用****之前已初始化HttpContext。假設所有字節都寫入這個原始流。如果您將Bodyto 引用(指向)更改為新的流對象,則根本不會更改context.Response.Body = a_new_Stream原始對象。Stream此外,如果您查看 的原始碼
ASP.NET Core,您會發現團隊總是將包裝流複製到最後的原始主體流,而不是進行簡單的替換(除非他們使用模擬流進行單元測試)。例如SPA Prerendering 中間件源碼:finally { context.Response.Body = originalResponseStream; ...和
ResponseCachingMiddleware原始碼:public async Task Invoke(HttpContext httpContext) { ... finally { UnshimResponseStream(context); } ... } internal static void UnshimResponseStream(ResponseCachingContext context) { // Unshim response stream context.HttpContext.Response.Body = context.OriginalResponseStream; // Remove IResponseCachingFeature RemoveResponseCachingFeature(context.HttpContext); }
- 作為一種解決方法,您可以將字節複製到原始流,如下所示:
public async Task Invoke(HttpContext context) { context.Response.ContentType = "text/plain"; using (var fs = new FileStream("valid-path-to-file-on-server.txt", FileMode.Open)) { await fs.CopyToAsync(context.Response.Body); } }或者,如果您想使用自己的流包裝器劫持原始數據:
HttpResponseStreamvar originalBody = HttpContext.Response.Body; var ms = new MemoryStream(); HttpContext.Response.Body = ms; try { await next(); HttpContext.Response.Body = originalBody; ms.Seek(0, SeekOrigin.Begin); await ms.CopyToAsync(HttpContext.Response.Body); } finally { response.Body = originalBody; }