Search code examples
c#asp.net-core

ASP.NET FormUrlEncode with child List KeyValuePair


I'm calling an API using HTTP POST with a form URL encoded body

The controller I'm calling looks like this:

public async Task<IHttpActionResult> DoSomethingAsync(ABCRequest widget)

[DataContract]
public class ABCRequest
{
  [DataMember(Name="name")]
  public string Name { get; set; }

  [DataMember(Name="number")]
  public string Number { get; set; }
}

I can happily call the API using the following method

var formData = new List<KeyValuePair<string, string>>
{
    new KeyValuePair<string, string>("Name", "John"),
    new KeyValuePair<string, string>("Number", "123")
};

HttpContent content = new FormUrlEncodedContent(formData);

Another API endpoint uses

public async Task<IHttpActionResult> DoSomething2Async(ABCRequest2 widget)
    
    [DataContract]
    public class ABCRequest2
    {
      [DataMember(Name="name")]
      public string Name { get; set; }

      [DataMember(Name="number")]
      public string Number { get; set; }

      [DataMember(Name="metadata")]
      public List<KeyValuePair<string, string>> Metadata { get; set; }
    }

How do I form URL encode the child List?


Solution

  • How do I form URL encode the child List?

    According ot your scenario and description along with the share code snippet, I have tried to simulate your scenario and I was able to send send child metadata list with URL encoded value.

    In order to form URL encoded child list of KeyValuePair<string, string> in your ABCRequest2 class, you need to flatten the structure into key-value pairs that can be properly encoded.

    First of all, you need to convert the child list into individual key-value pairs where each pair has a unique key representing its position or specific identifier.

    After constructing the key-value pairs, have to use FormUrlEncodedContent to encode the flat list.

    Let's have a look in practice, how we could achieve that:

    From a key value pairs encoded content:

    var formData = new List<KeyValuePair<string, string>>
    {
        new KeyValuePair<string, string>("name", "John"),
        new KeyValuePair<string, string>("number", "123")
    };
    
    var metadataList = new List<KeyValuePair<string, string>>
    {
        new KeyValuePair<string, string>("key1", "value1"),
        new KeyValuePair<string, string>("key2", "value2")
    };
    
    for (int i = 0; i < metadataList.Count; i++)
    {
        formData.Add(new KeyValuePair<string, string>($"metadata[{i}].Key", metadataList[i].Key));
        formData.Add(new KeyValuePair<string, string>($"metadata[{i}].Value", metadataList[i].Value));
    }
    
    HttpContent content = new FormUrlEncodedContent(formData);
    
    using (var client = new HttpClient())
    {
        var response = await client.PostAsync("https://localhost:7246/api/Receiving/ReceiveData", content);
        if (response.IsSuccessStatusCode)
        {
            var responseData = await response.Content.ReadAsStringAsync();
            return Ok(responseData);
        }
        return BadRequest("Failed to send data");
    }
    

    Receiving Controller:

    [Route("api/[controller]")]
    [ApiController]
    public class ReceivingController : ControllerBase
    {
        [HttpPost]
        [Route("ReceiveData")]
        public async Task<IActionResult> ReceiveData([FromForm] ABCRequest2 widget)
        {
           
            return Ok(widget);
        }
    }
    

    Output: enter image description here

    enter image description here enter image description here enter image description here

    Note: Please refer to this official document for additionl reference and sample