I am using ASP.net core. I have problem with implementing dbcontext into singleton.
I need my singleton IModuleRepository to be running right after start of the project. So I am creating new instance of this dependency in public void ConfigureServices(IServiceCollection services) in Startup.cs file.
This singleton is using another singleton, so I am using it like this:
services.AddDbContext<ModulesDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")).EnableSensitiveDataLogging());
...
services.AddSingleton<IModuleRepository, ModuleRepository>();
services.AddSingleton<ICommunicationRepository>(new CommunicationRepository(services.BuildServiceProvider().GetService<IModuleRepository>()));
In ModuleRepository I am using DBcontext.
// Db context
private readonly ModulesDbContext _modulesDbContext;
public ModuleRepository(ModulesDbContext modulesDbContext)
{
_modulesDbContext = modulesDbContext;
}
When I am calling _modulesDbContext.SomeModel.ToList(); I get error:
System.InvalidOperationException: An attempt was made to use the context while it is being configured. A DbContext instance cannot be used inside OnConfiguring since it is still being configured at this point.
How to avoid this error when I need this singleton to run after the project is started?
Thank you for your help.
As #Ilya Chumakov commented, you could just tell the DI container to use your concrete class like so:
services.AddSingleton<ICommunicationRepository, CommunicationRepository>();
Then any class can depend on ICommunicationRepository and get the concrete repository, which gets the Db context.
I figured out this problem. This calling of the dependencies were right. The error is that in CommunicationRepository I've created 2 Task and both of them were using the same DbContext - so it was using it multiple times. I had to say task.Wait();
Full code in constructor of the CommunicationRepository after correction:
// Add pernament communication
var task = new Task(AddPernamentCommunicationAll);
task.Start();
task.Wait();
// Add modules
var taskModules = new Task(AddModulesToList);
taskModules.Start();
Thank you for your answers.
Related
New to ASP. Created an application and everything(including db interactions) works fine, but my application should contain background services which are run on startup(and then work until manually stopped). It should have access to dbcontext and ideally load data before any user input.
Seems like it should be created somewhere in ConfigureServices and run in Configure?
Don't really understand how to implement it cause dependency injections. The main problem - I don't understand where and how I can get access to dbcontext. The only way I know is controllers, but it's obviously not the solution.
I know that 100% there is simple solution, but can't find it cause don't know what to search. Some kind of link on reference/Microsoft docs should be enough.
You should register your DbContext in ConfigureServices like so:
Host.CreateDefaultBuilder(args)
ConfigureServices((hostContext, services) =>
{
// Example to add SqlServer DB Context
string connectionString = //for example load connection string from config
services.AddDbContext<MyDbContext>(o => o.UseSqlServer(connectionString));
}
After registering your context like this, you are able to inject it into your other services via constructor injection.
public class MyBackgroundService
{
private readonly IServiceScopeFactory _scopeFactory;
public MyBackgroundServcice(IServiceScopeFactory serviceScopeFactory)
{
_scopeFactory= serviceScopeFactory;
}
public MyData GetData()
{
using IServiceScope scope = _scopeFactory.CreateScope();
MyDbContext context = scope.ServiceProvider.GetService<MyDbContext>();
// Do something with context ...
}
}
Architecture wise I would also suggest implementing a service for your database layer that you can inject in your background services since managing DbContext scopes would be a lot cleaner like this.
I have a Blazor server-side application that uses Quartz.NET to run a scheduled job. The job merely calls an injected helper class...
public class DownloadEmailsJob : IJob {
private readonly EmailDownloadHelper _edh;
public DownloadEmailsJob(EmailDownloadHelper edh) =>
_edh = edh;
public async Task Execute(IJobExecutionContext context) =>
await _edh.DownloadEmails();
}
EmailDownloadHelper uses injection to get various services, such as the DbContext, etc. That part is all working fine.
I now have a need to call a SignalR hub method from inside the helper class. Following the code in Microsoft's documentation, in order to create the hub connection, I need to do something like this...
_hubConnection = new HubConnectionBuilder()
.WithUrl(_navigationManager.ToAbsoluteUri(EmailNotifierHub.Endpoint))
.Build();
...where EmailNotifierHub contains the following line...
public const string Endpoint = "/EmailHub";
This means that I need an instance of NavigationManager in my job. I tried injecting it in the constructor (as I do with the other dependencies in this class), but when it tries to create the hub connection, I get an exception...
System.InvalidOperationException' in Microsoft.AspNetCore.Components.dll
'RemoteNavigationManager' has not been initialized
The instance of NavigationManager is injected fine, meaning it's not null, and the exception only comes when it tries to call ToAbsoluteUri
I've done this sort of thing before in injected classes, but not in a Quartz.NET job, which is where I suspect the problem lies.
Anyone able to explain what's going wrong, and how I fix it? Thanks
Your main issue is that NavigationManager does not work properly outside a Circuit, and Quartz is (presumably) set up once for the application. The DI, therefore, does not have a scope in which it can provide a NavigationManager.
In similar situations, I usually resign to setting the base url of the site in appsettings.json, and use that to construct the absolute urls I need.
I have a hosted service called StateMachineHost that I create like this (in Startup.cs):
services.AddSingleton<StateMachineHost>();
services.AddHostedService<StateMachineHost>(provider => provider.GetService<StateMachineHost>());
The StateMachineHost then starts by reading the database of how many StateMachines it shall create. This is done by injecting IServiceScopeFactory
public StateMachineHost(IServiceScopeFactory scopeFactory)
and then getting an ApplicationDbContext via DI like this:
using (var scope = scopeFactory.CreateScope())
{
dbContext = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
var itemRepository = new ItemRepository(dbContext);
Further down in that using statement I go on and create N amount of StateMachines. Each StateMachine will need to also access the database via an ItemRepository. The question is now, how do I dependency inject ApplicationDbContext into my StateMachines? The StateMachine want to access the database at any other given point (triggered from an WebApi call and/or Timer-Tick).
My StateMachineHost stores each StateMachine in a List meaning that the StateMachine instances live throughout the application lifecycle.
In the WebApi/Repository pattern, the ApplicationDbContext gets easily injected via ASP.NET Core in the Controller constructor. But since my StateMachine has its own state and logic, I don't understand how I should create/DI the ApplicationDbContext. As I understand, both the ApplicationDbContext and Repostitory should be re-created for each database access. Meaning that I would also like to encapsulate that code somehow in my StateMachine, otherwise it will be a lot of duplicate code everywhere simply creating an ApplicationDbContext.
Why aren't you simply registering your context (if you use AddDbContext extension, this will be done implicitly) and your repo as scoped services?
Inject the context in the constructor of your repo and get the repo from the service container similar to what you did...
using (var scope = scopeFactory.CreateScope())
{
itemRepo = scope.ServiceProvider.GetRequiredService<IItemRepo>();
}
As you create a scope for each StateMachine, you will get individual instances just out of the box...
Coming from a Java environment I'm having a few issues wrapping my head about the inheritable DBContext class. with Java EE I used to:
Set up one or multiple DB Contexts (if separate clusters of entities where affected);
Added the Context to respective DataAccessor classes that handled the query execution via DI;
Now with EF Core practically all samples I see create an instance of a MyDBContext by calling the default constructor:
using (var db = new myContext()){...}
This raises a few questions for me:
With this Method each DataAccessor class that calls the constructor has its own instance of the Context. Wouldn't it be nicer to only ave one and use DI to inject it when needed?
How do I call the constructor if i didn't overload OnConfiguring(...) to pass the options, but instead used AddDbContext as a Service in Startup.cs? Now the overloaded constructor with the options expects them to be passed on each time the constructor is called.
Is having multiple DBContexts per application/Db even a good practise with EF Core?
Normally you would want single instance per request scope
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
// use options as you would use them in the .OnConfiguring
options.UseSqlServer("your connectionString");
);
}
If you use constructor injection in services, ASP.NET service provider will resolve db context as constructor parameter. All services that have db context this way will share same instance.
public class ServiceDependentOnContext
{
private readonly ApplicationDbContext dbContext;
public ServiceDependentOnContext(ApplicationDbContext dbContext)
{
this.dbContext = dbContext;
}
}
Make sure you configure your service for dependency injection as well
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer("your connectionString")
);
services.AddScoped<ServiceDependentOnContext>();
}
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;