编码为multipart/form-data自定义类型(包括文件)如何自动绑定到webapi的action的参数里
application/x-www-form-urlencoded与 multipart/form-data:
Fom表单中如果没有type=file的控件,用默认的application/x-www-form-urlencoded就可以了。但是如果有type=file的话,就要用到multipart/form-data了。浏览器会把整个表单以控件为单位分割,并为每个部分加上 Content-Disposition(form-data或者file),Content-Type(默认为text/plain),name(控件 name)等信息,并加上分割符(boundary)。
multipart/form-data被webapi能够识别,需要自定义MediaTypeFormatter,关于webapi中的媒体类型格式化器(Media-type Formatter),它是一种能够做以下工作的对象:
- Read CLR objects from an HTTP message body
从HTTP消息体读取CLR(公共语言运行时)对象 - Write CLR objects into an HTTP message body
将CLR对象写入HTTP消息体
Web API提供了用于JSON和XML的媒体类型格式化器。框架已默认将这些格式化器插入到消息处理管线之中。客户端在HTTP请求的Accept报头中可以请求JSON或XML。
以下代码是multipart/form-data的格式化方法:
using System;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Formatting;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using MultipartDataMediaFormatter.Converters;
using MultipartDataMediaFormatter.Infrastructure;
using MultipartDataMediaFormatter.Infrastructure.Logger; namespace MultipartDataMediaFormatter
{
public class FormMultipartEncodedMediaTypeFormatter : MediaTypeFormatter
{
private const string SupportedMediaType = "multipart/form-data"; public FormMultipartEncodedMediaTypeFormatter()
{
SupportedMediaTypes.Add(new MediaTypeHeaderValue(SupportedMediaType));
} public override bool CanReadType(Type type)
{
return true;
} public override bool CanWriteType(Type type)
{
return true;
} public override void SetDefaultContentHeaders(Type type, HttpContentHeaders headers, MediaTypeHeaderValue mediaType)
{
base.SetDefaultContentHeaders(type, headers, mediaType); //need add boundary
//(if add when fill SupportedMediaTypes collection in class constructor then receive post with another boundary will not work - Unsupported Media Type exception will thrown)
if (headers.ContentType == null)
headers.ContentType = new MediaTypeHeaderValue(SupportedMediaType); if (!String.Equals(headers.ContentType.MediaType, SupportedMediaType, StringComparison.OrdinalIgnoreCase))
throw new Exception("Not a Multipart Content"); if (headers.ContentType.Parameters.All(m => m.Name != "boundary"))
headers.ContentType.Parameters.Add(new NameValueHeaderValue("boundary", "MultipartDataMediaFormatterBoundary1q2w3e"));
} public override async Task<object> ReadFromStreamAsync(Type type, Stream readStream, HttpContent content,
IFormatterLogger formatterLogger)
{
var httpContentToFormDataConverter = new HttpContentToFormDataConverter();
FormData multipartFormData = await httpContentToFormDataConverter.Convert(content); IFormDataConverterLogger logger;
if (formatterLogger != null)
logger = new FormatterLoggerAdapter(formatterLogger);
else
logger = new FormDataConverterLogger(); var dataToObjectConverter = new FormDataToObjectConverter(multipartFormData, logger);
object result = dataToObjectConverter.Convert(type); logger.EnsureNoErrors(); return result;
} public override async Task WriteToStreamAsync(Type type, object value, Stream writeStream, HttpContent content,
TransportContext transportContext)
{
if (!content.IsMimeMultipartContent())
throw new Exception("Not a Multipart Content"); var boudaryParameter = content.Headers.ContentType.Parameters.FirstOrDefault(m => m.Name == "boundary" && !String.IsNullOrWhiteSpace(m.Value));
if (boudaryParameter == null)
throw new Exception("multipart boundary not found"); var objectToMultipartDataByteArrayConverter = new ObjectToMultipartDataByteArrayConverter();
byte[] multipartData = objectToMultipartDataByteArrayConverter.Convert(value, boudaryParameter.Value); await writeStream.WriteAsync (multipartData, , multipartData.Length); content.Headers.ContentLength = multipartData.Length;
}
}
}
以IIs为宿主的webapi,加入以下代码
GlobalConfiguration.Configuration.Formatters.Add(new FormMultipartEncodedMediaTypeFormatter());
如果webapi是自我宿主,加入以下代码
new HttpSelfHostConfiguration(<url>).Formatters.Add(new FormMultipartEncodedMediaTypeFormatter());
发送对象时使用FormMultipartEncodedMediaTypeFormatter(测试代码如下):
private ApiResult<T> PostModel<T>(T model, string url)
{
var mediaTypeFormatter = new FormMultipartEncodedMediaTypeFormatter();
using (new WebApiHttpServer(BaseApiAddress, mediaTypeFormatter))
using (var client = CreateHttpClient(BaseApiAddress))
using (HttpResponseMessage response = client.PostAsync(url, model, mediaTypeFormatter).Result)
{
if (response.StatusCode != HttpStatusCode.OK)
{
var err = response.Content.ReadAsStringAsync().Result;
Assert.Fail(err);
} var resultModel = response.Content.ReadAsAsync<ApiResult<T>>(new[] { mediaTypeFormatter }).Result;
return resultModel;
}
}
使用MultipartDataMediaFormatter.Infrastructure.FormData这个类访问原始http数据
[HttpPost]
public void PostFileBindRawFormData(MultipartDataMediaFormatter.Infrastructure.FormData formData)
{
HttpFile file;
formData.TryGetValue(<key>, out file);
}
绑定自定义Model
//model example
public class PersonModel
{
public string FirstName {get; set;} public string LastName {get; set;} public DateTime? BirthDate {get; set;} public HttpFile AvatarImage {get; set;} public List<HttpFile> Attachments {get; set;} public List<PersonModel> ConnectedPersons {get; set;}
} //api controller example
[HttpPost]
public void PostPerson(PersonModel model)
{
//do something with the model
}
编码为multipart/form-data自定义类型(包括文件)如何自动绑定到webapi的action的参数里的更多相关文章
- Idea_学习_03_IDEA中使自定义类型的文件进行代码高亮识别
如果你只是想用xml的编辑模式来编辑*.screen文件的话,可以在 Settings->Editor->File Types 中,在Recognized File Types选中XML, ...
- HTTP请求中的Form Data与Request Payload的区别
前端开发中经常会用到AJAX发送异步请求,对于POST类型的请求会附带请求数据.而常用的两种传参方式为:Form Data 和 Request Payload. GET请求 使用get请求时,参数会以 ...
- html5 file upload and form data by ajax
html5 file upload and form data by ajax 最近接了一个小活,在短时间内实现一个活动报名页面,其中遇到了文件上传. 我预期的效果是一次ajax post请求,然后在 ...
- HTTP 请求中的 Form Data 与 Request Payload 的区别
HTTP 请求中的 Form Data 与 Request Payload 的区别 前端开发中经常会用到 AJAX 发送异步请求,对于 POST 类型的请求会附带请求数据.而常用的两种传参方式为:Fo ...
- Sending forms through JavaScript[form提交 form data]
https://developer.mozilla.org/en-US/docs/Learn/HTML/Forms/Sending_forms_through_JavaScript As in the ...
- sruts2 自定义类型转换器
1.1.1 Struts2中自定义类型转换器:(了解) 类型转换的过程是双向的过程: JSP---->Action参数提交:String---Date. Action---->JSP ...
- asp.net query string 及 form data 遇到的编码问题
当遇到此问题时,脑海里闪过的第一个解决方案是设置 web.config 的编码.但一想,就某一个页面的需求而导致其他跟着妥协,不是好的解决方案.于是网上搜索答案,下面做个小分享,遗憾的是研究不够深入, ...
- Qt自定义类型使用QHash等算法(Qt已经自定义了34种类型,包括int, QString, QDate等基本数据类型)
自定义类型 #include <QCoreApplication> #include <QSet> #include <QDebug> class testCust ...
- [整理]Ajax Post请求下的Form Data和Request Payload
Ajax Post请求下的Form Data和Request Payload 通常情况下,我们通过Post提交表单,以键值对的形式存储在请求体中.此时的reqeuest headers会有Conten ...
随机推荐
- 批处理+VBS+注册表实现开机自动启动EXE程序
批处理+VBS+注册表实现WINDOWS开机自动启动EXE程序 以下都是基于WINDOWS系统. 我们都知道当我们有想某个程序在开机时自动运行,只能有三个方式: 1.做成服务,然后对服务进行配置为自动 ...
- Python中的Class的讨论
尽管Python在Function Programming中有着其他语言难以企及的的优势,但是我们也不要忘了Python也是一门OO语言哦.因此我们关注Python在FP上的优势的同时,还得了解一下P ...
- JavaScript 返回值
Window.Open()返回值: 利用window.open(‘NewWindow.html’):打开新的窗口NewWindow.html后,如果有返回值需要处理,应通过window.opener. ...
- 深入理解PHP原理之变量作用域
26 Aug 08 深入理解PHP原理之变量作用域(Scope in PHP) 作者: Laruence( ) 本文地址: http://www.laruence.com/2008/08/26 ...
- karma+angular
下面的介绍以karma能正常运行为前提,看karma系列文章:http://www.cnblogs.com/laixiangran/tag/Karma/ 目录结构 步骤 安装 npm install ...
- HTML5自学笔记[ 18 ]canvas绘图基础5
获取图像数据:getImgData(x,y,w,h),返回的是一个ImageData对象,这个对象有三个属性保存图像信息:width/height/data.data是一个数组,保存了每个像素的信息, ...
- (08)odoo继承机制
* 全局的引用 所有的的模型定义外,都在注册中心注册了,我们可以用全局变量来引用这些模型 self.env[mode name] 比如得到合作伙伴这个模型 self.evn['res.pa ...
- ZigZag Conversion [LeetCode]
The string "PAYPALISHIRING" is written in a zigzag pattern on a given number of rows like ...
- 你不知道的JavaScript--面向对象高级程序设计
转载http://blog.csdn.net/i10630226/article/details/51088841 1. JS是基于原型的程序 建立一个简单的面向对象的类.有属性,有方法. funct ...
- Java 集合系列 04 LinkedList详细介绍(源码解析)和使用示例
java 集合系列目录: Java 集合系列 01 总体框架 Java 集合系列 02 Collection架构 Java 集合系列 03 ArrayList详细介绍(源码解析)和使用示例 Java ...