Create a Generic REST Client in C#
In this article, we will explore how to create a generic asynchronous RESTful HttpClient that can be used with any service. This class will simplify the process of creating RESTful clients that interact with RESTful services. It is especially useful if you need to build a RESTful cross-domain client. Let’s get started!
Why Do We Need a Generic Client?
When working with RESTful services, we often need to interact with multiple resources that have different types and identifiers. Instead of creating separate client classes for each resource, a generic client provides a flexible and reusable solution. By using a generic REST client, we can avoid code duplication and reduce maintenance effort.
The RestClient Class
First, let’s create a generic class called RestClient<TResource, TIdentifier>
that implements the IDisposable
interface and accepts two type parameters: TResource
and TIdentifier
. This class will serve as our REST client.
RestClient.cs
Create a generic class with two-parameter TResource
and TIdentifier
public class RestClient<TResource, TIdentifier> : IDisposable where TResource : class
{
private HttpClient httpClient;
protected readonly string _baseAddress;
private readonly string _addressSuffix;
private bool disposed = false;
public RestClient(string baseAddress, string addressSuffix)
{
_baseAddress = baseAddress;
_addressSuffix = addressSuffix;
httpClient = CreateHttpClient(_baseAddress);
}
protected virtual HttpClient CreateHttpClient(string serviceBaseAddress)
{
httpClient = new HttpClient();
httpClient.BaseAddress = new Uri(serviceBaseAddress);
return httpClient;
}
public async Task<TResource> GetAsync(TIdentifier identifier)
{
var responseMessage = await httpClient.GetAsync(_addressSuffix + identifier.ToString());
responseMessage.EnsureSuccessStatusCode();
return await responseMessage.Content.ReadAsAsync<TResource>();
}
public async Task<IEnumerable<TResource>> GetAll()
{
var responseMessage = await httpClient.GetAsync(_addressSuffix);
responseMessage.EnsureSuccessStatusCode();
return await responseMessage.Content.ReadAsAsync<IEnumerable<TResource>>();
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
if (!disposed && disposing)
{
if (httpClient != null)
{
httpClient.Dispose();
}
disposed = true;
}
}
}
Sequence Diagram
Now, let’s visualize the interaction between the generic REST client and the RESTful service using a Mermaid sequence diagram:
The TodoClient Class
Now, let’s create a class called TodoClient
that utilizes the generic RestClient
to interact with the “todos” resource. In this example, we’ll use the Todo
class as the resource type and string
as the identifier type.
public class Todo
{
public int userId { get; set; }
public int id { get; set; }
public string title { get; set; }
public bool completed { get; set; }
}
public class TodoClient
{
private readonly RestClient<Todo, string> _restClient;
private readonly string baseAddress = "https://jsonplaceholder.typicode.com/";
public TodoClient()
{
_restClient = new RestClient<Todo, string>(baseAddress, "todos/");
}
public async Task<Todo> Get(string id)
{
var result = await _restClient.GetAsync(id);
return result;
}
public async Task<IEnumerable<Todo>> GetAll()
{
var result = await _restClient.GetAll();
return result;
}
}
How to Use the Generic Client
To use the generic REST client, create an instance of the specific client, such as TodoClient
, and invoke its methods. Here’s an example of how to use the TodoClient
:
void Main()
{
var todoClient = new TodoClient();
var todo = todoClient.Get("1");
Console.WriteLine(todo);
var todos = todoClient.GetAll();
Console.WriteLine(todos);
}
Hi,
ReplyDeleteThis is nice
This would be perfect if you could add authentication using a Bearer and Refresh token
Are you sure that method Dispose() works?
ReplyDeleteYes it will work
Delete