【问题标题】:How create a MultipartFormFormatter for ASP.NET 4.5 Web API如何为 ASP.NET 4.5 Web API 创建 MultipartFormFormatter
【发布时间】:2013-07-29 12:54:01
【问题描述】:

这些链接对我没有帮助:

例子:

//Model:
public class Group
{
    public int Id { get; set; }        
    public File File { get; set; }
}

//Controller:
[HttpPost]
public void SaveGroup([FromBody]Group group) {}

//Formatter:
public class MultipartFormFormatter : MediaTypeFormatter
{
    private const string StringMultipartMediaType = "multipart/form-data";

    public MultipartFormFormatter()
    {
        this.SupportedMediaTypes.Add(new MediaTypeHeaderValue(StringMultipartMediaType));

    }

    public override bool CanReadType(Type type)
    {
        return true;
    }

    public override bool CanWriteType(Type type)
    {
        return false;
    }

    public async override Task<object> ReadFromStreamAsync(Type type, Stream readStream, HttpContent content, IFormatterLogger formatterLogger)
    {
        //Implementation? What here should be?
    }       
}

ReadFromStreamAsync 方法应该返回什么?

我该如何做才能正确地将参数传递给动作?

【问题讨论】:

    标签: asp.net-mvc asynchronous asp.net-web-api asp.net-4.5 mediatypeformatter


    【解决方案1】:
    public class MultipartFormFormatter : FormUrlEncodedMediaTypeFormatter
    {
        private const string StringMultipartMediaType = "multipart/form-data";
        private const string StringApplicationMediaType = "application/octet-stream";
    
        public MultipartFormFormatter()
        {
            this.SupportedMediaTypes.Add(new MediaTypeHeaderValue(StringMultipartMediaType));
            this.SupportedMediaTypes.Add(new MediaTypeHeaderValue(StringApplicationMediaType));
        }
    
        public override bool CanReadType(Type type)
        {
            return true;
        }
    
        public override bool CanWriteType(Type type)
        {
            return false;
        }
    
        public override async Task<object> ReadFromStreamAsync(Type type, Stream readStream, HttpContent content, IFormatterLogger formatterLogger)
        {
            var parts = await content.ReadAsMultipartAsync();
            var obj = Activator.CreateInstance(type);
            var propertiesFromObj = obj.GetType().GetRuntimeProperties().ToList();
    
            foreach (var property in propertiesFromObj.Where(x => x.PropertyType == typeof(FileModel)))
            {
                var file = parts.Contents.FirstOrDefault(x => x.Headers.ContentDisposition.Name.Contains(property.Name));
    
                if (file == null || file.Headers.ContentLength <= 0) continue;
    
                try
                {
                    var fileModel = new FileModel(file.Headers.ContentDisposition.FileName, Convert.ToInt32(file.Headers.ContentLength), ReadFully(file.ReadAsStreamAsync().Result));
                    property.SetValue(obj, fileModel);
                }
                catch (Exception e)
                {
                }
            }
    
            foreach (var property in propertiesFromObj.Where(x => x.PropertyType != typeof(FileModel)))
            {
                var formData = parts.Contents.FirstOrDefault(x => x.Headers.ContentDisposition.Name.Contains(property.Name));
    
                if (formData == null) continue;
    
                try
                {
                    var strValue = formData.ReadAsStringAsync().Result;
                    var valueType = Nullable.GetUnderlyingType(property.PropertyType) ?? property.PropertyType;
                    var value = Convert.ChangeType(strValue, valueType);
                    property.SetValue(obj, value);
                }
                catch (Exception e)
                {
                }
            }
    
            return obj;
        }
    
        private byte[] ReadFully(Stream input)
        {
            var buffer = new byte[16 * 1024];
            using (var ms = new MemoryStream())
            {
                int read;
                while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
                {
                    ms.Write(buffer, 0, read);
                }
                return ms.ToArray();
            }
        }
    }
    
    public class FileModel
    {
        public FileModel(string filename, int contentLength, byte[] content)
        {
            Filename = filename;
            ContentLength = contentLength;
            Content = content;
        }
    
        public string Filename { get; set; }
    
        public int ContentLength { get; set; }
    
        public byte[] Content { get; set; }
    
    }
    

    【讨论】:

    • 谢谢!在紧要关头帮助了我。我添加了 FileModel 类 def 以进行完整的复制/粘贴。要使用:在控制器操作的参数中向模型添加 FileModel 属性,不要忘记在引导过程中执行 GlobalConfiguration.Configuration.Formatters.Add(new MultipartFormFormatter());
    【解决方案2】:

    具体实现请看以下链接: https://github.com/iLexDev/ASP.NET-WebApi-MultipartDataMediaFormatter

    Nuget: https://www.nuget.org/packages/MultipartDataMediaFormatter/

    我今天实际上需要进行“multipart/form-data”文件上传和模型绑定,我在 nuget 上面尝试了 lib,结果证明它可以按我的预期工作。模型验证也可以正常工作。希望它有助于回答您的问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-04-04
      • 2012-03-19
      • 2013-06-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多