2012-05-04 33 views
29

Tôi đang làm việc với C# MVC 2 và ASP.NET. Một trong các biểu mẫu của tôi bao gồm trường nhập tệp cho phép sử dụng để chọn bất kỳ loại tệp nào sau đó sẽ được chuyển đổi thành một đốm màu và được lưu vào cơ sở dữ liệu. Vấn đề của tôi là bất cứ khi nào người dùng chọn một tập tin mà vượt quá một amoutn nhất định Mb (khoảng 8) Tôi nhận được một lỗi trang đó nói như sau:Xác thực cho các tệp lớn khi Tải lên

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

Tôi không quan tâm rằng có một giới hạn 8Mb đến các tệp mà người dùng đang tải lên tuy nhiên tôi cần dừng lỗi hiện tại và hiển thị thông báo xác thực hợp lệ (tốt nhất là với chức năng ModelState.AddModelError). Ai có thể giúp tôi? Tôi dường như không thể 'bắt' lỗi trước khi bất kỳ điều gì khác xảy ra trong trang vì nó xảy ra trước khi nó đến trong chức năng tải lên trong bộ điều khiển.

Trả lời

66

Một khả năng là để viết một thuộc tính xác nhận tùy chỉnh:

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()); 
    } 
} 

và sau đó bạn có thể có một mô hình điểm:

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

điều khiển:

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"); 
    } 
} 

và một cái nhìn:

@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> 
} 

Bây giờ tất nhiên để làm việc này bạn sẽ phải tăng tối đa cho phép kích thước tập tin tải lên trong web.config đến một giá trị đủ lớn:

<!-- 1GB (the value is in KB) --> 
<httpRuntime maxRequestLength="1048576" /> 

và cho IIS7:

<system.webServer> 
    <security> 
     <requestFiltering> 
      <!-- 1GB (the value is in Bytes) --> 
      <requestLimits maxAllowedContentLength="1073741824" /> 
     </requestFiltering> 
    </security> 
</system.webServer> 

Bây giờ chúng tôi có thể mang thuộc tính xác thực tùy chỉnh của mình thêm một bước nữa và bật xác thực phía máy khách để tránh lãng phí băng thông. Tất nhiên xác minh kích thước tập tin trước khi tải lên chỉ có thể với HTML5 File API. Kết quả là chỉ những trình duyệt hỗ trợ API này mới có thể tận dụng lợi thế của nó.

Vì vậy, bước đầu tiên là làm cho thuộc tính xác nhận tùy chỉnh của chúng tôi thực hiện các giao diện IClientValidatable mà sẽ cho phép chúng tôi đính kèm một bộ chuyển đổi tùy chỉnh trong 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; 
    } 
} 

và tất cả những gì còn lại là cấu hình adapter tùy chỉnh:

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; 
}, ''); 
+0

Trước hết, cảm ơn Darin rất nhiều. Tôi đang cố gắng để thực hiện giải pháp của bạn tuy nhiên tôi dường như không thể sử dụng 'IClientValidatable'. Tôi có System.Web.Mvc cả hai được thêm vào trong các tài liệu tham khảo của dự án và trong các trang sử dụng. Tôi đang làm gì sai? –

+0

Tôi không biết bạn đang làm gì sai. 'IClientValidatable' được thêm vào trong ASP.NET MVC 3 trong phần' System.Web.Mvc.dll' bên trong không gian tên 'System.Web.Mvc'. –

+0

Tôi đã xác minh và tôi đã nhầm lẫn khi nghĩ rằng chúng tôi đang sử dụng MVC3, chúng tôi đang sử dụng MVC2. Kể từ khi nâng cấp không phải là một lựa chọn cho tôi, bất kỳ phần nào của giải pháp này vẫn được áp dụng? –

1

Bạn có thể tăng chiều dài yêu cầu tối đa cho các url nhất định trong web.config:

<location path="fileupload"> 
    <system.web> 
    <httpRuntime executionTimeout="600" maxRequestLength="10485760" /> 
    </system.web> 
</location> 
Các vấn đề liên quan