无法为内容类型多部分配置 Web API [英] unable to configure Web API for content type multipart

查看:17
本文介绍了无法为内容类型多部分配置 Web API的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发 Web API - Web API 2.我的基本需求是创建一个 API 来更新用户的个人资料.在这种情况下,ios 和 android 将在 multipart/form-data 中向我发送请求.他们会给我发送一些带有图像的参数.但是每当我尝试创建 API 时,我的模型每次都为空.

I am working on Web API's - Web API 2. My basic need is to create an API to update profile of the user. In this the ios and android will send me the request in multipart/form-data. They will send me few parameters with an image. But whenever i try to create the API, my model comes to be null every time.

我也在 WebApiConfig 中添加了这一行:

I have added this line in WebApiConfig also:

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)
{
}

我什至没有在我的模型中获取参数值.我做错了什么吗?

I am even not getting parameter values in my Model. Am i doing something wrong ?

与此相关的所有答案都对我没有帮助.大约是第三天,我几乎尝试了所有方法和方法.但我无法实现.

None of the answers related to this were helpful for me. Its about 3rd day and i have tried almost everything and every method. but i am unable to achieve it.

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

Although i can use this but this as shown below but this doesn't seem to be a good approach. so i am avoiding it..

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

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

and for files i can do this:

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

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

Please help if you have any good approach for it Or Please explain me why i am unable to get this values in Model.

先谢谢了

推荐答案

JPgrassi 提供的答案是您将如何获得 MultiPart 数据.我觉得还需要补充的东西很少,所以我想写一个自己的答案.

The answer provided by JPgrassi is what you would be doing to have MultiPart data. I think there are few more things that needs to be added, so I thought of writing my own answer.

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

MultiPart form data, as the name suggest, is not single type of data, but specifies that the form will be sent as a MultiPart MIME message, so you cannot have predefined formatter to read all the contents. You need to use ReadAsync function to read byte stream and get your different types of data, identify them and de-serialize them.

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

There are two ways to read the contents. First one is to read and keep everything in memory and the second way is to use a provider that will stream all the file contents into some randomly name files(with GUID) and providing handle in form of local path to access file (The example provided by jpgrassi is doing the second).

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

//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<HttpResponseMessage> Post()
{

if (!request.Content.IsMimeMultipartContent()) return null;

        Dictionary<string, object> extractedMediaContents = new Dictionary<string, object>();

        //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 提供)

注意,这只是文件名.如果要处理文件或存储在不同的位置,则需要再次流式读取文件.

Point to note, this is only filename. If you want process file or store at different location, you need to stream read the file again.

 public async Task<HttpResponseMessage> 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;
}

这篇关于无法为内容类型多部分配置 Web API的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆