How do I use HttpClient PostAsync parameters properly?

36,824

Solution 1

In the PostRequest the following is done..

client.PostAsync(URI, new StringContent(PostParams));
HttpResponseMessage response = client.GetAsync(URI).GetAwaiter().GetResult();

Which does not capture the response of the POST.

Refactor to

public static string PostRequest(string URI, string PostParams) {            
    var response = client.PostAsync(URI, new StringContent(PostParams)).GetAwaiter().GetResult();
    var content = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
    return content;
}

HttpClient is primarily meant to be used async so consider refactoring to

public static async Task<string> PostRequestAsync(string URI, string PostParams) {            
    var response = await client.PostAsync(URI, new StringContent(PostParams));
    var content = await response.Content.ReadAsStringAsync();
    return content;
}

Solution 2

You need prepare object and then you will serialize the object using Newtonsoft.Json. After that you will prepare byte content from the buffer. We are using api url api/auth/login and it is not full api url as we used dependency injection and configure base address in startup, see the second code.

public async void Login(string username, string password)
    {
        LoginDTO login = new LoginDTO();
        login.Email = username;
        login.Password = password;
        var myContent = JsonConvert.SerializeObject(login);
        var buffer = System.Text.Encoding.UTF8.GetBytes(myContent);
        var byteContent = new ByteArrayContent(buffer);
        byteContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");

        var response = await httpClient.PostAsync("api/auth/login", byteContent);
        var contents = await response.Content.ReadAsStringAsync();
    }
services.AddHttpClient<IAuthService, AuthService>(client =>
        {
            client.BaseAddress = new Uri("https://localhost:44354/");
        });

.NET 5 Solution

In .NET 5, There is new class JsonContent and you can implement this easily

LoginDTO login = new LoginDTO();
login.Email = username;
login.Password = password;

JsonContent content = JsonContent.Create(login);
var url = "http://...";
HttpResponseMessage response = await httpClient.PostAsync(url, content);

Solution 3

I have worked the following (using the package Ngonzalez.ImageProcessorCore).

Query (ASP.NET Core 2 Controller):

async Task<byte[]> CreateImage(IFormFile file)
{
  using (var memoryStream = new MemoryStream())
  {
    await file.CopyToAsync(memoryStream);
    var image = new Image(memoryStream);
    var height = image.Height < 150 ? image.Height : 150;
    image.Resize((int)(image.Width * height / image.Height), height).Save(memoryStream);
    return memoryStream.ToArray();
  }
}

[HttpPost, ValidateAntiForgeryToken]
public async Task<IActionResult> ImageAdd(ImageAddVm vm)
{
  byte[] image = null;
  if (vm.File != null && vm.File.Length > 0)
     image = await CreateImage(vm.File);
  if (image != null)
  {
    var json = JsonConvert.SerializeObject(new { vm.ObjectId, image });
    var content = new StringContent(json, Encoding.UTF8, "application/json");
    var client= new HttpClient();
    await client.PostAsync($"{ApiUrl}/SaveImage", content);
  }
  return RedirectToAction("ReturnAction");
}

Api (ASP.NET Core 2 Controller):

public class ObjectImage
{
  public int ObjectId { get; set; }
  public byte[] Image { get; set; }
}

[HttpPost("SaveImage")]
public void SaveImage([FromBody]object content)
{
  var obj = JsonConvert.DeserializeObject<ObjectImage>(content.ToString());
  _db.Images.Find(obj.ObjectId).Image = obj.Image;
  _db.SaveChanges();
}
Share:
36,824
Aleks Slade
Author by

Aleks Slade

Updated on August 16, 2021

Comments

  • Aleks Slade
    Aleks Slade over 2 years

    So I am working on writing an extension class for my project using HttpClient since I am moving over from HttpWebRequest.

    When doing the POST request, how do I send a normal string as a parameter? No json or anything just a simple string.

    And this is what it looks like so far.

    static class HttpClientExtension
        {
            static HttpClient client = new HttpClient();
            public static string GetHttpResponse(string URL)
            {
                string fail = "Fail";
                client.BaseAddress = new Uri(URL);
                HttpResponseMessage Response = client.GetAsync(URL).GetAwaiter().GetResult();
                if (Response.IsSuccessStatusCode)
                    return Response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
                else
                    return fail;
            }
    
            public static string PostRequest(string URI, string PostParams)
            {
                client.PostAsync(URI, new StringContent(PostParams));
                HttpResponseMessage response = client.GetAsync(URI).GetAwaiter().GetResult();
                string content = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
                return content;
            }
        }
    

    If you look at this like

    client.PostAsync(URI, new StringContent(PostParams));
    

    You can see that I just tried creating new StringContent and passing a string into it and the response returned 404 page not found. How do I properly use Post.Async(); do I send a string or byte array? Because with HttpWebRequest you would do it like this

    public static void SetPost(this HttpWebRequest request, string postdata)
            {
                request.Method = "POST";
                byte[] bytes = Encoding.UTF8.GetBytes(postdata);
    
                using (Stream requestStream = request.GetRequestStream())
                    requestStream.Write(bytes, 0, bytes.Length);
            }