Una possibilità è quello di scrivere un attributo di convalida personalizzato:
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());
}
}
e poi si potrebbe avere un modello di vista:
public class MyViewModel
{
[Required]
[MaxFileSize(8 * 1024 * 1024, ErrorMessage = "Maximum allowed file size is {0} bytes")]
public HttpPostedFileBase File { get; set; }
}
regolatore:
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");
}
}
e 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)
<button type="submit">OK</button>
}
Ora, naturalmente, per questo al lavoro si dovrà aumentare la dimensione massima consentita file di caricamento nel web.config per un valore sufficientemente grande:
<!-- 1GB (the value is in KB) -->
<httpRuntime maxRequestLength="1048576" />
e per IIS7:
<system.webServer>
<security>
<requestFiltering>
<!-- 1GB (the value is in Bytes) -->
<requestLimits maxAllowedContentLength="1073741824" />
</requestFiltering>
</security>
</system.webServer>
Ora possiamo portare il nostro attributo di convalida personalizzato un ulteriore passo avanti e abilitare la convalida lato client per evitare lo spreco di larghezza di banda. Naturalmente verificare la dimensione del file prima del caricamento è possibile solo con HTML5 File API. Di conseguenza, solo i browser che supportano questa API potranno trarne vantaggio.
Quindi il primo passo è quello di rendere attribuiamo il nostro convalida personalizzata implementare l'interfaccia IClientValidatable che ci permetterà di allegare un adattatore personalizzato in 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<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
var rule = new ModelClientValidationRule
{
ErrorMessage = FormatErrorMessage(_maxFileSize.ToString()),
ValidationType = "filesize"
};
rule.ValidationParameters["maxsize"] = _maxFileSize;
yield return rule;
}
}
e tutto quello che resta è configurare l'adattatore personalizzato:
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;
}, '');
Prima di tutto, grazie mille Darin. Sto tentando di implementare la tua soluzione, ma non riesco a utilizzare IClientValidatable. Ho il System.Web.Sia Mvc aggiunto nei riferimenti del progetto e negli usi della pagina. Che cosa sto facendo di sbagliato? –
Non so cosa stai facendo male. Il 'IClientValidatable' è stato aggiunto in ASP.NET MVC 3 nell'assembly' System.Web.Mvc.dll' all'interno dello spazio dei nomi 'System.Web.Mvc'. –
Ho verificato e mi sono sbagliato a pensare che stessimo usando MVC3, stiamo infatti utilizzando MVC2. Poiché l'aggiornamento non è un'opzione per me, è possibile applicare una parte qualsiasi di questa soluzione? –