Leggo spesso di gente che ha problemi con l'upload di file molto grandi. L'errore che si riscontra non è gestibile dall'applicativo. Molti sanno che è possibile aumentare la dimensione dei file in upload (che poi si tratta effettivamente della dimensione della richiesta http) ed eventuali timeout di sessione direttamente nel web.config.
Ma questo spesso non basta...
Tempo fa avevo trovato il modo di gestire il tutto da un articolo. Purtroppo non posso fornire riferimenti (l'autore è libero di chiedermi di togliere questo codice da questa pagina o darmi il link) ma proverò a ricostruire il contenuto. Si trattava di un HttpModule, ovvero di un qualcosa che si va a inserire nella pipeline della gestione della richiesta.
Web.Config (aggiungiamo l'httpModule e una sezione di configurazione)
<configuration xmlns="...">
<configsections>
<section type="MyNameSpace.MyClassHandler, MyAssembly" name="UploadModuleManagement"/>
</configsections>
<uploadmodulemanagement pages="pagine da dove si effettua l'upload separate da virgola con MyApp.MyPage.aspx" buffersize="16384"/>
...
<system.web>
<httpmodules><add type="MyNameSpace.MyClassHandler, Assembly" name="MyClassHandler"/></httpmodules>
...
Poi la classe
using System.Web;
using System;
using System.Reflection;
using System.Data;
using System.Configuration;
using System.Threading;
using System.Xml;
using System.IO;
namespace MyNameSpace
{
public sealed class MyClassHandler : IHttpModule, IConfigurationSectionHandler
{
private const string configSection = "UploadModuleManagement";
private const string bufferSizeKey = "bufferSize";
private const string pagesKey = "pages";
public void Dispose()
{}
public object Create(object parent, object configContext, XmlNode section)
{
if (section != null)
{
HttpContext.Current.Application[bufferSizeKey] = Int32.Parse(section.SelectSingleNode("@bufferSize").Value);
HttpContext.Current.Application[pagesKey] = section.SelectSingleNode("@pages").Value.Split(',');
}
else
{
HttpContext.Current.Application[bufferSizeKey] = 1024;
HttpContext.Current.Application[pagesKey] = new string[] { "" };
}
return null;
}
private bool IsUploadPages()
{
HttpApplication app = HttpContext.Current.ApplicationInstance;
string[] uploadPages = (string[])app.Application[pagesKey];
for (int i = 0; i < uploadPages.Length; i++)
{
if (uploadPages[i].ToLower() == app.Request.Path.Substring(1).ToLower())
return true;
}
return false;
}
public void Init(HttpApplication app)
{
System.Configuration.ConfigurationManager.GetSection(configSection);
app.BeginRequest += new EventHandler(context_BeginRequest);
}
private void context_BeginRequest(object sender, EventArgs e)
{
HttpApplication app = sender as HttpApplication;
IServiceProvider provider = (IServiceProvider)HttpContext.Current;
HttpWorkerRequest worker = (HttpWorkerRequest)provider.GetService(typeof(HttpWorkerRequest));
int bufferSize = (int)app.Application[bufferSizeKey];
if (IsUploadPages())
{
if (app.Context.Request.ContentLength > 0)
{
MemoryStream mem = new MemoryStream(app.Context.Request.ContentLength);
byte[] data = worker.GetPreloadedEntityBody();
mem.Write(data, 0, data.Length);
int read = 0;
int counter = data.Length;
while (counter < app.Context.Request.ContentLength)
{
if (counter + bufferSize > app.Context.Request.ContentLength)
bufferSize = app.Context.Request.ContentLength - counter;
data = new byte[bufferSize];
read = worker.ReadEntityBody(data, bufferSize);
counter += read;
mem.Write(data, 0, bufferSize);
}
mem.Position = 0;
byte[] memData = new byte[mem.Length];
mem.Read(memData, 0, (int)mem.Length);
//finito di intercettare, rimanda tutti i dati al worker process
PushRequestToIIS(worker, memData);
}
}
}
private void PushRequestToIIS(HttpWorkerRequest request, byte[] textParts)
{
BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.NonPublic;
Type type = request.GetType();
while ((type != null) && (type.FullName != "System.Web.Hosting.ISAPIWorkerRequest"))
type = type.BaseType;
if (type != null)
{
type.GetField("_contentAvailLength", bindingFlags).SetValue(request, textParts.Length);
type.GetField("_contentTotalLength", bindingFlags).SetValue(request, textParts.Length);
type.GetField("_preloadedContent", bindingFlags).SetValue(request, textParts);
type.GetField("_preloadedContentRead", bindingFlags).SetValue(request, true);
}
}
}
}
Technorati tags: .NET