【问题标题】:ASP.NET How read a multipart form data in Web API?ASP.NET 如何在 Web API 中读取多部分表单数据?
【发布时间】:2017-03-30 15:29:11
【问题描述】:

我像这样向我的 Web API 发送多部分表单数据:

string example = "my string";
HttpContent stringContent = new StringContent(example);
HttpContent fileStreamContent = new StreamContent(stream);
using (var client = new HttpClient())
{
    using (var content = new MultipartFormDataContent())
    {
         content.Add(stringContent, "example", "example");
         content.Add(fileStreamContent, "stream", "stream");
         var uri = "http://localhost:58690/api/method";
         HttpResponseMessage response = await client.PostAsync(uri, content);

这是 Web API:

[HttpPost]
[Route("api/method")]
public async Task<HttpResponseMessage> Method()
    {
         // take contents and do something
    }

如何在我的 Web API 中从请求正文中读取字符串和流?

【问题讨论】:

    标签: c# asp.net asp.net-web-api


    【解决方案1】:

    这应该可以帮助您入门:

     var uploadPath = HostingEnvironment.MapPath("/") + @"/Uploads";
     Directory.CreateDirectory(uploadPath);
     var provider = new MultipartFormDataStreamProvider(uploadPath);
     await Request.Content.ReadAsMultipartAsync(provider);
    
     // Files
     //
     foreach (MultipartFileData file in provider.FileData)
     {
         Debug.WriteLine(file.Headers.ContentDisposition.FileName);
         Debug.WriteLine("File path: " + file.LocalFileName);
     }
    
     // Form data
     //
     foreach (var key in provider.FormData.AllKeys)
     {
         foreach (var val in provider.FormData.GetValues(key))
         {
              Debug.WriteLine(string.Format("{0}: {1}", key, val));
         }
     }
    

    【讨论】:

    • 谢谢!如果我不需要将参数保存在我的 Web API 所在的服务器上,而只是对其进行操作,那么过程是否相同?
    • @Giobbo ...我不确定您保存参数是什么意思。您是指请求正文的内容(文件等)吗?如果是这样,不,您可以将它们保存在内存中,但要小心大文件。
    • 是的,对不起(我的英语很糟糕)。在我的示例中,我指的是正文内容、流和字符串。我想简单地从身体中取出并用它们做点什么。
    【解决方案2】:

    这是我之前用来接收 json 数据 + 一个可选文件的代码:

    var result = await Request.Content.ReadAsMultipartAsync();
    
    var requestJson = await result.Contents[0].ReadAsStringAsync();
    var request = JsonConvert.DeserializeObject<MyRequestType>(requestJson);
    
    if (result.Contents.Count > 1)
    {
        var fileByteArray = await result.Contents[1].ReadAsByteArrayAsync();
        ...
    }
    

    你可以像这样在请求中组合不同类型的数据,这真是太棒了。

    编辑:如何发送此请求的示例:

    let serialisedJson = JSON.stringify(anyObject);
    let formData = new FormData();
    formData.append('initializationData', serialisedJson);
    // fileObject is an instance of File
    if (fileObject) {
        // the 'jsonFile' name might cause some confusion: 
        // in this case, the uploaded file is actually a textfile containing json data
        formData.append('jsonFile', fileObject);
    }
    
    return new Promise((resolve, reject) => {
        let xhr = new XMLHttpRequest();
        xhr.open('POST', 'http://somewhere.com', true);
        xhr.onload = function(e: any) {
            if (e.target.status === 200) {
                resolve(JSON.parse(e.target.response));
            }
            else {
                reject(JSON.parse(e.target.response));
            }
        };
        xhr.send(formData);
    });
    

    【讨论】:

    • 请求是什么样的?
    • 对于这个例子,在我的客户端代码中,我实例化了一个 FormData 类,然后我将序列化的 json 添加到其中(所以不是对象本身,而是字符串化的版本),并且可选地我还可以添加一个文件对象,然后我用 XmlHttpRequest 发送 FormData 实例(我实际上是使用 angular2 来做这个请求,但是 angular 的 Http 服务不允许你这样做,所以你需要自己处理 XmlHttpRequest)
    • 我实际上刚刚通过 Angular $http 服务发送了一个包含一些字段和一个文件的 FormData 对象,该服务为我的项目工作。主要的奇怪之处在于我必须将内容类型显式设置为未定义......而且我没有序列化任何东西,只是将主体设置为 FormData 对象。不过我使用的是 Angular 1.6。
    • 哦,你正在使用一个 xml 请求,我的最终是一个表单/多部分,有趣.. :)
    【解决方案3】:

    您可以读取内容并获取所有文件信息(在我的示例图像中),而无需通过这种方式复制到本地磁盘:

    public async Task<IHttpActionResult> UploadFile()
    {
        if (!Request.Content.IsMimeMultipartContent())
        {
            return StatusCode(HttpStatusCode.UnsupportedMediaType);
        }        
    
        var filesReadToProvider = await Request.Content.ReadAsMultipartAsync();
    
        foreach (var stream in filesReadToProvider.Contents)
        {
            // Getting of content as byte[], picture name and picture type
            var fileBytes = await stream.ReadAsByteArrayAsync();
            var pictureName = stream.Headers.ContentDisposition.FileName;
            var contentType = stream.Headers.ContentType.MediaType;
        }
    }
    

    【讨论】:

      【解决方案4】:

      用于发送多个文件

              System.Web.HttpFileCollection hfc = System.Web.HttpContext.Current.Request.Files;
      
              //// CHECK THE FILE COUNT.
              for (int iCnt = 0; iCnt <= hfc.Count - 1; iCnt++)
              {
                  System.Web.HttpPostedFile hpf = hfc[iCnt];
                  string Image = UploadDocuments.GetDocumentorfileUri(hpf);
                  UploadDocuments.UploadDocumentsIntoData(Image, hpf.FileName, id);
      
              }
      

      Sending HTML Form Data in ASP.NET Web API: File Upload and Multipart MIME

      【讨论】:

        【解决方案5】:
         // read the file content without copying to local disk and write the content byte to file 
               try
               {
                   var filesReadToProvider = await Request.Content.ReadAsMultipartAsync();
                   JavaScriptSerializer json_serializer = new JavaScriptSerializer();
        
                   foreach (var stream in filesReadToProvider.Contents)
                   {
        
                       //getting of content as byte[], picture name and picture type
                       var fileBytes = await stream.ReadAsByteArrayAsync();
                       var fileName = stream.Headers.ContentDisposition.Name;
        
                       var pictureName = stream.Headers.ContentDisposition.FileName;
                       var contentType = stream.Headers.ContentType.MediaType;
                       var path = Path.Combine(HttpContext.Current.Server.MapPath("~/Images/Upload/"), json_serializer.Deserialize<string>(pictureName));
        
                       File.WriteAllBytes(path, fileBytes);
                   }
        
                   return Request.CreateResponse(HttpStatusCode.OK);
               }catch(Exception ex)
               {
                   return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, ex);
               }
        

        【讨论】:

          【解决方案6】:

          //Web用户界面方法 protected void btnPrescAdd_Click(对象发送者,EventArgs e) {

                  NameValueCollection collection = new NameValueCollection();
          
                  collection.Set("c1", Session["CredID"].ToString());
                  collection.Set("p1", "");
                  collection.Set("p2", Request.Form["ctl00$MainContent$hdnHlthId"]);
                  collection.Set("p3", Request.Form["ctl00$MainContent$PresStartDate"]);
                  collection.Set("p4", Request.Form["ctl00$MainContent$PrescEndDate"]);
          
                  FileUpload fileUpload = PrescUpload;
          
                  ApiServices<Status> obj = new ApiServices<Status>();
                  Status objReturn = obj.FetchObjectUploadAPI("POSTUHRPL", collection, 
                   fileUpload, ApiServices<Status>.ControllerType.DU);
          
              }
          

          //请求方法

            public T1 FetchObjectUploadAPI(string strAPIMethod, NameValueCollection collection, FileUpload file, ControllerType enObj)
              {
                  T1 objReturn;
                  try
                  {
                      string url = strWebAPIUrl + getControllerName(enObj) + strAPIMethod;
          
                      MultipartFormDataContent content = new MultipartFormDataContent();
          
          
          
                      int count = collection.Count;
                      List<string> Keys = new List<string>();
                      List<string> Values = new List<string>();
          
                      //MemoryStream filedata = new MemoryStream(file);
                      //Stream  stream = filedata;
                      for (int i = 0; i < count; i++)
                      {
                          Keys.Add(collection.AllKeys[i]);
                          Values.Add(collection.Get(i));
          
                      }
          
                      for (int i = 0; i < count; i++)
                      {
                          content.Add(new StringContent(Values[i], Encoding.UTF8, "multipart/form-data"), Keys[i]);
                      }
          
                      int fileCount = file.PostedFiles.Count();
          
                      HttpContent filecontent = new StreamContent(file.PostedFile.InputStream);
          
          
                      content.Add(filecontent, "files");
          
                      HttpClient client = new HttpClient();
          
          
                      HttpResponseMessage response = client.PostAsync(url, content).Result;
          
                      if (response.IsSuccessStatusCode)
                      {
                          objReturn = (new JavaScriptSerializer()).Deserialize<T1>(response.Content.ReadAsStringAsync().Result);
                      }
                      else
                          objReturn = default(T1);
          
                  }
                  catch (Exception ex)
                  {
                      Logger.WriteLog("FetchObjectAPI", ex, log4net_vayam.Constants.levels.ERROR);
                      throw (ex);
                  }
                  return objReturn;
          
              }
          

          https://stackoverflow.com/users/9600164/gaurav-sharma

          【讨论】:

            【解决方案7】:

            派对迟到了,但其他人必须使用 ASP.NET Web API (1/2):

                [HttpPost, Route("img/up")]
                public async Task<IHttpActionResult> ItemImage()
                {
                    var data = HttpContext.Current.Request.Form["example"];
                    var item = JsonConvert.DeserializeObject<Example>(data);
                    if (item == null) return BadRequest("Invalid request: Example cannot be null");
            
                    var path = HostingEnvironment.MapPath("/") + @"img";
                    if (!Directory.Exists(path))
                        Directory.CreateDirectory(path);
            
                    try
                    {
                        var image = HttpContext.Current.Request.Files["stream"];
                        if (image == null) return BadRequest("Invalid request: no image received.");
                        path = $@"{path}\{DateTime.Now:MMddyyHHmmss}.png";
                        image.SaveAs(path);
                    }
                    catch (Exception e)
                    {
                        // TODO: Document Exception
                    }
                    return Ok();
                }
            

            在这里您可以看到我们正在接受对 /api/img/up 端点的 HttpPost 请求。 目前我们没有检查 Mime 类型,但您可以根据需要检查。

            首先,我们为您的“示例”获取表单数据并将其从 json 反序列化为 Example 类(将其替换为您用作模型的内容)

            然后我们确保 img 目录存在(如果您希望它位于 API 文件之外的某个位置,请修改路径)

            然后我们从HttpContext.Current.Request.Files["stream"] 中获取stream 对象 我从文件名是时间戳的端点获取了这个 sn-p(以支持同一标识符的多个图像)

            我尽量保持简单和甜美,由于客户端/服务器分层,它可能有点抽象。

            如果你需要测试我推荐PostMan:

            【讨论】:

              猜你喜欢
              • 2023-04-04
              • 1970-01-01
              • 2019-06-08
              • 2017-09-26
              • 2014-01-08
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多