【问题标题】:Web API model binder doesn't work with HttpPostedFileBase?Web API 模型绑定器不适用于 HttpPostedFileBase?
【发布时间】:2016-01-07 06:00:56
【问题描述】:

测试用于文件上传的 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”。你可以开始here

标签: asp.net-mvc asp.net-web-api


【解决方案1】:

您可以编写自定义MediaTypeFormatter 以方便您的场景,也可以使用MultipartFormDataStreamProvider.FormData.AllKeys 集合手动从请求中提取数据。这样您就可以在一个请求中同时发布文件和其他字段。

Mike Wasson 的优秀教程可在此处获得:http://www.asp.net/web-api/overview/working-with-http/sending-html-form-data,-part-2

【讨论】:

  • 所以看完这篇文章,我明白了这是怎么做到的。但是,除非我有误解,否则仍然无法使用模型绑定器(以及随之而来的所有各种数据注释)。所以我们现在必须手动验证所有输入?您是否偶然知道为什么在模型活页夹中需要进行此更改?它非常有效地打破了能够将现有模型用于 API 项目的概念,而且似乎是一个非常奇怪的方向。
【解决方案2】:

查看我的原始答案 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);
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-10-10
    • 2013-02-08
    • 1970-01-01
    • 2012-08-28
    • 2019-07-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多