使用 MVC 从数据主体调用 post API

Posted

技术标签:

【中文标题】使用 MVC 从数据主体调用 post API【英文标题】:Call post API from-data body using MVC 【发布时间】:2020-10-12 08:49:36 【问题描述】:

如何使用 MVC 客户端调用在正文消息中使用表单数据的 post API。

API 正文在表单数据中有两个属性,即消息,另一个是附件:

我尝试了一些方法,但由于格式错误而返回错误。这是我的代码:

var client = new HttpClient();
        string APIUrl = "https://mynewuploadapi.azurewebsites.net/api/v1/customers/discount";
        client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1c2VyIiwiZXhwIjoxNTkzMzYyMTYwLCJpc3MiOiJQbHVzbWlsZXNBUEkifQ.DC42fI7dmKCTwzXPyrI5vs6Sxp0FMrOgvvr_uECzJ7Q");
        client.BaseAddress = new Uri("https://mynewuploadapi.azurewebsites.net/api/v1/customers/discount");
        client.Timeout = TimeSpan.FromMilliseconds(1000000);
        
        var converter = new javascriptSerializer().Serialize(model);
        var formContent = new FormUrlEncodedContent(new[]
        
            new KeyValuePair<string, string>("message", @converter),
            new KeyValuePair<string, string>("attachements", null)
        );

        var HTTPcontent = new StringContent(@converter, Encoding.UTF8, "multipart/form-data");

        var response = await client.PostAsync(APIUrl, HTTPcontent);

它在邮递员上工作,如下图所示:

这是我的控制器上的另一个尝试,它也是返回码:500

#region New Try 26Jun
        var newclient = new HttpClient();
        newclient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1c2VyIiwiZXhwIjoxNTkzMzYyMTYwLCJpc3MiOiJQbHVzbWlsZXNBUEkifQ.DC42fI7dmKCTwzXPyrI5vs6Sxp0FMrOgvvr_uECzJ7Q");
        newclient.Timeout = TimeSpan.FromMilliseconds(1000000);
        var dict = new Dictionary<string, string>
        
             "message", jsonDeserilizeFromModel,
             "attachements", null 
        ;
        var values = new FormUrlEncodedContent(dict);
        var newresponse = await newclient.PostAsync(APIUrl, values);
        newresponse.EnsureSuccessStatusCode();
        #endregion

详细邮递员电话如下: 网址 - https://mynewuploadapi. azurewebsites.com/api/v1/customers/discount

标题: 授权:Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1c2VyIiwiZXhwIjoxNTkzNDIzNzg2LCJpc3MiOiJQbHVzbWlsZXNBUEkifQ.MWa-pbYneOUKvO0_dVVXVFENwBrpU3eGWc47j1YpcmQ

身体。方法(表单-发布) 留言:

 
  "tx_type": "Kad Perjalanan",
  "applicant_type": "Pekerja/Pelajar",
  "reg_type": "Permohonan Baharu",
  "ic_type": "NRIC",
  "ic_no": "821210-10-1010",
  "title": "Encik",
  "ic_name": "Ali",
  "dob": "1982-12-10",
  "gender": "Lelaki / Male",
  "mailing_address": "",
  "state": "Selangor",
  "postcode": "40000",
  "city": "Subang",
  "email": "ali@plusti.my",
  "mobile_no": "01020202020",
  "v_make": "Proton",
  "v_model": "Saga",
  "v_year": "2009",
  "v_grant": "12345",
  "v_plateno": "BTP2021VC",
  "co_name": "PLUSTI",
  "co_address": "Tepi PLUSTI Highway",
  "co_postcode": "40000",
  "co_state": "Selangor",
  "co_phone": "0375525251",
  "tngcardno": "1234554321",
  "tngcard_expiry": null,
  "rfidtagno": null,
  "v_owner": "Y",
  "discount_type":"JPP"

表单后正文示例截图:

有人可以帮我解决这个问题吗?谢谢

【问题讨论】:

你能告诉我们控制器签名和完整的错误信息吗? 响应结果的消息是错误代码500。 邮递员没有发送用户名和密码。标头中的不记名 JWT 令牌。和源代码中的一样 @HoomanBahreini 我只是用控制器上的代码更新我的问题 我要求的是控制器代码(服务器端)而不是客户端... 【参考方案1】:

我对此进行了测试,它确实有效:

 var client = new HttpClient();
            string APIUrl = "https://localhost:44398/api/values/test1";
            client.Timeout = TimeSpan.FromMilliseconds(1000000);
            var dict = new Dictionary<string, string>
            
                 "message", "message" ,
                 "attachements", null 
            ;
            var values = new FormUrlEncodedContent(dict);
            var response = await client.PostAsync(APIUrl, values);
            response.EnsureSuccessStatusCode();
            Console.WriteLine(await response.Content.ReadAsStringAsync());

【讨论】:

我刚刚更新了我的问题,附上邮递员成功【参考方案2】:

成功了:


  using (var response = await Task.Run(() => httpClient.PostAsync(httpClient.BaseAddress, httpContent)))
                    
                        var bodyString = await response.Content.ReadAsStringAsync();
                        if (response.StatusCode == HttpStatusCode.OK)
                        
                            return new HttpResponseResult<T>()
                            
                                StatusCode = response.StatusCode,
                                Body = JsonConvert.DeserializeObject<T>(bodyString),
                                ContentType = response.Content.Headers.ContentType?.MediaType
                            ;
                        

【讨论】:

【参考方案3】:

这对我有用

 var baseUrl = "https://mynewuploadapi.azurewebsites.net/api/v1/customers/discount";
        var token = "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1c2VyIiwiZXhwIjoxNTkzMzYyMTYwLCJpc3MiOiJQbHVzbWlsZXNBUEkifQ.DC42fI7dmKCTwzXPyrI5vs6Sxp0FMrOgvvr_uECzJ7Q";

        using (var httpClient = new HttpClient())
        
         
            using (var formData = new MultipartFormDataContent())
            
                formData.Add(new JsonContent(message), "message");
                formData.Add(new JsonContent(fileContent), "attachements");

                httpClient.Timeout = TimeSpan.FromMilliseconds(1000000);
                httpClient.DefaultRequestHeaders.Add("Authorization", "Bearer " + token);
                var response = await httpClient.PostAsync(baseUrl, formData);
                if (!response.IsSuccessStatusCode)
                
                    //ErrorEventArgs handling here
                
            
        

【讨论】:

【参考方案4】:

首先,这是您代码中HttpClient.BaseAddress误用。你必须像这样使用它:

string APIUrl = "https://mynewuploadapi.azurewebsites.net/api/v1";
client.BaseAddress = new Uri(APIUrl);

//then call api with the following
var response = await client.PostAsync("/customers/discount", content);

其次,根据target api期望参数发送给他的方式,你应该弄清楚请求结构,这里你不知道它,除非尝试执行一些测试。所以让我们专注于代码的重要部分:

授权

您采用了正确的方式发送授权承载,即:

httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "Your Oauth token");

数据

您第一次尝试序列化然后编码两次使用FormUrlEncodedContentStringContent看起来不寻常。您的第二次尝试在 Dictionary 中使用 jsonDeserilizeFromModel 作为 string,而这不是合并模型的方法。根据目标 API 中的预期请求表单,您可以使用以下解决方案之一:

解决方案 A(当您可以从 模型 中创建 Dictionary&lt;string, string&gt; 时):

MultipartFormDataContent form = new MultipartFormDataContent();
HttpContent file = new StringContent("file to upload as StreamContent");
HttpContent msgItems = new FormUrlEncodedContent(model.ToDictionary());//<string, string>
form.Add(file, "attachements");
form.Add(msgItems, "message");
var response = await client.PostAsync("/customers/discount", form);

解决方案 B 创建一个包含 消息 模型和 附件 的新 model(例如 unitModel):

var json = JsonConvert.SerializeObject(unitModel);// or JavaScriptSerializer().Serialize
var data = new StringContent(json, Encoding.UTF8, "application/json");
var response = await client.PostAsync("/customers/discount", data);

解决方案 C 以 Json 身份发布:

//'unitModel' is a class containing both 'message' & 'attachements'
var result = await client.PostAsJsonAsync("/customers/discount", unitModel);

我们不知道哪一个可以帮助您,因为我们无法重现您的问题。考虑到任何额外的操作,例如编码绑定请求正文 可能是目标API返回错误的原因.

【讨论】:

以上是关于使用 MVC 从数据主体调用 post API的主要内容,如果未能解决你的问题,请参考以下文章

NodeJ使用请求承诺来调用外部API,从响应主体中保存数据

使用表单主体的 Spring MVC Controller 方法映射

POST请求标头与rest api中敏感数据的请求主体

在 POST 数据中从 Api 控制器重定向到 MVC 控制器

在 ASP.NET MVC 5 控制器中使用 POST 从 dotnet Core Web API 下载文件

使用 mvc 视图中的参数从 jquery 调用 web api