我正在使用Web API - Web API 2.我的基本需求是创建一个API来更新用户的配置文件.在这里,ios和android会以multipart/form-data的形式向我发送请求.他们会向我发送一些图像参数.但每当我尝试创建API时,我的模型每次都变为null.
我在WebApiConfig中添加了这一行:
config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("multipart/form-data"));
这是我的班级:
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 }
如果您有任何好的方法,请帮助或者请解释我为什么我无法在模型中获得此值.
非常感谢提前
JPgrassi提供的答案就是您要使用MultiPart数据.我认为还有一些事情需要补充,所以我想写自己的答案.
顾名思义,MultiPart表单数据不是单一类型的数据,而是指定表单将作为MultiPart MIME消息发送,因此您无法使用预定义的格式化程序来读取所有内容.您需要使用ReadAsync函数来读取字节流并获取不同类型的数据,识别它们并对它们进行反序列化.
有两种方法可以阅读内容.第一种方法是读取并保留内存中的所有内容,第二种方法是使用提供程序将所有文件内容流式传输到一些随机名称文件(使用GUID)并以本地路径的形式提供句柄以访问文件(提供的示例)由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 TaskPost() { 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 TaskPost() { 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; }
默认情况下,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/