Dependency injection with Unit of Work pattern - c#

I'm trying to implement unit of work pattern for my repositories in C#/.NET. My plan is to give UoW as a parameter to repositories. Here's an example how it could be used:
using (var uow = new UnitOfWork())
{
var itemRepository = new ItemRepository(uow);
itemRepository.Add(new Item());
uow.Commit();
}
Also, for simple operations (when transactions are not needed) repositories should be able to be used without Unit of Work:
var itemRepository = new ItemRepository();
var item = itemRepository.Get(itemId);
UnitOfWork/Repository could get a database connection from ConnectionFactory. Connection factory receives connection options via dependency injection. However, here's my problem: How do repositories get reference to ConnectionFactory instance? Repositories are created manually, so they can't have dependencies injected via constructor. One option would be to have repository factories, which could have their dependencies injected. In that case usage could be like this:
using (var uow = new UnitOfWork())
{
var itemRepository = itemRepositoryFactory.Create(uow);
itemRepository.Add(new Item());
uow.Commit();
}
The drawback in that solution is that each repository will need its own factory, and there will be quite many. Are there any other solutions to circumvent this problem?

I would definitely register the UOW as a scoped dependency.
Scoped dependencies live for the lifetime of the container that creates them. Typically, frameworks would generate a child container from the parent container in order to execute some piece of work. For example, ASP.NET Core spawns a child container for a request and then disposes it when the request is finished. This would mean that the UOW instance that is getting injected is the same instance throughout the object graph for that request only.
You can also create your own scopes, if needed. I have done this twice for example:
A job scheduler, so that each job ran in it's own scope
A message handler, so that each message was processed in its own scope
This is how you would achieve this using Microsoft's DI framework:
var collection = new ServiceCollection();
collection.AddScoped<IUnitOfWork, UnitOfWork>();
var provider = collection.BuildServiceProvider();
var puow = provider.GetRequiredService<IUnitOfWork>();
for(int i = 0; i < 2; i++)
{
//Create the new scope
using var childContainer = provider.CreateScope();
//IUnitOfWork will be a singleton instance in this scope.
var c1uow = childContainer.ServiceProvider.GetRequiredService<IUnitOfWork>();
var c2uow = childContainer.ServiceProvider.GetRequiredService<IUnitOfWork>();
// This should true, since they come from the same scope.
var sameScope = c1uow == c2uow;
//With the requested IUnitOfWork from provider instead, it would be a different instance
//Therefore, this should be false
var diffScope = puow == c1uow;
}
This would allow you to simply inject IUnitOfWork into each repo, without having to create a factory for each repo.
This would work out of the box if you are writing an application in ASP.NET Core. Simply register the dependency as scope, as so
collection.AddScoped<IUnitOfWork, UnitOfWork>();
and then have it injected into the repos that you need. You don't have to worry about creating a new scope since the framework does that for you for each http request that the application receives.
I would really recommend reading Mark Seemann's book "Dependency Injection Principles, Practices, and Patterns". It really goes in depth about what dependency injection is and how it works. Not only that, I find him to be a great writer.

Related

Start a new LifetimeScope when a Masstransit consumer is triggered

We have the following code to configure the recieveEndpoint:
private Action<IServiceBusReceiveEndpointConfigurator> GetReceiveEndpointConfigurator(IEnumerable<Type> consumerTypes)
{
return c =>
{
c.EnableDeadLetteringOnMessageExpiration = true;
c.SubscribeMessageTopics = false;
c.MaxDeliveryCount = 3;
c.EnableDeadLetteringOnMessageExpiration = true;
c.UseRetry(Retry.Exponential(3, TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(30), TimeSpan.FromSeconds(1)));
foreach (var consumerType in consumerTypes)
{
c.Consumer(consumerType, p => _componentContext.Resolve(p));
}
};
}
All of our consumers are autodiscovered through reflection once our application starts up. We have a DbContext that we want to use in many of our consumers. The problem we face is that the DbContext is disposed due to it being registered as InstancePerLifetimeScope. More details here:
AspNet Core Autofac disposing my DbContext even if its registered as SingleInstance
Two suggestions came from this post:
Register the DbContext as InstancePerDependency
Create a new Scope within the consumer to start a new LifetimeScope
The first suggestion wont work in our application as we have a UnitOfWork which triggers the SaveChangesAsync on the DbContext. The result would be that the Repository and the UnitOfWork will get two different instances of the DbContext and SaveChangesAsync will not persist our changes as the ChangeTracker has no changes in the UnitOfWork implementation, but these changes belongs to the instance in the Repository.
The second suggestion works perfectly. Within my Consumer I create a new LifetimeScope and resolves the components that I need:
public async Task Consume(ConsumeContext<RetailerCreatedEvent> context)
{
using (var scope = _serviceProvider.CreateScope())
{
var unitOfWork = scope.ServiceProvider.GetRequiredService<IUnitOfWork<MyDbContext>>();
}
}
It works, but it doesn't look that good.
Is there a way to start a new LifetimeScope before the Consumer triggers? Or should I rewrite my UnitOfWork-pattern to ensure that the same DbContext is being reused in the Repositories and the UnitOfWork?
Suggestions are much appreciated
You need to use the MassTransit.Autofac package to resolve your consumers, which will use the AutofacScopeProvider (part of the package) to create a lifetime scope and resolve your consumer.
The documentation shows the configuration, including how to automatically discover your consumers via scanning and add them to MassTransit.
Your consumers shouldn't have any container code in them using this package, they should just add DbContext as a constructor dependency and let Autofac do the work.

Cleaner way to choose LifetimeScope in a dependency chain with Autofac

I'm using a web app with Autofac injecting services into controllers. Those services are sometimes injected with other services, and repositories. Repositories are injected with DbContexts. These 3 layers (service, repository, context) are all registered with Autofac. My default lifetime for these is InstancePerLifetimeScope.
Unfortunately, I have some code in a specific controller that I want to execute in parallel threads. Since DbContext is not thread-safe, this means I need to give a factory method to each thread to resolve a Service in a per dependency lifetime scope, which in turn will need to resolve per dependency repositories and db contexts.
The options I am considering are to create a new lifetime scope per thread, or to use a separate registration using a named or keyed registration to resolve the per-dependency services.
The challenge with creating a new lifetime scope per thread is that I need access to some per-scope objects. Some objects would need to be inherited and to not have a new instance created in the new scope, but other objects (the non-thread-safe DbContexts) need to have new instances generated in the new scope. I have no idea how to control this behavior implicitly when creating my new lifetime scope.
The other method would be to use a registration key so that when I execute the factory method to resolve a service on each thread, it would resolve one in the per-dependency scope. This would work if the service had no dependencies, but since it depends on a bunch of repositories or services for which the default lifetime scope is set to InstancePerLifetimeScope, I have to write something like this:
builder.RegisterType<MyService>()
.As<IMyService>()
.Named<IMyService>(RegistrationKeys.PerDependency)
.WithParameter(new ResolvedParameter(
(pi, ctx) => pi.ParameterType == typeof(IMyRepository),
(pi, ctx) => ctx.ResolveNamed<IMyRepository>(RegistrationKeys.PerDependency))
).InstancePerDependency();
Since the repositories depend on the DbContext, each repository has to be registered separately using this registration name. And it needs to be configured to resolve the DbContext using the registration name. And the DbContext needs to be registered using the registration name.
With 10 services each using about 4-5 repositories, I wager the amount of boilerplate registration code I will have to write will be around 10-20 full pages. It's not going to be maintainable.
So my question is, is there a way to create a specific type of lifetime scope that will allow me to easily control which objects will have a new instance or which will be inherited from the parent lifetime scope that won't break the asp.net per-request lifetime scope?
Or is there a way I can register or resolve a service to explicitly resolve all of its dependencies in the same scope without relying on their default registrations and without having to hard code an entire second set of registrations for everything?
The challenge with creating a new lifetime scope per thread is that I need access to some per-scope objects. Some objects would need to be inherited and to not have a new instance created in the new scope, but other objects (the non-thread-safe DbContexts) need to have new instances generated in the new scope. I have no idea how to control this behavior implicitly when creating my new lifetime scope.
This is the challenge InstancePerRequest solve. You can create child scope and object scoped to Request will be shared amongst child scope. To do this, tagged lifetimescope and InstancePerMatchingLifetimeScope is used.
You can see InstancePerRequest and Tagging a lifetime scope in the official documentation.
Example :
builder.RegisterType<Service>().As<IService>().InstancePerMatchingLifetimeScope("KEY");
builder.RegisterType<DbContext>().InstancePerLifetimeScope();
// ...
using (ILifetimeScope scope = container.BeginLifetimeScope("KEY"))
{
scope.Resolve<IService>(); // Instance #1
using (ILifetimeScope childScope = scope.BeginLifetimeScope())
{
childScope.Resolve<DbContext>();
childScope.Resolve<IService>(); // shared instance (#1)
}
}
but that's mean you have to change all your InstancePerLifetimeScope to InstancePerMatchingLifetimeScope and can control the creation of the unit of work lifetime scope which can be quite difficult.
Another way of doing this is by using Owned<T> with Func<T>. You can get more information here : Owned instance
builder.RegisterType<Service>().As<IService>().InstancePerLifetimeScope();
builder.RegisterType<DbContext>().InstancePerLifetimeScope();
builder.RegisterType<Operation>().As<IOperation>().InstancePerLifetimeScope();
public class Operation : IOperation
{
public Operation(Func<Owned<DbContext>> contextFactory, IService service)
{
this._contextFactory = contextFactory;
this._service = service;
}
private readonly Func<Owned<DbContext>> _contextFactory;
private readonly IService _service;
public void Do()
{
using Owned<DbContext> context = this._contextFactory();
context.Value // => new instance
this._service // shared instance (#1)
}
}
using (ILifetimeScope scope = container.BeginLifetimeScope())
{
scope.Resolve<IService>(); // Instance #1
IEnumerable<IOperation> operations = scope.Resolve<IEnumerable<IOperation>>();
operations.AsParallel()
.ForAll(operation => operation.Do());
}
The only downside of this solution is that your service will have dependency on Autofac but if you don't want it, it is quite easy to create your own abstraction over Owned
If you don't want to use Owned<T> or your own abstraction instead of trying to make DbContext a special case you can reverse the problem and manually share some dependency between your custom scope.
Something like :
using ILifetimeScope childScope = scope.BeginLifetimeScope(b => {
b.Register<XContext>(c => scope.Resolve<XContext>()).ExternallyOwned();
});
var operation = childScope.Resolve<IOperation>();
operation.Do();
This way IOperation would be resolved in a new scope but XContext will be from parent scope

Connect to database using dependency injection

I am trying to learn how to use dependency injection, but I have some trouble when it comes to my database. This is my process so far:
I have an MVC project where the controllers use different repositories from my classlibrary.
All repositories use the same database.
At first, I used SimpleInjector to register the Repositories Application_start method:
var container = new Container();
container.Options.DefaultScopedLifestyle = new WebRequestLifestyle();
var client = new GraphClient(uri, username, password);
container.Register<IRepoA>(() => new RepoA(client);
container.Register<IRepoB>(() => new RepoB(client);
container.RegisterMvcControllers(Assembly.GetExecutingAssembly());
container.Verify();
DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container));
And in every method, I did like this:
client.Connect();
client.performSomeQuery();
client.Dispose();
This works, but it means that I am reconnecting to the database every single time I call a method.
To avoid this a moved the connect-call to here:
var container = new Container();
container.Options.DefaultScopedLifestyle = new WebRequestLifestyle();
var client = new GraphClient(uri, username, password);
client.Connect();
container.Register<IRepoA>(() => new RepoA(client);
container.Register<IRepoB>(() => new RepoB(client);
container.RegisterMvcControllers(Assembly.GetExecutingAssembly());
container.Verify();
But then I never get my connection disposed.
I thought now is to register my databaseclient;
container.RegisterSingleton(() =>
{
var client = new GraphClient(uri, username, password);
client.Connect();
return client;
});
And then inject it like this:
container.Register<IRepoA>(() => new RepoA(container.GetInstance<GraphClient>()));
Is this the correct way to do it?
Is it corretly understood that the connection will get disposed by the end of the containers lifetime?
I do get a "Implicitly captured closure: container" when I register the client.
there is more than one way to do things ... so asking for THE correct way might get you on the wrong path sometimes ...
but here is what i'd do in your case ...
i would introduce a pattern called unit-of-work ... think of it as a business transaction
you open a unit of work and within its lifetime you perform various DB interactions, possibly all within one database transaction. All those interactions may spread across different repositories. if your whole batch of interactions is done without errors that would require a rollback, you declare the unit of work complete and leave its scope (scope as in a using(...) scope)
if there is an error you do not declare it complete before its lifetime ends ...
on the end of lifetime of your unit of work, you can either commit or roll back all underlaying db transactions (usually it's only one) depending on the fact if complete was declared or not
this unit of work object usually also holds my db connection object(s) and provides connections to repositories
again with dependency injection, you can have factory methods that provide different db connections based on the interface the repository requests during instantiation ...
usually the first repo that needs a connection causes the factory to create one and open it (optionally you can have different connections based on the used repos) while the second repo that asks for a connection gets a connection that has been created and opened before ...
the end of the unit of work (see IDisposable) also means the end of the connectionfactory ... end of connectionfactory means the end of open connections and repos ... since the later are instantiated insied of a using block, and based on the used resource, they should never leave said block

How to make AutoFac use same instance of nested dependency per top-level object? (SignalR dependency injection per hub)

I am trying to set up my AutoFac registration in such a way that this test passes:
[Test]
public void Autofac_registration_test()
{
// Given
var builder = new ContainerBuilder();
RegisterServices(builder);
var container = builder.Build();
// When
var firstHub = container.Resolve<Hub>();
var secondHub = container.Resolve<Hub>();
// Then
firstHub.Should().NotBe(secondHub);
firstHub.FooRepo.Context.Should().Be(firstHub.BarRepo.Context);
firstHub.FooRepo.Context.Should().NotBe(secondHub.FooRepo.Context);
}
i.e. I want to use the same Context object all the way down within a single Hub, but use a different one when a new Hub is created.
RegisterServices is currently just:
private void RegisterServices(ContainerBuilder builder)
{
builder.RegisterType<MyHub>();
builder.RegisterType<FooRepo>();
builder.RegisterType<BarRepo>();
builder.RegisterType<Context>(); // How should I scope this?
}
Which fails at firstHub.FooRepo.Context.Should().Be(firstHub.BarRepo.Context); because Context is transiently scoped.
But scoping context per lifetime also fails, this time at firstHub.FooRepo.Context.Should().NotBe(secondHub.FooRepo.Context);.
It feels like this is a reasonable thing to want to do, so am I missing anything obvious out-of-the-box here?
Or will I have to do something manual to track Hub creation?
(For context, this is for a SignalR app. Hubs are created per SignalR request, so this was an attempt to match the unit-of-work lifetime of an HTTP request in normal webby situations).
What #Steven said in his comment was correct, I needed a per-object-graph lifestyle.
Castle.Windsor supports this, so I swicthed to using that for my dependency injection instead of AutoFac. The registration now looks like:
container.Register(Component.For<Hub>().LifestyleTransient());
container.Register(Component.For<FooRepo>().LifestyleTransient());
container.Register(Component.For<BarRepo>().LifestyleTransient());
container.Register(Component.For<Context>().LifestyleBoundTo<Hub>()); // Important bit
For more information, see: http://docs.castleproject.org/Windsor.LifeStyles.ashx?HL=scope#Bound_8

How to register types in the main container, but resolve in a child container?

I have a unity container and use RegisterType to register the following repository and implementer using ContainerControlledLifetimeManager.
public interface IPersonRepository
{
Person GetByID(ObjectSpace objectSpace, int id);
}
Using this pattern I am able to have multiple threads (it's a web app) using the same repository instance at the same time despite the fact that each thread is using a different ObjectSpace (which is a local cache + mechanism for fetching objects from the DB + a unit of work etc). But this makes me feel "dirty", and not the good kind :-)
What I would really like is:
public interface IPersonRepository
{
Person GetByID(int id);
}
To achieve this I would have to create a child container and use RegisterInstance to register my ObjectSpace. This would work fine as long as I either:
Register IPersonRepository in the child container instead
Change the lifetime manager to TransientLifetimeManager
I don't want to do either. (1) Would just be too much work, I want to register once in the parent container and then no more. (2) Would work but if there are a lot of dependencies then all of these would have to be transient too and this would result in a lot of instances being created every time I needed the person repository.
So my question is: Is there a way to register the type in the parent, but to have a container lifetime instance resolved and stored in the child container instead of the parent container? Maybe there is a way using a custom lifetime manager or something?
What I would like to achieve is this:
UnityContainer unityContainer = new UnityContainer();
//Might be a custom manager or something
unityContainer.RegisterType<IPersonRepository, PersonRepository>
(new ContainerControlledLifetimeManager());
using (var childContainer = unityContainer.CreateChildContainer())
{
childContainer.RegisterInstance<ObjectSpace>(new MyObjectSpace());
//01 Resolves a new instance inside the child container
var repository = childContainer.Resolve<IPersonRepository>();
//02 resolves same instance as 01
repository = childContainer.Resolve<IPersonRepository>();
}
using (var childContainer = unityContainer.CreateChildContainer())
{
childContainer.RegisterInstance<ObjectSpace>(new MyObjectSpace());
//03 Resolves a new instance inside the child container
var repository = childContainer.Resolve<IPersonRepository>();
//04 resolves same instance as 03
repository = childContainer.Resolve<IPersonRepository>(); //Resolves the same instance
}
Since asking the question a new HierarchicalLifetimeManager has been added to Unity, this should be used when registering the type.

Categories