代码之家  ›  专栏  ›  技术社区  ›  intrepidus

Web API模型绑定器不适用于HttpPostedFileBase?

  •  5
  • intrepidus  · 技术社区  · 12 年前

    测试用于文件上传的Web API,有一个简单的视图模型,如下所示:

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

    用于方法:

    [HttpPost]
    public void Create(TestModel model)
    

    当我尝试将多部分/表单数据编码表单发布到操作时,我会收到以下异常:

    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) 
    

    这适用于默认的MVC模型绑定器,但显然不适用于Web API。发现有人提到,上传文件时不能使用视图模型,只能将数据分为两个调用。这对我来说不起作用,因为我需要发布其他字段,以便对上传的文件进行实际操作。有办法做到这一点吗?

    2 回复  |  直到 12 年前
        1
  •  5
  •   Filip W    12 年前

    你可以写一个自定义 MediaTypeFormatter 为了方便您的场景,或者您可以使用手动从请求中提取数据 MultipartFormDataStreamProvider.FormData.AllKeys 收集通过这种方式,您可以在一个请求中发布文件和其他字段。

    Mike Wasson的一个很好的教程可以在这里找到: http://www.asp.net/web-api/overview/working-with-http/sending-html-form-data,-part-2

        2
  •  3
  •   Community Ian Goodfellow    7 年前

    查看我的原始答案 https://stackoverflow.com/a/12603828/1171321

    基本上结合我在博客文章中的方法和TryValidateProperty()建议来维护模型验证注释。

    编辑: 我继续在博客文章中对我的代码进行了代码增强。我很快就会发布这个更新的代码。下面是一个简单的示例,它验证每个属性并允许您访问结果数组。只是一种方法的示例

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