Validación de archivos grandes al Cargar

Estoy trabajando con c # MVC 2 y ASP.NET. Uno de mis formularios incluye un campo de entrada de archivo que permite un uso para seleccionar cualquier tipo de archivo que luego se convertirá en un blob y se guardará en la base de datos. Mi problema es que cada vez que un usuario selecciona un archivo que excede una cierta cantidad de Mb (alrededor de 8) aparece un error de página que dice lo siguiente:

The connection was reset The connection to the server was reset while the page was loading. 

No me importa que haya un límite de 8Mb para los archivos que cargan los usuarios, sin embargo, debo detener el error actual y mostrar un mensaje de validación adecuado (preferiblemente con la función ModelState.AddModelError). Alguien puede ayudarme? Parece que no puedo ‘detectar’ el error antes de que ocurra algo más en la página, ya que está sucediendo antes de que llegue a la función de carga dentro del controlador.

Una posibilidad es escribir un atributo de validación personalizado:

 public class MaxFileSizeAttribute : ValidationAttribute { private readonly int _maxFileSize; public MaxFileSizeAttribute(int maxFileSize) { _maxFileSize = maxFileSize; } public override bool IsValid(object value) { var file = value as HttpPostedFileBase; if (file == null) { return false; } return file.ContentLength <= _maxFileSize; } public override string FormatErrorMessage(string name) { return base.FormatErrorMessage(_maxFileSize.ToString()); } } 

y luego podrías tener un modelo de vista:

 public class MyViewModel { [Required] [MaxFileSize(8 * 1024 * 1024, ErrorMessage = "Maximum allowed file size is {0} bytes")] public HttpPostedFileBase File { get; set; } } 

controlador:

 public class HomeController : Controller { public ActionResult Index() { return View(new MyViewModel()); } [HttpPost] public ActionResult Index(MyViewModel model) { if (!ModelState.IsValid) { // validation failed => redisplay the view return View(model); } // the model is valid => we could process the file here var fileName = Path.GetFileName(model.File.FileName); var path = Path.Combine(Server.MapPath("~/App_Data/uploads"), fileName); model.File.SaveAs(path); return RedirectToAction("Success"); } } 

y una vista:

 @model MyViewModel @using (Html.BeginForm(null, null, FormMethod.Post, new { enctype = "multipart/form-data" })) { @Html.TextBoxFor(x => x.File, new { type = "file" }) @Html.ValidationMessageFor(x => x.File)  } 

Ahora, por supuesto, para que esto funcione, tendrá que boost el tamaño máximo de archivo de carga permitido en web.config a un valor suficientemente grande:

   

y para IIS7:

         

Ahora podemos llevar nuestro atributo de validación personalizada un paso más allá y permitir la validación del lado del cliente para evitar el desperdicio de ancho de banda. Por supuesto, verificar el tamaño del archivo antes de subirlo solo es posible con HTML5 File API . Como consecuencia, solo los navegadores compatibles con esta API podrán aprovecharlo.

Entonces, el primer paso es hacer que nuestro atributo de validación personalizada implemente la interfaz IClientValidatable que nos permitirá adjuntar un adaptador personalizado en javascript:

 public class MaxFileSizeAttribute : ValidationAttribute, IClientValidatable { private readonly int _maxFileSize; public MaxFileSizeAttribute(int maxFileSize) { _maxFileSize = maxFileSize; } public override bool IsValid(object value) { var file = value as HttpPostedFileBase; if (file == null) { return false; } return file.ContentLength <= _maxFileSize; } public override string FormatErrorMessage(string name) { return base.FormatErrorMessage(_maxFileSize.ToString()); } public IEnumerable GetClientValidationRules(ModelMetadata metadata, ControllerContext context) { var rule = new ModelClientValidationRule { ErrorMessage = FormatErrorMessage(_maxFileSize.ToString()), ValidationType = "filesize" }; rule.ValidationParameters["maxsize"] = _maxFileSize; yield return rule; } } 

y todo lo que queda es configurar el adaptador personalizado:

 jQuery.validator.unobtrusive.adapters.add( 'filesize', [ 'maxsize' ], function (options) { options.rules['filesize'] = options.params; if (options.message) { options.messages['filesize'] = options.message; } } ); jQuery.validator.addMethod('filesize', function (value, element, params) { if (element.files.length < 1) { // No files selected return true; } if (!element.files || !element.files[0].size) { // This browser doesn't support the HTML5 API return true; } return element.files[0].size < params.maxsize; }, ''); 

Puede boost la longitud máxima de la solicitud para ciertas URL en web.config:

      

Busqué en Google un poco y se me ocurrieron las siguientes dos URL que parecen sugerir que este problema o excepción se maneja mejor en el evento Error de la aplicación en Global.asax.

  1. Captura ‘Se excedió la longitud máxima de solicitud’
  2. Cómo manejar la excepción “Longitud de solicitud máxima excedida”