dotnet core-Logging in class library - c#

is it possible to use Microsoft.Extensions.Logging like use logging in controllers(put in constructor and framework handle it with DI), in class library which my ASP.NET Core web application use that library? and how instantiate class and use method?
public class MyMathCalculator
{
private readonly ILogger<MyMathCalculator> logger;
public MyMathCalculator(ILogger<MyMathCalculator> logger)
{
this.logger = logger;
}
public int Fact(int n)
{
//logger.LogInformation($"Fact({n}) called.");
if (n == 0)
{
return 1;
}
return Fact(n - 1) * n;
}
}

Taked from a previous answer:
...That is the magic of dependency injection, just let the system create the object for you, you just have to ask for the type.
This is also a big topic, ... basically, all you have to do is to define classes as dependencies, so, when you ask for one, the system itself check the dependencies, and the dependencies of that objects, until resolves all the tree of dependencies.
With this, if you need one more dependency latter in your class, you can add directly but you do not need to modify all the classes that uses that class.
To use this in the controller, please check the official docs, you just have to add you dependencies to the constructor, and win!, basically two parts:
Add in your Startup.class
public void ConfigureServices(IServiceCollection services)
{
...
services.AddTransient<MySpecialClassWithDependencies>();
...
}
Then in your controller:
public class HomeController : Controller
{
private readonly MySpecialClassWithDependencies _mySpecialClassWithDependencies;
public HomeController(MySpecialClassWithDependencies mySpecialClassWithDependencies)
{
_mySpecialClassWithDependencies = mySpecialClassWithDependencies;
}
public IActionResult Index()
{
// Now i can use my object here, the framework already initialized for me!
return View();
}
This sould be no different if you library class is in other project, at the end of the day you will be adding the class to the startup, that is how asp net knows what to load.
If you want your code clean, you can use an Extension method to group all your declarations and the just calling services.AddMyAwesomeLibrary(), for example:
In your awesomeLibraryProject:
public static class MyAwesomeLibraryExtensions
{
public static void AddMyAwesomeLibrary(this IServiceCollection services)
{
services.AddSingleton<SomeSingleton>();
services.AddTransient<SomeTransientService>();
}
}
And in your Startup
public void ConfigureServices(IServiceCollection services)
{
...
services.AddMyAwesomeLibrary();
}

Related

Dependency Injection in .NET Core inside a class library

How can I inject one class into another inside a .NET Core library project?
Where should I configure DI as it is done in StartUp Class ConfigureServices in API project?
After googling a lot I could not find a comprehensive answer with an example to this question. Here is what should be done to use DI in Class library.
In your library:
public class TestService : ITestService
{
private readonly ITestManager _testManager;
public TestService(ITestManager testManager)
{
_testManager = testManager;
}
}
public class TestManager : ITestManager
{
private readonly ITestManager _testManager;
public TestManager()
{
}
}
Then extend IServiceCollection in the library:
public static class ServiceCollectionExtensions
{
public static void AddTest(this IServiceCollection services)
{
services.AddScoped<ITestManager, TestManager>();
services.AddScoped<ITestService, TestService>();
}
}
Lastly in the main app StartUp (API, Console, etc):
public void ConfigureServices(IServiceCollection services)
{
services.AddTest();
}
There are many thought processes for how you manage this, as eventually, the caller will need to register your DI processes for you.
If you look at the methods used by Microsoft and others, you will typically have an extension method defined with a method such as "AddMyCustomLibrary" as an extension method off of the IServiceCollection. There is some discussion on this here.
Dependency Injection is configured at the Composition Root, basically the application entry point. If you do not have control over the application entry point you can not force anyone to use dependency injection with your class library. However you can use interface based programming and create helper classes to register every type in your library for a variety of Composition Root scenarios which will allow people to use IOC to instantiate your services regardless of whatever type of program they are creating.
What you can do is make services in your class library depend on interfaces of other services in your library so that the natural way to use them would be to register your services with the container that is in use and also allow for more efficient unit testing.
I'm not sure I fully understood your intent... But maybe you can make your implementation spin its own private ServiceProvider, something like this:
using System.IO;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
public class MyBlackBox {
private readonly IServiceProvider _services = BuildServices();
protected MyBlackBox() {}
public static MyBlackBox Create() {
return _services.GetRequiredService<MyBlackBox>();
}
private static void ConfigureServices(IServiceCollection services) {
services.AddTransient<MyBlackBox>();
// insert your dependencies here
}
private static IServiceProvider BuildServices() {
var serviceCollection = new ServiceCollection();
serviceCollection.AddLogging();
serviceCollection.AddOptions();
serviceCollection.AddSingleton(config);
serviceCollection.AddSingleton<IConfiguration>(config);
ConfigureServices(serviceCollection);
return serviceCollection.BuildServiceProvider();
}
private static IConfigurationRoot BuildConfig() {
var path = Directory.GetCurrentDirectory();
var builder = new ConfigurationBuilder().SetBasePath(path).AddJsonFile("appsettings.json");
return builder.Build();
}
}
You can then register your implementation on the "Parent" ServiceProvider, and your dependencies would not be registered on it.
The downside is that you'll have to reconfigure everything, mainly logging and configuration.
If you need access to some services from the parent ServiceProvider, you can create something to bind them together:
public static void BindParentProvider(IServiceProvider parent) {
_services.AddSingleton<SomeService>(() => parent.GetRequiredService<SomeService>());
}
I'm pretty sure there's better ways to create nested ServiceProviders, though.
You can use Hosting Startup assemblies class library as an alternative to explicitly register them from the calling assembly.
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/host/platform-specific-configuration?view=aspnetcore-3.1#class-library
[assembly: HostingStartup(typeof(HostingStartupLibrary.ServiceKeyInjection))]
namespace HostingStartupLibrary
{
public class Startup : IHostingStartup
{
public void Configure(IWebHostBuilder builder)
{
builder.ConfigureServices((context, services) => {
services.AddSingleton<ServiceA>();
});
}
}
}
You can look at ServiceCollection Extension Pattern.
https://dotnetcoretutorials.com/2017/01/24/servicecollection-extension-pattern/
If you write this extension in class library, you can inject classes/services in this.
But I don't know is it a good pattern ?
so I can call the library with its services already attached, just use them.
this works for me:
public class LibraryBase
{
ctor... (mĂșltiple services)
public static IHostBuilder CreateHostBuilder(IHostBuilder host)
{
return host.ConfigureServices(... services)
}
}
Main:
public class Program
{
Main{... ConfigureServicesAsync()}
private static async Task ConfigureServicesAsync(string[] args)
{
IHostBuilder? host = new HostBuilder();
host = Host.CreateDefaultBuilder(args);
LibraryBase.CreateHostBuilder(host);
host.ConfigureHostConfiguration()
// ... start app
await host.StartAsync();
}
}

How to refactor from static methods to Dependency Injection using MS.DI and .NET Core?

I am in the process of migrating a project from .Net Framework to .Net Core. In the existing project we have a utility class with a few functions like below:
public static class BudgetUtilities
{
public static decimal CalculateBudgetRemaining(string fiscalYear = null)
{
if (string.IsNullOrWhiteSpace(fiscalYear))
fiscalYear = DateTime.Now.GetFiscalYear().ToString();
using (AppContext _context = new AppContext())
{
FiscalYearBudget currentBudget = _context.FiscalYearBudgets.Find(fiscalYear);
return currentBudget.BudgetAllocation - currentBudget.ExpenditureToDate;
}
}
// other functions removed for brevity
}
I can then reference it anywhere else using BudgetUtilities.CalculateBudgetRemaining(). Very simple and straightforward.
When migrating this function to .Net Core I need to use Dependency Injection so I have amended the class by removing the static modifier (since static constructors cannot have parameters) and injecting the AppContext into the constructor:
public class BudgetUtilities
{
private readonly AppContext _context;
public BudgetUtilities(AppContext context)
{
_context = context;
}
public decimal CalculateBudgetRemaining(string financialYear = null)
{
if (string.IsNullOrWhiteSpace(fiscalYear))
fiscalYear = DateTime.Now.GetFiscalYear().ToString();
FiscalYearBudget currentBudget = _context.FiscalYearBudgets.Find(fiscalYear);
return currentBudget.BudgetAllocation - currentBudget.ExpenditureToDate;
}
}
I then tried to call my code by doing the following:
BudgetUtilities utils = new BudgetUtilities();
decimal remaining = utils.CalculateBudgetRemaining();
But I cannot make a new instance of BudgetUtilities without providing an AppContext in the constructor which makes sense. Every method in this application is at some point initiated by a controller action, and I know that DbContexts are supposed to be short lived, so I assume passing the context the whole way down to this BudgetUtilities class from the initial controller is a bad idea.
The only other option I can see is to keep going back up the call stack from where CalculateBudgetRemaining() is referenced and keep adding in constructor injections until I get to a controller but this is not the only class I will have to inject like this so my constructors further up the chain are going to be really bloated and this will make my ConfigureServices() method bloated too.
I'm sure there's a simple way to do this but I just can't see it.
Don't manually create a new BudgetUtilities instance, that type should also be registered with the DI Framework, preferably interfaced:
public interface IBudgetUtilities
{
decimal CalculateBudgetRemaining(string financialYear);
}
public class BudgetUtilities : IBudgetUtilities
Then in Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
//...
services.AddScoped<IBudgetUtilities, BudgetUtilities>();
}
Then it can be injected into any class that needs it, such as a controller:
public class YourController : Controller
{
private readonly IBudgetUtilities _utils;
public YourController(IBudgetUtilities utils)
{
_utils = utils;
}
public ActionResult YourMethod()
{
//...
decimal remaining = _utils.CalculateBudgetRemaining();
}
}
By default, registered DbContexts have a scoped lifetime, which means a single instance is used for the entirety of a HTTP request.

Retrieve Service and use it in some arbitrary class in net core

There are plenty of examples how to set controllers to use services etc. But what about plain old class? Lets use some simple configuration service
JSON
{
....,
"AppSettings": {
"SchemaFile": "some file name.xml"
}
}
POCO
public class AppSettings
{
public string SchemaFile { get;set; }
}
In startup.cs
public void ConfigureServices(IServiceCollection services)
{
IConfigurationSection appSettingsSection = Configuration.GetSection("AppSettings");
services.Configure<AppSettings>(appSettingsSection);
. . . .
}
This is the point where all examples move directly to the controller. But we are going to have plenty of code outside controller. What I need is to access this service using provider.GetService(typeof(T)) or provider.GetRequiredService(typeof(T)), from, lets say a static class
internal static MyClass
{
internal static void DosomeThing()
{
// acquire my service
// use it to retrieve some value
// continue with my logic
}
}
Thanks
Just as the services can be injected into controllers, so too can they be injected into other classes.
static classes however to not lend themselves well to dependency injection by default.
Instead of using a static class, make a regular class and explicitly depend on the desired service via constructor injection
internal class MyClass : IMyService {
readonly AppSettings settings;
public MyClass(AppSettings settings) {
this.settings = settings;
}
internal void DosomeThing() {
// retrieve some value from settings
// continue with my logic
}
}
You can then register your desired POCO and utilities with the service container
public void ConfigureServices(IServiceCollection services) {
AppSettings appSettings = Configuration.GetSection("AppSettings").Get<AppSettings>();
services.AddSingleton(appSettings);
services.AddSingleton<IMyService, MyClass>();
//. . . .
}
Inject your service where it is needed and it will have access to the POCO when being resolved for injection.
There really is no need to be passing IServiceProvider around as that can be seen as a code smell.
Simplifying your design to follow explicit dependency principle should make your code more SOLID and easier to follow and maintain.
You should pass AppSettings as parameter from the caller method
public class HomeController : Controller
{
public HomeController(AppSettings settings)
{
this.Settings = settings;
}
private AppSettings Settings { get; }
public IActionResult Index()
{
MyClass.DosomeThing(this.Settings);
}
}
internal static MyClass
{
internal static void DosomeThing(AppSettings settings)
{
// acquire my service
// use it to retrieve some value
// continue with my logic
}
}

Is it possible to extend IServiceProvider during runtime

TLDR: Is it possible to modify the IServiceProvider after the Startup has ran?
I am running dll's (which implement a interface of me) during run-time. Therefore there's a file listener background job, which waits till the plugin-dll is dropped. Now I want to register classes of this dll to the dependency-injection system. Therefore I added IServiceCollection as a Singleton to the DI inside ConfigureServices to use inside another method.
In therefore I created a test-project and just tried to modify the ServiceCollection in the controller, because it was easier than stripping the background job down.
services.AddSingleton<IServiceCollection>(services);
So I added IServiceCollection to my controller to check if I can add a class to the DI after the Startup class has ran.
[Route("api/v1/test")]
public class TestController : Microsoft.AspNetCore.Mvc.Controller
{
private readonly IServiceCollection _services;
public TestController(IServiceCollection services)
{
_services = services;
var myInterface = HttpContext.RequestServices.GetService<IMyInterface>();
if (myInterface == null)
{
//check if dll exist and load it
//....
var implementation = new ForeignClassFromExternalDll();
_services.AddSingleton<IMyInterface>(implementation);
}
}
[HttpGet]
public IActionResult Test()
{
var myInterface = HttpContext.RequestServices.GetService<IMyInterface>();
return Json(myInterface.DoSomething());
}
}
public interface IMyInterface { /* ... */ }
public class ForeignClassFromExternalDll : IMyInterface { /* ... */ }
The Service was successfully added to the IServiceCollection, but the change is not persisted yet to HttpContext.RequestServices even after multiple calls the service count increases each time but I don't get the reference by the IServiceProvider.
Now my question is: Is that possible to achieve and yes how. Or should I rather not do that?
Is it possible to modify the IServiceProvider after the Startup has ran?
Short answer: No.
Once IServiceCollection.BuildServiceProvider() has been invoked, any changes to the collection has no effect on the built provider.
Use a factory delegate to defer the loading of the external implementation but this has to be done at start up like the rest of registration.
services.AddSingleton<IMyInterface>(_ => {
//check if dll exist and load it
//....
var implementation = new ForeignClassFromExternalDll();
return implementation;
});
You can now explicitly inject your interface into the controller constructor
private readonly IMyInterface myInterface;
public MyController(IMyInterface myInterface) {
this.myInterface = myInterface;
}
[HttpGet]
public IActionResult MyAction() {
return Json(myInterface.DoSomething());
}
and the load dll logic will be invoked when that interface is being resolved as the controller is resolved.

Dependency Injection pass parameters by constructor

We have a project where we need to use DI and ASP Core.
I'm very new to this and have a question.
I have a controller named HomeController like this:
public class HomeController : BaseController {
private IOrderService _orderService;
public HomeController(IOrderService orderService) {
_orderService = orderService;
}
public IActionResult Index() {
var orders = _orderService.GetMyOrders();
return View(orders);
}
}
The code looks like this:
public class OrderService : BaseService, IOrderService {
public OrderService(IDataContextService dataContextService) {
_dataContextService = dataContextService;
}
public List<Orders> GetMyOrders() {
var orders = // do my code here which works fine!;
// here i need some code do check orders for delivery so
DeliveryService deliveryService = new DeliveryService(_dataContextService);
// update my orders and return these orders
return orders;
}
}
public class DeliveryService : BaseService, IDeliveryService {
public DeliveryService(IDataContextService dataContextService) {
_dataContextService = dataContextService;
}
public void MyMethod() {
}
}
public class BaseService {
protected IDataContextService _dataContextService;
}
Almost all my services have a constructor like the OrderService and DeliveryService. My question is, do I have to pass the _dataContextService every time, or is there a solution within the dependency pattern?
You should keep it the way you have it and asp.net core IoC will inject it for you, but make sure it is injected per request, this will help to insantiate only one context for each request and dispose it after the request is served.
You can register the context and services in the ConfigureServices method inside the Startup class as below
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
// Add application services.
services.AddTransient<HomeController>();
services.AddTransient<IOrderService , OrderService >();
services.AddTransient<IDeliveryService, DeliveryService>();
services.AddScoped<IDataContextService , YourDataContextService >();
}
The AddScoped method will create only one instance of the object for each HTTP request
If I understand correctly what you are asking, you are looking for an IoC container. .NET Core has built in support for dependency injection. Basically, you just indicate which implementation should be provided when an interface is requested. Then the container will instantiate the types for you. See for example https://learn.microsoft.com/en-us/aspnet/core/mvc/controllers/dependency-injection.
Hope that helps

Categories

Resources