C
C#17mo ago
big OOF

❔ 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
Angius
Angius17mo ago
Looks good, except the static stuff Use DI Inject HttpContextFactory into the service, inject the service into the controller Or better yet, use typed clients
pip
pip17mo ago
tldr: resolving a client from IHttpFactory = best static HttpClient = good disposed local HttpClient = very situational non diposed local HttpClient = no good
Florian Voß
Florian Voß17mo ago
why not inject httpclient instance if that's what he needs? Perhaps as a singleton. Why take this HttpContextFactory?
Angius
Angius17mo ago
So that the DI has better control over creating new clients if/when needed, etc
Florian Voß
Florian Voß17mo ago
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 mweh
pip
pip17mo ago
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.
Florian Voß
Florian Voß17mo ago
see and that's not what I want I want a shared httpclient instance usually
big OOF
big OOF17mo ago
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? 🙂
pip
pip17mo ago
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.
class Stuff
{
private readonly Thing1 _thing1;
private readonly Thing2 _thing2;
private readonly Thing3 _thing3;
public Stuff(IThing1 thing1, IThing2 thing2, IThing3 thing3)
{
_thing1 = thing1;
_thing2 = thing2;
_thing3 = thing3;
}
}
class Stuff
{
private readonly Thing1 _thing1;
private readonly Thing2 _thing2;
private readonly Thing3 _thing3;
public Stuff(IThing1 thing1, IThing2 thing2, IThing3 thing3)
{
_thing1 = thing1;
_thing2 = thing2;
_thing3 = thing3;
}
}
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
big OOF
big OOF17mo ago
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
services.AddSingleton<Thing1>();
services.AddSingleton<Thing1>();
class Stuff
{
private readonly Thing1 _thing1;
private readonly Thing2 _thing2;
private readonly Thing3 _thing3;
public Stuff(IThing1 thing1, IThing2 thing2, IThing3 thing3)
{
_thing1 = thing1;
_thing2 = thing2;
_thing3 = thing3;
}
}
class Stuff
{
private readonly Thing1 _thing1;
private readonly Thing2 _thing2;
private readonly Thing3 _thing3;
public Stuff(IThing1 thing1, IThing2 thing2, IThing3 thing3)
{
_thing1 = thing1;
_thing2 = thing2;
_thing3 = thing3;
}
}
I think it was the case with singleton that got me confused because using DI doesn't look to different to declaring it like:
private static Thing1 instance = new Thing1();
private static Thing1 instance = new Thing1();
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!
Accord
Accord17mo ago
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.
Want results from more Discord servers?
Add your server
More Posts