.Net Core C# HttpClient

Several Ways To Send Request And Get Response Via HttpClient

Matt 2020/09/10 16:56:30
112

Like I mentioned before, using HttpClient is a large nad important subject in many programming languages.

Therefore, let's talk about that how to send requests through HttpClient. Think about it, the easiest request: In our system, how can we grab data from a remote service? Such as Weathers, Financial information. And how to do that ?

Workshop

Here are some examples about sending requests, getting response via HttpClient.

In many situations, working on HttpClient with System.Net.Http.Json, will have a great help. img "NuGet: System.Net.Http.Json"

-Basic HttpGet

    try
    {
        const string url = "https://jsonplaceholder.typicode.com/posts";

        Console.WriteLine($"== result ==\n");
        var result = httpClient.GetAsync(url).GetAwaiter().GetResult().Content.ReadAsStringAsync().GetAwaiter().GetResult();
        Console.WriteLine(result+"\n\n");
		

        Console.WriteLine($"== result 2 ==\n");
		
        // the result is same as result2 with few different calling
        var result2 = httpClient.GetStringAsync(url).GetAwaiter().GetResult();
        Console.WriteLine(result2 + "\n\n");
		

        Console.WriteLine($"== result 3 ==\n");
		
        // deserialize result2 string into IEnumerable<Pdata> strong type object
        var result3 = System.Text.Json.JsonSerializer.Deserialize<IEnumerable<Pdata>>(result2);
        foreach(var item in result3)
        {
            Console.WriteLine($"{item?.Id}, {item?.UserId}, {item?.Title}, {item?.Body}\n\n");
        }
		

        Console.WriteLine($"== result 4 ==\n");
		
        // result4 is same as result3, but using an easier way with System.Net.Http.Json extension.
        var result4 = httpClient.GetFromJsonAsync<IEnumerable<Pdata>>(url).GetAwaiter().GetResult();
        foreach (var item in result4)
        {
            Console.WriteLine($"{item?.Id}, {item?.UserId}, {item?.Title}, {item?.Body}\n\n");
        }


        Console.WriteLine($"== result 5 ==\n");
		
        // result5 is a standard way to send request, it can help us to fully control about HttpRequest, HttpResponse
        var req = new HttpRequestMessage(HttpMethod.Get, url);
        var sendReq = _httpClient.SendAsync(req).GetAwaiter().GetResult().Content.ReadAsStringAsync().GetAwaiter().GetResult();
        var result5 = System.Text.Json.JsonSerializer.Deserialize<IEnumerable<Pdata>>(sendReq);
        foreach (var item in result5)
        {
            Console.WriteLine($"{item?.Id}, {item?.UserId}, {item?.Title}, {item?.Body}\n\n");
        }
    }
    catch
    {
        throw;
    }

The result is same as result2 with few different calling.

The result3 is deserializing result2 (or result) string into IEnumerable<Pdata>, a strong type object.

The result4 is same as result3, but using an easier way with System.Net.Http.Json extension.

The result5 is a standard way to send request, it can help us to fully control about HttpRequest, HttpResponse.

Result, Basic HttpGet

img "Result, Basic HttpGet"

-HttpGet with Authorization Bearer token

    try
    {
        const string url = "https://api.spotify.com/v1/me/playlists";

        _httpClient.DefaultRequestHeaders.Add("Authorization", "Bearer YOUR_SPOYIFY_AUTHORIZATION_TOKEN");
        var playlist = _httpClient.GetFromJsonAsync<ObjectPagingList<Playlist>>(url).GetAwaiter().GetResult();
		
        ...
		
    }
    catch
    {
        throw;
    }

Calling api with Bearer Token.

Result, HttpGet with Authorization Bearer token

img "Result, HttpGet with Authorization Bearer token"

-HttpPost Json Data to Create

    try
    {
        const string url = "https://jsonplaceholder.typicode.com/posts";
        var data = new Pdata
        {
            Title = "foo",
            Body = "bar",
            UserId = 1991
        };
		
        // while sending Json data to api, don't forget to set up content-type.
        // if not, we might get 405 Method Not Allowed, or wrong data deliveried.
        //_httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        //_httpClient.DefaultRequestHeaders.Accept.TryParseAdd("application/json");

        // or setting it up directly in StringContent
        var jstr = _httpClient.PostAsync(url, 
            new StringContent(JsonSerializer.Serialize(data), Encoding.UTF8, "application/json")
            ).GetAwaiter().GetResult().Content.ReadAsStringAsync().GetAwaiter().GetResult();

        var pdata = JsonSerializer.Deserialize<Pdata>(jstr);
		
        // or we can easily called ReadFromJsonAsync function supported by System.Net.Http.Json extension
        //var pdata = _httpClient.PostAsJsonAsync(url, data).GetAwaiter().GetResult().Content.ReadFromJsonAsync<Pdata>().GetAwaiter().GetResult();
		
        ...
		
    }
    catch
    {
        throw;
    }

While sending Json data to api, don't forget to set up content-type. If not, we might get 405 Method Not Allowed, or wrong data delivered.

HttpPost Json Data to Create while Wrong Content-Type Setting

img "Error Content-Type"

Result, HttpPost Json Data to Create

img "Result, HttpPost Json Data to Create"

-HttpPost by Form (default to enctype="application/x-www-form-urlencoded")

    var tokenUrl = "https://accounts.spotify.com/api/token";
    var req = new HttpRequestMessage(HttpMethod.Post, tokenUrl) {
        Content = new FormUrlEncodedContent(new Dictionary<string, string> {
            { "grant_type", "authorization_code" },
            { "code", code },
            { "redirect_uri", "_YOUR_CALLBACK_URL_" },
        }),
    };
    try
    {
        httpClient.DefaultRequestHeaders.Add("Authorization", $"Basic {_YOUR_BASIC_AUTHORIZATION_}");
        var sendReq = _httpClient.SendAsync(req).GetAwaiter().GetResult();
        if (sendReq.IsSuccessStatusCode)
        {
            var json = sendReq.Content.ReadAsStringAsync().GetAwaiter().GetResult();
            var pdata = JsonSerializer.Deserialize<TokenData>(json);
			
            ...
			
        }
        return default;
    }
    catch
    {
        throw;
    }

Aka standard Form Submit, a common way of sending data.

Result, HttpPost by Form (default to enctype="application/x-www-form-urlencoded")

img "Result, HttpPost by Form (default to enctype=〞application/x-www-form-urlencoded〞)"

-HttpPost An Image File by multipart/form-data

    try
    {
        using var stream = new FileStream(@"r:\animage.jpg", FileMode.Open);
        var streamContent = new StreamContent(stream);
        streamContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
        {
            Name = "image",
            FileName = "animage.jpg"
        };
        const string url = "https://api.imgur.com/3/image";
        var req = new HttpRequestMessage(HttpMethod.Post, url) {
            Content = new MultipartFormDataContent
            {
                { streamContent, "image", "animage.jpg" },

                // based on imgur api, add more fields to post
                { new StringContent("file"), "type" },
                { new StringContent("animage.jpg"), "name" },
                { new StringContent("an image upload test"), "title" },
                { new StringContent("a description"), "description" }
            }
        };

        _httpClient.DefaultRequestHeaders.Add("Authorization", "Bearer YOUR_IMGUR_AUTHORIZATION_TOKEN");
        var sendReq = _httpClient.SendAsync(req).GetAwaiter().GetResult();
        //var sendReq2 = _httpClient.PostAsync(url, multipartFormDataContent).GetAwaiter().GetResult();
		
        ...
		
    }
    catch
    {
        throw;
    }

An other important, and more useful way of sending data to an api.

Result, HttpPost An Image File by multipart/form-data

img "Result, HttpPost An Image File by multipart/form-data"

-HttpPut Request

    try
    {
        const string url = "https://jsonplaceholder.typicode.com/posts/1";
        var data = new Pdata
        {
            Title = "foo-1",
            Body = "bar-1",
            Id = 1
        };
        var res = _httpClient.PutAsync(url,
            new StringContent(JsonSerializer.Serialize(data), Encoding.UTF8, "application/json")
            ).GetAwaiter().GetResult().Content.ReadAsStringAsync().GetAwaiter().GetResult();
			
        ...
		
    }
    catch
    {
        throw;
    }

Result, HttpPut Request

img "Result, HttpPut Request"

-HttpPatch Request

    try
    {
        const string url = "https://jsonplaceholder.typicode.com/posts/1";
        var data = new Pdata
        {
            Title = "foo-2",
            Body = "bar-2",
            Id = 1
        };
        var jstr = _httpClient.PatchAsync(url,
            new StringContent(JsonSerializer.Serialize(data), Encoding.UTF8, "application/json")
            ).GetAwaiter().GetResult().Content.ReadAsStringAsync().GetAwaiter().GetResult();
			
        ...
		
    }
    catch
    {
        throw;
    }

Result, HttpPatch Request

img "Result, HttpPatch Request"

And, that's it. These're almost all kinds of sending and grabbing operations through the HttpClient.

Enjoy it.


References:

Make HTTP requests using IHttpClientFactory in ASP.NET Core

使用者驗證與授權 - Token Based Authentication:驗證 JSON Web Token

C# HttpClient WebAPI : 6. 使用 POST 要求與 multipart/form-data MIME 類型編碼內容 呼叫 Web API

.NET 非同步程式小技巧:GetAwaiter().GetResult() 與 Result 的差異

閱讀筆記 - 使用 .NET Async/Await 的常見錯誤

405 Method Not Allowed

Matt