【问题标题】:Multipart/form-data request empty多部分/表单数据请求为空
【发布时间】:2018-07-02 00:41:47
【问题描述】:

我正在尝试在 MultipartFormDataContent 对象中上传图像以及一些 json 数据。但是由于某种原因,我的 webapi 没有正确接收请求。最初,api 以 415 响应直接拒绝请求。为了解决这个问题,我添加了一个用于 multipart/form-data 的 xml 格式化程序到 WebApiConfig.cs

 public static void Register(HttpConfiguration config)
    {
        // Web API configuration and services
        // Configure Web API to use only bearer token authentication.
        config.SuppressDefaultHostAuthentication();
        config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
        config.Formatters.XmlFormatter.SupportedMediaTypes.Add(new System.Net.Http.Headers.MediaTypeHeaderValue("multipart/form-data"));

        // Web API routes
        config.MapHttpAttributeRoutes();

        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{action}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );
    }

这似乎在大多数情况下都有效,我使用 ARC 对其进行了测试,它接收了多部分的所有部分,唯一的问题是字符串内容没有出现在表单中,它在文件中,但我把它归结为请求没有被格式化为StringContent 对象。

我当前遇到的问题是我的 Xamarin 应用程序在发送多部分请求时似乎没有发布任何内容。当请求到达 API Controller 时,内容头和所有内容都在那里,但文件和表单字段都是空的。

在做了一些研究之后,似乎我必须编写一个自定义的MediaTypeFormatter,但我发现的似乎都不是我要找的。​​p>

这是我的其余代码:

API 控制器:

[HttpPost]
    public SimpleResponse UploadImage(Image action)
    {
        SimpleResponse ReturnValue = new SimpleResponse();

        try
        {
            if (HttpContext.Current.Request.Files.AllKeys.Any())
            {
                var httpPostedFile = HttpContext.Current.Request.Files["uploadedImage"];
                var httpPostedFileData = HttpContext.Current.Request.Form["imageDetails"];

                if (httpPostedFile != null) 
                {
                    MiscFunctions misctools = new MiscFunctions();

                    string fileName = User.Identity.Name + "_" + misctools.ConvertDateTimeToUnix(DateTime.Now) + ".jpg";
                    string path = User.Identity.Name + "/" + DateTime.Now.ToString("yyyy-mm-dd");
                    string fullPath = path + fileName;

                    UploadedFiles uploadedImageDetails = JsonConvert.DeserializeObject<UploadedFiles>(httpPostedFileData);

                    Uploaded_Files imageDetails = new Uploaded_Files();

                    imageDetails.FileName = fileName;
                    imageDetails.ContentType = "image/jpeg";
                    imageDetails.DateCreated = DateTime.Now;
                    imageDetails.UserID = User.Identity.GetUserId();
                    imageDetails.FullPath = fullPath;

                    Stream imageStream = httpPostedFile.InputStream;
                    int imageLength = httpPostedFile.ContentLength;

                    byte[] image = new byte[imageLength];

                    imageStream.Read(image, 0, imageLength);

                    Image_Data imageObject = new Image_Data();
                    imageObject.Image_Data1 = image;

                    using (var context = new trackerEntities())
                    {
                        context.Image_Data.Add(imageObject);
                        context.SaveChanges();

                        imageDetails.MediaID = imageObject.ImageID;
                        context.Uploaded_Files.Add(imageDetails);
                        context.SaveChanges();
                    }

                    ReturnValue.Success = true;
                    ReturnValue.Message = "success";
                    ReturnValue.ID = imageDetails.ID;
                }
            }
            else
            {
                ReturnValue.Success = false;
                ReturnValue.Message = "Empty Request";
                ReturnValue.ID = 0;
            }
        }
        catch(Exception ex)
        {
            ReturnValue.Success = false;
            ReturnValue.Message = ex.Message;
            ReturnValue.ID = 0;
        }

        return ReturnValue;
    }

Xamarin 应用 Web 请求:

public async Task<SimpleResponse> UploadImage(ImageUpload action)
    {
        SimpleResponse ReturnValue = new SimpleResponse();

        NSUserDefaults GlobalVar = NSUserDefaults.StandardUserDefaults;
        string token = GlobalVar.StringForKey("token");

        TaskCompletionSource<SimpleResponse> tcs = new TaskCompletionSource<SimpleResponse>();

        try
        {
            using (HttpClient httpClient = new HttpClient())
            {
                httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
                httpClient.DefaultRequestHeaders.Add("Accept", "application/xml");

                using (var httpContent = new MultipartFormDataContent())
                {
                    ByteArrayContent baContent = new ByteArrayContent(action.Image.Data);
                    baContent.Headers.ContentType = new MediaTypeHeaderValue("Image/Jpeg");

                    string jsonString = JsonConvert.SerializeObject(action.UploadFiles);

                    StringContent stringContent = new StringContent(jsonString);
                    stringContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");

                    using (HttpResponseMessage httpResponse = await httpClient.PostAsync(new Uri("http://10.0.0.89/api/Location/UploadImage"), httpContent))
                    {
                        string returnData = httpResponse.Content.ReadAsStringAsync().Result;

                        SimpleResponse jsondoc = JsonConvert.DeserializeObject<SimpleResponse>(returnData);

                        ReturnValue.ID = jsondoc.ID;
                        ReturnValue.Message = jsondoc.Message;
                        ReturnValue.Success = jsondoc.Success;
                    }
                }
            }
        }
        catch(WebException ex)
        {
            ReturnValue.Success = false;

            if (ex.Status == WebExceptionStatus.Timeout)
            {
                ReturnValue.Message = "Request timed out.";
            }
            else
            {
                ReturnValue.Message = "Error";
            }

            tcs.SetResult(ReturnValue);
        }
        catch (Exception e)
        {
            ReturnValue.Success = false;
            ReturnValue.Message = "Something went wrong";
            tcs.SetResult(ReturnValue);
        }

        return ReturnValue;
    }

【问题讨论】:

  • 在什么时候提出请求时,您会将部件添加到httpContent?示例代码没有显示任何内容,因此您基本上是在发送一个空的MultipartFormDataContent
  • 检查链接中接受的答案:forums.xamarin.com/discussion/105805/…。我认为它可以说明您的问题。

标签: c# xamarin asp.net-web-api2


【解决方案1】:
try
   {
var jsonData = "{your json"}";
var content = new MultipartFormDataContent();

content.Add(new StringContent(jsonData.ToString()), "jsonData");
try
   {
     //Checking picture exists for upload or not using a bool variable
     if (isPicture)
       {
         content.Add(new StreamContent(_mediaFile.GetStream()), "\"file\"", $"\"{_mediaFile.Path}\"");
       }
     else
      {
         //If no picture for upload
         content.Add(new StreamContent(null), "file");
      }
   }
  catch (Exception exc)
   {
      System.Diagnostics.Debug.WriteLine("Exception:>" + exc);
   }

var httpClient = new HttpClient();
var response = await httpClient.PostAsync(new Uri("Your rest uri"), content);

 if (response.IsSuccessStatusCode)
 {
   //Do your stuff  
 } 
}
catch(Exception e)
 {
 System.Diagnostics.Debug.WriteLine("Exception:>" + e);
}

其中 _mediaFile 是从图库或相机中选择的文件。 https://forums.xamarin.com/discussion/105805/photo-json-in-xamarin-post-webservice#latest

【讨论】:

    【解决方案2】:

    在尝试发送内容之前,您没有将部分添加到内容中

    //...code removed for brevity
    
    httpContent.Add(baContent, "uploadedImage");
    httpContent.Add(stringContent, "imageDetails");
    
    //...send content
    

    在服务器端你可以检查这个答案

    Http MultipartFormDataContent

    关于如何读取传入的多部分请求

    【讨论】:

    • 我觉得错过了它很愚蠢,一定是在弄乱它的时候把它删除了。它没有解决问题,但是请求的内容长度似乎与请求有效负载的内容长度匹配,所以现在我认为主体已填充,但 httpcontext 没有正确处理它。
    • 我遇到了其他问题,但它似乎已经解决了我在这个问题中提到的问题,如果您想发布链接作为我会接受的答案。感谢您抽出宝贵时间
    猜你喜欢
    • 2014-09-21
    • 2012-11-27
    • 2016-12-17
    • 2012-03-16
    • 2016-11-11
    • 2013-02-12
    • 1970-01-01
    • 2017-10-05
    相关资源
    最近更新 更多