{"id":90980,"date":"2019-03-27T20:51:50","date_gmt":"2019-03-27T20:51:50","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/aspnet\/?p=21694"},"modified":"2019-03-27T20:51:50","modified_gmt":"2019-03-27T20:51:50","slug":"re-reading-asp-net-core-request-bodies-with-enablebuffering","status":"publish","type":"post","link":"https:\/\/sickgaming.net\/blog\/2019\/03\/27\/re-reading-asp-net-core-request-bodies-with-enablebuffering\/","title":{"rendered":"Re-reading ASP.Net Core request bodies with EnableBuffering()"},"content":{"rendered":"<div class=\"row justify-content-center\">\n<div class=\"col-md-2\">\n<div><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.sickgaming.net\/blog\/wp-content\/uploads\/2019\/03\/re-reading-asp-net-core-request-bodies-with-enablebuffering.jpg\" width=\"58\" height=\"58\" alt=\"Avatar\" class=\"avatar avatar-58 wp-user-avatar wp-user-avatar-58 photo avatar-default\"><\/p>\n<p>Jeremy<\/p>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"entry-meta\">\n<p>March 27th, 2019<\/p>\n<p> &lt;!&#8211;<span class=\"posted-on\">Posted on <a href=\"https:\/\/devblogs.microsoft.com\/aspnet\/re-reading-asp-net-core-request-bodies-with-enablebuffering\/\" rel=\"bookmark\"><time class=\"entry-date published updated\" datetime=\"2019-03-27T13:51:50+00:00\">March 27, 2019<\/time><\/a><\/span><span class=\"byline\"> by <span class=\"author vcard\"><a class=\"url fn n\" href=\"https:\/\/devblogs.microsoft.com\/aspnet\/author\/yumengmicrosoft-com\/\">Jeremy Meng<\/a><\/span><\/span>&#8211;&gt; <\/div>\n<p><!-- .entry-meta --> <\/p>\n<p>In some scenarios there\u2019s a need to read the request body multiple times. Some examples include<\/p>\n<ul>\n<li>Logging the raw requests to replay in load test environment<\/li>\n<li>Middleware that read the request body multiple times to process it<\/li>\n<\/ul>\n<p>Usually <code>Request.Body<\/code> does not support rewinding, so it can only be read once. A straightforward solution is to save a copy of the stream in another stream that supports seeking so the content can be read multiple times from the copy.<\/p>\n<p>In ASP.NET framework it was possible to read the body of an HTTP request multiple times using <a href=\"https:\/\/docs.microsoft.com\/en-us\/dotnet\/api\/system.web.httprequest.getbufferedinputstream?view=netframework-4.7.2\"><code>HttpRequest.GetBufferedInputStream<\/code> method<\/a>. However, in ASP.NET Core a different approach must be used.<\/p>\n<p>In ASP.NET Core 2.1 we added <a href=\"https:\/\/docs.microsoft.com\/en-us\/dotnet\/api\/microsoft.aspnetcore.http.httprequestrewindextensions.enablebuffering?view=aspnetcore-2.1\">an extension method <code>EnableBuffering()<\/code><\/a> for <code>HttpRequest<\/code>. This is the suggested way to enable request body for multiple reads. Here is an example usage in the <code>InvokeAsync()<\/code> method of a custom ASP.NET middleware:<\/p>\n<pre><code class=\"csharp\">public async Task InvokeAsync(HttpContext context, RequestDelegate next)\n{ context.Request.EnableBuffering(); \/\/ Leave the body open so the next middleware can read it. using (var reader = new StreamReader( context.Request.Body, encoding: Encoding.UTF8, detectEncodingFromByteOrderMarks: false, bufferSize: bufferSize, leaveOpen: true)) { var body = await reader.ReadToEndAsync(); \/\/ Do some processing with body\u2026 \/\/ Reset the request body stream position so the next middleware can read it context.Request.Body.Position = 0; } \/\/ Call the next delegate\/middleware in the pipeline await next(context);\n}\n<\/code><\/pre>\n<p>The backing <code>FileBufferingReadStream<\/code> uses memory stream of a certain size first then falls back to a temporary file stream. By default the size of the memory stream is 30KB. There are also other <code>EnableBuffering()<\/code> overloads that allow specifying a different threshold, and\/or a limit for the total size:<\/p>\n<pre><code class=\"csharp\">public static void EnableBuffering(this HttpRequest request, int bufferThreshold) public static void EnableBuffering(this HttpRequest request, long bufferLimit) public static void EnableBuffering(this HttpRequest request, int bufferThreshold, long bufferLimit)\n<\/code><\/pre>\n<p>For example, a call of<\/p>\n<pre><code class=\"csharp\">context.Request.EnableBuffering(bufferThreshold: 1024 * 45, bufferLimit: 1024 * 100);\n<\/code><\/pre>\n<p>enables a read buffer with limit of 100KB. Data is buffered in memory until the content exceeds 45KB, then it\u2019s moved to a temporary file. By default there\u2019s no limit on the buffer size but if there\u2019s one specified and the content of request body exceeds the limit, an <code>System.IOException<\/code> will be thrown.<\/p>\n<p>These overloads offer flexibility if there\u2019s a need to fine-tune the buffering behaviors. Just keep in mind that:<\/p>\n<ul>\n<li>Even though the memory stream is rented from a pool, it still has memory cost associated with it.<\/li>\n<li>After the read is over the <code>bufferThreshold<\/code> the performance will be slower since a file stream will be used.<\/li>\n<\/ul>\n<div class=\"authorinfoarea\">\n<div><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.sickgaming.net\/blog\/wp-content\/uploads\/2019\/03\/re-reading-asp-net-core-request-bodies-with-enablebuffering-1.jpg\" width=\"96\" height=\"96\" alt=\"Avatar\" class=\"avatar avatar-96 wp-user-avatar wp-user-avatar-96 photo avatar-default\"><\/div>\n<div>\n<h5><a class=\"no-underline\" aria-label=\"Jeremy Meng\" target=\"_blank\" href=\"https:\/\/devblogs.microsoft.com\/aspnet\/author\/yumengmicrosoft-com\/\" rel=\"noopener noreferrer\">Jeremy Meng<\/a><\/h5>\n<p>Software Development Engineer<\/p>\n<p><strong>Follow Jeremy<\/strong>&nbsp;&nbsp;&nbsp;<a class=\"no-underline stayinformed hvr-pop\" aria-label=\"Jeremy Meng RSS Feed\" target=\"_blank\" href=\"https:\/\/devblogs.microsoft.com\/aspnet\/author\/yumengmicrosoft-com\/feed\/\" rel=\"noopener noreferrer\"><\/a><\/p>\n<p> &lt;!&#8211;<\/p>\n<hr class=\"authorarea\">&#8211;&gt; <\/div>\n<\/p><\/div>\n","protected":false},"excerpt":{"rendered":"<p>Jeremy March 27th, 2019 &lt;!&#8211;Posted on March 27, 2019 by Jeremy Meng&#8211;&gt; In some scenarios there\u2019s a need to read the request body multiple times. Some examples include Logging the raw requests to replay in load test environment Middleware that read the request body multiple times to process it Usually Request.Body does not support rewinding, [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":90981,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[66,1],"tags":[102],"class_list":["post-90980","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-microsoft-webdev","category-uncategorized","tag-uncategorized"],"_links":{"self":[{"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/posts\/90980","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/comments?post=90980"}],"version-history":[{"count":0,"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/posts\/90980\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/media\/90981"}],"wp:attachment":[{"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/media?parent=90980"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/categories?post=90980"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/tags?post=90980"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}