24

Có cách nào để nhận tệp được đăng (<input type="file" />) để tham gia vào mô hình ràng buộc trong ASP.NET MVC mà không cần nhìn vào bối cảnh yêu cầu theo cách thủ công và không tạo phương thức hành động riêng mà chỉ lấy tệp được đăng là đầu vào?ASP.NET MVC đăng mô hình tập tin ràng buộc khi tham số là Model

Tôi đã có thể nghĩ rằng điều này sẽ làm việc:

class MyModel { 
    public HttpPostedFileBase MyFile { get; set; } 
    public int? OtherProperty { get; set; } 
} 

<form enctype="multipart/form-data"> 
    <input type="file" name="MyFile" /> 
    <input type="text" name="OtherProperty" /> 
</form> 

public ActionResult Create(MyModel myModel) { ... } 

Nhưng với kịch bản trên, MyFile không phải là thậm chí một phần của giá trị nhà cung cấp giá trị trong bối cảnh ràng buộc. (OtherProperty là, tất nhiên.) Nhưng nó hoạt động nếu tôi làm điều này:

public ActionResult Create(HttpPostedFileBase postedFile, ...) { ... } 

Vì vậy, tại sao không có ràng buộc xảy ra khi các tham số là một mô hình, và làm thế nào tôi có thể làm cho nó hoạt động? Tôi không có vấn đề với việc sử dụng một mô hình tùy chỉnh chất kết dính, nhưng làm thế nào tôi có thể làm điều này trong một chất kết dính mô hình tùy chỉnh mà không cần nhìn vào Request.Files["MyFile"]?

Để nhất quán, rõ ràng và có thể kiểm tra, tôi muốn mã của mình cung cấp tính ràng buộc tự động của tất cả các thuộc tính trên mô hình, bao gồm cả các thuộc tính được gắn với tệp được đăng mà không kiểm tra ngữ cảnh yêu cầu theo cách thủ công. Tôi hiện đang thử nghiệm mô hình ràng buộc sử dụng the approach Scott Hanselman wrote about.

Hoặc tôi đang đi về điều này theo cách sai? Làm thế nào bạn sẽ giải quyết điều này? Hay điều này là không thể bởi thiết kế do lịch sử tách biệt giữa Request.Form và Request.Files?

Trả lời

29

Nó chỉ ra lý do là ValueProviderDictionary chỉ trông ở Request.Form, RouteDataRequest.QueryString để điền từ điển của nhà cung cấp giá trị vào ngữ cảnh ràng buộc mô hình. Vì vậy, không có cách nào cho một mô hình tùy chỉnh chất kết dính để cho phép các tập tin được đăng tham gia vào mô hình ràng buộc mà không kiểm tra việc thu thập tập tin trong bối cảnh yêu cầu trực tiếp.Đây là cách gần nhất tôi đã tìm thấy để thực hiện được điều tương tự:

public ActionResult Create(MyModel myModel, HttpPostedFileBase myModelFile) { } 

Chừng nào myModelFile thực sự là tên của các trường mẫu file đầu vào, không cần cho bất kỳ công cụ tùy chỉnh.

+5

* Lưu ý: * không bỏ qua thuộc tính 'enctype' trên biểu mẫu. Nó phải được xác định là '" multipart/form-data "'. Nếu không, đối số 'HttpPostedFileBase' với tên trùng khớp với thuộc tính' name' trên thẻ đầu vào, sẽ vẫn là 'null' trên POST. –

+0

Tôi đã sử dụng tương tự nhưng đã nhận lỗi: - Không thể liên kết nhiều tham số, trong $ .ajax tôi đã đặt: - type: 'POST', dataType: 'json', contentType: 'multipart/form-data' , data: formData – ujjaval

6

Bạn đã xem this post mà anh ấy liên kết đến từ the one you linked to (qua another one ...)?

Nếu không, có vẻ khá đơn giản. Đây là mô hình binder ông sử dụng:

public class HttpPostedFileBaseModelBinder : IModelBinder { 
    public ModelBinderResult BindModel(ModelBindingContext bindingContext) { 
     HttpPostedFileBase theFile = 
      bindingContext.HttpContext.Request.Files[bindingContext.ModelName]; 
     return new ModelBinderResult(theFile); 
    } 
} 

Ông đăng ký nó trong Global.asax.cs như sau:

ModelBinders.Binders[typeof(HttpPostedFileBase)] = 
    new HttpPostedFileBaseModelBinder(); 

và viết với một hình thức trông như thế này:

<form action="/File/UploadAFile" enctype="multipart/form-data" method="post"> 
    Choose file: <input type="file" name="theFile" /> 
    <input type="submit" /> 
</form> 

Tất cả các mã được sao chép thẳng ra khỏi bài đăng trên blog ...

+0

Thực ra, đây là phương pháp tôi hiện đang sử dụng. Nhưng có hai vấn đề với cách tiếp cận này: 1; nó sử dụng ngữ cảnh yêu cầu (thông qua bindingContext.HttpContext.Request), mà tôi thực sự không muốn, và 2; nó chỉ xử lý một kịch bản mà bài viết chỉ bao gồm một tập tin được tải lên (điều này có thể tất nhiên dễ dàng được thay đổi mặc dù). – bzlm

+0

Ngoài ra, BindModel (ModelBindingContext bindingContext) trông giống như mã tiền phát hành. Có một ControllerContext trong đó là tốt. – bzlm

+1

Bạn đã xem mã nguồn của MVC Framework chưa? Tôi không chắc làm thế nào mô hình "bình thường" chất kết dính làm việc, nhưng tôi không thể thực sự thấy làm thế nào bạn sẽ có thể lấy các giá trị hình thức mà không sử dụng HttpContext.Current.Request.Form [] bộ sưu tập * một nơi nào đó * dọc theo con đường ... http://weblogs.asp.net/scottgu/archive/2008/03/21/asp-net-mvc-source-code-now-available.aspx –

-16

Bạn không cần phải đăng ký một chất kết dính tùy chỉnh, HttpPostedFileBase được đăng ký bởi mặc định trong khuôn khổ:

public ActionResult Create(HttpPostedFileBase myFile) 
{ 
    ... 
} 

Nó giúp read a book mỗi một lần trong một thời gian, thay vì chỉ dựa trên các blog và các diễn đàn web.

+0

Tôi đã chỉnh sửa câu hỏi để rõ ràng hơn về thực tế là tôi không muốn một phương thức hành động có tệp được đăng là tham số duy nhất của nó. Có cách nào để thực hiện tương tự nếu tệp được đăng chỉ là một trong nhiều thuộc tính trên mô hình không? (Tôi có cuốn sách ASP.NET MVC khác, nhân tiện. :) – bzlm

+0

Đây là câu trả lời đúng; Tôi đã có cùng một vấn đề trong khi trở lại. HttpPostedFileBase sẽ ràng buộc nhưng HttpPostedFile sẽ không. –

+0

Không, HttpPostedFileBase sẽ không ràng buộc bằng cách sử dụng giá trị ràng buộc của nhà cung cấp tiêu chuẩn trong trình kết nối mô hình mặc định. Tuy nhiên, nó sẽ ràng buộc trong phương thức trong câu trả lời này. – bzlm

14

Một cách khác là thêm một lĩnh vực tiềm ẩn với tên giống như đầu vào: sau đó

<input type="hidden" name="MyFile" id="MyFileSubmitPlaceHolder" /> 

Các DefaultModelBinder sẽ thấy một lĩnh vực và tạo ra chất kết dính chính xác.

+2

Dường như ASP.NET MVC 2 RC xử lý điều này mà không có trường ẩn. –

+0

hoàn toàn chính xác, tôi đang sử dụng ASP.NET MVC 2 và tôi có thể thành công ràng buộc đầu vào tập tin của tôi để mô hình của tôi mà không làm bất kỳ công việc phụ nào. Tuyệt diệu! – Pandincus

Các vấn đề liên quan