Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
Question
Wednesday, January 23, 2019 4:14 PM
I am trying to make a c# client to communicate with a Rest Api. A singleton client with generic methods to send get/post requests to the server. Only, i am not sure if it's the correct way to do it and would like to get some feedback about it:
internal class ApiClient : HttpClient
{
private static readonly Lazy<ApiClient> lazyApiClient =
new Lazy<ApiClient>(() => new ApiClient());
private static readonly ApiClient instance = new ApiClient();
static ApiClient() { }
private ApiClient() : base()
{
}
public static ApiClient Instance
{ get { return lazyApiClient.Value; } }
private async Task<T> SendAsyncRequest<T>(HttpRequestMessage httpRequestMessage) where T : IApiResponse
{
using (httpRequestMessage)
{
HttpResponseMessage response = await SendAsync(httpRequestMessage, HttpCompletionOption.ResponseContentRead)
.ConfigureAwait(false);
{
response.EnsureSuccessStatusCode();
string responeString = response.Content.ReadAsStringAsync().Result;
return await response.Content.ReadAsAsync<T>();
}
}
}
public async Task<T> Get<T>(string uriString) where T : IApiResponse
{
if (string.IsNullOrEmpty(uriString)) throw new Exception("missing request url");
HttpRequestMessage httpRequestMessage = new HttpRequestMessage { Method = HttpMethod.Get, RequestUri = new Uri(uriString) };
return await SendAsyncRequest<T>(httpRequestMessage);
}
public async Task<T> Post<T>(string jsonContent, string uriString) where T : IApiResponse
{
if (string.IsNullOrEmpty(jsonContent)) throw new ArgumentNullException("missing json content");
if (string.IsNullOrEmpty(uriString)) throw new Exception("missing request url");
StringContent stringContent = new StringContent(jsonContent, Encoding.UTF8, "application/json");
HttpRequestMessage httpRequestMessage = new HttpRequestMessage { Content = stringContent, Method = HttpMethod.Post, RequestUri = new Uri(uriString) };
return await SendAsyncRequest<T>(httpRequestMessage);
}
}
All replies (2)
Thursday, January 24, 2019 6:15 AM
Hi KBid,
Thank you for posting here.
For your question, what is the type of your project? Due the code is not completed, I could not test the code.
Do you get the error from the code? If yes, please provide the error message.
Best Regards,
Wendy
MSDN Community Support
Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact [email protected].
Thursday, January 24, 2019 3:14 PM
This is a common approach but you don't need the generic stuff. HttpClient already has generic implementations and you can use extension methods as well. Refer to the code I use as an example.
While you really only want 1 instance of HttpClient per URL I don't think a singleton is the correct approach. The problem with this approach is that you get one instance. But you need a separate HttpClient for each URL that you'll connect to. This makes it unclear when to use the singleton and when not to. In .NET Core they added the HttpClientFactory to help apps manage this. I wrote my own version for .NET Framework (in the same repo linked earlier). This is how I'd solve it as you can create the instance once per URL.
You also generally want the app to be responsible for creating the initial HttpClient. The creation of the client is where things like logging need to be hooked up and that is app-specific functionality. For example you may want to log calls to external APIs but not internal ones. The client creation is where that needs to happen. If you're using IoC then creating the client via the IoC is the best choice and creation could involve using a client factory to create a single instance.
Michael Taylor http://www.michaeltaylorp3.net