❔ Retrieve API data in C#
What structure would you use if you want to create an API that retrieves data from another API and returns it to the user.
Im thinking:
1. API controller takes the GET request from user and calls the service class
2. Service class that makes the API call
At the moment im instantiating a httpClient in the service class but ideally i would want the functions in the service class to be static, but then i cant instantiate httpclient.
Is this the right "way/structure" to do it and/or do any tips regarding the static service class ? 🙂
Thanks!
12 Replies
Looks good, except the static stuff
Use DI
Inject
HttpContextFactory
into the service, inject the service into the controller
Or better yet, use typed clientsalso this might be worth a read when dealing with HttpClient -> https://josef.codes/you-are-probably-still-using-httpclient-wrong-and-it-is-destabilizing-your-software/#:~:text=You%27re%20%28probably%20still%29%20using%20HttpClient%20wrong...%20Don%27t%20use,custom%20json%20deserializer.%20Reuse%20HttpClient%20%28or%20use%20IHttpClientFactory%29
Josef Ottosson
You're (probably still) using HttpClient wrong and it is destabiliz...
I try to optimize the fetching and deserialization of data in dotnet core as much as possible. HttpClientFactory and streams are my best friends
tldr: resolving a client from IHttpFactory = best
static HttpClient = good
disposed local HttpClient = very situational
non diposed local HttpClient = no good
why not inject httpclient instance if that's what he needs? Perhaps as a singleton. Why take this
HttpContextFactory
?So that the DI has better control over creating new clients if/when needed, etc
okk
not sure if I wanna give microsoft control over that @Angius given the fact that httpclient implements IDisposable and everwhere in docs they say its best practice to have it in a using block but having httpclient in a using block leaves socket connections open after disposing and is super bad for performance
From Microsoft:
Each time you get an HttpClient object from the IHttpClientFactory, a new instance is returned. But each HttpClient uses an HttpMessageHandler that's pooled and reused by the IHttpClientFactory to reduce resource consumption, as long as the HttpMessageHandler's lifetime hasn't expired.
Pooling of handlers is desirable as each handler typically manages its own underlying HTTP connections; creating more handlers than necessary can result in connection delays. Some handlers also keep connections open indefinitely, which can prevent the handler from reacting to DNS changes.
see and that's not what I want
I want a shared httpclient instance usually
Thanks for all the responses! Indeed a great read @pip, but i do have one question regarding the article:
He adds services like this:
services.AddSingleton<GetAllProjectsQuery>();
services.AddHttpClient<GitHubClient>(x => { x.BaseAddress = new Uri(GitHubConstants.ApiBaseUrl); });
services.AddSingleton<GitHubClientFactory>();
services.AddSingleton<JsonSerializer>();
The only reason you declare the singletons like above is so that you can access it via DI and dont have to instantiate a new class? For example,
This: services.AddSingleton<GetAllProjectsQuery>();
Replaces: private readonly GetAllProjectsQuery _getAllProjectsQuery;
Am i understanding it correctly? 🙂
What DI provides you is the ability to specify what kind of "thing" to pass into your classes/methods/etc, and what a DI container does is resolve all of the "things" that every class depends on. So to your question, i'd say it doesn't replace a private field, it compliments it.
Register "Stuff" to the DI container to properly inject IThing1, IThing2, IThing3 so that you have the correct implementations when you resolve "Stuff"
tbh i didn't do a good job of explaining this, there's plenty of videos on DI containers and their uses
I think i understand the concept, i just got it twisted! In the case of adding a singleton:
1. Add singleton to service
2. Pass singleton to class via DI
I think it was the case with singleton that got me confused because using DI doesn't look to different to declaring it like:
If you understand what i mean 🙂
But i understand the value of having it in the container instead of declaring it in the class.
Thanks!
Was this issue resolved? If so, run
/close
- otherwise I will mark this as stale and this post will be archived until there is new activity.