3

I am trying to pass a List to my Web API but I keep getting a null value. I am converting the list in to a string before passing it to the API. Any ideas how can I bind it correctly?

public async Task<ReturnViewModel> ModContactsAsync(List<ContactsDTO> Contacts)
 {
     ReturnViewModel vm = new ReturnViewModel();

    var postContactsUri = new UriBuilder(AppConfig.ServiceUrlBase);

    //Converts object into a string
    var jsonObject = new JavaScriptSerializer().Serialize(Contacts);


    postContactsUri.Path = string.Format(POST_CONTACTS_API_PATH, jsonObject);
    //Calls API
    var response = await _httpClient.PostAsync(postContactsUri.ToString());

    return vm;
}

POST - API CALL List prod is null

[HttpPost]
[Route("contacts/Save")]
[ResponseType(typeof(ReturnMessage))]
public async Task<IHttpActionResult> ModContacts([FromBody] List<ContactsDTO> prods)
{
    try
    {
        await Task.Delay(10);

        return Ok();
    }
    catch (Exception ex)
    {
        throw new PropertyPortalWebApiException(HttpStatusCode.InternalServerError, "Contact information does not exist.", ex);
    }
  }
Apollo
  • 1,990
  • 12
  • 44
  • 65

5 Answers5

1

You should simply search and understand GET/POST difference and how to post with HttpClient.

First you are adding your content in URL and trying to post it with HttpClient.

var response = await _httpClient.PostAsync(postContactsUri.ToString());

And then in your API you are reading the object FromBody which has been passed in URL.

public async Task<IHttpActionResult> ModContacts([FromBody] List<ContactsDTO> prods)

The signature of PostAsync method is

public Task PostAsync(Uri uri, HttpContent content)

So you should pass URL in first parameter and your list object in form of HttpContent as second parameter.

Or you can use PostAsJsonAsync extension method.

Mukesh Modhvadiya
  • 2,178
  • 2
  • 27
  • 32
0
public IActionResult GetAllContacts()
{
     List<Contacts> contacts = contactService.RetrieveAllContacts();
     return Json(contacts);
}

So in theory the above would be your API. A user would request GetAllContacts, in which you would get the contacts from the database, then return via Json.

The consumer would then write code to consume:

var request = CreateWebRequest(url) as HttpWebRequest;
if(request != null)
     using(var response = request.GetResponse.GetResponseStream())
          var content = Json.DeserializeObject(request.ReadToEnd());

Something like the above, should return a List<Contacts> for you.

I believe that is what you're trying to do.


Update:

I noticed that you want the consumer to save the data. You would do something along these lines:

public IActionResult SaveContact([FromBody] List<Contacts>)
{
     // Validate and Save
}

The consumer would do either Ajax or something a long these lines:

List<Contact> contacts = contactService.GetAllContacts(); // User would have a collection for you.
var post = Json.SerializeObject(contacts);

var request = WebRequest.Create(url) as HttpWebRequest;
request.Method = "POST";
request.ContentType = ...
request.ContentLength = post.Length;
request.UserAgent = ...
request.Accept = ...
request.Referer = ...

using(var writer = new StreamWriter(request.GetRequestStream())
{
     writer.Write(post); 
     request.GetResponse();
     request.Close();
}

You don't need all the parameters for request I denoted, but they exist. Hopefully this helps.

Greg
  • 11,302
  • 2
  • 48
  • 79
0

I figured out the issue. Just add the Contacts object to the PostAsync to the second parameter and voila. You don't need to convert the object to JSON.

public async Task<ReturnViewModel> ModContactsAsync(List<ContactsDTO> Contacts)
{
    ReturnViewModel vm = new ReturnViewModel();

    var postContactsUri = new UriBuilder(AppConfig.ServiceUrlBase);

    postContactsUri.Path = string.Format(POST_CONTACTS_API_PATH, jsonObject);
    //Add Contacts to second parameter
    var response = await _httpClient.PostAsync(postContactsUri.ToString(), Contacts);

return vm;

}

Apollo
  • 1,990
  • 12
  • 44
  • 65
  • What will be the sending mechanism if I have to pass the list of some object inside main object. Please refer question [here](https://stackoverflow.com/questions/51171160/pass-list-of-object-with-main-object-in-web-api-from-asp-net-mvc). – 3 rules Jul 04 '18 at 10:15
0

Solved my case which was similar to yours (solution here).

Basically:

public async Task<ReturnViewModel> ModContactsAsync(List<ContactsDTO> Contacts)
{
    ReturnViewModel vm = new ReturnViewModel();

    var bodyContent = JsonConvert.SerializeObject(Contacts);

    using (var client = new HttpClient())
    {
        var response = await client.PostAsync(AppConfig.ServiceUrlBase, new StringContent(bodyContent, Encoding.UTF8, "application/json"));

        return responseString.Result.Content.ReadAsStringAsync().Result;
    }

    return vm;
}

As you already know from previous comments, client can't send a list as a query parameter and the server is expecting it on the body.

With the code above, the client sends the list in the body and the server reads it from the body.

Never send a list as a query parameter, even if it's a small list. There is a limitation on URL length and also why exposing your parameters on the URL if the POST method allows you to use the request body to send information...

Fábio
  • 477
  • 5
  • 12
-1

Yes, it's null that is because you try to send a model, but in another method, you try to get the list of objects. You must get the object that involves the list of objects after that your request will read.

ModContacts([FromBody] ContactDTO prod)

In ContactDTO you must have a list of object that will serializable

Andrew
  • 84
  • 2
  • 9