Call post API from-data body using MVC

Viewed 518

How to call post API that using form-data in body message by using MVC client-side.

The API body has TWO attributes in form-data that is message another one is attachments:

enter image description here

I have tried a few methods but its return error due to malformed. This is my code:

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);

and its worked on postman as the screenshot below: enter image description here

This is another try on my controller which is also return code: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

Details postman call below: URL - https://mynewuploadapi. azurewebsites.com/api/v1/customers/discount

Header: Authorization : Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1c2VyIiwiZXhwIjoxNTkzNDIzNzg2LCJpc3MiOiJQbHVzbWlsZXNBUEkifQ.MWa-pbYneOUKvO0_dVVXVFENwBrpU3eGWc47j1YpcmQ

Body. Method (form-post) message:

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

Sample screenshot post-form body: enter image description here

Anyone could please help me regarding this? Thank you

4 Answers

I tested this and it worked:

 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());

It is worked:


  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
                            };
                        }}

this did the trick for me

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

First of all, this is misuse of HttpClient.BaseAddress in your code. you must employ it like :

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);

Second, depending on which way target api expects parameters to be sent him, you should figure out the request structure, Here you don't know about it unless trying to perform some tests. So let's focus on important parts of code :

Authorization

You employed right way to send authorization bearer which is:

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

Data

Your first try in order to serialize then encoding twice with FormUrlEncodedContent & StringContent looks unusual. Your second try suffers from using jsonDeserilizeFromModel as string in Dictionary while this is not the way to merge models. Based on expecting request form in target API, you can make use of one of the following solutions:

Solution A (when you can make a Dictionary<string, string> from the model):

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);

Solution B create a new model (e.g unitModel) containing both message model and attachements:

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);

Solution C Post as Json :

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

We don't know which one can help you since we can't reproduce your problem. Considering that any extra operation such as encoding or bundling the request body can be a reason for target API to return error.

Related