无法为内容类型multipart配置Web API

我正在使用Web API – Web API 2.我的基本需求是创建一个API来更新用户的配置文件。 在这里,ios和android将以multipart / form-data的forms向我发送请求。 他们会向我发送一些图像参数。 但每当我尝试创建API时,我的模型每次都变为null。

我在WebApiConfig中添加了这一行:

config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("multipart/form-data")); 

这是我的class级:

 public class UpdateProfileModel { public HttpPostedFileBase ProfileImage { get; set; } public string Name { get; set; } } 

这是我的控制器:

 [Route("api/Account/UpdateProfile")] [HttpPost] public HttpResponseMessage UpdateProfile(UpdateProfileModel model) { } 

我甚至没有在我的模型中获取参数值。 难道我做错了什么 ?

没有与此相关的答案对我有帮助。 它大约第3天,我已经尝试了几乎所有的方法。 但我无法实现它。

虽然我可以使用它,但如下所示,但这似乎不是一个好方法。 所以我避免它..

 var httpRequest = HttpContext.Current.Request; if (httpRequest.Form["ParameterName"] != null) { var parameterName = httpRequest.Form["ParameterName"]; } 

对于文件,我可以这样做:

 if (httpRequest.Files.Count > 0) { //i can access my files here and save them } 

如果您有任何好的方法请帮助或者请解释我为什么我无法在模型中获得此值。

非常感谢提前

默认情况下,api中没有内置的媒体类型格式化程序可以处理multipart / form-data并执行模型绑定。 内置媒体类型格式化程序是:

  JsonMediaTypeFormatter: application/json, text/json XmlMediaTypeFormatter: application/xml, text/xml FormUrlEncodedMediaTypeFormatter: application/x-www-form-urlencoded JQueryMvcFormUrlEncodedFormatter: application/x-www-form-urlencoded 

这就是为什么大多数答案涉及接管责任直接从控制器内部的请求读取数据的原因。 但是,Web API 2格式化程序集合应该是开发人员的起点,并不是所有实现的解决方案。 还有其他解决方案可用于创建将处理多部分表单数据的MediaFormatter。 一旦创建了MediaTypeFormatter类,就可以在Web API的多个实现中重用它。

如何为ASP.NET 4.5 Web API创建MultipartFormFormatter

您可以下载并构建Web api 2源代码的完整实现,并查看媒体格式化程序的默认实现本身不处理多部分数据。 https://aspnetwebstack.codeplex.com/

JPgrassi提供的答案就是您要使用MultiPart数据。 我认为还有一些事情需要补充,所以我想写自己的答案。

顾名思义,MultiPart表单数据不是单一类型的数据,而是指定表单将作为MultiPart MIME消息发送,因此您无法使用预定义的格式化程序来读取所有内容。 您需要使用ReadAsync函数来读取字节流并获取不同类型的数据,识别它们并对它们进行反序列化。

有两种方法可以阅读内容。 第一种方法是读取并保留内存中的所有内容,第二种方法是使用提供程序将所有文件内容流式传输到一些随机名称文件(使用GUID)并以本地路径的forms提供句柄以访问文件(提供的示例)由jpgrassi做第二次)。

第一种方法:将所有内容保存在内存中

 //Async because this is asynchronous process and would read stream data in a buffer. //If you don't make this async, you would be only reading a few KBs (buffer size) //and you wont be able to know why it is not working public async Task Post() { if (!request.Content.IsMimeMultipartContent()) return null; Dictionary extractedMediaContents = new Dictionary(); //Here I am going with assumption that I am sending data in two parts, //JSON object, which will come to me as string and a file. You need to customize this in the way you want it to. extractedMediaContents.Add(BASE64_FILE_CONTENTS, null); extractedMediaContents.Add(SERIALIZED_JSON_CONTENTS, null); request.Content.ReadAsMultipartAsync() .ContinueWith(multiPart => { if (multiPart.IsFaulted || multiPart.IsCanceled) { Request.CreateErrorResponse(HttpStatusCode.InternalServerError, multiPart.Exception); } foreach (var part in multiPart.Result.Contents) { using (var stream = part.ReadAsStreamAsync()) { stream.Wait(); Stream requestStream = stream.Result; using (var memoryStream = new MemoryStream()) { requestStream.CopyTo(memoryStream); //filename attribute is identifier for file vs other contents. if (part.Headers.ToString().IndexOf("filename") > -1) { extractedMediaContents[BASE64_FILE_CONTENTS] = memoryStream.ToArray(); } else { string jsonString = System.Text.Encoding.ASCII.GetString(memoryStream.ToArray()); //If you need just string, this is enough, otherwise you need to de-serialize based on the content type. //Each content is identified by name in content headers. extractedMediaContents[SERIALIZED_JSON_CONTENTS] = jsonString; } } } } }).Wait(); //extractedMediaContents; This now has the contents of Request in-memory. } 

第二种方法:使用提供者(由jpgrassi提供)

注意,这只是文件名。 如果您希望在不同位置处理文件或存储,则需要再次流读取该文件。

  public async Task Post() { HttpResponseMessage response; //Check if request is MultiPart if (!Request.Content.IsMimeMultipartContent()) { throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType); } //This specifies local path on server where file will be created string root = HttpContext.Current.Server.MapPath("~/App_Data"); var provider = new MultipartFormDataStreamProvider(root); //This write the file in your App_Data with a random name await Request.Content.ReadAsMultipartAsync(provider); foreach (MultipartFileData file in provider.FileData) { //Here you can get the full file path on the server //and other data regarding the file //Point to note, this is only filename. If you want to keep / process file, you need to stream read the file again. tempFileName = file.LocalFileName; } // You values are inside FormData. You can access them in this way foreach (var key in provider.FormData.AllKeys) { foreach (var val in provider.FormData.GetValues(key)) { Trace.WriteLine(string.Format("{0}: {1}", key, val)); } } //Or directly (not safe) string name = provider.FormData.GetValues("name").FirstOrDefault(); response = Request.CreateResponse(HttpStatusCode.Ok); return response; } 

你不能在你的控制器中有这样的参数,因为没有内置的媒体类型格式化程序来处理Multipart / Formdata。 除非您创建自己的格式化程序,否则可以访问通过MultipartFormDataStreamProvider访问的文件和可选字段:

发布方法

  public async Task Post() { HttpResponseMessage response; //Check if request is MultiPart if (!Request.Content.IsMimeMultipartContent()) { throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType); } string root = HttpContext.Current.Server.MapPath("~/App_Data"); var provider = new MultipartFormDataStreamProvider(root); //This write the file in your App_Data with a random name await Request.Content.ReadAsMultipartAsync(provider); foreach (MultipartFileData file in provider.FileData) { //Here you can get the full file path on the server //and other data regarding the file tempFileName = file.LocalFileName; } // You values are inside FormData. You can access them in this way foreach (var key in provider.FormData.AllKeys) { foreach (var val in provider.FormData.GetValues(key)) { Trace.WriteLine(string.Format("{0}: {1}", key, val)); } } //Or directly (not safe) string name = provider.FormData.GetValues("name").FirstOrDefault(); response = Request.CreateResponse(HttpStatusCode.Ok); return response; } 

以下是一个更详细的示例列表: 在ASP.NET Web API中发送HTML表单数据:文件上载和多部分MIME

不太确定这会对你的情况有所帮助,看一看

带模型的mvc上传文件 – 第二个参数发布文件为空

ASP.Net MVC – 从HttpPostedFileBase读取文件而不保存

那么,对我有用的是 –

 [Route("api/Account/UpdateProfile")] [HttpPost] public Task UpdateProfile(/* UpdateProfileModel model */) { string root = HttpContext.Current.Server.MapPath("~/App_Data"); var provider = new MultipartFormDataStreamProvider(root); await Request.Content.ReadAsMultipartAsync(provider); foreach (MultipartFileData file in provider.FileData) { } } 

还 –

 config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("multipart/form-data")); 

不是必需的。

我想multipart / form-data是在提交表单后的某个地方内部处理的。

这里非常清楚地描述 –

http://www.asp.net/web-api/overview/advanced/sending-html-form-data-part-2