Inject IHttpClientFactory into class that's in another project - c#

I'm currently developing an ASP NET Core project with a linked API project, so we can have shared code between different projects. I'm wanting to inject an IHttpClientFactory into one of the classes in the API project, but it doesn't seem to be working. Is there a way to inject the factory or a way to create a client factory for the API itself?
Worst case, we can handle just a static HttpClient object and just use that in classes, but we'd prefer to use this method to have those instances managed cleanly.
Here's an example of the code we've tried.
services.AddHttpClient<Logger>(client =>
{
/* Redacted */
});
public class Logger
{
private static HttpClient _httpClient;
public Logger(HttpClient httpClient)
{
_httpClient = httpClient;
}
}
The Logger class is part of our API project.

In your Logger class you need to add it in the constructor. DI will resolve it for you.
public class Logger
{
private static HttpClient _httpClient;
public Logger(IHttpClientFactory httpClientFactory)
{
_httpClient = httpClientFactory.CreateClient("clientName")
}
}
or don't create the HttpClient right away just save the HttpClientFactory and create the client when you are using it. The factory will manage the connections for you.

Related

.Net Core DI - inject via constructor vs resolve using scope

Recently I have started using Worker Services and DI in .NET Core and I am confused about the difference between injecting a service via constructor vs by using scopes.
I have port forwarding software that creates a number of port forwardings as requested by user by creating many PortForwarding class instances.
My code - just the lines related to the question:
This is how I register the service:
static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseSerilog()
.ConfigureServices((hostContext, services) =>
{
services.AddLogging();
services.AddScoped<ISocket, TheSocket>(); //TheSocket creates System.Net.Sockets.Socket
services.AddScoped<IPortForwarding, PortForwarding>();
<more implementation>
});
Then in PortForwarding object I need an instance of TheSocket : ISocket, which I can create in two ways:
By creating a scope and requesting the ISocket:
public Socket Socket {get; set;}
private readonly ILogger<PortForwarding> logger;
private readonly IServiceScopeFactory serviceScopeFactory;
public PortForwarding(ILogger<PortForwarding> logger, IServiceScopeFactory
serviceScopeFactory)
{
this.logger = logger;
this.serviceScopeFactory = serviceScopeFactory;
using IServiceScope scope = serviceScopeFactory.CreateScope();
var socket = scope.ServiceProvider.GetRequiredService<ISocket>();
Socket = socket.Socket;
}
With constructor injection:
public Socket Socket {get; set;}
private readonly ILogger<PortForwarding> logger;
public PortForwarding(ILogger<PortForwarding> logger, ISocket iSocket)
{
this.logger = logger;
Socket = iSocket.Socket;
}
Then I make use of the Socket and the application works fine in both cases.
I have read Microsoft Docs about DI but since both versions work the same way - at least during my tests - I am not sure which one to use and why.
The only difference I can see is that with constructor injection I create one instance of the Socket and by using IServiceScopeFactory, I could request more instances - am I right, and is this the only difference between those two methods of DI?
Appreciate any clarifications.
You should go with the constructor injection.
The first approach looks like you are using some parts of DI internals instead of actually letting DI container do its job and it ends up looking like a "ServiceLocator" which is by now considered widely as an anti-pattern.
If you try to have this covered by unit tests you will find yourself making mocks of interfaces totally unrelated to job the class is supposed to fulfill.
The first method actually creates a sub container, and then you get service instances from the sub container.
Generally, it is recommended to inject from the construction method. The reason is that if you create a sub container, the objects created from the sub container will be destroyed when the sub container is recycled, which means that you need to manage the life cycle of the sub container and its creation service by yourself

ILogger and DependencyInjection Architecture in ASP.NET Core

My team is pretty big on DependencyInjection. Personally I'm a bit too far out of the loop lately to really judge the correct usage of this. But I do see more and more code like this:
public AuthenticationApi(ILogger<AuthenticationApi> logger,
HttpClient httpClient,
IJsonConverter jsonConverter,
IDtoConverter dtoConverter) : base(logger, httpClient, jsonConverter)
{
_dtoConverter = dtoConverter;
}
And then this multiplies across the code, where half of our code is just calling constructors with endless
DependencyInjection related stuff. My team told me, that's the way of .NET Core. And yes, answers like this confirm it:
ILogger and DependencyInjection in ASP.NET Core 2+
And discussions like that would be more along my gut feeling that things like logging, etc. should just be transparent and not handled in endless DependencyInjection constructor chains:
https://softwareengineering.stackexchange.com/questions/371722/criticism-and-disadvantages-of-dependency-injection
In another place (unfortunately I can't find the article anymore), I read that this constructor issues are mainly a result of badly implemented Service Factories.
Thoughts on the topic are appreciated.
Based on the discussion below, this is the baseclass and uses both the Logger and the HttpClient:
internal class ApiBase
{
private readonly ILogger _logger;
private readonly IJsonConverter _jsonConverter;
private readonly HttpClient _httpClient;
public ApiBase(ILogger logger, HttpClient httpClient, IJsonConverter jsonConverter)
{
_logger = logger;
_jsonConverter = jsonConverter;
_httpClient = httpClient;
}
protected async Task<T> GetAsync<T>(string path, HttpContent content = null)
{
_logger.LogDebug($"Sending GET request to {path}");
using (var request = new HttpRequestMessage(HttpMethod.Get, path))
{
request.Content = content;
using (var response = await _httpClient.SendAsync(request).ConfigureAwait(false))
{
if (response.IsSuccessStatusCode)
{
_logger.LogDebug($"GET request to {path} was successful.");
var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
var deserializeResponseContent = _jsonConverter.Deserialize<T>(responseContent);
return deserializeResponseContent;
}
var message = GetErrorMessage("GET", path, response);
_logger.LogError(message);
throw new HttpRequestException(message);
}
}
}
And then this multiplies across the code, where half of our code is just calling constructors with endless DependencyInjection related stuff. My team told me, that's the way of .NET Core.
Yes and no. Constructor injection of dependencies is a standard method in .NET Core to organize your dependencies. And it works great.
What is non-standard is your base class and the fact that you have those constructor chains where half your parameters aren't actually needed, but just go into the base class constructor. I will bet that this base class does not actually do anything worthwhile.
Remove the base class. See what you still need for every controller. Only inject that. These base classes and their own constructors are a great way to obfuscate what the actual dependencies are. Because now suddenly every class needs an IJsonConverter, must be pretty important. But you will have a hard time figuring out who actually makes use of the base class functionality that uses it. So of your 20 classes derived of the base, who really needs it, and who only requires it to make the compiler happy?
My advice is to remove the base class. Inject into each controller what they need, not more and not less. So you can actually see the dependencies. If you have common functionality in that base class, it can probably be a static method somewhere that gets those fields as parameters. Or maybe it can be a service of it's own that is injected where needed. But only where needed.

IHttpClientFactory Singleton .NET Framework

Scenario
I am trying to change my existing HttpClient to IHttpClientFactory. When I verified the existing code, its using using{...} statement which causes issues and it is mentioned here. So I thought of implementing singleton Http client and reached another blog related to this and it is here.
From all these, I understood that the best one is IHttpClientFactory introduced in .NET Core.
Implementation Plan
As this application is in ASP.NET MVC 4 and does not use DI, I have to do something to use without the DI framework. Based on my search, got answers from StackOverflow and planned to implement the same way. Meanwhile, I also got another project, which already removed all the dependencies and is ready to use in earlier projects without doing all things. The repo is HttpClientFactoryLite.
Question
Now I can use HttpClientFactoryLite by initializing this class? The description also mentioned it can be used along with the existing DI framework so that ClientFactory can be registered as a singleton. Please find the wordings from the readme
using HttpClientFactoryLite;
var httpClientFactory = new HttpClientFactory(); //bliss
If you are using dependency injection, make sure that IHttpClientFactory is registered as a singleton.
In my scenario, I don't have any DI framework added. So I am going to initialize the factory wherever I needed. Here I am confused that in 2 things
Is it necessary to make a singleton class for HttpClientFactoryLite?
How is this HttpClientFactory class disposed? Is there a need to dispose of it as part of the controller or same using statement etc?
Based on the answer from this, Microsoft.Extensions.Http provides the HttpClientFactory only, not the new optimized HttpClient. This is only available in .NET Core 2.1. So any difference in implementing IHttpClientFactory?
Please advise
ASP.NET 3.1:
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddSingleton<IHttpClientFactory, HttpClientFactory>();
}
ASP.NET will automatically pass the correct singleton to controllers which demand an IHttpClientFactory in their constructor.
Poormans variation without DI-Container:
public static class Singleton<TInterface>
{
private static TInterface instance;
public static TInterface Instance
{
get => instance;
private set => instance ??= value;
}
public static void Add<TConcrete>() where TConcrete : TInterface, new()
=> Instance = new TConcrete();
public static void Add<TConcrete>(TConcrete instance) where TConcrete : TInterface
=> Instance = instance;
// put dispose logic if necessary
}
Usage:
// Application Entrypoint
Singleton<IHttpClientFactory>.Add<HttpClientFactory>();
// Class/Controller Property
private readonly IHttpClientFactory httpClientFactory
= Singleton<IHttpClientFactory>.Instance;

How to log NLog calls from a class library in my ASP.NET Core MVC app?

Let's pretend I have two projects.
The first one is an ASP.NET Core MVC project that relies on NLog.Extensions.Logging for its logging. This is great; I can use dependency injection on my controllers to get an ILogger instance, and the nlog.config file contains, well, my NLog config.
The second one is a class library, which the API depends on, that relies directly on NLog for its logging. It contains calls like this:
public class SampleClass
{
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
public void DoStuff()
{
if (_failed) Logger.Error("oh no");
}
}
These classes are instantiated with some reflexive wizardry, and I can't use dependency injection to replace their logger. You can also think of them as some sort of model, which can't get instantiated at startup.
How do I get my library's logs to show up in the API's logging output? I would expect them to get caught by the nlog.config automatically, but they don't seem to be.
You don't need separate configuration file.
If your ASP.net MVC core project has nlog.config and it is successfully copied during build process then same configuration will get load when
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
Make sure you have copied file correctly. Also MinLevel properly set in configuration NLog.config.
Make sure you have .NET Core ClassLibrary ( Just to make sure it is loading successfully)
In your case too you can use Dependency Injection but it is different Story.
Here is the complete example with NLog
You need to get NLog and NLog.Web.AspnetCore Package
In Program.cs
public static IWebHostBuilder CreateWebHostBuilder(string[] args)
{
return WebHost.CreateDefaultBuilder(args)
.ConfigureLogging(logging =>
{
logging.ClearProviders();
logging.SetMinimumLevel(LogLevel.Trace);
}).UseNLog()
.UseStartup<Startup>();
}
Now In ClassLibrary Project Just Add Referece for NLog.
Note : Here Make sure that ILogger is from Microsoft.Extensions.Logging not from NLog.
public class Class1
{
//private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
private ILogger<Class1> _logger = null;
public Class1(ILogger<Class1> logger)
{
this._logger = logger;
}
public void DoStuff()
{
var _failed = true;
if (_failed) _logger.LogError("oh no");
}
}
Now it will work without any issue as well.
Class libraries should never depend on a particular logging implementation. Instead, you should use an abstraction, referred to as a facade. The Microsoft.Extensions.Logging library is one such facade you can utilize, but there's others like Common.Logging. Regardless, the classes that need to utilize logging should be injected with this abstract logging facade. For example:
public class SampleClass
{
private readonly ILogger _logger;
public SampleClass(ILogger<SampleClass> logger)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
public void DoStuff()
{
if (_failed) _logger.LogError("oh no");
}
}
Then, in your web application or whatever other concrete application that is utilizing your class library, that is where you actually set up your logging implementation, and register that via your DI container to injected in into your logging facade.
Long and short, your class library depends only on your logging facade, which allows it to generically call stuff like LogError. The application that uses your library sets up its actual concrete logging implementation, which will then be utilized under the hood by the facade for the logging the library does.

Add Microsoft.Extensions.Logging to .NETStandard project without assuming Dependency Injection available

I want to support logging in my .NETStandard project that will be consumed by a .NET Core Console or Web Client. However I don't want to presume the client uses a constructor that requires a ILogger dependency in the constructor of the classes I wish to log from.
If the logger does not exist, I basically don't want to fail because of this.
So my question is how can I reference ILogger in my code without passing it to the constructor?
using Microsoft.Extensions.Logging;
namespace MyApp
{
public class MyClass
{
//slf4net logger implementation
private static readonly slf4net.ILogger _slf4netLogger = slf4net.LoggerFactory.GetLogger(typeof(MyClass));
//Microsoft.Extensions.Logging???
private static readonly ILogger<MyClass> _logger = ???
public MyClass()
{
//Constructor empty
}
public void MyMethod()
{
//slf4net logger works like this
_slf4netLogger.Trace("This got logged");
//this won't work because the logger was never passed from the constructor
_logger.LogInformation("A message for the log if one is listening");
}
}
}
references:
https://github.com/ef-labs/slf4net
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/logging?tabs=aspnetcore2x
It seems like I'm not alone with my frustration here
Accessing the Logging API Outside of a MVC Controller
OK, so this is where the new logging API quickly becomes a nightmare.
- https://stackify.com/net-core-loggerfactory-use-correctly/

Categories

Resources