How to gzip static content in ASP.NET Core in a self host environment - asp.net-core

Is there are way to serve gzip static cotent when using self host environment to publish an ASP.NET Core website?

[Edit 2016-11-13]
There is another way to serve gzipped files that replaces steps 2 and 3. It's basically quite the same idea, but there is a nuget package that does it all for you readily available. It basically checks if the is .gz or .br file that matches the requested one. If it exists it returns it with the appropriate headers. It does verify that the request has a header for the corresponding algorithm. Github code if you want to compile it yourself is here.
There is also an issue to support that in the official repository, so I really hope Microsoft will have the standard plugin to do that, since it's rather common and logical to use that nowadays.
I think I have found the most optimized way of serving the compressed content. The main idea is to pre-compress the files and since the default ASP.NET 5 way is to use gulp to build js, it is as easy to do as this:
1. Add a gulp step to gzip the bundled libraries:
gulp.task("buildApplication:js", function () {
return gulp.src(...)
...
.pipe(gzip())
...
});
This will produce something like libraries.js.gz in your bundles folder
2. Refernce the libraries.js.gz instead of libraries.js in the cshtml file
3. Amend the static file handler to fix the returned headers
We need to add Content-Encoding and change the Content-Type from default application/x-gzip to application/javascript because not all browsers are smart enough to read js properly from x-gzip
app.UseStaticFiles(new StaticFileOptions
{
OnPrepareResponse = context =>
{
if (headers.ContentType.MediaType == "application/x-gzip")
{
if (context.File.Name.EndsWith("js.gz"))
{
headers.ContentType = new MediaTypeHeaderValue("application/javascript");
}
else if (context.File.Name.EndsWith("css.gz"))
{
headers.ContentType = new MediaTypeHeaderValue("text/css");
}
context.Context.Response.Headers.Add("Content-Encoding", "gzip");
}
}
});
Now all there is no CPU cycles to waste to gzip the same content all the time and it's the best possible performance in serving the files. To improve it even further all of js has to be bunlded and minified before gzipping. Another upgrade is to set CacheControl max age in the same OnPrepareResponse to cache for one year and add asp-append-version="true" in the cshtml.
P.S. If you will host behind IIS you might need to turn off the static compression of js and css not to double compress, I am not sure how it will behave in this situation.

This is a fixed version of method 3 from Ilyas answer that works with ASP.NET Core 1 RTM, and it serves pre-zipped javascript files:
app.UseStaticFiles(new StaticFileOptions
{
OnPrepareResponse = context =>
{
IHeaderDictionary headers = context.Context.Response.Headers;
string contentType = headers["Content-Type"];
if (contentType == "application/x-gzip")
{
if (context.File.Name.EndsWith("js.gz"))
{
contentType = "application/javascript";
}
else if (context.File.Name.EndsWith("css.gz"))
{
contentType = "text/css";
}
headers.Add("Content-Encoding", "gzip");
headers["Content-Type"] = contentType;
}
}
});

#Ilya's Answer is very good but here are two alternatives if you are not using Gulp.
ASP.NET Core Response Compression Middleware
In the ASP.NET Core BasicMiddlware repository, you can find (at time of writing) a pull request (PR) for Response Compression Middleware. You can download the code and add it to you IApplicationBuilder like so (at time of writing):
public void Configure(IApplicationBuilder app)
{
app.UseResponseCompression(
new ResponseCompressionOptions()
{
MimeTypes = new string[] { "text/plain" }
});
// ...Omitted
}
IIS (Internet Information Server)
IIS (Internet Information Server) has a native static file module that is independent of the ASP.NET static file middleware components that you’ve learned about in this article. As the ASP.NET modules are run before the IIS native module, they take precedence over the IIS native module. As of ASP.NET Beta 7, the IIS host has changed so that requests that are not handled by ASP.NET will return empty 404 responses instead of allowing the IIS native modules to run. To opt into running the IIS native modules, add the following call to the end of Startup.Configure.
public void Configure(IApplicationBuilder app)
{
// ...Omitted
// Enable the IIS native module to run after the ASP.NET middleware components.
// This call should be placed at the end of your Startup.Configure method so that
// it doesn't interfere with other middleware functionality.
app.RunIISPipeline();
}
Then in your Web.config use the following settings to turn on GZIP compression (Note that I included some extra lines to compress things like .json files which are otherwise left uncompressed by IIS):
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<!-- httpCompression - GZip compress static file content. Overrides the server default which only compresses static
files over 2700 bytes. See http://zoompf.com/blog/2012/02/lose-the-wait-http-compression and
http://www.iis.net/configreference/system.webserver/httpcompression -->
<!-- minFileSizeForComp - The minimum file size to compress. -->
<httpCompression directory="%SystemDrive%\inetpub\temp\IIS Temporary Compressed Files" minFileSizeForComp="1024">
<scheme name="gzip" dll="%Windir%\system32\inetsrv\gzip.dll" />
<dynamicTypes>
<add mimeType="text/*" enabled="true" />
<add mimeType="message/*" enabled="true" />
<add mimeType="application/x-javascript" enabled="true" />
<!-- Compress XML files -->
<add mimeType="application/xml" enabled="true" />
<!-- Compress JavaScript files -->
<add mimeType="application/javascript" enabled="true" />
<!-- Compress JSON files -->
<add mimeType="application/json" enabled="true" />
<!-- Compress SVG files -->
<add mimeType="image/svg+xml" enabled="true" />
<!-- Compress RSS feeds -->
<add mimeType="application/rss+xml" enabled="true" />
<!-- Compress Atom feeds -->
<add mimeType="application/atom+xml" enabled="true" />
<add mimeType="*/*" enabled="false" />
</dynamicTypes>
<staticTypes>
<add mimeType="text/*" enabled="true" />
<add mimeType="message/*" enabled="true" />
<add mimeType="application/x-javascript" enabled="true" />
<add mimeType="application/atom+xml" enabled="true" />
<add mimeType="application/xaml+xml" enabled="true" />
<!-- Compress ICO icon files (Note that most .ico files are uncompressed but there are some that can contain
PNG compressed images. If you are doing this, remove this line). -->
<add mimeType="image/x-icon" enabled="true" />
<!-- Compress XML files -->
<add mimeType="application/xml" enabled="true" />
<add mimeType="application/xml; charset=UTF-8" enabled="true" />
<!-- Compress JavaScript files -->
<add mimeType="application/javascript" enabled="true" />
<!-- Compress JSON files -->
<add mimeType="application/json" enabled="true" />
<!-- Compress SVG files -->
<add mimeType="image/svg+xml" enabled="true" />
<!-- Compress EOT font files -->
<add mimeType="application/vnd.ms-fontobject" enabled="true" />
<!-- Compress TTF font files - application/font-ttf will probably be the new correct MIME type. IIS still uses application/x-font-ttf. -->
<!--<add mimeType="application/font-ttf" enabled="true" />-->
<add mimeType="application/x-font-ttf" enabled="true" />
<!-- Compress OTF font files - application/font-opentype will probably be the new correct MIME type. IIS still uses font/otf. -->
<!--<add mimeType="application/font-opentype" enabled="true" />-->
<add mimeType="font/otf" enabled="true" />
<!-- Compress RSS feeds -->
<add mimeType="application/rss+xml" enabled="true" />
<add mimeType="application/rss+xml; charset=UTF-8" enabled="true" />
<add mimeType="*/*" enabled="false" />
</staticTypes>
</httpCompression>
<!-- Enable gzip and deflate HTTP compression. See http://www.iis.net/configreference/system.webserver/urlcompression
doDynamicCompression - enables or disables dynamic content compression at the site, application, or folder level.
doStaticCompression - enables or disables static content compression at the site, application, or folder level.
dynamicCompressionBeforeCache - specifies whether IIS will dynamically compress content that has not been cached.
When the dynamicCompressionBeforeCache attribute is true, IIS dynamically compresses
the response the first time a request is made and queues the content for compression.
Subsequent requests are served dynamically until the compressed response has been
added to the cache directory. Once the compressed response is added to the cache
directory, the cached response is sent to clients for subsequent requests. When
dynamicCompressionBeforeCache is false, IIS returns the uncompressed response until
the compressed response has been added to the cache directory.
Note: This is set to false in Debug mode to enable Browser Link to work when debugging.
The value is set to true in Release mode (See web.Release.config).-->
<urlCompression doDynamicCompression="true" doStaticCompression="true" dynamicCompressionBeforeCache="false" />
</system.webServer>
</configuration>

You could implement an action filter that compresses the contents of the response if the client supports it.
Here is an example from MVC5. You should be able to modify that to work with MVC 6:
http://www.erwinvandervalk.net/2015/02/enabling-gzip-compression-in-webapi-and.html

Related

Filepond http uploading files IIS server setup problem 405

I'm trying to get a uploading script running, filepond, uploading files through webpage. On IIS10, on co-located server.
When uploading, using POST, I get the following error:
HTTP Error 405.0 - Method Not Allowed
The page you are looking for cannot be displayed because an invalid method (HTTP verb) is being used.
in details:
Module DirectoryListingModule
Notification ExecuteRequestHandler
Handler StaticFile
Error Code 0x80070001
Requested URL https://www.example.com:443/upl/files/
Physical Path W:\www.example.com\www\upl\files\
Logon Method Anonymous
Logon User Anonymous
Request Tracing Directory C:\inetpub\logs\FailedReqLogFiles
port 443 is open.
The folder has the following web.config:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<handlers accessPolicy="Read, Write, Execute, Script">
<remove name="StaticFile" />
<add name="StaticFile" path="*" verb="GET,HEAD,POST,DEBUG" modules="StaticFileModule,DefaultDocumentModule,DirectoryListingModule" resourceType="Either" requireAccess="Write" />
</handlers>
</system.webServer>
</configuration>
The folder has the following attributes:
IIS > site > folder > configuration Editor > system.webServer/handlers
FROM SITE/upl/files Web.config > accesPolicy: Read, Write, Execute, Script
FROM SITE/upl Web.config > accesPolicy: Read, Execute, Script (no solution when adding "Write")
FROM ApplicationHost.config accesPolicy: "Read, Execute, Script"
Athentication: Anonymous Athentication status enabled, rest disabled
Handler Mappings > Static File
Path: *, State: enabled,
PathType: File or Folder,
Handler: StaticFileModule,DefaultDocumentModule,DirectoryListingModule,
Entry Type: Local
EDIT > Request Restrictions > Mapping : selected Invoke handler only if request is mapped to File or folder, Verbs: GET,HEAD,POST,DEBUG,
Access: Write ( I dont understant why there is no Read/Write option, only read / write / script / execute )
Properties > security >
even when giving full control on that folder to Everyone + IUSR + IIS_IUSRS + Users : still same error.
I did notice in Handler Mappings there is no *.js record.
In Handler Mappings changing the *.asp > edit > "file" to "file and folder" had no effect either.
Jic: I could not find Filepond using a temp folder that I forgot to give acces rights to.
Jic; these are my present FilePond server settings:
FilePond.setOptions({
server: {
url: 'https://www.example.com/upl/',
timeout: 3000,
process: {
url: 'files/',
method: 'POST',
headers: {
'x-customheader': 'Hello World',
},
withCredentials: false,
onload: (response) => response.key,
onerror: (response) => response.data,
ondata: (formData) => {
formData.append('Hello', 'World');
return formData;
},
},
revert: './revert',
restore: './restore/',
load: './load/',
fetch: './fetch/',
}
});
I looked at all the previous answers here and elsewhere for over a day now, but seem to miss a tiny vital thing. Any help is very much appreciated !!
Alex
------------ replying to Samwu:
Thank you for helping.
The above represents most of the solutions I looked at.
I followed the link, found this earlier and here are some findings:
the client makes a Hypertext Transfer Protocol (HTTP) request by using an HTTP method that doesn't comply with the HTTP specifications.
In the ApplicationHost.config file, Make sure that all the handlers use valid HTTP methods.
from my applicationHost.config:
<handlers accessPolicy="Read, Execute, Script">
<add name="ASPClassic" path="*.asp" verb="GET,HEAD,POST" modules="IsapiModule" scriptProcessor="%windir%\system32\inetsrv\asp.dll" resourceType="File" />
<add name="StaticFile" path="*" verb="GET,POST" modules="StaticFileModule,DefaultDocumentModule,DirectoryListingModule" resourceType="Either" requireAccess="Write" />
</handlers>
<sectionGroup name="webdav">
<section name="globalSettings" overrideModeDefault="Deny" />
<section name="authoring" overrideModeDefault="Deny" />
<section name="authoringRules" overrideModeDefault="Deny" />
</sectionGroup>
all the modules are stated in applicationHost.config modules
I did notice however something: in the www root there is a web.config that says:
<remove name="ASPClassic" />
<remove name="StaticFile" />
<add name="StaticFile" path="*" verb="GET,HEAD,POST,DEBUG" modules="StaticFileModule,DefaultDocumentModule,DirectoryListingModule" resourceType="Either" requireAccess="Script" />
<add name="ASPClassic" path="*.asp" verb="GET,HEAD,POST" modules="IsapiModule" scriptProcessor="%windir%\system32\inetsrv\asp.dll" resourceType="Either" requireAccess="Script" />
</handlers>
in the upl / files / dir there is a webconfig saying:
<system.webServer>
<handlers accessPolicy="Read, Write, Execute, Script">
<remove name="StaticFile" />
<add name="StaticFile" path="*" verb="GET,HEAD,POST,DEBUG" modules="StaticFileModule,DefaultDocumentModule,DirectoryListingModule" resourceType="Either" requireAccess="Write" />
</handlers>
</system.webServer>
notice the " requireAccess="Script" instead of Write
"Send the POST request to a page that's configured to be handled by a handler other than the StaticFile handler. For example, the ASPClassic handler. "
I assume that if my filepond js module is included in a .asp page that this is what I am all ready doing.
WebDav is not installed, it is still stated in the applicationHost.config. Removing that gives an error on restarting the site in IIS.
I hope that clearifies.

Partial view not found exception with asp.net core in IIS only

We are having problems with partial views after migrating to .net 5. The main page will optionally render a custom partial view to allow per-customer customizations. After migrating we are unable to render these partial views. the error message is:
InvalidOperationException: The partial view ~/Resources/Customer/Views/File.cshtml was not found. The following locations were searched: ~/Resources/Customer/Views/File.cshtml
We know the path is valid because if we rename the file the page renders (without customizations). If we debug in visual studio the page renders as expected but in a deployed IIS server it fails. We suspect there is a permissions issue but we have been unable to find it. So far we haven't been able to find anything in google searches or SO
Here is a snippet where we handle the custom file:
// load file path from config
string url = configuration.OrderPageSetting["OrderInfoViewRenderFile"];
bool exists = false;
// determine the path
if (!string.IsNullOrWhiteSpace(url))
{
string _url = url;
if (_url.StartsWith("~/")) _url = _url.Substring(2);
else if (_url.StartsWith("/")) _url = _url.Substring(1);
exists = System.IO.File.Exists(System.IO.Path.Combine(Resource.SystemDirectory, _url));
}
// test for and render custom view
if (exists)
{
var data = new ViewDataDictionary<object>(new EmptyModelMetadataProvider(), new ModelStateDictionary());
data.Add("Order", order);
data.Add("Config", configuration);
await Html.RenderPartialAsync(url, data);
}
else
{
... default rendering ...
}
The application is hosted in a virtual directory with a dedicated application pool. This problem occurs without a web.config at the site level. On the same server, the prior .net framework version of the application works correctly.
here is the applications web.config:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<location path="." inheritInChildApplications="false">
<system.webServer>
<handlers>
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" />
</handlers>
<aspNetCore processPath="dotnet" arguments=".\myapp.dll" stdoutLogEnabled="false" hostingModel="InProcess" stdoutLogFile=".\logs\stdout">
<environmentVariables>
<environmentVariable name="ASPNETCORE_ENVIRONMENT" value="Development" />
</environmentVariables>
</aspNetCore>
</system.webServer>
</location>
</configuration>
A co-worker found the solution the problem, the clue was in https://weblog.west-wind.com/posts/2019/Sep/30/Serving-ASPNET-Core-Web-Content-from-External-Folders
There were 2 changes required:
Add package: Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation
called extension to support runtime complication on the controllers/views:
services.AddControllersWithViews().AddRazorRuntimeCompilation(opt =>
{
opt.FileProviders.Add(
new PhysicalFileProvider(System.IO.Path.Combine(Environment.ContentRootPath, ""))
);
})
if you want to change where the dynamic compilation is supported, simply change the "" to the path where it is permitted.

Remove response Server header on Azure Web App from the first redirect request to HTTPS

I’m trying to remove the response Server header from an Azure Web App ( with an ASP Net core application )
After many tries of changing the web.config and removing the header in app code using a middleware, Microsoft doesn’t give up and set the response header to Server: Microsoft-IIS/10.0 :)
The problem appears only when I’m trying to access the server on http (not https). Response code from the server is 301, and this is the only response that has the Server header.
Checking the logs I was not able to find any request to http://, and perhaps this is why I’m not able to remove header, because the request is not process in my application code.
A solution that I’m thinking is to disable the azure HTTPS only and do the redirect to https in my code (I tested and is working - server header is removed)
Is there another workaround without disabling the HTTPS only option?
Here is what I tried
Startup.cs
public void Configure(IApplicationBuilder app)
{
app.Use(async (context, next) =>
{
context.Response.Headers.Add("server", string.Empty)
}
app.UseHttpsRedirection();
}
web.config
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.web>
<httpRuntime enableVersionHeader="false" />
<!-- Removes ASP.NET version header. -->
</system.web>
<system.webServer>
<httpProtocol>
<customHeaders>
<remove name="Server" />
<remove name="X-Powered-By" />
</customHeaders>
<redirectHeaders>
<clear />
</redirectHeaders>
</httpProtocol>
<security>
<requestFiltering removeServerHeader="true" />
<!-- Removes Server header in IIS10 or later and also in Azure Web Apps -->
</security>
<rewrite>
<outboundRules>
<rule name="Change Server Header"> <!-- if you're not removing it completely -->
<match serverVariable="RESPONSE_Server" pattern=".+" />
<action type="Rewrite" value="Unknown" />
</rule>
</outboundRules>
</rewrite>
</system.webServer>
</configuration>
UPDATE
When the URL of http:// is requested, IIS will process it, this time without code. So we can't control it by the code, we can only set it on the server, such as some scripts or tools. But on Azure, we have no way to directly operate as a physical server, so after exploration, I suggest that Front Door can be used to deal with this problem. Hiding server information through proxy should be a better way.
After my test, the server information is hidden, you can refer to this document . We can see from the picture that there is no 301 redirect request, and no server information in other requests.
PREVIOUS
You need to modify Global.asax.cs and Web.config file in your program.
In Global.asax.cs.
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
MvcHandler.DisableMvcResponseHeader = true;
PreSendRequestHeaders += Application_PreSendRequestHeaders;
}
protected void Application_PreSendRequestHeaders(object sender, EventArgs e)
{
//HttpContext.Current.Response.Headers.Remove("Server");
HttpContext.Current.Response.Headers.Set("Server","N/A");
}
}
And In Web.config.
<system.webServer>
<modules runAllManagedModulesForAllRequests="true" >
</modules>
<httpProtocol>
<customHeaders>
<remove name="X-Powered-By" />
</customHeaders>
</httpProtocol>
</system.webServer>
Then u can deploy your app. After the above code modification, access to the interface or static resources can see that the server information is modified, of course, it can also be deleted by Remove.
You also can handle special event by http status code.
protected void Application_PreSendRequestHeaders(object sender, EventArgs e)
{
//HttpContext.Current.Response.Headers.Remove("Server");
int StatusCode= HttpContext.Current.Response.StatusCode;
// handle like http status code 301
HttpContext.Current.Response.Headers.Set("Server","N/A");
}

How to increase the upload file size limit in ASP.NET core 2.1 project? [duplicate]

Currently, I am working with Asp.Net Core and MVC6 need to upload file size unlimited. I have searched its solution but still not getting the actual answer.
I have tried this link
If anyone have any idea please help.
Thanks.
The other answers solve the IIS restriction. However, as of ASP.NET Core 2.0, Kestrel server also imposes its own default limits.
Github of KestrelServerLimits.cs
Announcement of request body size limit and solution (quoted below)
MVC Instructions
If you want to change the max request body size limit for a specific MVC action or controller, you can use the RequestSizeLimit attribute. The following would allow MyAction to accept request bodies up to 100,000,000 bytes.
[HttpPost]
[RequestSizeLimit(100_000_000)]
public IActionResult MyAction([FromBody] MyViewModel data)
{
[DisableRequestSizeLimit] can be used to make request size unlimited. This effectively restores pre-2.0.0 behavior for just the attributed action or controller.
Generic Middleware Instructions
If the request is not being handled by an MVC action, the limit can still be modified on a per request basis using the IHttpMaxRequestBodySizeFeature. For example:
app.Run(async context =>
{
context.Features.Get<IHttpMaxRequestBodySizeFeature>().MaxRequestBodySize = 100_000_000;
MaxRequestBodySize is a nullable long. Setting it to null disables the limit like MVC's [DisableRequestSizeLimit].
You can only configure the limit on a request if the application hasn’t started reading yet; otherwise an exception is thrown. There’s an IsReadOnly property that tells you if the MaxRequestBodySize property is in read-only state, meaning it’s too late to configure the limit.
Global Config Instructions
If you want to modify the max request body size globally, this can be done by modifying a MaxRequestBodySize property in the callback of either UseKestrel or UseHttpSys. MaxRequestBodySize is a nullable long in both cases. For example:
.UseKestrel(options =>
{
options.Limits.MaxRequestBodySize = null;
or
.UseHttpSys(options =>
{
options.MaxRequestBodySize = 100_000_000;
You're probably getting a 404.13 HTTP status code when you upload any file over 30MB. If you're running your ASP.Net Core application in IIS, then the IIS pipeline is intercepting your request before it hits your application.
Update your web.config:
<system.webServer>
<handlers>
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified"/>
</handlers>
<aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" forwardWindowsAuthToken="false"/>
<!-- Add this section for file size... -->
<security>
<requestFiltering>
<!-- Measured in Bytes -->
<requestLimits maxAllowedContentLength="1073741824" /> <!-- 1 GB-->
</requestFiltering>
</security>
</system.webServer>
Previous ASP.Net applications also needed this section, but it's not needed anymore in Core as your requests are handled by middleware:
<system.web>
<!-- Measured in kilobytes -->
<httpRuntime maxRequestLength="1048576" />
</system.web>
Maybe I am late here but here is the complete solution for uploading a file with a size of more than 30.0 MB in ASP.NET Core Version >=2.0:
You need to do the following three steps:
1. IIS content length limit
The default request limit (maxAllowedContentLength) is 30,000,000 bytes, which is approximately 28.6 MB. Customize the limit in the web.config file:
<system.webServer>
<security>
<requestFiltering>
<!-- Handle requests up to 1 GB -->
<requestLimits maxAllowedContentLength="1073741824" />
</requestFiltering>
</security>
</system.webServer>
Note: without this application running on IIS would not work.
2. ASP.NET Core Request length limit
For application running on IIS:
services.Configure<IISServerOptions>(options =>
{
options.MaxRequestBodySize = int.MaxValue;
});
For application running on Kestrel:
services.Configure<KestrelServerOptions>(options =>
{
options.Limits.MaxRequestBodySize = int.MaxValue; // if don't set default value is: 30 MB
});
3. Form's MultipartBodyLengthLimit
services.Configure<FormOptions>(options =>
{
options.ValueLengthLimit = int.MaxValue;
options.MultipartBodyLengthLimit = int.MaxValue; // if don't set default value is: 128 MB
options.MultipartHeadersLengthLimit = int.MaxValue;
});
Adding all the above options will solve the problem related to the file upload with a size of more than 30.0 MB.
In ASP.NET Core 1.1 project that created by Visual Studio 2017, if you want to increase upload file size. You need to create web.config file by yourself, and add these content:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<security>
<requestFiltering>
<!-- 1 GB -->
<requestLimits maxAllowedContentLength="1073741824" />
</requestFiltering>
</security>
</system.webServer>
</configuration>
In Startup.cs file, add these content:
public void ConfigureServices(IServiceCollection services)
{
services.Configure<FormOptions>(x =>
{
x.ValueLengthLimit = int.MaxValue;
x.MultipartBodyLengthLimit = int.MaxValue;
x.MultipartHeadersLengthLimit = int.MaxValue;
});
services.AddMvc();
}
In your startup.cs configure FormsOptions Http Feature:
public void ConfigureServices(IServiceCollection services)
{
services.Configure<FormOptions>(o => // currently all set to max, configure it to your needs!
{
o.ValueLengthLimit = int.MaxValue;
o.MultipartBodyLengthLimit = long.MaxValue; // <-- !!! long.MaxValue
o.MultipartBoundaryLengthLimit = int.MaxValue;
o.MultipartHeadersCountLimit = int.MaxValue;
o.MultipartHeadersLengthLimit = int.MaxValue;
});
}
UseIHttpMaxRequestBodySizeFeature Http Feature to configure MaxRequestBodySize
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.Use(async (context, next) =>
{
context.Features.Get<IHttpMaxRequestBodySizeFeature>().MaxRequestBodySize = null; // unlimited I guess
await next.Invoke();
});
}
Kestrel:
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>().UseKestrel(o => o.Limits.MaxRequestBodySize = null);
});
IIS --> web.config:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.web>
<!-- ~ 2GB -->
<httpRuntime maxRequestLength="2147483647" /> // kbytes
</system.web>
<system.webServer>
<security>
<requestFiltering>
<!-- ~ 4GB -->
<requestLimits maxAllowedContentLength="4294967295" /> // bytes
</requestFiltering>
</security>
</system.webServer>
</configuration>
Http.sys:
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>().UseHttpSys(options =>
{
options.MaxRequestBodySize = null;
});
});
If you want to upload a very large file, potentially several GB large and you want to buffer it into a `MemoryStream` on the server, you will get an error message `Stream was too long`, because the capacity of the `MemoryStream` is `int.MaxValue`.
You would ahve to implement your own custom MemoryStream class.
But anyway, buffering such large files makes no sense.
Using a web.config might compromise the architecture of .NET core and you might face problem while deploying the solution on Linux or on Mac.
Better is to use the Startup.cs for configuring this setting: Ex:
services.Configure<FormOptions>(x =>
{
x.ValueLengthLimit = int.MaxValue;
x.MultipartBodyLengthLimit = int.MaxValue; // In case of multipart
});
Here is a correction:
You need to add web.config as well because when the request hits the IIS then it will search for the web.config and will check the maxupload length: sample :
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<security>
<requestFiltering>
<!-- 1 GB -->
<requestLimits maxAllowedContentLength="1073741824" />
</requestFiltering>
</security>
In my case, I needed to increase the file upload size limit, but for a single page only.
The file upload size limit is a security feature, and switching it off or increasing it globally often isn't a good idea. You wouldn't want some script kiddie DOSing your login page with extremely large file uploads. This file upload limit gives you some protection against that, so switching it off or increasing it globally isn't always a good idea.
So, to increase the limit for a single page instead of globally:
(I am using ASP.NET MVC Core 3.1 and IIS, Linux config would be different)
1. Add a web.config
otherwise IIS (or IIS Express, if debugging in Visual Studio) will block the request with a "HTTP Error 413.1 - Request Entity Too Large" before it even reaches your code.
Note the "location" tag, which restricts the upload limit to a specific page
You will also need the "handlers" tag, otherwise you will get a HTTP 404 error when browsing to that path
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<location path="SomeController/Upload">
<system.webServer>
<handlers>
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" />
</handlers>
<security>
<requestFiltering>
<!--unit is bytes => 500 Mb-->
<requestLimits maxAllowedContentLength="524288000" />
</requestFiltering>
</security>
</system.webServer>
</location>
</configuration>
Next you will need to add the RequestSizeLimit attribute to your controller action, since Kestrel has its own limits too.
(you can instead do it via middleware as per other answers if you prefer)
[HttpPost]
[RequestSizeLimit(500 * 1024 * 1024)] //unit is bytes => 500Mb
public IActionResult Upload(SomeViewModel model)
{
//blah blah
}
and for completeness (if using MVC), your view and view model could look like this:
view
<form method="post" enctype="multipart/form-data" asp-controller="SomeController" asp-action="Upload">
<input type="file" name="#Model.File" />
</form>
View Model
public class SomeViewModel
{
public IFormFile File { get; set; }
}
and, if you are uploading files greater than 128Mb via form post, you may run in to this error too
InvalidDataException: Multipart body length limit 134217728 exceeded.
So on your controller action you could add the RequestFormLimits attribute
[HttpPost]
[RequestSizeLimit(500 * 1024 * 1024)] //unit is bytes => 500Mb
[RequestFormLimits(MultipartBodyLengthLimit = 500 * 1024 * 1024)]
public IActionResult Upload(SomeViewModel model)
{
//blah blah
}
In your web.config:
<system.webServer>
<security>
<requestFiltering>
<requestLimits maxAllowedContentLength="2147483648" />
</requestFiltering>
</security>
</system.webServer>
Manually edit the ApplicationHost.config file:
Click Start. In the Start Search box, type Notepad. Right-click Notepad, and then click "Run as administrator".
On the File menu, click Open. In the File name box, type "%windir%\system32\inetsrv\config\applicationhost.config", and then click Open.
In the ApplicationHost.config file, locate the <requestLimits> node.
Remove the maxAllowedContentLength property. Or, add a value that matches the size of the Content-Length header that the client sends as part of the request. By default, the value of the maxAllowedContentLength property is 30000000.
Save the ApplicationHost.config file.
I will add this for completeness for other unlucky lads like me that ended up here, Source
In Startup.cs:
services.Configure<FormOptions>(options =>
{
options.MultipartBodyLengthLimit = 60000000;
});
Using Visual Studio 2022 (v 17.1.6) and .net core 6, I did not need to change anything in the Program.cs class. I only needed to add these two attributes (in addition to [HttpPost] and [Route]) to my controller method while running locally to accept a 100MB upload:
[RequestSizeLimit(100 * 1024 * 1024)]
[RequestFormLimits(MultipartBodyLengthLimit = 100 * 1024 * 1024)]
If you have scrolled down this far, that means you have tried above solutions. If you are using latest NET CORE versions (5.., 6..) and using IIS for hosting do this.
Add the web.config file to your project and then add the following code there:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<security>
<requestFiltering>
<!-- Handle requests up to 1 GB -->
<requestLimits maxAllowedContentLength="1073741824" />
</requestFiltering>
</security>
</system.webServer>
</configuration>
Set up the Form Options and IIS Server Options in your Startup.cs file like this:
services.Configure<IISServerOptions>(options =>
{
options.MaxRequestBodySize = int.MaxValue;
});
services.Configure<FormOptions>(o =>
{
o.ValueLengthLimit = int.MaxValue;
o.MultipartBodyLengthLimit = int.MaxValue;
o.MultipartBoundaryLengthLimit = int.MaxValue;
o.MultipartHeadersCountLimit = int.MaxValue;
o.MultipartHeadersLengthLimit = int.MaxValue;
o.BufferBodyLengthLimit = int.MaxValue;
o.BufferBody = true;
o.ValueCountLimit = int.MaxValue;
});
I was trying to upload a big file but somehow the file wasn't reaching the controller action method and the parameters including the file one was still null like this:
[HttpPost]
public async Task<IActionResult> ImportMedicalFFSFile(
Guid operationProgressID,
IFormFile file, // <= getting null here
DateTime lastModifiedDate)
{
...
}
What fixed it was adding the [DisableRequestSizeLimit] attribute to the action method or the entire controller\BaseController if you prefer:
[DisableRequestSizeLimit]
public class ImportedFileController : BaseController
{
...
}
More info here:
DisableRequestSizeLimitAttribute Class

Large file (> 2gb) is not written to disk

I have a Web API 2 project which accepts file uploads. Uploading small files works pretty well, but when it comes to large files, they simply are not written to disk. It appears to me that this happens with files that are somewhere around 2 GB. Files of about 1 gb upload pretty well.
These are the relevant parts of my web.config:
<system.web>
<compilation debug="true" targetFramework="4.6.1" />
<httpRuntime targetFramework="4.6.1" maxRequestLength="2147483647" />
</system.web>
...
<system.webServer>
<handlers>
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
<security>
<requestFiltering>
<requestLimits maxAllowedContentLength="4294967295" />
</requestFiltering>
</security>
</system.webServer>
I got the values for maxAllowedContentLength and maxRequestLength from this answer.
Since I am running IIS 8 I would expect to meet the maxAllowedContentLength value.
And this is the Action responsible for handling the upload, based on this blog post by Filip W:
[HttpPost]
public async Task<HttpResponseMessage> Post()
{
//Check if the request contains multipart/form-data.
if (!Request.Content.IsMimeMultipartContent())
{
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
string uploadPath = #"C:\temp\upload"; // in reality this is retrieved from DB
try
{
var provider = new MultipartFormDataStreamProvider(uploadPath);
var content = new StreamContent(HttpContext.Current.Request.GetBufferlessInputStream(true));
foreach (var header in Request.Content.Headers)
{
content.Headers.TryAddWithoutValidation(header.Key, header.Value);
}
var result = await content.ReadAsMultipartAsync(provider);
return Request.CreateResponse(HttpStatusCode.Accepted);
}
catch(Exception e)
{
return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, e);
}
}
Uploading small files works. I see them written to c:\temp\upload. But large files are not saved, although I see them coming in (by watching Task Manager > Performance:
Does anyone have an idea why I don't see large requests saved to disk, while smaller files do get saved?