编码为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 ...
随机推荐
- 线程高级应用-心得6-java5线程并发库中同步工具类(synchronizers),新知识大用途
1.新知识普及 2. Semaphore工具类的使用案例 package com.java5.thread.newSkill; import java.util.concurrent.Executor ...
- Java中的数学运算BigDecimal
Math类 package ch7; /** * Created by Jiqing on 2016/11/24. */ public class MathDemo { public static v ...
- Android 视频投射之NanoHTTPD
Android 视频投射之NanoHTTPD 号称用一个java文件实现Http服务器 有必要对其源码及例子进行分析 public abstract class NanoHTTPD { //异步执行请 ...
- hdu 4965 Fast Matrix Calculation
题目链接:hdu 4965,题目大意:给你一个 n*k 的矩阵 A 和一个 k*n 的矩阵 B,定义矩阵 C= A*B,然后矩阵 M= C^(n*n),矩阵中一切元素皆 mod 6,最后求出 M 中所 ...
- JVM系列三:JVM参数设置、分析
不管是YGC还是Full GC,GC过程中都会对导致程序运行中中断,正确的选择不同的GC策略,调整JVM.GC的参数,可以极大的减少由于GC工作,而导致的程序运行中断方面的问题,进而适当的提高Java ...
- 转:C++语言的15个晦涩特性
转自 http://blog.jobbole.com/54140/ 操作符重载和检查顺序 重载,(逗号),||或者&&操作符会引起混乱,因为它打破了正常的检查规则.通常情况下,逗号操作 ...
- OpenGL的glPushMatrix和glPopMatrix矩阵栈顶操作函数详解
OpenGL中图形绘制后,往往需要一系列的变换来达到用户的目的,而这种变换实现的原理是又通过矩阵进行操作的.opengl中的变换一般包括视图变换.模型变换.投影变换等,在每次变换后,opengl将会呈 ...
- 图片左右滚动的js代码
html代码 <div class="demo" id="demo" style="overflow:hidden; width:660px; ...
- 31-View如何从Action取得数据
从Action取得数据,在ASP.NET MVC可区分成两种方式,一种是“使用弱类型取得数据”,另一种则是“使用强类型取得数据”,两者的差别在于View页面最上方声明的方式. 如果View页面使用弱类 ...
- 《Java程序设计》第五周学习总结
20145224 <Java程序设计>第五周学习总结 教材学习内容总结 第八章异常处理 8.1.1使用try.catch ·教材范例用户连续输入整数,输入0结束后显示输入数的平均值(代码如 ...