Problem:
If you want to upload large files or videos with 200 MB or 1.5 GB in asp.net core 2.1 mvc, then you quickly realize
that the upload of the form or the ajax webapi is answered with the error 404.13 or 502.3.
That's because with Asp.net Core you have to set the allowed upload limit of the standard.
Solution:
I have now a good two days looking for a solution in forums and Microsoft and finally found in a small contribution, the solution
You have to set the services.configure in the startup.cs
//--< set uploadsize large files >---- services.Configure<FormOptions>(options => { options.ValueLengthLimit = int.MaxValue; options.MultipartBodyLengthLimit = int.MaxValue; options.MultipartHeadersLengthLimit = int.MaxValue; }); //--</ set uploadsize large files >----
|
Startup.cs:
Complete startup.cs for reference
Code sample under https://Readdy.net
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Readdy.Data; using Readdy.Models; using Readdy.Services; using Microsoft.AspNetCore.Rewrite; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Features;
namespace Readdy { public class Startup {
public Startup(IHostingEnvironment env) { var builder = new ConfigurationBuilder(); builder.AddUserSecrets<Startup>();
Configuration = builder.Build(); }
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { //-----------< ConfigureServices() >----------- //Website_Constants.Connectionstring = Configuration["DefaultConnection"].ToString();
services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(Website_Constants.Connectionstring));
//--< Facebook Api >-- services.AddIdentity<ApplicationUser, IdentityRole>(config => { //< send Register Email > //*prevents registered users from logging in until their email is confirmed. config.SignIn.RequireConfirmedEmail = true; //</ send Register Email > }) .AddEntityFrameworkStores<ApplicationDbContext>() .AddDefaultTokenProviders();
services.AddAuthentication().AddFacebook(facebookOptions => { facebookOptions.AppId = Website_Constants.fp_appID; facebookOptions.AppSecret = Website_Constants.fp_secret; }); //--</ Facebook Api >--
// Add application services. services.AddTransient<IEmailSender, EmailSender>();
var optRewrite = new RewriteOptions() .AddRedirectToHttpsPermanent();
services.AddMvc();
//--< set uploadsize large files >---- services.Configure<FormOptions>(options => { options.ValueLengthLimit = int.MaxValue; options.MultipartBodyLengthLimit = int.MaxValue; options.MultipartHeadersLengthLimit = int.MaxValue; }); //--</ set uploadsize large files >----
//-----------</ ConfigureServices() >----------- }
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env) { //-----------< Configure() >-----------
if (env.IsDevelopment()) { app.UseBrowserLink(); app.UseDeveloperExceptionPage(); app.UseDatabaseErrorPage(); } else { app.UseExceptionHandler("/Home/Error"); }
#region Url_Umleitungen ////----< URL Umleitungen >---- //if (env.IsProduction()) //{ // //----< redirect http to https >---- // try // {
// app.Use(async (context, next) => // { // //*check the website-content and all elements like images // string sHost = context.Request.Host.HasValue == true ? context.Request.Host.Value : ""; //domain without :80 port .ToString(); // sHost = sHost.ToLower(); // string sPath = context.Request.Path.HasValue == true ? context.Request.Path.Value : ""; // string sQuerystring = context.Request.QueryString.HasValue == true ? context.Request.QueryString.Value : "";
// //----< check https >---- // // check if the request is *not* using the HTTPS scheme // if (!context.Request.IsHttps) // { // //--< is http >-- // string new_https_Url = "https://" + sHost; // if (sPath != "") // { // new_https_Url = new_https_Url + sPath; // } // if (sQuerystring != "") // { // new_https_Url = new_https_Url + sQuerystring; // } // context.Response.Redirect(new_https_Url);
// return; // //--</ is http >-- // } // //----</ check https >----
// //----< check www >---- // if (sHost.IndexOf("www.") == 0) // { // //--< is www. >-- // string new_Url_without_www = "https://" + sHost.Replace("www.", ""); // if (sPath != "") // { // new_Url_without_www = new_Url_without_www + sPath; // } // if (sQuerystring != "") // { // new_Url_without_www = new_Url_without_www + sQuerystring; // } // context.Response.Redirect(new_Url_without_www);
// return; // //--</ is http >-- // } // //----</ check www >----
// //also check images inside the content // await next(); // });
// } // catch (Exception) // {
// //throw; // } // //----< redirect http to https >----
// //----< redirecturl >---- // try // {
// app.Use(async (context, next) => // { // string sHost = context.Request.Host.HasValue == true ? context.Request.Host.Value : ""; //domain without :80 port .ToString(); // sHost = sHost.ToLower(); // string sPath = context.Request.Path.HasValue == true ? context.Request.Path.Value : "";
// if (sPath.Length > 1) // { // string sTest = sPath.Substring(1, 1); // if (int.TryParse(sTest, out int i0)) // { // string sNr_Test = sPath.Substring(1); // long PathNr; // if (long.TryParse(sNr_Test, out PathNr)) // { // //--< path isNumeric >-- // string new_Url = "https://" + sHost + "/Notes/Details" + sPath; // context.Response.Redirect(new_Url);
// return; // //--</ path isNumeric >-- // } // } // } // //----</ check www >---- // await next(); // });
// } // catch (Exception) // {
// //throw; // } // //----< redirect url >----
// //----< DeviceSwitcher Mobile Desktop >---- // //*MobileDesktop_Parameter_to_Cookie // try // { // app.Use(async (context, next) => // { // //----< check Parameter >---- // //*Parameter ?v=ViewDevice m=Mobile oder d=Desktop // var queryParameter_DeviceSwitcher = context.Request.Query["ds"].FirstOrDefault(); // if (queryParameter_DeviceSwitcher != null) // { // //--< DeviceSwitcher >-- // //*has DeviceSwitcher as Parameter // //*sendback as cookie // CookieOptions options = new CookieOptions(); // options.Expires = DateTime.Now.AddDays(100); // context.Response.Cookies.Append("ds", queryParameter_DeviceSwitcher, options); // //--</ DeviceSwitcher >-- // } // //----</ check Parameter >----
// //also check images inside the content // await next(); // });
// } // catch (Exception) // {
// //throw; // } // //----</ DeviceSwitcher Mobile Desktop >---- //} ////----</ URL Umleitungen >----
#endregion /Url_Umleitungen
app.UseStaticFiles();
app.UseAuthentication();
app.UseMvc(routes => {
//--< Emoticons >-- routes.MapRoute( name: "🏠", template: "🏠", defaults: new { controller = "Home", action = "Index" } ); routes.MapRoute( name: "📢", template: "📢", defaults: new { controller = "Home", action = "Index" } ); routes.MapRoute( name: "📜", template: "📜", defaults: new { controller = "Notes", action = "Index_all" } ); //--</ Emoticons >--
routes.MapRoute( name: "Notes", // Route name template: "Notes", // URL with parameters defaults: new { controller = "Notes", action = "Index_all" } );
routes.MapRoute( name: "default", template: "{controller=Notes}/{action=Index_all}/{id?}");
} );
//seed dbContext Database.EF_Model.Initialize_DbContext_in_Startup(app.ApplicationServices); //-----------</ Configure() >----------- } } }
|
In the Web.config as usual the requestFiltering supplemented.
If these are missing, then the error 404 arises
<!--Limit Upload--> <!--*to 1GB=1073741824--> <security> <requestFiltering> <requestLimits maxAllowedContentLength="1073741824" /> </requestFiltering> </security> <!--/ Limit Upload-->
|
Web.config in asp.net core
If there is no web.config in the project, then you can insert a config file via project-> add
Complete web.config as code
<?xml version="1.0" encoding="utf-8"?> <configuration> <system.webServer> <aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" stdoutLogEnabled="true" stdoutLogFile=".\logs\stdout" requestTimeout="01:00:00" /> <handlers> <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified" /> </handlers>
<!--Limit Upload--> <!--*to 1GB=1073741824--> <security> <requestFiltering> <requestLimits maxAllowedContentLength="1073741824" /> </requestFiltering> </security> <!--/ Limit Upload--> </system.webServer>
</configuration>
|
program.cs
In program.cs you can set the timeouts.
.UseKestrel(options => { options.Limits.KeepAliveTimeout = TimeSpan.FromMinutes(120); options.Limits.RequestHeadersTimeout = TimeSpan.FromMinutes(120); }) |
In visual studio
Complete C # code for program.cs
using System; using Microsoft.AspNetCore; using Microsoft.AspNetCore.Hosting;
namespace Readdy { public class Program { //--------< class: Program >-------- public static void Main(string[] args) { BuildWebHost(args).Run(); }
public static IWebHost BuildWebHost(string[] args) => WebHost.CreateDefaultBuilder(args)
.UseIISIntegration() //*!! Important Asp.Net Core2 on IIS !!
//< set upload timeout > .UseKestrel(options => { options.Limits.KeepAliveTimeout = TimeSpan.FromMinutes(120); options.Limits.RequestHeadersTimeout = TimeSpan.FromMinutes(120); //options.Limits.MaxRequestBodySize = 500_000_000; //options.Limits.MaxRequestBufferSize = null; //options.Limits.MaxResponseBufferSize = null; }) //</ set upload timeout >
.UseStartup<Startup>()
.Build() ; //--------</ class: Program >-------- } }
|
Asp.Net Core MVC Controller
In the actual controller method, you can set the upload limits again specifically for this method.
For this you can put the attribute RequestSizeLimit before the method
//[DisableRequestSizeLimit] [RequestSizeLimit(500000000)] //30.000.000=28,6MB |
controller
Complete upload method in the controller as a reference
[HttpPost] [Authorize] //[DisableRequestSizeLimit] [RequestSizeLimit(500000000)] //30.000.000=28,6MB public async Task<IActionResult> Edit_Upload_Video() { // -------------< Edit_Upload_Video() > ------------- try { //------< try_upload_Video >-------- //string sFiles_uploaded = ""; List<string> response_list_of_Filenames = new List<string>();
//< get ID and SubNr > //*from Querysting like Notes/Edit_Upload_Images?IDNote=11&ImageNr=1 string sIDNote = Request.Query["IDNote"]; long IDNote = System.Convert.ToInt64(sIDNote); //</ get ID and SubNr >
//--< Get User ID >-- //internal referenz-Number for tracking in tables long IDCurrent_User = await UserInfo_Methods.getIDUser_as_Number(this.User, _dbContext); //--</ Get User ID >--
//< get_database > NoteModel note; if (IDNote == 0) { note = _dbContext.tbl_Notes.SingleOrDefault(n => n.IDUser == IDCurrent_User && n.IsDraft == true); if (note == null) { note = new NoteModel(); note.IsDraft = true; note.DtCreated = DateTime.Now; note.IDUser = IDCurrent_User; note.Title = "#"; note.sumImages = 0; note.DtEdit = DateTime.Now;
//< save > await _dbContext.tbl_Notes.AddAsync(note); //IDNote: 0->-99999 await _dbContext.SaveChangesAsync(true); //IDNote: -99999->16 //</ save >
//< new ID > IDNote = note.IDNote; //Console.WriteLine("new IDNote=" + note.IDNote); //</ new ID > } else { //< last draft > IDNote = note.IDNote; //</ last draft > } } else { note = _dbContext.tbl_Notes.SingleOrDefault(n => n.IDNote == IDNote); }
if (note == null) { return Json("NoMatch for IDNote=" + IDNote); } //</ get_database >
//< add_response > response_list_of_Filenames.Add("IDNote=" + IDNote); //</ add_response >
//< check Owner > long IDOwner = note.IDUser; if (IDOwner != IDCurrent_User) { return Content("You are not the Owner"); } //</ check Owner >
//< init > //long uploaded_size = 0; string path_for_Uploaded_Files = _hostingEnvironment.WebRootPath + "\\User_Files\\Notes\\Videos"; //</ init >
//< get form_files > //IFormFile uploaded_File var uploaded_files = Request.Form.Files; //</ get form_files >
//--< get last Image >-- //*get User Summary Table Note_Video_Model videoData = new Note_Video_Model();
//< last_Image > Note_Video_Model video = await _dbContext.tbl_Notes_Videos.Where(vid => vid.IDNote == IDNote).FirstOrDefaultAsync(); int videoNr = 0; //</ last_Image > //------< @Loop: Uploaded Files >------ foreach (var uploaded_file in uploaded_files) { //----< Uploaded File >---- try { if (uploaded_file.ContentType.IndexOf("video") == 0) //*video/mp4 { //------< Is_TypeVideo >------ string uploaded_Filename = uploaded_file.FileName; int posExtension = uploaded_Filename.LastIndexOf("."); string sExtension = uploaded_Filename.Substring(posExtension + 1); sExtension = sExtension.ToLower();
if (" .mp4 .mov".IndexOf("." + sExtension) > 0) { //----< Is_Video >----
//--< New Note_Image >-- Note_Video_Model newVideoData = new Note_Video_Model(); newVideoData.IDNote = IDNote; newVideoData.dtCreate = DateTime.Now; newVideoData.VideoNr = videoNr;
//< save ImageData > await _dbContext.tbl_Notes_Videos.AddAsync(newVideoData); await _dbContext.SaveChangesAsync(true); //</ save ImageData >
//< add_response > response_list_of_Filenames.Add("Video_" + IDNote + "_0"); //</ add_response >
//< Filename > string image_webname = "Video_" + IDNote + "_0." + sExtension; string new_FullFilename_on_Server = path_for_Uploaded_Files + "\\" + image_webname; //</ Filename >
//< Copy File to Target > if (System.IO.File.Exists(new_FullFilename_on_Server)) { System.IO.File.Delete(new_FullFilename_on_Server); } using (FileStream stream = new FileStream(new_FullFilename_on_Server, FileMode.Create)) { await uploaded_file.CopyToAsync(stream); } //</ Copy File to Target >
//----< check Properties >----
//----</ check Properties >----
if (sExtension != "mp4") { //----< IsNot_Mp4 >----
//< convert > //</ convert > //----</ IsNot_Mp4 >---- } else {
}
//----</ Is_jpg >---- } //------</ Is_TypeImage >------ } } catch (System.Exception ex) //ex { //< error > response_list_of_Filenames.Add("Error:" + ex.Message + Environment.NewLine + ex.StackTrace); //Console.WriteLine(ex.Message); //</ error > } //----</ Uploaded File >----
break; //only 1 Video } //------</ @Loop: Uploaded Files >------
//----< Save Data >---- //--< data >-- note.sumVideos = 1; note.DtEdit = DateTime.Now; //--</ data >--
try { //todo: _dbContext.Update(note); await _dbContext.SaveChangesAsync(true); } catch (DbUpdateConcurrencyException) { return Content("Update Error"); } //----</ Save Data >----
//< response > return Json(response_list_of_Filenames); //</ response >
//------</ try_upload_Video >-------- } catch (Exception ex) { //------< fail: try_upload_Video >-------- string sError = "Upload Video Error: " + ex.Message + Environment.NewLine + ex.StackTrace ; return Json(sError); //------</ fail: try_upload_Video >-------- }
// -------------</ Edit_Upload_Video() > ------------- }
|
Browser upload ajax
And then finally the calling upload video function in the browser client. in jQuery ajax upload
function editor_Upload_Video_Files() { //------< editor_Upload_Video_Files() >------
//--< get selected files >-- var fileUpload = $("#files_input_field").get(0); var files = fileUpload.files; if (files.length == 0) return;
//< status > $("#ctlProgress").css("visibility", "visible"); //</ status >
//< load into FormData > //only 1.file var data = new FormData(); data.append(files[0].name, files[0]); //</ load into FormData >
//--< ajax upload >-- $.ajax({ type: "POST", url: "/Notes/Edit_Upload_Video?IDNote=" + IDNote, xhr: function () { var xhr = new window.XMLHttpRequest(); //Upload progress xhr.upload.addEventListener("progress", function (evt) { if (evt.lengthComputable) { var percentComplete = evt.loaded / evt.total; $("#ctlProgress").val(percentComplete * 100); if (percentComplete > 0.9) { $("#ctlProgress").css("visibility", "visible"); } } }, false); //Download progress xhr.addEventListener("progress", function (evt) { if (evt.lengthComputable) { var percentComplete = evt.loaded / evt.total; //Do something with download progress console.log(percentComplete); } }, false); return xhr; },
contentType: false, //default: 'application/x-www-form-urlencoded; charset=UTF-8' processData: false, //default: data, other DOMDocument data: data, //Type: PlainObject or String or Array //jQuery 1.8 success->done error->fail success: function (json_down_data) { //----< ajax_after_Upload_Successfull() >---- $("#ctlProgress").css("visibility", "hidden");
//---< show return >--- //---< Insert Video >--- //--< Loop: each Result >-- //$.each(data, function (index, item) var arrData = json_down_data; for (var i = 0; i < arrData.length; i++) { //--< Item >-- var item = arrData[i]; if (item.indexOf("IDNote=") == 0) { //--< set ID >-- if (IDNote == "0") { IDNote = item.substring(7); document.getElementById("Note_IDNote").value = IDNote; document.getElementById("frmEdit").action = "/Notes/Edit/" + IDNote; //#todo on 0 } //--</ set ID >-- } else if (item.indexOf("Error") == 0) { //--< set ID >-- alert(item); //--</ set ID >-- } else {
if (editor_check_Video_exists(item) == false) { //--< add Image >-- var divEditor = document.getElementById("ctlEditor_HTML");
//*show uploaded Image in div-Results var br = document.createElement("br"); divEditor.insertBefore(br, divEditor.childNodes[0]);
//< create image > var video = document.createElement("video"); video.src = "/User_Files/Notes/Videos/" + item + ".mp4" video.setAttribute("width","640"); video.setAttribute("height", "480"); video.setAttribute("controls",""); //video.setAttribute("autoplay",""); video.style.width = "100%"; video.style.maxWidth = "100%"; video.style.height = "auto"; video.style.display = "block"; video.style.borderWidth = "2px"; video.style.borderColor = "black"; video.style.borderStyle = "solid"; //</ create image >
//*at position 0 divEditor.insertBefore(video, divEditor.childNodes[0]);
var ctlTitle = document.getElementById("ctlTitle"); ctlTitle.value = "🎬 " + ctlTitle.value;
save();
//var txtVideo = document.createTextNode("🎞"); //if (ctlTitle.childNodes.length > 0) //{ ctlTitle.insertBefore(txtVideo, ctlTitle.childNodes[0]); } //else //{ ctlTitle.appendChild(txtVideo); }
//--< add Video >-- } //--</ Item >-- } //--</ Loop: each Result >-- //---</ Insert Video >--- }
//---</ show return >---
//----</ ajax_after_Upload_Successfull() >---- }, error: function (request, status, error) { alert("Errortext:\n" + request.responseText); } }); //--</ ajax upload >-- //------</ editor_Upload_Video_Files() >------
}
|
Error documentation:
Until the solution ..
502 Web server received invalid response as gateway or proxy server
Upload 435 MB to Asp.Net Core in the Productiv system.
Log Script while searching for the solution
Solution:
18:15 webconfig on 1GB
18:24 system web und webserver in web.config 502.3 bad gateway
17:56 setting in progam-kestrel und controller auf 500 Error 404.13 Not Found
17:52 [RequestSizeLimit(500_000)] removed all settings Error 404.13
17:41 [RequestSizeLimit(500_000)] all settings Error 502.3
<requestLimits maxAllowedContentLength="500000000" /> [RequestSizeLimit(500_000_000)] options.Limits.MaxRequestBodySize = 500_000_000; -->ergibt viedeo aber kaputt.... keine Datei
[DisableRequestSizeLimit] ->502.3 Bad Gateway
<requestLimits maxAllowedContentLength="3000000000" /> [RequestSizeLimit(400_000_000)] ->502.3 Bad Gateway
[RequestSizeLimit(300000000)] <requestLimits maxAllowedContentLength="300000000" /> ->502.3 Bad Gateway
[RequestSizeLimit(300*1024)] options.Limits.MaxRequestBodySize = null; <requestLimits maxAllowedContentLength="3000000000" /> 502.3 Bad Gateway
[RequestSizeLimit(0)] options.Limits.MaxRequestBodySize = null; <requestLimits maxAllowedContentLength="3000000000" /> 502.3 Bad Gateway
<requestLimits maxAllowedContentLength="3000000000" /> [RequestSizeLimit(1000000000000000000)] //30.000.000=28,6MB
[RequestSizeLimit(300000000)] //30.000.000=28,6MB 502.3 Bad Gateway
[RequestSizeLimit(500000000)] Folge: 502.3 Bad Gateway
|