ASP.NET Core initialize singleton after configuring DI - c#

So let's say I have a singleton class instance that I register in the DI like this:
services.AddSingleton<IFoo, Foo>();
And let's say the Foo class has a number of other dependencies (mostly repository classes that allow it to load data).
With my current understanding, the Foo instance is not created until it's first used (asked). Is there a way to initialize this class other than the constructor? Like right after ConfigureServices() completes? Or should the initialization code (loading data from db) be done in Foo's constructor?
(It would be nice if this class could load its data before the first use to speed up first time access)

Do it yourself during startup.
var foo = new Foo();
services.AddSingleton<IFoo>(foo);
Or "warm it up"
public void Configure(IApplicationBuilder app)
{
app.ApplicationServices.GetService<IFoo>();
}
or alternatively
public void Configure(IApplicationBuilder app, IFoo foo)
{
...
}
But this feels just dirty and is more a problem with your design, if you do something that you shouldn't in the constructor. Class instantiation has to be fast and if you do long-running operations within it, you break against a bunch of best practices and need to refactor your code base rather than looking for ways to hack around it

I got the same problem and I find Andrew Lock blog:
https://andrewlock.net/running-async-tasks-on-app-startup-in-asp-net-core-3/
He explains how to do this with asp .net core 3, but he also refers to his pages on how to to this with previous version.

Lately I've been creating it as an IHostedService if it needs initialization, because to me it seems more logical to let the initialization be handled by the service itself rather than outside of it.
You can even use a BackgroundService instead of IHostedService as it's pretty similar and it only needs the implementation of ExecuteAsync
Here's the documentation for them
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/host/hosted-services
An example of how to add the service so you can inject it directly:
services
.AddHostedService<MyService>()
.AddSingleton<MyService>(x => x
.GetServices<IHostedService>()
.OfType<MyService>()
.First());
Example of a simple service:
public class MyService : IHostedService
{
// This function will be called automatically when the host `starts`
public async Task StartAsync(CancellationToken cancellationToken)
{
// Do initialization logic
}
// This function will be called automatically when the host `stops`
public Task StopAsync(CancellationToken cancellationToken)
{
// Do cleanup if needed
return Task.CompletedTask;
}
}
Some extension methods I created later on because i needed to use the same pattern again
public static class HostedServiceExtensions
{
public static IServiceCollection AddHostedServiceAsService<T>(this IServiceCollection services) where T : class, IHostedService
=> services.AddHostedService<T>().AddSingleton(x => x.GetServices<IHostedService>().OfType<T>().First());
public static IServiceCollection AddHostedServiceAsService<T>(this IServiceCollection services, Func<IServiceProvider, T> factory) where T : class, IHostedService
=> services.AddHostedService(factory).AddSingleton(x => x.GetServices<IHostedService>().OfType<T>().First());
}
Used like
services.AddHostedServiceAsService<MyService>();
// Or like this if you need a factory
services.AddHostedServiceAsService<MyService>(x => new MyService());

Adding detail to Jérôme FLAMEN's answer, as it provided the key I required to calling an async Initialization task to a singleton:
Create a class that implements IHostedService:
public class PostStartup : IHostedService
{
private readonly YourSingleton yourSingleton;
public PostStartup(YourSingleton _yourSingleton)
{
yourSingleton = _yourSingleton;
}
// you may wish to make use of the cancellationToken
public async Task StartAsync(CancellationToken cancellationToken)
{
await yourSingleton.Initialize();
}
// implement as you see fit
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
}
Then, in your ConfigureServices, add a HostedService reference:
services.AddHostedService<PostStartup>();
From link.

I made some manager and I need to subscribe to events of the other services.
I didn't like doing this in the
webBuilder.Configure (applicationBuilder => ...
I think it should be in the section
webBuilder.ConfigureServices ((context, services) => ...
So, here is my answer (test on net.core 3):
public static IHostBuilder CreateHostBuilder (string [] args) =>
Host.CreateDefaultBuilder (args)
.ConfigureWebHostDefaults (webBuilder =>
{
...
services.AddSingleton<ISomeSingletonService,SomeSingletonService>();
var buildServiceProvider = services.BuildServiceProvider();
var someSingletonService = buildServiceProvider.GetRequiredService <ISomeSingletonService>();
...
});

Related

Register IModel and ILogger in Startup.cs with SimpleInjector [duplicate]

I'm working with a project which utilizes Simple Injector as dependency injector. On the other hand, this project uses Microsoft.Extensions.Logging in order to log the events that occurs in certain classes.
My technical issue is pretty simple to explain.
I want to register in my DI the ILogger independently of the class T which is being invoked, but I DO NEED to do it from my ILoggerFactory.CreateLogger<T>() method because this gets the logger configuration using Microsoft.Extensions.Configuration.
I need to use something like this in order to instance my logger:
private Microsoft.Extensions.Logging.ILogger CreateLogger<T>()
{
var factory = this.ResolveService<ILoggerFactory>();
var logger = factory.CreateLogger<T>();
return logger;
}
I could achieve the injection by doing:
Container.Register(typeof(ILogger<>), typeof(Logger<>));
And this allows us to resolve something like:
public class SomeApiController : ApiController
{
public SomeApiController(ILogger<SomeApiController> logger)
{
//logger is well instantiated, but doesn't got the configuration
logger.LogInformation("test log.");
}
}
But as I said, this does it without passing through the configuration obtained from the Microsoft.Extensions.Logging.ILoggerFactory class, so this isn't useful.
Is there a way to register ILogger<T> by using my CreateLogger<T>?
Use the following registrations:
container.RegisterInstance<ILoggerFactory>(loggerFactory);
container.RegisterSingleton(typeof(ILogger<>), typeof(Logger<>));
Or, in case you are integrating Simple Injector into a generic host or ASP.NET Core application, make use of the .AddLogging() extension method to even inject a non-generic ILogger into your application components, as demonstrates in this ASP.NET Core Startup class:
public class Startup
{
...
public void ConfigureServices(IServiceCollection services)
{
services.AddLogging(); // Adds logging to the framework
// AddSimpleInjector enables "cross wiring," which means you can let
// Simple Injector-resolved components to depend on the generic
// ILogger<T> abstraction.
services.AddSimpleInjector(container, options =>
{
options.AddAspNetCore();
// AddLogger allows Simple Injector-resolved components to depend on
// the non-generic Microsoft.Extensions.Logging.ILogger interface.
// Simple Injector will automatically inject the correct ILogger<T>
// for you.
options.AddLogging();
});
}
...
}
For a full example, see the ASP.NET Core and ASP.NET Core MVC Integration Guide.
Letting application components depend on ILogger instead of ILogger<T>, makes your code simpler, easier to test, and less error prone. If you're using Simple Injector without Service Collection integration (as the previous example showed, you can use the following registration to let Simple Injector ensure the correct Logger<T> is still injected whenever an ILogger is injected:
container.RegisterConditional(
typeof(ILogger),
c => typeof(Logger<>).MakeGenericType(c.Consumer.ImplementationType),
Lifestyle.Singleton,
_ => true);
This ensures that every application component gets its own Logger<T> instance, where T is the type of the component the logger is injected into. Take the following class for example that depends on ILogger:
public class ComponentA : IService
{
public ComponentA(ILogger logger) { ... }
}
The above registration will ensure that ComponentA is injected with a Logger<ComponentA>, even though it simply depends on ILogger and not on ILogger<T>.
You can stop reading here if the above suits your needs... or continue reading if you're interested in a more SOLID solution.
A SOLID solution
Instead of letting application components depend on the framework-defined ILogger abstraction, you could also choose to define an application-specific logger abstraction, as prescribed by the Dependency Inversion Principle (DIP).
The DIP states that abstractions should be defined by the application itself—this means you define your own logger abstraction (also see this for an explanation of why you want to do this) and on top of that you build an adapter, much like described here. You can simply derive your generic adapter from the described MicrosoftLoggingAdapter as follows:
public sealed class MicrosoftLoggingAdapter<T> : MicrosoftLoggingAdapter
{
public MicrosoftLoggingAdapter(ILoggerFactory factory)
: base(factory.CreateLogger<T>()) { }
}
Using this generic adapter, you can configure Simple Injector as follows:
container.RegisterInstance<ILoggerFactory>(factory);
container.RegisterConditional(
typeof(MyApplication.Abstractions.ILogger),
c => typeof(MicrosoftLoggingAdapter<>).MakeGenericType(c.Consumer.ImplementationType),
Lifestyle.Singleton,
_ => true);
Based on Steven's solution, I post my answer to help anyone else:
private void RegisterServices()
{
Container.Register(ConfigureLogger, Lifestyle.Singleton);
Container.Register(typeof(ILogger<>), typeof(LoggingAdapter<>));
}
private ILoggerFactory ConfigureLogger()
{
LoggerFactory factory = new LoggerFactory();
var config = new ConfigurationBuilder()
.AddJsonFile("logging.json")
.Build();
//serilog provider configuration
var log = new LoggerConfiguration()
//.ReadFrom.Configuration(config)
.WriteTo
.RollingFile(ConfigSettings.LogsPath)
.CreateLogger();
factory.AddSerilog(log);
return factory;
}
public class LoggingAdapter<T> : ILogger<T>
{
private readonly Microsoft.Extensions.Logging.ILogger adaptee;
public LoggingAdapter(ILoggerFactory factory)
{
adaptee = factory.CreateLogger<T>();
}
public IDisposable BeginScope<TState>(TState state)
{
return adaptee.BeginScope(state);
}
public bool IsEnabled(LogLevel logLevel)
{
return adaptee.IsEnabled(logLevel);
}
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
adaptee.Log(logLevel, eventId, state, exception, formatter);
}
}
As you can see, my solution is using Serilog as a provider for logging in Microsoft.Extensions.Logging.
Hope it helps!

Is it not possible to get the class added with IServiceCollection::AddHostedService()?

I created the default ASP.NET Core Web Application MVC project. Then, I added this.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddHostedService<MyService>(); //<-- What I added.
}
MyService is a dummy class that implements IHostedService
public class MyService : IHostedService
{
public Task StartAsync(CancellationToken cancellationToken)
{
Debug.WriteLine("Hello world");
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken)
{
Debug.WriteLine("Goodbye world");
return Task.CompletedTask;
}
}
Now, in the HomeController, I tried the following two things to get the instance of MyService, but both caused not-found or null exceptions.
public IActionResult Index([FromServices] MyService ms)
{
public IActionResult Index([FromServices] IServiceProvider sp)
{
var ms = sp.GetService(typeof(MyService));
Is it not possible to get it? The modifications above are all I did to the default scaffolding, but if you need to browse the full source code, I uploaded it to this Git repository.
Why do you want to inject your IHostedService in your controller? Seems really weird to me.
Anyhow, AddHostedService registers the implementation as Transient as can be seen here...
public static IServiceCollection AddHostedService<THostedService>(this IServiceCollection services)
where THostedService : class, IHostedService
=> services.AddTransient<IHostedService, THostedService>();
}
...so the following should "work"
services.AddTransient<MyService>();
services.AddTransient<IHostedService>(x => return x.GetRequiredService<MyService>());
The only problem with this is that you will get a new fresh instance of your service everytime you inject/resolve it, and I don't think that's what you want.
So, why do you want to do this, what problem are you trying to solve?

ASP.NET core call async init on singleton service

I have a service that asynchronously reads some content from a file in a method called InitAsync
public class MyService : IService {
private readonly IDependency injectedDependency;
public MyService(IDependency injectedDependency) {
this.injectedDependency = injectedDependency;
}
public async Task InitAsync() {
// async loading from file.
}
}
Now this service is injected into my controller.
public class MyController : Controller {
private readonly IService service;
public MyController(IService service) {
this.service = service;
}
}
Now I want a singleton instance of MyService. And I want to call InitAsync in startup.
public class Startup {
public void ConfigureServices(IServiceCollection services) {
......
services.AddSingleton<IService, MyService>();
var serviceProvider = services.BuildServiceProvider();
// perform async init.
serviceProvider.GetRequiredService<IService>().InitAsync();
}
}
What is happening is at the time of startup, an instance of MyService is created and InitAsync() is called on it. Then when I called the controller class, another instance of MyService is created which is then reused for consequent calls.
What I need is to initialize only 1 instance, called InitAsync() on it in startup and have it be reused by controllers as well.
What is happening is at the time of startup, an instance of MyService is created and InitAsync() is called on it. Then when I called the controller class, another instance of MyService is created which is then reused for consequent calls.
When you call BuildServiceProvider(), you create a separate instance of IServiceProvider, which creates its own singleton instance of IService. The IServiceProvider that gets used when resolving the IService that's provided for MyController is different to the one you created yourself and so the IService itself is also different (and uninitialised).
What I need is to initialize only 1 instance, called InitAsync() on it in startup and have it be reused by controllers as well.
Rather than attempting to resolve and initialise IService inside of Startup.ConfigureServices, you can do so in Program.Main. This allows for two things:
Using the same instance of IService for initialisation and later use.
awaiting the call to InitAsync, which is currently fire-and-forget in the approach you've shown.
Here's an example of how Program.Main might look:
public static async Task Main(string[] args)
{
var webHost = CreateWebHostBuilder(args).Build();
await webHost.Services.GetRequiredService<IService>().InitAsync();
webHost.Run();
// await webHost.RunAsync();
}
This uses async Main to enable use of await, builds the IWebHost and uses its IServiceProvider to resolve and initialise IService. The code also shows how you can use await with RunAsync if you prefer, now that the method is async.
You can use simply way to do that with nuget HostInitActions
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IService, MyService>();
services.AddAsyncServiceInitialization()
.AddInitAction<IService>(async (service) =>
{
await service.InitAsync();
});
}
This nugget ensures that your initialization action will be performed asynchronously before the application starts.
Another advantage of this approach is that this initialization action can be defined from any place where services are installed into the IServiceCollection (For example, in an extension method in another project that installs internal implementations of public interfaces). This means that the ASP.NET Core project does not need to know what service and how it should be initialized, and it will still be done.

Short running background task in .NET Core

I just discovered IHostedService and .NET Core 2.1 BackgroundService class. I think idea is awesome. Documentation.
All examples I found are used for long running tasks (until application die).
But I need it for short time. Which is the correct way of doing it?
For example:
I want to execute a few queries (they will take approx. 10 seconds) after application starts. And only if in development mode. I do not want to delay application startup so IHostedService seems good approach. I can not use Task.Factory.StartNew, because I need dependency injection.
Currently I am doing like this:
public class UpdateTranslatesBackgroundService: BackgroundService
{
private readonly MyService _service;
public UpdateTranslatesBackgroundService(MyService service)
{
//MService injects DbContext, IConfiguration, IMemoryCache, ...
this._service = service;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
await ...
}
}
startup:
public static IServiceProvider Build(IServiceCollection services, ...)
{
//.....
if (hostingEnvironment.IsDevelopment())
services.AddSingleton<IHostedService, UpdateTranslatesBackgroundService>();
//.....
}
But this seems overkill. Is it? Register singleton (that means class exists while application lives). I don't need this. Just create class, run method, dispose class. All in background task.
There's no need to do any magic for this to work.
Simply:
Register the service you need to run in ConfigureServices
Resolve the instance you need in Configure and run it.
To avoid blocking, use Task.Run.
You must register the instance, or dependency injection won't work. That's unavoidable; if you need DI, then you have to do it.
Beyond that, it's trivial to do what you ask, like this:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddTransient<MyTasks>(); // <--- This
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
// Blocking
app.ApplicationServices.GetRequiredService<MyTasks>().Execute();
// Non-blocking
Task.Run(() => { app.ApplicationServices.GetRequiredService<MyTasks>().Execute(); });
}
else
{
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseMvc();
}
}
public class MyTasks
{
private readonly ILogger _logger;
public MyTasks(ILogger<MyTasks> logger)
{
_logger = logger;
}
public void Execute()
{
_logger.LogInformation("Hello World");
}
}
BackgroundService exists specifically for long running processes; if it's a once of, don't use it.
Well I think there is more then one question here.
First let me point out something you are probably aware of async != multithreaded.
So BackgroundService will not make you app "multithreaded" it can run inside a single thread without no problem. And if you are doing blocking operations on that thread it will still block startup. Lets say in the class you implement all the sql queries in a not real async way something similar to
public class StopStartupService : BackgroundService
{
protected override Task ExecuteAsync(CancellationToken stoppingToken)
{
System.Threading.Thread.Sleep(1000);
return Task.CompletedTask;
}
}
This will still block startup.
So there is another question.
How should you run background jobs?
For this in simple cases Task.Run(Try to avoid Task.Factory.StartNew if you are not sure how to configure it) should do the job, but that is not to say this is the best or a good way to do it. There are a bunch of open source libraries that will do this for you and it might be good to have a look at what they provide. There are a lot of problems you might not be aware of , that can create frustrating bugs if you just use Task.Run
The second question I can see is.
Should I do fire and forget in c#?
For me this is a definite NO(but XAML people might not agree). No matter what you do, you need to keep track of when the thing you are doing is done. In your case you might want to do a rollback in the database if someone stops the app before the queries are done. But more than that you would want to know when you can start using the data that the queries provided. So BackgroundService helps you to simplify the execution but is difficult to keep track of completion.
Should you use a singleton?
As you already mentioned using singletons can be a dangerous thing especially if you don't clean things properly, but more than that the context of the service you are using will be the same for the life time of the object. So with this all depends on your implementation of the service if there will be problems.
I do something like this to do what you want.
public interface IStartupJob
{
Task ExecuteAsync(CancellationToken stoppingToken);
}
public class DBJob : IStartupJob
{
public Task ExecuteAsync(CancellationToken stoppingToken)
{
return Task.Run(() => System.Threading.Thread.Sleep(10000));
}
}
public class StartupJobService<TJob> : IHostedService, IDisposable where TJob: class,IStartupJob
{
//This ensures a single start of the task this is important on a singletone
private readonly Lazy<Task> _executingTask;
private readonly CancellationTokenSource _stoppingCts = new CancellationTokenSource();
public StartupJobService(Func<TJob> factory)
{
//In order for the transient item to be in memory as long as it is needed not to be in memory for the lifetime of the singleton I use a simple factory
_executingTask = new Lazy<Task>(() => factory().ExecuteAsync(_stoppingCts.Token));
}
//You can use this to tell if the job is done
public virtual Task Done => _executingTask.IsValueCreated ? _executingTask.Value : throw new Exception("BackgroundService not started");
public virtual Task StartAsync(CancellationToken cancellationToken)
{
if (_executingTask.Value.IsCompleted)
{
return _executingTask.Value;
}
return Task.CompletedTask;
}
public virtual async Task StopAsync(CancellationToken cancellationToken)
{
if (_executingTask == null)
{
return;
}
try
{
_stoppingCts.Cancel();
}
finally
{
await Task.WhenAny(_executingTask.Value, Task.Delay(Timeout.Infinite,
cancellationToken));
}
}
public virtual void Dispose()
{
_stoppingCts.Cancel();
}
public static void AddService(IServiceCollection services)
{
//Helper to register the job
services.AddTransient<TJob, TJob>();
services.AddSingleton<Func<TJob>>(cont =>
{
return () => cont.GetService<TJob>();
});
services.AddSingleton<IHostedService, StartupJobService<TJob>>();
}
}
There is a library called Communist.StartupTasks that handles this exact scenario. It's available on Nuget.
It's designed specifically to run tasks during application launch in a .NET Core App. It fully supports dependency injection.
Please note that it executes tasks sequentially and it blocks until all tasks are complete (i.e. your app won't accept requests until startup tasks complete).

Masstransit Filter with IoC injection/Database

I have to validate incoming message before passing it to my consumer.
To do it, I need to request some data from the database.
Following the tutorials, I created extension method to apply my specification + filter to the consumer pipe. Something like this:
public static void UseArticlesImportValidation(this IConsumePipeConfigurator configurator){}
public class ArticlesImportValidationSpecification : IPipeSpecification<ConsumeContext<ArticlesImportNotification>>
and the Filter
public class ArticlesImportValidationFilter : IFilter<ConsumeContext<ArticlesImportNotification>>
Everything looks good, but I want to injection some business services in my Filter to reuse some functionality + DAL services. This works completely fine for my Consumer using Autofac extension method builder.RegisterConsumers(Assembly.GetExecutingAssembly());.
Should I use middleware for this at all? Any suggestions?
You need to have the built container in your specification (it is easy to pass as a parameter when you call AddPipeSpecification and then in the specification:
public void Apply(IPipeBuilder<T> builder)
{
builder.AddFilter(new ArticlesImportValidationFilter(container.Resolve<IDataAccessSomethingUseful>()));
}
But I would validate in the consumer or, if you want to keep them separate, have one consumer to validate and send the next message to do the actual job.
You should use Scoped Filters in this situation
Let's say you have a filter with dependency
public class MyConsumeFilter<T> :
IFilter<ConsumeContext<T>>
where T : class
{
public MyConsumeFilter(IMyDependency dependency) { }
public async Task Send(ConsumeContext<T> context, IPipe<ConsumeContext<T>> next) { }
public void Probe(ProbeContext context) { }
}
you should register this dependency in your DI container
services.AddScoped<IMyDependency, MyDependency>(); //register dependency
And now you are ready to add this filter to the consumer pipe by calling UseConsumeFilter method:
services.AddConsumer<MyConsumer>();
services.AddMassTransit(x =>
{
x.UsingRabbitMq((context, cfg) =>
{
cfg.ReceiveEndpoint("input-queue", e =>
{
e.UseConsumeFilter(typeof(MyConsumeFilter<>), context); //generic filter
e.ConfigureConsumer<MyConsumer>();
});
});
});

Categories

Resources