Lets say I have a simple Index.cshtml
View:
<link href="~/libs/JQueryUI/jquery-ui.css" rel="stylesheet" />
<link href="~/libs/infragistics/css/themes/infragistics/infragistics.theme.css" rel="stylesheet" />
<link href="~/libs/infragistics/css/structure/infragistics.css" rel="stylesheet" />
@using CommonLib.Source.Common.Converters
@using CommonLib.Source.Common.Extensions
@using Infragistics.Web.Mvc
@using Microsoft.AspNetCore.Http
@{
ViewData["Title"] = "Index";
}
<h1>Index</h1>
<div id="chart" style="color: blue"></div>
<div id="indicator"></div>
<div id="igFileUpload" style="color: blue"></div>
<script src="~/libs/JQuery/jquery.js"></script>
<script src="~/libs/JQueryUI/jquery-ui.js"></script>
<script src="~/libs/infragistics/js/infragistics.core.js"></script>
<script src="~/libs/infragistics/js/infragistics.lob.js"></script>
<script src="~/libs/Lightweight-Charts/dist/lightweight-charts.standalone.development.js"></script>
<script src="~/MyScripts.js"></script>
@(
Html.Infragistics().Upload()
.ID("igFileUpload")
.Mode(UploadMode.Multiple)
.AutoStartUpload(true)
.ProgressUrl(Context.GetAbsoluteUrl("~/IGUploadStatusHandler.ashx"))
.UploadUrl(Context.GetAbsoluteUrl("~/Data/UploadedFiles")) // just use Url.Content for testing purposes
.ControlId("serverID1")
.Width("600px")
.Render()
)
<div id="error-message" style="color: #FF0000; font-weight: bold;"></div>
<script type="text/javascript">
$(function () {
$("#igFileUpload").bind({ iguploadonerror: function (e, args) {
$("#error-message").html(args.errorMessage).stop(true, true).fadeIn(500).delay(3000).fadeOut(500);
}
});
});
</script>
I also got Startup.cs
file:
using System;
using System.IO;
using CommonLib.Source.Common.Utils;
using Infragistics.Web.Mvc;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Hosting;
namespace CryptoBotCoreMVC
{
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddMvc(option => option.EnableEndpointRouting = false);
//services.Configure<UploadAppSettings>(options =>
//{
// options.FileUploadPath = $@"{Directory.GetCurrentDirectory()}\Data"; //WebUtils.GetWebAppAbsolutePath("
//}); // TODO: fu doesn't work | FileUploadPath is set in the View because it is too early to do it here
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IServiceProvider svp)
{
WebUtils.Configure(app.ApplicationServices.GetRequiredService<IHttpContextAccessor>(), env);
if (env.IsDevelopment())
app.UseDeveloperExceptionPage();
app.UseStaticFiles();
app.UseRouting();
app.UseUploadModuleMiddleware();
app.UseUploadHandlerMiddleware();
app.UseFileServer(new FileServerOptions
{
FileProvider = new PhysicalFileProvider($@"{Directory.GetCurrentDirectory()}\Data"),
RequestPath = "/Data",
EnableDirectoryBrowsing = true
});
app.UseMvc(routes =>
{
routes.MapRoute("default", "{controller=Home}/{action=Index}/{id?}");
});
}
}
}
Reference here: https://www.igniteui.com/help/using-igniteui-controls-in-asp.net-core-1.0-project
To be safe I set maximum file size in web.config
:
<security>
<requestFiltering>
<requestLimits maxAllowedContentLength="1073741824" /> <!-- 1 GB -->
</requestFiltering>
</security>
and in IIS:
This is what Fiddler shows:
1st:
2nd and 3rd:
According to this:
https://www.igniteui.com/help/igupload-using-http-handler-and-modules
The error means:
Status: 3 - File not found - this status is used when it is not found such key in the dictionary
Error: 5 - File does not exist with the specified key in the request
Here is the result itself:
Here is the reference for the control documentation (some of it is not applicable for ASP.NET CORE
):
https://www.igniteui.com/help/igupload-igupload
https://www.igniteui.com/file-upload/overview
The problem is that as you can see, while the control works, the files are not actually uploaded to the server. I don't believe this is a bug, I think that I am not familiar enough with CORE 3.0
and I am missing something rather obvious in configuration of IGUploadStatusHandler.ashx
.
I would rather want to avoid digging for IF default Web Handler code if possible.
/EDIT
As per @MasLoo suggestion I implemented the middleware to replace the apparently required IgnoreRoute
but I fail to understand how throwing 404 directly from it would make the Handler work:
(...)
app.UseMiddleware<IgnoreRouteMiddleware>();
(...)
:
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
namespace CryptoBotCoreMVC.Middlewares
{
public class IgnoreRouteMiddleware
{
private readonly RequestDelegate _next;
public IgnoreRouteMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
if (context.Request.Path.HasValue && context.Request.Path.Value.Contains("IGUploadStatusHandler.ashx"))
{
context.Response.StatusCode = 404;
return;
}
await _next.Invoke(context);
}
}
}
After doing a test it indeed throws 404 right away, actually twice:
On commenting the:
//context.Response.StatusCode = 404;
The fiddler catches this:
with the following message:
I didn't post the messages because they are exactly the same as the first one with Content-Length: 0
.
Further ideas would be warmly welcome.
// EDIT 2
I think I am almost there, but not quite. I noticed that for some reason if I keep urls default, the IF Code instead of looking for a folder for files in UploadUrl
it looks for ig_fua34sf345sdf13sdf3454erdsf2345asd3425df5235d54df345.aspx
path so I changed my HtmlHelper
into:
Html.Infragistics().Upload()
.ID("igFileUpload")
.Mode(UploadMode.Multiple)
.AutoStartUpload(true)
.ProgressUrl(Context.GetAbsoluteUrl("~/IGUploadStatusHandler.ashx"))
.UploadUrl(Context.GetAbsoluteUrl("~/ig_fua34sf345sdf13sdf3454erdsf2345asd3425df5235d54df345.aspx"))
.ControlId("serverID1")
.Width("600px")
.Render()
and now I am getting 500s:
with the following Stack Trace:
HTTP/1.1 500 Internal Server Error
Content-Type: text/plain
Server: Microsoft-IIS/10.0
X-Powered-By: ASP.NET
Date: Thu, 21 Nov 2019 00:17:16 GMT
Content-Length: 1398
System.InvalidOperationException: Synchronous operations are disallowed. Call ReadAsync or set AllowSynchronousIO to true instead.
at Microsoft.AspNetCore.Server.IIS.Core.HttpRequestStream.Read(Byte[] buffer, Int32 offset, Int32 count)
at Microsoft.AspNetCore.Server.IIS.Core.WrappingStream.Read(Byte[] buffer, Int32 offset, Int32 count)
at Infragistics.Web.Mvc.MiddleWare.UploadModuleMiddleware.ReadFully(Stream input)
at Infragistics.Web.Mvc.MiddleWare.UploadModuleMiddleware.Invoke(HttpContext context)
at CryptoBotCoreMVC.Middlewares.IgnoreRouteMiddleware.Invoke(HttpContext context) in <Path>\CSharp\Projects\CryptoBotCoreMVC\CryptoBotCoreMVC\Middlewares\IgnoreRouteMiddleware.cs:line 23
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
HEADERS
=======
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: pl-PL,pl;q=0.9,en-US;q=0.8,en;q=0.7
Cache-Control: no-cache
Connection: keep-alive
Content-Length: 244
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary3RFkBWmZhhsbjzXr
Host: localhost
Pragma: no-cache
Referer: http://localhost/CryptoBotCoreMVC
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.120 Safari/537.36
Sec-Fetch-Mode: cors
Origin: http://localhost
Sec-Fetch-Site: same-origin
Now we are getting somewhere, it seems that changing Kestrel
or IIS
configuration should be sufficient in this case:
services.Configure<KestrelServerOptions>(options =>
{
options.AllowSynchronousIO = true;
});
services.Configure<IISServerOptions>(options =>
{
options.AllowSynchronousIO = true;
});
and indeed it is, I am gonna post detailed answer soon.
In order to make IgUpload
Control from IgniteUI
work with ASP.NET CORE MVC 3.0
you need to perform the following steps (Be aware however that it still isn't streaming large files in chunks, for this refer to this article (which hasn't been updated for ASP.NET CORE
)):
Add Infragistics.Web.AspNetCore
and IgniteUI
NuGet packages OR add the scripts, .css
files and .dll
file manually from your Infragistics
installation folder as dependencies:
Set maxAllowedContentLength
in web.config
file:
Set Maximum allowed content length (Bytes)
in IIS
: CTRL + R
> inetmgr
> <Server or Website>
> IIS Category
> RequestFiltering
> Actions Pane (to the right side)
> Edit Feature Settings...
Include options.AllowSynchronousIO = true
in your Startup.cs
file for Kestrel
and/or IIS
to prevent Middleware
from throwing Synchronous operations are disallowed. Call ReadAsync or set AllowSynchronousIO to true instead
exception.
Set maxFileSizeLimit
to a positive value, because despite the documentation statement it will not work for larger files if you set it to null
, -1
or if you won't set this option at all.
Set FileUploadPath
to a Physical Directory on the application Drive (not the Virtual one).
Render the Control including ProgressUrl
, UploadUrl
and ControlID
options and set them to the exact values visible below to prevent Middleware
from throwing various inxeplicit 404
errors (code samples will be on the bottom of this answer).
Get the desired result:
IMPORTANT: IgnoreRoute
is NOT required!
Code samples:
Startup.cs
:
using System.IO;
using Infragistics.Web.Mvc;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace IgUpload
{
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(options => options.EnableEndpointRouting = false);
services.Configure<KestrelServerOptions>(options => options.AllowSynchronousIO = true);
services.Configure<IISServerOptions>(options => options.AllowSynchronousIO = true);
services.Configure<UploadAppSettings>(options =>
{
options.maxFileSizeLimit = "1073741824"; // 1 GB
options.FileUploadPath = $@"{Directory.GetCurrentDirectory()}\Data\UploadedFiles";
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment()) app.UseDeveloperExceptionPage();
app.UseStaticFiles();
app.UseRouting();
app.UseUploadModuleMiddleware();
app.UseUploadHandlerMiddleware();
app.UseMvc(routes => routes.MapRoute("default", "{controller=Home}/{action=Index}/{id?}"));
}
}
}
Index.cshtml
:
@using Infragistics.Web.Mvc
@using Microsoft.AspNetCore.Http
@{
ViewData["Title"] = "Index";
}
<div id="igFileUpload"></div>
<script src="~/libs/JQuery/jquery.js"></script>
<script src="~/libs/JQueryUI/jquery-ui.js"></script>
<script src="~/libs/infragistics/js/infragistics.core.js"></script>
<script src="~/libs/infragistics/js/infragistics.lob.js"></script>
@(
Html.Infragistics().Upload()
.ID("igFileUpload")
.Mode(UploadMode.Multiple)
.AutoStartUpload(true)
.ProgressUrl(Url.Content("~/IGUploadStatusHandler.ashx"))
.UploadUrl(Url.Content("~/ig_fua34sf345sdf13sdf3454erdsf2345asd3425df5235d54df345.aspx"))
.ControlId("serverID1")
.Width("600px")
.Render()
)
<div id="error-message" style="color: #FF0000; font-weight: bold;"></div>
<script type="text/javascript">
$(function () {
$("#igFileUpload").bind({ iguploadonerror: function (e, args) {
$("#error-message").html(args.errorMessage).stop(true, true).fadeIn(500).delay(3000).fadeOut(500);
}
});
});
</script>