Working with different type of WebClient to consume Web API

This is a list of web clients used in different environments to consume Web API.

Web Client in .NET Framework

To begin with, you have three different choices for consuming REST APIs when working in the .NET Framework: WebClient, HttpClient, and HttpWebRequest. In this post we will look at these three ways we can access REST APIs from within the managed environment, i.e., without resorting to third-party libraries. In the sections that follow I will illustrate these approaches with relevant code examples to help you gain a better understanding of the concepts.

In a nutshell, WebRequest—in its HTTP-specific implementation, HttpWebRequest—represents the original way to consume HTTP requests in .NET Framework. WebClient provides a simple but limited wrapper around HttpWebRequest. And HttpClient is the new and improved way of doing HTTP requests and posts, having arrived with .NET Framework 4.5.

Let’s start our discussion with the WebRequest abstract class.


The System.Net.WebRequest class is an abstract class. Thus you will need to create a HttpWebRequest or FileWebRequest to consume HTTP requests using this class. The following code snippet shows how you can work with WebRequest.

WebRequest webRequest = WebRequest.Create(uri);
webRequest.Credentials = CredentialCache.DefaultCredentials;
webRequest.Method ="GET";
HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse();

WebRequest was the first class provided in the .NET Framework to consume HTTP requests. It gives you a lot of flexibility in handling each and every aspect of the request and response objects, without blocking the user interface thread. You can use this class to access and work with headers, cookies, protocols, and timeouts when working with HTTP. The following code snippet illustrates how HttpWebRequest can be used.

HttpWebRequest http = HttpWebRequest)WebRequest.Create(“http://localhost:8900/api/default”);
WebResponse response = http.GetResponse();
MemoryStream memoryStream = response.GetResponseStream();
StreamReader streamReader = new StreamReader(memoryStream);
string data = streamReader.ReadToEnd();

You can find Microsoft’s documentation on HttpWebRequest here


The System.Net.WebClient class in .NET provides a high-level abstraction on top of HttpWebRequest. WebClient is just a wrapper around HttpWebRequest, so uses HttpWebRequest internally. Thus WebClient is a bit slow compared to HttpWebRequest, but requires you to write much less code. You can use WebClient for simple ways to connect to and work with HTTP services. It is generally a better choice than HttpWebRequest unless you need to leverage the additional features that HttpWebRequest provides. The following code snippet shows how you can work with WebClient.

string data = null;
using (var webClient = new WebClient())
    data = webClient.DownloadString(url);

HttpClient was introduced in .NET Framework 4.5. For developers using .NET 4.5 or later, it is the preferred way to consume HTTP requests unless you have a specific reason not to use it. In essence, HttpClient combines the flexibility of HttpWebRequest and the simplicity of WebClient, giving you the best of both the worlds.

The HttpWebRequest class provides a lot of control over the request/response object. However, you should be aware that HttpClient was never designed to be a replacement for WebClient. You should use HttpWebRequest instead of HttpClient whenever you need the additional features that HttpWebRequest provides. Further, unlike WebClient, HttpClient lacks support for progress reporting and custom URI schemes. 

Although HttpClient doesn’t support FTP, mocking and testing HttpClient is easier. All I/O bound methods in HttpClient are asynchronous, and you can use the same HttpClient instance to make concurrent requests as well. The following code snippet illustrates how you can work with HttpClient.

public async Task<Author> GetAuthorsAsync(string uri)
    Author author = null;
    HttpResponseMessage response = await client.GetAsync(uri);
    if (response.IsSuccessStatusCode)
        author = await response.Content.ReadAsAsync<Author>();
    return author;

Note that when there is an error in the response, HttpClient doesn’t throw an error. Rather, it sets the IsSuccessStatusCode property to false. If you want to throw an exception if the IsSuccessStatusCode property is false, you can make a call to the EnsureSuccessStatusCode method on the response instance as shown below.


HttpClient was designed to be instantiated once and reused throughout the application’s lifecycle—you should not create a new HttpClient instance for every request that your application needs to process. If you do, the available sockets could become exhausted by heavy traffic, resulting in SocketException errors. The recommended practice is to create a single, shared HttpClient instance.


To do…

Web Client in Angular

To do..

JSON Circular Reference Loop Error running Raw SQL in Web API using EF Core

I had a complex stored procedure that I needed to run using EF core in a Web API project. I cannot use LINQ to represent this query. I have followed all best practices outlined here;

Everything worked great except raw sql endpoint. It started giving me “Circular Reference loop error”. To keep thing simple, I am returning DTO from endpoint not the entity.

Newtonsoft.Json.JsonSerializationException: Self referencing loop detected for property 'task' with type 'System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1+AsyncStateMachineBox`1[System.Collections.Generic.IEnumerable`1[FM.Service.Shared.DTO.TranMasterViewDto],FM.Service.LedgerTranViewService+<GetTransactionForProjectActionAsync>d__4]'. Path 'stateMachine.<>t__builder'

Here is my configuration before and after the fix;

Newtonsoft Configuration in program.cs file before the fix;
Newtonsoft Configuration in program.cs file after the fix;
    options => 
    options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore)

The error is gone and I am getting this results.

    "stateMachine": {
        "<>1__state": 0,
        "<>t__builder": {},
        "projectActionID": "82ee5154-971a-ed11-90e6-00155d717606",
        "trackChanges": false,
        "<>4__this": {}
    "context": {},
    "moveNextAction": {
        "method": {
            "name": "MoveNext",

Wait…This is not what I expected. Why I am getting Tasks result where I need to see my Dto results.

It turns out that I am not returning results from my Async method but the task;

public async Task<IActionResult> GetTransactionForProjectActionAsync(Guid projectActionId)
   return Ok(_service.LedgerTranViewService.GetTransactionForProjectActionAsync(projectActionId, trackChanges: false));

Fixing the return type has solved all of my problems;

return Ok(_service.LedgerTranViewService.GetTransactionForProjectActionAsync(projectActionId, trackChanges: false).Result);
        "id": 20221,
        "projectActionID": "82ee5154-971a-ed11-90e6-00155d717606",        
        "tranMasterDetail": [
                "tranMasterId": "9358b0c5-6d30-ed11-90e8-00155d717606",
                "ledgerID": "63302216-0946-ea11-ac82-f81654967f7a",
                "tranDescription": "Rent paid",
                "tranDate": "2022-01-03T00:00:00",
                "tranFlag": 0,
                "tranAmount": 1300.00

Remove Newtonsoft ReferenceLoopHandler from program.cs file.


Hope this will help someone.


Resolve the issue of request matched multiple endpoints in .NET Core Web API

If there are two endpoint with same route, .NET Core Web API will throw request matched multiple endpoints error. Here is an example;

// api/menus/{menuId}/menuitems
public IActionResult GetAllMenuItemsByMenuId(int menuId)

// api/menus/{menuId}/menuitems?userId={userId}
public IActionResult GetMenuItemsByMenuAndUser(int menuId, int userId)

This is impossible because the actions are dynamically activated. The request data (such as a query string) cannot be bound until the framework knows the action signature. It can’t know the action signature until it follows the route. Therefore, we can’t make routing dependent on things the framework doesn’t even know yet.

Long and short, we need to differentiate the routes in some way: either some other static path or making the userId a route param. However, we don’t actually need separate actions here. All action params are optional by default. Therefore, we can just have:

public IActionResult GetMenuItemsByMenu(int menuId, int userId)

And then we can branch on whether userId == 0 (the default). That should be fine here, because there will never be a user with an id of 0, but we may also consider making the param nullable and then branching on userId.HasValue instead, which is a bit more explicit.

We can also continue to keep the logic separate, if we prefer, by utilizing private methods. For example:

public IActionResult GetMenuItems(int menuId, int userId) =>
    userId == 0 ? GetMenuItemsByMenuId(menuId) : GetMenuItemsByUserId(menuId, userId);

private IActionResult GetMenuItemsByMenuId(int menuId)

private IActionResult GetMenuItemsByUserId(int menuId, int userId)

Have fun.

Read more here.

Protected web api configuration

Like web apps, the ASP.NET and ASP.NET Core web APIs are protected because their controller actions are prefixed with the [Authorize] attribute. The controller actions can be called only if the API is called with an authorized identity.

Consider the following questions:

  • Only an app can call a web API. How does the API know the identity of the app that calls it?
  • If the app calls the API on behalf of a user, what’s the user’s identity?

Read more here;

Microservice and Idempotent method

Idempotent method is the one that results in same behavior either in a single or mutiple calls. For example a delete method will delete a resource
and return 204 first time. on subsequent calls it will return 404. return codes has nothting to do with idempotent behavior but the fact is that
behavior of call will always be the same.

| Method | Safe | Idempotent |
| CONNECT | no | no |
| DELETE | no | yes |
| GET | yes | yes |
| HEAD | yes | yes |
| OPTIONS | yes | yes |
| POST | no | no |
| PUT | no | yes |
| TRACE | yes | yes |