Closing database connection when using StructureMap IoC / Entity Framework? - c#

I am a bit new to StructureMap's IoC (and IoC in general). From examples, I have my stuff set up like this:
DefaultRegistry:
public DefaultRegistry() {
Scan(
scan => {
scan.TheCallingAssembly();
scan.WithDefaultConventions();
scan.With(new ControllerConvention());
});
For<IRepository>().Use<Repository>().Ctor<string>("connectionString").Is(ConfigurationManager.ConnectionStrings["DBConnection"].ConnectionString);
//For<IExample>().Use<Example>();
}
Then, in each controller that any Action needs the database, I have:
private IRepository _Repository;
public TipsController(IRepository repository)
{
_Repository = repository;
}
When I need to use it, I just do:
data.Information = await _Repository.GetInformationAsync();
When I used ADO.NET, I always had a using statement around everything. I've seen examples of Entity Framework that utilizes the using statement. But, when using EF in conjunction with StuctureMap, do I need to somehow wrap a using statement around it? If so, how do I?

If you create a context and use it within the scope of a single method then it's always recommended that you wrap your DbContext use within a using statement as you mentioned, however when your DbContext life time is not bound to the execution of a single method then you have to dispose of the context youself.
A common pattern (and the one recommended in the StructureMap 3 documentation) is to have harness nested containers that are bound to the HttpContext.
This works by creating a nested container at the beginning of a user's Http request and then disposing of the nested container (and the DbContext instance) at the end of the request.
When using an ORM such as Entity Framework with an IoC Container like StructureMap, you can use this nested container that's bound to the HTTP request to control the lifetime of your DbContext. So as a request begins, a new database connection is created and then close and disposed at the end of the request.
This is probably the most complete tutorial that I've found that best describes setting up nested StructureMap containers that are bound to the Http request, and is almost identical to the way the StructureMap.MVC5 package does it that's referenced in the documentation.
Once this is implemented all you would need to do pull the open database connection from the container and dispose of it at the end of the Http request within application_endrequest in your Global.asax.cs file

Related

Best practices around async initialization before IOC registration

Perhaps I'm just using the wrong terms while searching, but I haven't found any solid guidance around how to do what I'm seeking to do.
All the guidance around DI registration follows something like the following:
builder.Services.AddSingleton<MyService>(() => new MyService("connectionString"));
But this seems too simple for me to use over here in the real world. I don't store my various credentials in my applications, but rather put them somewhere else like Azure Key Vault or authenticate using a managed identity that itself retrieves connection strings and keys.
This introduces the need then to access the credentials/connection string first, which increasingly is exposed only as an asynchronous operation and introduces the problem I regularly face: namely, asynchronous registration isn't a thing.
I could register a service that itself retrieves and exposes the credential in an async method, but now every downstream service is going to need to know about that method in order to utilize it - I can't simply abstract it away in a DI registration.
I could just use .Result or Wait(), but there's plenty of solid guidance that suggests this shouldn't be done for deadlocking reasons. Because this code may be intended for a library that's consumed by an app with a UI, that's a no-go.
So the question is: When I'm unable to synchronously provide my credentials, how do I register my services?
Real-world example
For example, let's say I've got a web app that needs to access Cosmos DB, but via a managed identity, following the instructions here. I need to store some information about the Cosmos DB instance which means a dependency on IConfiguration and I'd like to use a singleton HttpClient to retrieve the necessary keys.
I want to put this into a separate service responsible for setting up the Cosmos DB client so that downstream usages can just inject the CosmosClient, so my class looks like:
public class CosmosKeyService
{
private readonly MyCosmosOptions _cosmosOptions;
private readonly HttpClient _http;
public CosmosKeyService(IOptions<MyCosmosOptions> options, HttpClient http)
{
_cosmosOptions = options.Value;
_http = http;
}
private async Task<string> GetCosmosKey()
{
//Follow instructions at https://learn.microsoft.com/en-us/azure/cosmos-db/managed-identity-based-authentication#programmatically-access-the-azure-cosmos-db-keys
//...
var keys = await result.Content.ReadFromJsonAsync<CosmosKeys>();
return keys.PrimaryMasterKey;
}
public async Task<CosmosClient> GetCosmosClient()
{
var key = await GetCosmosKey();
return new CosmosClient(_cosmosOptions.CosmosDbEndpoint, key);
}
}
To support the DI used in this class, my registration then looks like:
builder.Services.Configure<MyCosmosOptions>(builder.Configuration.GetSection("cosmosdb"));
builder.Services.AddSingleton<HttpClient>();
And of course I'm going to need to register this service:
builder.Services.AddSingleton<CosmosKeyService>();
But now I'd also like to register the CosmosClient as created by the method in that service and this is where I start getting confused about the best way forward.
I can't retrieve an instance of the CosmosKeyService from the builder because I haven't yet built it, and after I do, I can't then register new services.
I can't use async methods in the registration itself or I could easily do something like:
builder.Services.AddSingleton<CosmosClient>(async services => {
var keyService = services.GetService<CosmosKeyService>();
return await keyService.GetCosmosClient();
});
...and downstream services could simply inject CosmosClient in their various constructors.
Again, any downstream consumer can just inject a CosmosKeyService, but now they're all going to have to "remember" to call the initialization method first so they can retrieve the CosmosClient and utilize it. I'd rather that be handled in registration so that 1) this initialization is hidden and centrally located and 2) the CosmosClient is truly a singleton and not just an artifact of every utilization.
I could create another intermediate service that injects this Key resolver service and retrieve the keys, but it too will need to have this async method that retrieves the keys since I can't just hide that initialization in a registration somewhere (for lack of async support).
For example, I could make another service:
public class CosmosBuilder
{
private readonly CosmosKeyService _keySvc;
public CosmosBuilder(CosmosKeyService keySvc)
{
_keySvc = keySvc;
}
public async Task<CosmosClient> GetCosmosClient()
{
return async _keySvc.GetCosmosClient();
}
}
But this ultimately still requires a downstream service to inject this service and call that initialization method and if that's necessary, I might as well just stick with injecting the CosmosKeyService and call the method there.
What I'd ideally like to see is some way to hide any async initialization in the registration so that downstream consumers can simply inject CosmosClient and it works, but it's beyond me how that's intended to happen. Can anyone shed some light on this?
Edit to address comment:
I don't want to comment on a 4-year old answer, but the issue I assert with the accepted answer boils down to this part:
Move [initialization] into the Composition Root. At that point, you can create an initialize those classes before registering them in the container and feed those initialized classes into the container as part of registrations.
That's all well and good except:
I only get to "build" my container a single time. I can't build it, then utilize the registrations to accomplish the initialization, then append still more registrations to it for later use.
In my example above, I explicitly utilize elements registered in DI by ASP.NET Core itself (namely IConfiguration), so there's simply no way to even access these except via DI (which, per #1, precludes me from being able to initialize and later supplement my registrations with more implementations).

Best practice for Blazor server side using MVVM and EF

I've got a Blazor server app using MVVM with Entity Framework. I've got a scenario where the user can change the search criteria very quickly resulting in a second async call to EF before the first call is complete causing the following exception from EF: "There is already an open DataReader associated with this Connection which must be closed first". I can get around it by creating scope for the DbContext with IServiceScopeFactory but it got me thinking that if I need this work around I might not have things set up in the best way possible.
My view model is scoped which gets a reference to my model (also scoped) via constructor injection, and the model gets a reference to the EF context (transient) also via constructor injection. Given that I'm using Blazor server, scoped vs transient isn't really going matter in my scenario because there's only one request for the object instances. So my question is this: Am I appropriately preventing a second async call to EF by using IServiceScopeFactory or is there a better way?
Thanks in advance for your thoughts.
In a normal Blazor componenent, I'd just use a bool flag, something like the following. I'd rather eat my keyboard than go back to MVVM/MVC, so this is the best I can offer you:
#inject MyDataService DBS
<input #bind="SearchString"/><button #onclick="DoSearch">Search</button>
#code{
string SearchString {get; set;} = "";
bool IsSearching;
async Task DoSearch (){
if (!IsSearching){
IsSearching = true;
var results = await DBS.DoDataBaseSearch(SearchString);
IsSearching = false;
}
}
}
Microsoft's best practice for dealing with this situation is to use DbContextFactory.
ASP.NET Core Blazor Server with Entity Framework Core
Pre-.NET 5 you have to implement IDbContextFactory but the code is in the documentation if you switch the version drop down in the link to 3.1. .NET 5 and later it's implemented for you.
Startup.cs
services.AddDbContextFactory<MyContextClass>(options =>
{
options.UseSqlServer(Configuration["MyConnectionString"]);
}, ServiceLifetime.Transient);
Data access class constructor:
public MyDataAccessClass(IDbContextFactory<MyContextClass> contextFactory)
{
_contextFactory = contextFactory;
}
Data access method:
using var context = _contextFactory.CreateDbContext();
Then use the context like you normally would. This is a great solution for controlling the lifespan of the DbContext instance in Blazor server given the persistent connection.

Entity Framework Core ApplicationDbContext DI in instances created from a HostedService

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...

Can I resolve a scoped instance from inside a singleton instance in asp.net 5

I've been using a trick for a while to help with maintaining an audit trail. In or before the controller, I create a User which is bound in some way to the request. I can use DI to create most of my application as singletons and I can just inject a Func<User> wherever I think I need User information. I get the per-request User from the Func and can easily add audit information to everything.
This keeps my domain classes User agnostic and lets my DI container act as a User management system.
Now I'm using asp.net 5 and I'm having trouble doing the same thing. Honestly I've never been sure I should be able to do this, but I've gotten used to it.
I'm trying to do something like this:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddScoped<IUser, User>();
services.AddSingleton<IDependantOnUser, DependantOnUser>
services.AddScoped<Func<IUser>(c => c.GetRequiredService<IUser>);
}
Then in or before my controller I create and populate the user instance.
public class ValuesController : Controller
{
public ValuesController(Func<User> userFunc)
{
user = userFunc();
// hydrate user instance as needed
}
}
Then finally, I should have access to the user instance in my singleton object.
public class DependantOnUser : IDependantOnUser
{
public DependantOnUser(Func<User> userFunc)
{
user = userFunc();
// I want this to be the same instance as that generated by the controller
}
}
But I can't get this to work. Before asp.net 5, I've been using Autofac to achieve this, but haven't had any luck there. I've tried playing around with transient/scoped/singleton a bit with no luck. I've even tried resolving my own IServiceProvider and using it directly instead of just generating a user with c => c.GetRequiredService<IUser>
Everything I do seems to be working with the wrong IServiceProvider instance. Is there a way resolve an instance from a different ServiceProvider? Any other suggestions would also be helpful.
Before you suggest I just register everything using AddScoped(), some of the objects between my presentation and persistence layers work a lot better as singletons.
Also I would prefer not to just pass User information as a parameter to every method in my domain (we record it with nearly every CRUD operation and pass it with most external calls we make)
I believe that it is antipattern to inject scope depedency to singleton one, please refer to Captive Dependencies
Autofac Captive Dependencies

Castle Windsor scoped life style fails to register per scope

I am using a framework that allow me to intercept in some entry points.
The framework scope is not Web Request, not thread and not transient, its something like thread based, but i saw a lot of places with thread reuse.
So i need a custom scope, where i say where to start and where to end the scope.
Since I have a lot of dependencies, most of them are defined in static contractor, because they are stateless.
I have one dependency that actually need to be injected on every framework interception.
This is the interception method, and how I do the injection (I am not calling this method, the framework does). So what i need here is to inject the AppContext and make sure that Castle always resolve me the correct context (within the scope)
public void Execute(AppContext context)
{
using (var s = CastleContainer.Container.BeginScope())
{
CastleContainer.Container.Register(Component.For<AppContext>().LifestyleScoped().Instance(context));
var logic = CastleContainer.Container.Resolve<ICustomerLogic>();
// begin invocation
}
}
ICustomerLogic has dependency in ICustomreDal and ICustomreDal has dependency in AppContext.
So when I resolve Resolve<ICustomerLogic>() I want to be sure that ICustomreDal has the current AppContext.
ICustomerLogic and registered as singleton, and ICustomreDal registered as transient.
The first execution works fine, the second execution I get the error:
AppContext could not be registered. There is already a component with
that name. Did you want to modify the existing component instead? If
not, make sure you specify a unique name.
Isn't castle suppose to do the scope segmentation so each scope has its own dependencies?
What am I doing wrong?
Please note that we are talking about 50 executions in a second.
The BeginScope is not about registration, it is only about component resolving. It will make sure that any component that is created within the using statment, with lifestyle Scoped gets released (disposed if necessary) when the using statements end. It does not unregister components that are registered in the block. In general it is a bad idea to register your components in multiple places. Only register components at the startup of your application.
I've been struggling a lot with something similair and finally used this workaround with I was not totally happy with but if there is anyone with a better solution I would love to hear. Adapted to your situation it would look something like this:
in your registration code use:
Component.For<ICustomerLogic>().ImplementedBy<CustomerLogic>().LifestyleScoped
Component.For<AppContext >().UsingFactoryMethod(() => (AppContext)Thread.GetNamedDataSlot("context")).LifestyleTransient() // or scoped
adapt your Execute function to:
public void Execute(AppContext context)
{
using (var s = CastleContainer.Container.BeginScope())
{
Thread.SetData(Thread.GetNamedDataSlot("context"), context);
var logic = CastleContainer.Container.Resolve<ICustomerLogic>();
Thread.SetData(Thread.GetNamedDataSlot("context"), null);
// begin invocation
}
}
Goodluck,
Marwijn.

Categories

Resources