2012-10-02 42 views
5

Testing ra Web API cho tập tin tải lên, có một mô hình nhìn đơn giản như thế này:Trình kết nối mô hình API Web không hoạt động với HttpPostedFileBase?

public class TestModel { 
    public string UserId {get;set;} 
    public HttpPostedFileBase ImageFile {get;set;} 
} 

Được sử dụng trong phương pháp này:

[HttpPost] 
public void Create(TestModel model) 

Khi tôi cố gắng để gửi một multipart/form form-data mã hóa cho hành động này, tôi nhận được ngoại lệ này:

System.InvalidOperationException: No MediaTypeFormatter is available to read an object of type 'TestModel' from content with media type 'multipart/form-data'. 
    at System.Net.Http.HttpContentExtensions.ReadAsAsync[T](HttpContent content, Type type, IEnumerable`1 formatters, IFormatterLogger formatterLogger) 
    at System.Net.Http.HttpContentExtensions.ReadAsAsync(HttpContent content, Type type, IEnumerable`1 formatters, IFormatterLogger formatterLogger) 
    at System.Web.Http.ModelBinding.FormatterParameterBinding.ReadContentAsync(HttpRequestMessage request, Type type, IEnumerable`1 formatters, IFormatterLogger formatterLogger) 
    at System.Web.Http.ModelBinding.FormatterParameterBinding.ExecuteBindingAsync(ModelMetadataProvider metadataProvider, HttpActionContext actionContext, CancellationToken cancellationToken) 
    at System.Web.Http.Controllers.HttpActionBinding.<>c__DisplayClass1.<ExecuteBindingAsync>b__0(HttpParameterBinding parameterBinder) 
    at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext() 
    at System.Threading.Tasks.TaskHelpers.IterateImpl(IEnumerator`1 enumerator, CancellationToken cancellationToken) 

Điều này hoạt động với chất kết dính mô hình MVC mặc định, nhưng dường như không phải với API của Web. Tìm thấy một số đề cập rằng bạn không thể sử dụng mô hình chế độ xem khi tải lên tệp và chỉ tách dữ liệu thành hai cuộc gọi. Điều đó không hiệu quả đối với tôi, vì tôi cần các trường khác đang được đăng để thực sự làm điều gì đó với tệp được tải lên. Có cách nào để hoàn thành nó không?

+0

Bạn cần phải viết một 'MediaTypeFormatter' tùy chỉnh để làm cho nó hoạt động. Như bạn đã trải nghiệm "multipart/form-data" không được hỗ trợ trong hộp. Bạn có thể bắt đầu [ở đây] (http://lonetechie.com/2012/09/23/web-api-generic-mediatypeformatter-for-file-upload/) – nemesv

Trả lời

3

Xem câu trả lời ban đầu của tôi https://stackoverflow.com/a/12603828/1171321

Về cơ bản kết hợp phương pháp của tôi trong bài viết trên blog của tôi và TryValidateProperty() gợi ý để duy trì chú thích mô hình xác nhận.

Chỉnh sửa: Tôi đã tiếp tục và nâng cấp mã lên mã của tôi trong bài đăng trên blog. Tôi sẽ sớm đăng mã cập nhật này. Dưới đây là một ví dụ đơn giản xác nhận từng thuộc tính và cung cấp cho bạn quyền truy cập vào một mảng các kết quả. Chỉ cần một mẫu của một cách tiếp cận

public class FileUpload<T> 
{ 
    private readonly string _RawValue; 

    public T Value { get; set; } 
    public string FileName { get; set; } 
    public string MediaType { get; set; } 
    public byte[] Buffer { get; set; } 

    public List<ValidationResult> ValidationResults = new List<ValidationResult>(); 

    public FileUpload(byte[] buffer, string mediaType, string fileName, string value) 
    { 
     Buffer = buffer; 
     MediaType = mediaType; 
     FileName = fileName.Replace("\"",""); 
     _RawValue = value; 

     Value = JsonConvert.DeserializeObject<T>(_RawValue); 

     foreach (PropertyInfo Property in Value.GetType().GetProperties()) 
     { 
      var Results = new List<ValidationResult>(); 
      Validator.TryValidateProperty(Property.GetValue(Value), 
              new ValidationContext(Value) {MemberName = Property.Name}, Results); 
      ValidationResults.AddRange(Results); 
     } 
    } 

    public void Save(string path, int userId) 
    { 
     if (!Directory.Exists(path)) 
     { 
      Directory.CreateDirectory(path); 
     } 
     var SafeFileName = Md5Hash.GetSaltedFileName(userId,FileName); 
     var NewPath = Path.Combine(path, SafeFileName); 
     if (File.Exists(NewPath)) 
     { 
      File.Delete(NewPath); 
     } 

     File.WriteAllBytes(NewPath, Buffer); 

     var Property = Value.GetType().GetProperty("FileName"); 
     Property.SetValue(Value, SafeFileName, null); 
    } 
} 
5

Bạn có thể viết MediaTypeFormatter tùy chỉnh để tạo điều kiện cho kịch bản của mình hoặc bạn có thể lấy dữ liệu ra khỏi yêu cầu bằng tay bằng cách sử dụng bộ sưu tập MultipartFormDataStreamProvider.FormData.AllKeys. Bằng cách này, bạn có thể đăng cả (các) tệp và các trường bổ sung trong một yêu cầu.

Một hướng dẫn tốt bởi Mike Wasson có sẵn ở đây: http://www.asp.net/web-api/overview/working-with-http/sending-html-form-data,-part-2

+7

Vì vậy, sau khi đọc bài viết, tôi thấy làm thế nào điều này có thể được thực hiện . Tuy nhiên, trừ khi tôi hiểu lầm, vẫn không có cách nào để sử dụng mô hình kết dính (và do đó tất cả các chú thích dữ liệu khác nhau đi kèm với nó). Vì vậy, bây giờ chúng ta phải xác nhận tất cả các đầu vào bằng tay? Bạn có cơ hội biết tại sao thay đổi này là cần thiết trong chất kết dính mô hình? Nó khá hiệu quả phá vỡ khái niệm về việc có thể sử dụng các mô hình hiện có cho các dự án API, và có vẻ như một hướng thực sự kỳ lạ để thực hiện. – heyseuss

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