Web API模型绑定器无法与HttpPostedFileBase一起使用?

5

测试Web API文件上传功能,有个简单的视图模型如下:

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

在方法中使用:

[HttpPost]
public void Create(TestModel model)

当我尝试将一个multipart/form-data编码的表单提交到操作时,我收到了这个异常:
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。我发现一些提到上传文件时不能使用视图模型的内容,并建议将数据分成两个调用。这对我来说行不通,因为我需要在上传文件后处理其他字段的提交。有没有办法实现这个功能?


你需要编写一个自定义的MediaTypeFormatter来使其工作。正如你所经历的那样,“multipart/form-data”不支持开箱即用。你可以从这里开始:http://lonetechie.com/2012/09/23/web-api-generic-mediatypeformatter-for-file-upload/ - nemesv
2个回答

5

7
阅读完这篇文章后,我明白了如何做到这一点。然而,除非我误解了,仍然无法使用模型绑定器(因此所有相关的数据注释也都无法使用)。所以我们现在必须手动验证所有的输入?你是否知道为什么模型绑定器需要进行这种更改?这很有效地破坏了可以在API项目中使用现有模型的想法,并且似乎是一个非常奇怪的方向。 - intrepidus

3

请查看我的原始回答https://dev59.com/-mcs5IYBdhLWcg3ww2tP#12603828

基本上,结合我的博客文章中的方法和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);
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接