It'll probably take a few more questions to understand this subject quite well.
I've read a lot of documentations, yet I can't figure it out completely.
Say for example :
Singleton1 = resolved in lifetimeScope1
Singleton1 handles messages coming from Tcp/Ip.
DataService handles messages coming from web controllers, and it handles messages from Singleton1 (meaning - messages from Tcp/Ip).
In DataService there is a component registered as PerLifetimeScope (DbContext).
The things I can't understand is:
How will DataService know if it currently handles Http request (and should use instance 1 of DbContext) or Tcp/Ip (and use instance 2 of DbContext)?
My final goal is to configure Autofac to create me a new lifetime scope for each Tcp/Ip request I get as well. Just like it automatically does with Http requests!
Note:
If it'll be easier to understand with code, I'll put it, I just thought it could complicate things.
If anything I said was stupid or incorrect please fix me. Having hard time learning this.
Thanks!
Edit:
Adding code to explain my problem better:
public class Singleton1 : ISingleton1
{
private IDataService _dataService;
public Singleton1(IDataService dataService)
{
_dataService = dataService;
}
public void HandleExternalAddItemMessage(AddItemMessage msg)
{
_dataService.AddItem(msg.Item);
}
}
public interface IUnitOfWork : IDisposable
{
void Commit();
}
public EFUnitOfWork : IUnitOfWork
{
private DbContext _context;
public EFUnitOfWork(DbContext context)
{
_context = context;
}
public void Commit()
{
_context.SaveChanges();
}
}
public class DataService
{
private Func<Owned<IUnitOfWork>> _unitOfWorkFactory;
public (Func<Owned<IUnitOfWork>> unitOfWorkFactory)
{
_unitOfWorkFactory = unitOfWorkFactory;
}
// This method is called from both controllers and external Tcp/Ip calls. How do I do it - how do I set the context that is in the unit of work???
public void AddItem(Item item)
{
using(unitOfWork = _unitOfWorkFactory())
{
...
}
}
}
Startup code:
{
_container.RegisterType<IDataService, DataService>().SingleInstance();
_container.RegisterType<Singleton1, ISingleton1>().SingleInstance();
_container.RegisterType<EFUnitOfWork, IUnitOfWork>().PerDepnendecny();
_container.RegisterType<DbContext, MyDbContext>().InstancePerLifetimeScope();
}
This is a great article by Nicholas Blumhardt touching on many issues surrounding object lifetime including common pitfalls by developers attempting to own the object disposal in Autofac.
http://nblumhardt.com/2011/01/an-autofac-lifetime-primer/
I think what you're attempting to do is probably overly complicated and the model can probably be simplified however it is possible to register a new instance of an object by manually creating your own LifetimeScope.
public class Singleton1 : ISingleton1
{
private readonly ILifetimeScope _lifetimeScope;
public Singleton1(ILifetimeScope lifetimeScope)
{
_lifetimeScope = lifetimeScope;
}
public void HandleExternalAddItemMessage(AddItemMessage msg)
{
using(var scope = _lifetimeScope.BeginLifetimeScope())
{
var dataService = scope.Resolve<IDataService>();
dataService.AddItem(msg.Item);
}
}
}
As the article will explain you're now brewing up a nice batch of "scope soup".
Pay close attention to Nested lifetime scopes and Scope Sharing. Your usage of singletons is likely to trip you up.
Related
Im learning about generics and was wondering about how a generic controller, service and ef core repo design would look like.
My case: lets say an incomming post request to add Smartphone and keyboard object to smartphone and keyboard tables
My repository setup is
public class GenericRepository<TEntity> : IGenericRepository<TEntity>
where TEntity : class, IProductGenericEntities
{
private readonly MyDbContext _db;
public GenericRepository(MyDbContext db)
{
_db = db;
}
public async Task<bool> AddProduct(TEntity entity)
{
try
{
_db.Set<TEntity>().AddAsync(entity);
return (await _db.SaveChangesAsync()) > 0;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return false;
}
}
}
And my service
public class ProductService<TEntity> : IProductService<TEntity>
where TEntity : class
{
private readonly IGenericRepository<TEntity> _repo;
public ProductService(IGenericRepository<TEntity> repo)
{
_repo = repo;
}
public async Task<bool> AddProduct(TEntity entity)
{
return await _repo.AddProduct(entity);
}
}
And my Controller.cs
[ApiController]
[Route("api/[controller]")]
public class ProductController
{
private readonly IProductService<Keyboards> _keyService;
private readonly IProductService<Smartphones> _smartService;
public ProductController(IProductService<Keyboards> keyService, IProductService<Smartphones> smartService)
{
_keyService = keyService;
_smartService = smartService;
}
[HttpPost("Post-generated-items")]
public async Task<ActionResult> PostProducts(List<TEntity> entities)
{
foreach(var item in entities)
{
and sort the objects here
}
}
}
is it correct to initialize 2 of IProductServices and sort the incomming objects to their correct DI on the controller?
private readonly IProductService<Keyboards> _keyService;
private readonly IProductService<Smartphones> _smartService;
Is there a way to make it more automatic by detecting incomming object type and then initilize it all the way to repo so i dont need 2 of IProductService<>?
Or is it what im doing plain wrong with a generic service layor?
Ok, so your approach is completely valid, i would not worry about initializing two repositories, since they're essentially empty memory vise since they just take reference to existant DbContext which by default is registered with Scoped lifecycle.
There will be a time when you need to use several repositories to complete task at hand. I would suggest going for NON-generic services approach. This way you could make ProductsService which has all the needed generic repositories injected and can orchestrate their work to achieve use case goal.
You might as well look into UOW (Unit Of Work) pattern for even more complex situations.
Answering your question:
Is there a way to make it more automatic by detecting incomming object type and then initilize it all the way to repo so i dont need 2 of IProductService<>?
You might write some code that would do just that for you using Reflection, but i would suggest against doing so. By initializing your repositories specifically you make yourself less error prone and code becomes more self-documenting.
For example now you have a controller that asks DI for two services and that instantly set's you up for what's going on in this controller. On the other hand if everything would be generic, you would end up with one huge knot of spaghetti that "Does everything".
I see a lot of questions and answers on this topic, however the vast majority are dealing with ASP.Net or other web based applications and something called .InRequestScope. I have yet to find this method in Ninject with a Windows Application.
I have the usual Unit of Work (UoW) and Repository (Repo) classes and Interfaces, but I am wanting to inject the same DbContext into both, each time a UoW is run from the DIContainer. My code looks like this;
public class UnitOfWork : IUnitOfWork, IDisposable
{
private readonly FinancialContext _context;
private IAccountRepository _accountRepository;
public IAccountRepository Accounts
{
get { return _accountRepository; }
}
UnitOfWork(IMyContext context, IAccountRepository accountRepository)
{
_context = context;
_accountRepository = accountRepository;
}
public void SaveChanges()
{
_context.SaveChanges();
}
public void Dispose()
{
_context.Dispose();
}
}
public class AccountRepository : Repository<Account>, IAccountRepository
{
public AccountRepository(IMyContext context) : base(context) { }
}
The DIContainer holds the following associations;
Bind<IUnitOfWork>().To<UnitOfWork>().InTransientScope();
Bind<IUnitOfWorkFactory>().ToFactory();
Bind<IMyContext>().To<MyContext>().InSingletonScope();
Bind<IAccountTypeRepository>().To<AccountTypeRepository>().InTransientScope();
I'll come back to the .InSingletonScope();
The way I have seen people do this normally has been in the UoW Properties for each Repo to have code to this effect;
private IAccountRepository _accountRepository;
public IAccountRepository Accounts
{
get
{
if(_accountRepository = null)
{
_accountRepository = new AccountRepository(_context);
}
return _accountRepository;
}
}
And remove the injected repositories from the Constructor, there by ensuring that each instance of a repository using the same _context.
However in my mind this breaks the Dependency Injection for this class. Is there a way to do this where each creation of a UoW like so;
public TestUnitOfWork(IUnitOfWorkFactory unitOfWork)
{
using (var UoW = unitOfWork.Create())
{
Work done on UoW...
}
}
Currently the .InSingletonScope allows this, but is this keeping an instance of the context always open? Introducing the errors associated with not disposing a context properly?
Or is it better to create a Factory for the Repositories and give them a context parameter, then in the properties initialise it like so;
private IAccountRepository _accountRepository;
public IAccountRepository Accounts
{
get
{
if(_accountRepository = null)
{
_accountRepository = RepositoryFactory.CreateAccountRepository(_context);
}
return _accountRepository;
}
}
Thanks in advance for any help!
The solution is the use Ninject's Extensions.Factory class and pass in an IAccountFactory.Create() to initialise a new object. This then uses the DI Container to resolve its dependencies and doesn't break the DI approach.
We are trying to use Ninject within an Owin with WebAPI pipeline. We have everything setup according to this documentation, but we cannot get InRequestScope() to work.
Here's the significant part of the startup.cs
public class Startup
{
public void Configuration(IAppBuilder app)
{
HttpConfiguration config = new HttpConfiguration();
// Web API routes
config.MapHttpAttributeRoutes();
// Ninject Setup
app.UseNinjectMiddleware(NinjectConfig.CreateKernel);
app.UseNinjectWebApi(config);
}
}
NinjectConfig looks something like this:
public sealed class NinjectConfig
{
public static IKernel CreateKernel()
{
var kernel = new StandardKernel();
INinjectModule[] modules =
{
new ApplicationModule()
};
instance.Load(modules);
// Do we still need to do this wtih Owin?
instance.Bind<IHttpModule>().To<OnePerRequestHttpModule>();
}
}
Our ApplicationModule lives in a separate infrastructure project with access to all of our different layers, for handling DI & Mapping:
public class ApplicationModule: NinjectModule
{
public override void Load()
{
// IUnitOfWork / EF Setups
Bind<ApplicationContext>().ToSelf().InRequestScope();
Bind<IUnitOfWork>().ToMethod(ctx => ctx.Kernel.Get<ApplicationContext>()});
Bind<ApplicationContext>().ToMethod(ctx => ctx.Kernel.Get<ChromLimsContext>()}).WhenInjectedInto<IDal>();
// other bindings for dals and business objects, etc.
}
}
Then we have a couple interfaces:
public interface IUnitOfWork()
{
void SaveChanges();
Task SaveChangesAsync();
}
and
public interface IDal()
{
// Crud operations, Sync and Async
}
then our actual classes using these:
public class SomeBusinessObject
{
private IUnitOfWork _uow;
private IDal _someDal;
public SomeBusinessObject(IUnitOfWork uow, IDal someDal)
{
_uow = uow;
_someDal = someDal;
}
public Task<SomeResult> SaveSomething(Something something)
{
_someDal.Save(something);
_uow.SaveChanges();
}
}
Some Dal
public class SomeDal : IDal {
private ApplicationContext _applicationContext;
public SomeDal(ApplicationContext applicationContext)
{
_applicationContext = applicationContext;
}
public void Save(Something something)
{
_applicationContext.Somethings.Add(something);
}
}
Our EF DbContext
public class ApplicationContext : DbContext, IUnitOfWork
{
// EF DBSet Definitions
public void SaveChanges()
{
base.SaveChanges();
}
}
The expectation is that for every request, a single instance of ApplicationContext is created and injected into the business objects as an IUnitOfWork implementation and into the IDals as an ApplicationContext.
Instead what is happening is that a new instance of ApplicationContext is being created for every single class that uses it. If I switch the scope from InRequestScope to InSingletonScope, then (as expected) exactly 1 instance is created for the entire application, and injected properly into the specified classes. Since that works, I'm assuming this isn't a binding issue, but instead an issue with the InRequestScope extension.
The only issue I could find similar to what I'm experiencing is this one, but unfortunately the solution did not work. I'm already referencing all of the packages he specified in both the WebApi and Infrastructure projects, and I double checked to make sure they are being copied to the build directory.
What am I doing wrong?
Edit:
Some additional information. Looking at the Ninject source code in both Ninject.Web.WebApi.OwinHost and Ninject.Web.Common.OwinHost, it appears that the Owin Middleware adds the OwinWebApiRequestScopeProvider as the IWebApiRequestScopeProvider. This provider is then used in the InRequestScope() extension method to return a named scope called "Ninject_WebApiScope". This will be present until the target class that being injected into switches. The named scope then disappears, and a new scope is created. I think this may be what #BatteryBackupUnit was referring to in their comment, but I don't know how to correct it.
This thread is related to this issue...
https://github.com/ninject/Ninject.Web.WebApi/issues/17
I've found that behavior of InRequestScope seems to change depending on how you inject them. For example...
public ValuesController(IValuesProvider valuesProvider1, IValuesProvider valuesProvider2)
{
this.valuesProvider1 = valuesProvider1;
this.valuesProvider2 = valuesProvider2;
}
Ninject will create and inject the same instance of IValuesProvider. However if the method were written as...
/// <summary>
/// Initializes a new instance of the <see cref="ValuesController"/> class.
/// </summary>
/// <param name="valuesProvider">The values provider.</param>
public Values2Controller(IKernel kernel)
{
this.valuesProvider1 = kernel.Get<IValuesProvider>();
this.valuesProvider2 = kernel.Get<IValuesProvider>();
}
...this will create two new instances.
Based on the information in the link in #Mick's post I ended up adding my own extension method like this. I am not sure about the downsides.
public static class CustomRequestScope
{
public static Ninject.Syntax.IBindingNamedWithOrOnSyntax<T> InCustomRequestScope<T>(this Ninject.Syntax.IBindingInSyntax<T> syntax)
{
return syntax.InScope(ctx => HttpContext.Current.Handler == null ? null : HttpContext.Current.Request);
}
}
I do consider switching to another container because of this issue.
I have been reading Mark Seemann's excellent book on DI and hope to implement it in my next WPF project. However I have a query regarding object lifetime. So far, most examples seem to explain the repository pattern per request for MVC applications. In WPF there isn't really an alternative to this (I think). Seeing as the object graph of the entire application is constructed in the composition root, how can I make sure that my unit-of-work stuff is working properly. For example:
public class ContextFactory : IContextFactory
{
DBContext context;
public ContextFactory()
{
context = new MyDBContext();
}
public DBContext GetContext()
{
return context;
}
}
public class ItemOneRepository() : IItemOneRepository
{
DBContext context;
public ItemOneRepository(IContextFactory contextFactory)
{
this.context = contextFactory.GetContext();
}
public IEnumerable GetItems()
{
return context.ItemOnes;
}
}
public class ItemTwoRepository() : IItemTwoRepository
{
DBContext context;
public ItemTwoRepository(IContextFactory contextFactory)
{
this.context = contextFactory.GetContext();
}
public IEnumerable GetItemsByItemOneID(int itemOneID)
{
return context.ItemTwos.Where(i => i.itemOneID == itemOneID);
}
}
public class ThingService : IThingService
{
IItemOneRepository itemOneRepo;
IItemTwoRepository itemTwoRepo;
public ThingService(
IItemOneRepository itemOneRepository,
IItemTwoRepository itemTwoRepository)
{
itemOneRepo = itemOneRepository;
itemTwoRepo = itemTwoRepository;
}
public IEnumerable Things GetThing()
{
var ItemOnes = itemOneRepo.GetItems();
return ItemOnes.Select(i =>
new Thing(
i.FieldOne,
i.FieldFour,
itemRepoTwo.GetItemsByItemOneID(i.ID)
)
);
}
}
In this case the MyDBContext instance is created through ContextFactory in the composition root. ItemOneRepository and ItemTwoRepository are using the same unit-of-work (MyDBContext), but so is the rest of the application which is plainly wrong. What if I changed the repositories to accept a DBContext instead of ContextFactory and added a ThingServiceFactory class like:
public ThingServiceFactory : IThingServiceFactory
{
IContextFactory contextFactory;
public ThingServiceFactory(IContextFactory factory)
{
contextFactory = factory;
}
public IThingService Create()
{
MyDBContext context = contextFactory.Create();
ItemOneRepository itemOneRepo = new ItemOneRepository(context);
ItemOneRepository itemTwoRepo = new ItemTwoRepository(context);
return new ThingService(itemOneRepo, itemTwoRepo);
}
}
This is better as I can now pass the ThingServiceFactory to my ViewModels instead of an instance of ThingService (complete with DBContext). I can then create a unit-of-work whenever I need one and instantly dispose of it when I’ve finished. However, is this really the correct approach. Do I really need to write a factory for every unit-of-work operation I need? Surely there is a better way...
There's IMO only one good solution to this problem and that is to apply a command-based and query-based application design.
When you define a single ICommandHandler<TCommand> abstraction to define business transactions, you can inject closed versions of that interface into any form that needs this. Say for instance you have a "move customer" 'command' operation:
public class MoveCustomer
{
public Guid CustomerId;
public Address NewAddress;
}
And you can create a class that will be able to execute this command:
public class MoveCustomerHandler : ICommandHandler<MoveCustomer>
{
private readonly DBContext context;
// Here we simply inject the DbContext, not a factory.
public MoveCustomerHandler(DbContext context)
{
this.context = context;
}
public void Handle(MoveCustomer command)
{
// write business transaction here.
}
}
Now your WPF Windows class can depend on ICommandHandler<MoveCustomer> as follows:
public class MoveCustomerWindow : Window
{
private readonly ICommandHandler<MoveCustomer> handler;
public MoveCustomerWindows(ICommandHandler<MoveCustomer> handler)
{
this.handler = handler;
}
public void Button1Click(object sender, EventArgs e)
{
// Here we call the command handler and pass in a newly created command.
this.handler.Handle(new MoveCustomer
{
CustomerId = this.CustomerDropDown.SelectedValue,
NewAddress = this.AddressDropDown.SelectedValue,
});
}
}
Since MoveCustomerWindow lives for quite some time, it will drag on its dependencies for as long as it lives. If those dependencies shouldn't live that long (for instance your DbContext) you will be in trouble and Mark Seemann calls this problem Captive Dependency.
But since we now have a single ICommandHandler<TCommand> abstraction between our presentation layer and our business layer, it becomes very easy to define a single decorator that allows postponing the creation of the real MoveCustomerHandler. For instance:
public class ScopedCommandHandlerProxy<TCommand> : ICommandHandler<TCommand>
{
private readonly Func<ICommandHandler<TCommand>> decorateeFactory;
private readonly Container container;
// We inject a Func<T> that is able to create the command handler decoratee
// when needed.
public ScopedCommandHandlerProxy(
Func<ICommandHandler<TCommand>> decorateeFactory,
Container container)
{
this.decorateeFactory = decorateeFactory;
this.container = container;
}
public void Handle(TCommand command)
{
// Start some sort of 'scope' here that allows you to have a single
// instance of DbContext during that scope. How to do this depends
// on your DI library (if you use any).
using (container.BeginLifetimeScope())
{
// Create a wrapped handler inside the scope. This way it will get
// a fresh DbContext.
ICommandHandler<TCommand> decoratee =this.decorateeFactory.Invoke();
// Pass the command on to this handler.
decoratee.Handle(command);
}
}
}
This sounds a bit complex, but this completely allows you to hide the fact that a new DbContext is needed from the client Window and you hide this complexity as well from your business layer; you can simply inject a DbContext into your handler. Both sides know nothing about this little peace of infrastructure.
Of course you still have to wire this up. Without a DI library you do something like this:
var handler = new ScopedCommandHandlerProxy<MoveCustomerCommand>(
() => new MoveCustomerCommandHandler(new DbContext()),
container);
How to register this in a DI library is completely depending on the library of choice, but with Simple Injector you do it as follows:
// Register all command handler implementation all at once.
container.Register(
typeof(ICommandHandler<>),
typeof(ICommandHandler<>).Assembly);
// Tell Simple Injector to wrap each ICommandHandler<T> implementation with a
// ScopedCommandHandlerProxy<T>. Simple Injector will take care of the rest and
// will inject the Func<ICommandHandler<T>> for you. The proxy can be a
// singleton, since it will create the decoratee on each call to Handle.
container.RegisterDecorator(
typeof(ICommandHandler<>),
typeof(ScopedCommandHandlerProxy<>),
Lifestyle.Singleton);
This is just one of the many advantages that this type of design gives you. Other advantages is that it makes much easier to apply all sorts of cross-cutting concerns such as audit trailing, logging, security, validation, de-duplication, caching, deadlock-prevention or retry mechanisms, etc, etc. The possibilities are endless.
ItemOneRepository and ItemTwoRepository are using the same
unit-of-work (MyDBContext), but so is the rest of the application
which is plainly wrong.
If your factory is registered with a transient lifecycle, you will get a new instance every time it's injected, which will be a new DBContext each time.
However, I would recommend a more explicit unit of work implementation:
public DBContext GetContext() //I would rename this "Create()"
{
return new MyDBContext();
}
And:
public IEnumerable GetItemsByItemOneID(int itemOneID)
{
using (var context = contextFactory.Create())
{
return context.ItemTwos.Where(i => i.itemOneID == itemOneID);
}
}
This gives you fine-grained control over the unit of work and transaction.
You might also ask yourself if the repositories are gaining you anything vs. just using the context directly via the factory. Depending on the complexity of your application, the repositories may be unnecessary overhead.
I have inherited a Windows service where all the dependencies are created when the service starts and are injected in the transient scope.
We are having a number of problems with this service, not least we have a DbContext which lives for the whole time the service is running, and different instances of it are injected each time.
I would like to refactor so that each worker thread gets it’s own DbContext injected which will live for just the duration of each tick.
I have looked at the custom scope. It looks fine for a single threaded app, but not multi-threaded. I also considered InThreadScope. Whilst that would give each thread it’s own instance, they are singletons as far as the thread is concerned so it does not fulfil the per tick requirement.
My current thinking is to use the named scope extension and to inject a scope factory which I can use to create a new scope on every tick.
Is this the way to go? Any suggestions, tips or alternatives would be appreciated.
UPDATE
Due to a time constraint we ended up using the named scope, but it wasn't as clean as #BatteryBackupUnit's solution. There were some dependencies further down the graph which needed a DbContext and we had to inject the scope factory again to get it. Using #BatteryBackupUnit's solution we could have reused the same instance from the ThreadLocal storage instead.
Regarding Named Scope: Consider that when you are creating a DbContext from the same thread but from an object (p.Ex. factory) which was created before the scope was created, it won't work. Either it will fail because there is no scope, or it will inject another instance of DbContext because there is a different scope.
If you don't do this, then a scope like named scope or call scope can work for you.
We are doing the following instead:
When a DbContext is requested, we check a ThreadLocal
(http://msdn.microsoft.com/de-de/library/dd642243%28v=vs.110%29.aspx) whether there is already one. In case there is, we use that one. Otherwise, we create a new one and assign it to the ThreadLocal<DbContext>.Value.
Once all operations are done, we release the DbContext and reset the ThreadLocal<DbContext>.Value.
See this (simplified, not perfect) code for an example:
public interface IUnitOfWork
{
IUnitOfWorkScope Start();
}
internal class UnitOfWork : IUnitOfWork
{
public static readonly ThreadLocal<IUnitOfWorkScope> LocalUnitOfWork = new ThreadLocal<IUnitOfWorkScope>();
private readonly IResolutionRoot resolutionRoot;
public UnitOfWork(IResolutionRoot resolutionRoot)
{
this.resolutionRoot = resolutionRoot;
}
public IUnitOfWorkScope Start()
{
if (LocalUnitOfWork.Value == null)
{
LocalUnitOfWork.Value = this.resolutionRoot.Get<IUnitOfWorkScope>();
}
return LocalUnitOfWork.Value;
}
}
public interface IUnitOfWorkScope : IDisposable
{
Guid Id { get; }
}
public class UnitOfWorkScope : IUnitOfWorkScope
{
public UnitOfWorkScope()
{
this.Id = Guid.NewGuid();
}
public Guid Id { get; private set; }
public void Dispose()
{
UnitOfWork.LocalUnitOfWork.Value = null;
}
}
public class UnitOfWorkIntegrationTest : IDisposable
{
private readonly IKernel kernel;
public UnitOfWorkIntegrationTest()
{
this.kernel = new StandardKernel();
this.kernel.Bind<IUnitOfWork>().To<UnitOfWork>();
this.kernel.Bind<IUnitOfWorkScope>().To<UnitOfWorkScope>();
}
[Fact]
public void MustCreateNewScopeWhenOldOneWasDisposed()
{
Guid scopeId1;
using (IUnitOfWorkScope scope = this.kernel.Get<IUnitOfWork>().Start())
{
scopeId1 = scope.Id;
}
Guid scopeId2;
using (IUnitOfWorkScope scope = this.kernel.Get<IUnitOfWork>().Start())
{
scopeId2 = scope.Id;
}
scopeId1.Should().NotBe(scopeId2);
}
[Fact]
public void NestedScope_MustReuseSameScope()
{
Guid scopeId1;
Guid scopeId2;
using (IUnitOfWorkScope scope1 = this.kernel.Get<IUnitOfWork>().Start())
{
scopeId1 = scope1.Id;
using (IUnitOfWorkScope scope2 = this.kernel.Get<IUnitOfWork>().Start())
{
scopeId2 = scope2.Id;
}
}
scopeId1.Should().Be(scopeId2);
}
[Fact]
public void MultipleThreads_MustCreateNewScopePerThread()
{
var unitOfWork = this.kernel.Get<IUnitOfWork>();
Guid scopeId1;
Guid scopeId2 = Guid.Empty;
using (IUnitOfWorkScope scope1 = unitOfWork.Start())
{
scopeId1 = scope1.Id;
Task otherThread = Task.Factory.StartNew(() =>
{
using (IUnitOfWorkScope scope2 = unitOfWork.Start())
{
scopeId2 = scope2.Id;
}
},
TaskCreationOptions.LongRunning);
if (!otherThread.Wait(TimeSpan.FromSeconds(5)))
{
throw new TimeoutException();
}
}
scopeId2.Should().NotBeEmpty();
scopeId1.Should().NotBe(scopeId2);
}
public void Dispose()
{
this.kernel.Dispose();
}
}
Note: i'm using nuget packages: ninject, xUnit.Net, Fluent Assertions
Also note, that you can replace the IUnitOfWork.Start with a ToProvider<IUnitOfWorkScope>() binding. Of course you need to implement the corresponding logic in the provider.
A proper unit-of-work scope, implemented in Ninject.Extensions.UnitOfWork, solves this problem.
Setup:
_kernel.Bind<IService>().To<Service>().InUnitOfWorkScope();
Usage:
using(UnitOfWorkScope.Create()){
// resolves, async/await, manual TPL ops, etc
}