C# 无法为内容类型多部分配置Web API

C# 无法为内容类型多部分配置Web API,c#,asp.net-web-api,asp.net-mvc-5,asp.net-web-api2,C#,Asp.net Web Api,Asp.net Mvc 5,Asp.net Web Api2,我正在开发Web API的-Web API 2。我的基本需要是创建一个API来更新用户的配置文件。在这种情况下,ios和android将以多部分/表单数据的形式向我发送请求。他们会给我发送一些带有图像的参数。但是每当我尝试创建API时,我的模型每次都是空的 我在WebApiConfig中也添加了这一行: config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("multipart/form-

我正在开发Web API的-Web API 2。我的基本需要是创建一个API来更新用户的配置文件。在这种情况下,ios和android将以多部分/表单数据的形式向我发送请求。他们会给我发送一些带有图像的参数。但是每当我尝试创建API时,我的模型每次都是空的

我在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)
{
}
我甚至没有在我的模型中得到参数值。我做错什么了吗

与此相关的答案对我都没有帮助。大约是第三天,我已经尝试了几乎所有的方法。但我无法做到这一点

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

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
}
请帮助,如果你有任何好的方法,它或请解释我为什么我不能得到这个模型中的值


事先非常感谢

不太确定这对您的情况是否有帮助,请看一看


所以,对我有效的是-

[Route("api/Account/UpdateProfile")]
[HttpPost]
public Task<HttpResponseMessage> 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)
        {

        }
}
这不是必需的

我猜多部分/表单数据是在表单提交后的某个地方进行内部处理的

这里描述得很清楚-


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

发布方法

 public async Task<HttpResponseMessage> 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;
}
public async Task Post()
{
HttpResponseMessage响应;
//检查请求是否为多部分
如果(!Request.Content.IsMimeMultipartContent())
{
抛出新的HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
string root=HttpContext.Current.Server.MapPath(“~/App_Data”);
var provider=新的MultipartFormDataStreamProvider(根);
//这将使用随机名称在应用程序数据中写入文件
wait Request.Content.ReadAsMultipartAsync(提供程序);
foreach(provider.FileData中的MultipartFileData文件)
{
//在这里,您可以获得服务器上的完整文件路径
//和其他有关该文件的数据
tempFileName=file.LocalFileName;
}
//您的值位于FormData中。您可以通过这种方式访问它们
foreach(provider.FormData.AllKeys中的var键)
{
foreach(provider.FormData.GetValues(键)中的var val)
{
Trace.WriteLine(string.Format(“{0}:{1}”,key,val));
}
}
//或直接(不安全)
字符串名称=provider.FormData.GetValues(“名称”).FirstOrDefault();
response=Request.CreateResponse(HttpStatusCode.Ok);
返回响应;
}
下面是更详细的示例列表:

默认情况下,api中没有内置的媒体类型格式化程序可以处理多部分/表单数据并执行模型绑定。内置媒体类型格式化程序包括:

 JsonMediaTypeFormatter: application/json, text/json
 XmlMediaTypeFormatter: application/xml, text/xml
 FormUrlEncodedMediaTypeFormatter: application/x-www-form-urlencoded
 JQueryMvcFormUrlEncodedFormatter: application/x-www-form-urlencoded
这就是为什么大多数答案都涉及直接从控制器内部的请求读取数据的责任。然而,WebAPI2格式化程序集合是开发人员的起点,而不是所有实现的解决方案。还创建了其他解决方案来创建将处理多部分表单数据的MediaFormatter。创建MediaTypeFormatter类后,它可以在Web API的多个实现中重复使用

您可以下载并构建web api 2源代码的完整实现,并看到媒体格式化程序的默认实现不会以本机方式处理多部分数据。

JPgrassi提供的答案是您将如何获得多部分数据。我想没有什么需要补充的了,所以我想写我自己的答案

顾名思义,多部分表单数据不是单一类型的数据,而是指定表单将作为多部分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 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.
}
//异步,因为这是一个异步进程,将读取缓冲区中的流数据。
//如果不使其异步,则只能读取几个KBs(缓冲区大小)
//你将无法知道它为什么不起作用
公共异步任务Post()
{
如果(!request.Content.IsMimeMultipartContent())返回null;
Dictionary extractedMediaContents=新字典();
//这里我假设我发送的数据分为两部分,
//JSON对象,它将以字符串和文件的形式呈现给我。您需要以您希望的方式自定义它。
extractedMediaContents.Add(BASE64\u文件内容,null);
extractedMediaContents.Add(序列化的内容,null);
request.Content.ReadAsMultipartAsync()
.ContinueWith(多部分=>
{
if(multiPart.IsFaulted | | multiPart.IsCanceled)
{
Request.CreateErrorResponse(HttpStatusCode.InternalServerError,multiPart.Exception);
}
foreach(multiPart.Result.Contents中的var部分)
{
使用
//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.
}
 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;
}