Let's say i've a DbContextFactory which I use in repositories to get DbContext
(I'm not sure it'a the best solution).
public class DbContextFactory : Disposable, IDbContextFactory
{
private readonly Dictionary<Type, System.Data.Entity.DbContext> _dbContexts;
public DbContextFactory()
{
_dbContexts = new Dictionary<Type, System.Data.Entity.DbContext>();
}
public T GetDbContext<T>() where T : System.Data.Entity.DbContext, new()
{
if (!_dbContexts.ContainsKey(typeof(T)))
{
_dbContexts.Add(typeof(T), new T());
}
return _dbContexts[typeof(T)] as T;
}
protected override void DisposeCore()
{
foreach (var kvpDbContext in _dbContexts)
{
kvpDbContext.Value?.Dispose();
}
}
}
And i have UnitOfWork which i inject in BusinessLogic class
public class UnitOfWork<T> : IUnitOfWork
where T : System.Data.Entity.DbContext, new()
{
private readonly IDbContextFactory _dbContextFactory;
private T _dbContext;
public UnitOfWork(IDbContextFactory dbContextFactory)
{
_dbContextFactory = dbContextFactory;
}
public T DbContext => _dbContext ?? (_dbContext = _dbContextFactory.GetDbContext<T>());
public void Commit()
{
DbContext.SaveChanges();
}
}
than i call repository method, and let's say it throws an exception:
public void CreateUser(User user)
{
_userRepository.Add(user);
throw new Exception();
UnitOfWork.Commit();
}
what happend if i call other repository method in the same request (or just do not use factory as instance-per-request), and that method end successfully, and UnitOfWork.Commit() will be called and does it means that changes made in CreateUser method which failed will be saved too ? or just after throwing exception the connection close and there's no risk the changes from that method will be saved?
To make it more clear:
I want to host that in WCF service, let's say in singleton mode.
And then - one request call method which contains multiple (for example 5) repository calls, and first three will success and the fourth will fail, it means i won't call UnitOfWork.Commit() there.
And then other request come, and it's just success. Does it mean, changes from first three repositories calls from previous method will be saved?
Because of singleton - there'll be still the same DbContextFactory sa the same DbContext.
As #Igor said in the comments, whether you handled or not that exception makes a difference, but as your scenario involves calling anothet repository on the same request, I'll assume you did handled It.
As you said you would reuse the same instance of your DbContextFactory and that's the guy holding your DbContext instances, it's safe to say that, unless you disposed that factory somewhere else, your context would still have that same instance of User added to it and thus calling Commit on that same context on anothet repository would still insert said User.
Related
There is a question I always ask myself when I'm using a Factory pattern inside my code (C#, but it applies to any language I suppose).
I have a "Service" that takes care of interacting with my database, do stuff with objects and interacts with my object model.
This Service uses a Factory sometimes to delegate the instanciation of an object.
But this factory obviously needs to interact by itself with the database to instanciate my object properly.
Is it a good/bad practice to pass the Database context to the Create method for example?
Like this :
var myNewObject = MyFactory.Create(myDatabaseContext);
the other way would be to let the Service always be the only one to talk with the database.
var myNewObject = MyFactory.Create();
var extraProperty = myDatabaseContext.Get(something);
myNewObject.extraProp = extraProperty;
Any advices?
The idea of passing the database context into the factory create method is called method injection. This is a form of dependency injection, so you are on the right track.
You can use dependency injection to manage your database context inside of your factory via the constructor. The factory could look something like this:
public class MyFactory
{
private readonly IMyDbContext dbContext;
public MyFactory(IMyDbContext dbContext)
{
this.dbContext = dbContext;
}
public object Create()
{
// Use the dbContext, etc
}
}
Constructor injection is usually favored because it leaves method signatures less cluttered. We will also most likely have one type of database context so there will be no need to take advantage of polymorphism based on some other runtime information.
You can choose to use a Dependency Injection Container like Ninject or, my favorite, SimpleInjector to manage the dependencies for you.
It is OK to have the DbContext only used by the factory. One thing you may want to watch out for is that a user of your factory may not realize that the factory is calling to the database. This could be a bad thing and have negative performance implications. Typically, construction information is passed into the factory method, not initialized into the factory method from the DB. You could even take it a step further and use the Repository Pattern to abstract away some more of the data access logic if you think it is necessary and you don't have that already.
To learn more about Dependency Injection, in case you are unfamiliar, you can start here.
My ideal structure may look like this:
public class MyFactory : IFactory
{
public object Create(object someProperty)
{
// build object
}
}
public class MyService
{
private readonly IMyDbContext dbContext;
private readonly IFactory factory;
public MyService(IMyDbContext dbContext, IFactory factory)
{
this.dbContext = dbContext;
this.factory = factory;
}
public void DoWork()
{
var property = dbContext.Get(something);
var newObj = factory.Create(property);
// Use stuff
}
}
In the project I am working on, we try to keep all database access inside the Service. If the Factory needs objects that must be loaded from the DB, the Service should load them and pass them to the Factory. If the object returned by the Factory shall be persisted, the Service should add it to the DbContext.
This corresponds to the second way you have shown. The advantage is that the Factory can be unit tested without any need to mock the DbContext.
If you want to keep the DB access inside the Factory anyways, I would inject the DbContext into the constructor of the Factory, instead of passing it to the Create() method.
The Service gets an instance of the Factory injected in turn (instead of accessing static methods of the Factory). Again, this will make mocking much easier.
public class Service {
private readonly IMyDbContext _myDatabaseContext;
private readonly IMyFactory _myfactory;
public Service (IMyDbContext myDbContext, IMyFactory myfactory) {
_myDatabaseContext = myDbContext;
_myfactory = myfactory
}
public void Create() {
var extraProperty = myDatabaseContext.Get(something);
var myNewObject = _myFactory.Create(extraProperty);
_myDatabaseContext.Add(myNewObject);
_myDatabaseContext.SaveChanges();
}
}
I am working on a big project that 80% completed (Some features need to be implemented though).But recently we discovered that the project doesn't allow concurrent requests (I mean multiple users request to same repository). Sometime we get null referece & sometimes "Executed can not open available connection , connection state is closed" etc.
Our source code is strongly restricted outside of the world. Here is some code.Let me know if there is any architectural problem, as architectural guys left company. It's using ninject 3.0. I already used InRequestScope() for all manager's repositories but no luck
Update: I am not using any ORM here, I am trying to connect SqlServer through data adapter in my DbContext class
public class DbContext
{
//execute query , nonquery etc using adapter & datatable
//Example
var dt=new DataTable();
_adapter=new _dbfactory.CreateAdapter();
_adapter.Fill(dt);
return dt;
}
//MyController
public class MyController
{
private readonly IMyManager_iMyManager;
public MyController(IMyManager iMyManager){_iMyManager=iMyManager}
public ActionResult Save()
{
_iMyManager.Save()
}
}
// My Manager
public class MyManager:IMyManager
{
private readonly IMyRepository _iMyRepository;
DbContext _dbContext=new
DbContext("someParameter","connectionstring");
public MyManager
(
IMyRepository iMyRepository, DbContext dbContext
)
{
_iMyRepository=iMyRepository;
_dbContext=dbContext;
}
Public DataTable GetDataTable()
{
try
{
_dbContext.Open();
_iMyRepository.GetDataTable()
}
catch(Exception ex){}
finally{_dbContext.Close()}
}
}
// here is the repository
Public class MyRepository:IMyRepository
{
public _dbContext;
public MyRepository(DbContext dbContext)
{
_dbContext=dbContext;
}
public DataTable GetDataTable()
{ return _dbContext.ExecuteQuery()}
}
Finally Here is our ninject binding
public class NinjectDependencyResolver()
{
var context=new DbContext("someparameter","connectionStrin");
kernel.Bind<IMyManager>().To<MyManager>().WithConstructorArgument("_dbContext",context);
kernel.Bind<IMyRepository >().To<MyRepository >().WithConstructorArgument("_dbContext",context);
}
there can have some typo in my code as I wrote everything in so editor
I think you did this too complicated in Ninject Dependency Resolver.
You shouldn't create DbContext with a new keyword. Instead you should make Ninject to be resolving DbContext in request scope or in thread scope.
To register DbContext you can do it like this:
kernel.Bind<DbContext>().To<MyDbContext>().WithConstructorArgument("someArgument", "someValue").InRequestScope();
kernel.Bind<IMyManager>().To<MyManager>().InRequestScope();
kernel.Bind<IMyRepository>().To<MyRepository>().InRequestScope();
You don't need to precise the constructor argument to DbContext as DbContext is only once registered in the Ninject.
You can also register DbContext to a DbContextProvider class and there you can add some specific logic to resolve object.
Example:
kernel.Bind<DbContext>().ToProvider<MyDbContextProvider>().InRequestScope();
internal class MyDbContextProvider : Ninject.Activation.IProvider
{
public object Create(IContext context)
{
return new MyDbContext("connectionStringArgument";
}
public Type Type { get { return typeof (MyDbContext); } }
}
I hope this helps.
You need to remove this initialization in the MyManager since you pass the initialized DbContext via IoC.
DbContext _dbContext=new
DbContext("someParameter","connectionstring");
You also need to remove the finally block in the GetDataTable in the MyManager class since as a rule of thumb, if the object is initialized via IoC, it should be destroyed by IoC as well.
finally{_dbContext.Close()}
If you are initializing something in the field level then why would you initialize it again from the constructor?
private readonly IMyRepository _iMyRepository;
DbContext _dbContext=new DbContext("someParameter","connectionstring");
public MyManager(IMyRepository iMyRepository, DbContext dbContext)
{
_iMyRepository=iMyRepository;
_dbContext=dbContext;
}
This may also be a typo. Either remove the _dbContext initialization from the constructor or delegate the task of initialization to the caller of this class.
Multiple initialization can also be the problem. since you are doing dbcontext initialization both in NinjectDependencyResolver() and MyManager. For this you are getting two different exceptions. This is a platform design issue i guess
Two problems:
// My Manager
public class MyManager:IMyManager
{
private readonly IMyRepository _iMyRepository;
DbContext _dbContext=new
DbContext("someParameter","connectionstring");
public MyManager
(
IMyRepository iMyRepository, DbContext dbContext
)
{
_iMyRepository=iMyRepository;
_dbContext=dbContext;
}
The new that is created for the field will be overwritten when the constructor is called.
public class NinjectDependencyResolver()
{
var context=new DbContext("someparameter","connectionStrin");
kernel.Bind<IMyManager>().To<MyManager>().WithConstructorArgument("_dbContext",context);
kernel.Bind<IMyRepository >().To<MyRepository >().WithConstructorArgument("_dbContext",context);
}
You create the context here once and pass it to each object creation. So you are still reusing the context object instead of creating it for each request scope.
I'm using entity framework 6 and Autofac in my web application.
I inject unit of work with DbContext inside, both externally owned so I can dispose them myself.
DbContext registered PerLifetimeScope,
Unit of work is a factory, therefore registered as per dependency.
When Executing the first http Get action everthing works fine and I see the unit of work with the context are disposed after the response is coming from the db which is great.
My issue is that whenever I execute a second request, the context for some reason is disposed before I return an IQueryable. Therefore I get an execption saying:
The operation could not be executed because the DbContext is disposed.
For example - calling the GetFolders method works the first time, and afterwards fails..
I see the context is disposed too early, what I don't understand is what triggers it too soon in the second request..
public interface IUnitOfWork : IDisposable
{
bool Commit();
}
public EFUnitOfWork : IUnitOfWork
{
public IRepository<Folder> FoldersRepository {get; set;}
public IRepository<Letter> LettersRepository {get; set;}
private readonly DbContext _context;
public EFUnitOfWork(DbContext context, IRepository<Folder> foldersRepo, IRepository<Letter> lettersRepo)
{
_context = context;
_foldersRepo = foldersRepo;
LettersRepository = lettersRepo;
}
private bool disposed = false;
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!disposed)
{
if (disposing)
{
_context.Dispose();
}
disposed = true;
}
}
public bool Commit()
{
try
{
return SaveChanges() > 0;
}
catch (DbEntityValidationException exc)
{
// just to ease debugging
foreach (var error in exc.EntityValidationErrors)
{
foreach (var errorMsg in error.ValidationErrors)
{
logger.Log(LogLevel.Error, "Error trying to save EF changes - " + errorMsg.ErrorMessage);
}
}
return false;
throw exc;
}
}
}
public class Repository<T> : IRepository<T>
{
protected readonly DbContext Context;
protected readonly DbSet<T> DbSet;
public EFRepository(DbContext context)
{
Context = context;
}
public IQueryable<T> Get()
{
return DbSet;
}
public void Add(T item)
{
DbSet.Add(item);
}
public virtual Remove(T item)
{
DbSet.Remove(item);
}
public void Update(T item)
{
Context.Entry(item).State = EntityState.Modified;
}
public T FindById(int id)
{
return DbSet.Find(id);
}
}
public class DataService : IDataService
{
private Func<IUnitOfWork> _unitOfWorkFactory;
public (Func<IUnitOfWork> unitOfWorkFactory)
{
_unitOfWorkFactory = unitOfWorkFactory;
}
public List<FolderPreview> GetFolders()
{
using(unitOfWork = _unitOfWorkFactory())
{
var foldersRepository = unitOfWork.FoldersRepository;
var foldersData = foldersRepository.Get().Select(p => new FolderPreview
{
Id = p.Id,
Name = p.Name
}).ToList();
return foldersData;
}
}
}
public class FolderPreview
{
public int Id {get; set;}
public string Name {get; set;}
}
Startup code:
{
_container.RegisterGeneric<IRepository<>,Repository<>>().InstancePerLifetimeScope();
_container.RegisterType<IDataService, DataService>().SingleInstance();
_container.RegisterType<EFUnitOfWork, IUnitOfWork>().PerDepnendecny().ExternallyOwned();
_container.RegisterType<DbContext, MyDbContext>().InstancePerLifetimeScope().ExternallyOwned();
}
Is this related to singletons some how? Almost all of my application is singletons, the DataService is also Singleton. Anyone?
Thanks!
The problem is that you are instancing only one Repository and one DbContext per request, but are instancing one new IUnitOfWork every time.
So when you call GetFolders you are creating a new IUnitOfWork and disposing it (which disposes the DbContext -on IUnitOfWork.Dispose()-): so when you call GetFolders again, when you create a second IUnitOfWork, since it's the same lifetime scope, it's injecting the already-created repository and the already-created DbContext, which is disposed (the container doesn't try to create a new instance since you are on the same lifetime scope)...
So on the second call, your Repository and IUnitOfWork are trying to use the disposed instance of DbContext, thus the error you are seeing.
As a solution, you can just not dispose the DbContext on IUnitOfWork, and dispose it only at the end of your request... or you could even not dispose it at all: this may sound strange, but check this post
I'm copying the important part in case the link goes dead, by Diego Vega:
The default behavior of DbContext is that the underlying connection is automatically opened any time is needed and closed when it is no longer needed. E.g. when you execute a query and iterate over query results using “foreach”, the call to IEnumerable.GetEnumerator() will cause the connection to be opened, and when later there are no more results available, “foreach” will take care of calling Dispose on the enumerator, which will close the connection. In a similar way, a call to DbContext.SaveChanges() will open the connection before sending changes to the database and will close it before returning.
Given this default behavior, in many real-world cases it is harmless to leave the context without disposing it and just rely on garbage collection.
That said, there are two main reason our sample code tends to always use “using” or dispose the context in some other way:
The default automatic open/close behavior is relatively easy to override: you can assume control of when the connection is opened and closed by manually opening the connection. Once you start doing this in some part of your code, then forgetting to dipose the context becomes harmful, because you might be leaking open connections.
DbContext implements IDiposable following the recommended pattern, which includes exposing a virtual protected Dispose method that derived types can override if for example the need to aggregate other unmanaged resources into the lifetime of the context.
So basically, unless you are managing the connection, or have a specific need to dispose it, it's safe to not do it.
I'd still recommend disposing it, of course, but in case you don't see where it'd be a good time to do it, you may just not do it at all.
I have a simple repository that fetches some data using EF6. I'm also using a DI framework to inject the dependencies.
namespace Domain
{
public interface IMyRespository
{
List<MyObject> FetchObjects();
}
}
namespace Data
{
public class MyRepository : IMyRepository
{
private readonly MyDbContext _context;
public MyRepository(MyDbContext context)
{
_context = context;
}
public List<MyObjects> FetchObjects()
{
return _context.MyObjects.ToList();
}
}
}
A new requirement states that I need to log each FetchObjects() call and it's outputs. I thought this would be perfect example to apply the Decorator pattern.
namespace Domain
{
public class MyRepositoryDecorator : IMyRepository
{
private readonly IMyRepository _inner;
private readonly ILogRepository _logRepository;
public MyRepositoryDecorator(IMyRepository inner, ILogRepository logRepository)
{
_inner = inner;
_logRepository = logRepository;
}
public List<MyObjects> FetchObjects()
{
var objects = _inner.FetchObjects();
var logObject = new LogObject(objects);
_logRepository.Insert(logObject);
_logRepository.Save();
return objects;
}
}
}
Now I'm looking to employ the UnitOfWork pattern and I'm unsure how to implement in this case.
As I understand it some component needs to manage the UnitOfWork. So in this case a service class would make some calls and at the end call Save/Commit on the UnitOfWork class.
However if the repository interface indicates a readonly action there is no reason for the service class to wrap the call in a UnitOfWork and call Save/Commit at the end. It would look really weird too. However the decorator requires this to do it's job.
I'm probably missing some essential construct here. Any ideas on how to properly approach this scenario?
It would be a bad idea to mix UoW with Repository using Decorator (or similar) simply because it is not unusual for UoW to span across multiple repositories.
Also it is not up to the Repository to decide whether UoW should be committed or not. Repositories should know as less as possible about UoWs, ideally (and it is the case most of the time) nothing.
In your scenario the UnitOfWork class would pretty much only handles the transaction, so it can be implemented as a simple wrapper around TransactionScope, something like:
public sealed class UnitOfWork : IDisposable {
private readonly TransactionScope _transaction;
public UnitOfWork() { _transaction = new TransactionScope(); }
public void Commit { _transaction.Commit(); }
public void Dispose { _transaction.Dispose(); }
}
Now it is up to the service to instantiate/commit UoW, not up to Repository:
//assuming in a service
public void DoSomething() {
using(var uow = new UnitOfWork()) {
_repositoryA.UpdateSomething();
_repositoryB.DeleteSomething();
_uow.Commit();
}
}
And if your service only wants to read the data, then just do not use UnitOfWork in that operation (or use it without calling Commit so it will just be disposed).
In case if your repository needs to know about UoW, it will normally be passed as another parameter in its behavior method.
Note that it is not done because Repository wants to call Commit, but sometimes (rarely) it is needed for the repository to "enlist" to UoW. These cases are rather more complex.
In a WCF service project, I have created a simple wrapper for MEF CompositionContainer to simplify its instantiation :
internal class CompositionProxy
{
private static Lazy<CompositionContainer> m_lazyCC;
static CompositionProxy()
{
m_lazyCC = new Lazy<CompositionContainer>(() =>
{
var batch = new CompositionBatch();
var dc1 = new DirectoryCatalog(
HttpContext.Current.Server.MapPath("~/bin")
);
return new CompositionContainer(dc1);
}
);
}
public static CompositionContainer DefaultContainer
{
get
{
return m_lazyCC.Value;
}
}
}
The idea is to have one CompositionContainer for the application lifetime, which search for export in the bin directory.
Then, I set up some webservices, that requires to have on imported property :
All of them are built like this :
public class MyService: IMyService
{
public MyService()
{
CompositionProxy.DefaultContainer.SatisfyImportsOnce(this);
}
[Import]
private IContext Context { get; set; }
public void DoTheJob()
{
// Logic goes here
}
}
Elsewhere, I have one class that match this export :
[Export(typeof(IContext))]
public class MyContext
{
public MyContext(){
Log("MyContext created");
}
}
In the constructor, I ask the composition container to populate the IContext Context property.
This seems to work, in my service, I can see the Context property is correctly populated.
However, I'm experiencing memory leaks, and my tracing show me the MyContext class is instantiated only once.
Can you clarify if I'm misusing the composition framework ?
I supposed it's a good idea to have one composition container for the application lifetime, was I wrong ?
the multiple calls to SatisfyImportsOnce seems to populate the target with the same unique instance. Is it true ? If true, how can I simply change my code to have a new instance each time the method is called ?
Any suggestion to improve my code ?
I supposed it's a good idea to have one composition container for the application lifetime
Yes, you are supposed to create one container for the application lifetime.
the multiple calls to SatisfyImportsOnce seems to populate the target with the same unique instance. Is it true ? If true, how can I simply change my code to have a new instance each time the method is called ?
You need [Import(RequiredCreationPolicy=CreationPolicy.NonShared)].
Any suggestion to improve my code ?
If possible, do not expose the container as a global and litter your code with calls to it. That's the Service Locator pattern, which has some disadvantages when compared to Dependency Injection. Instead of your service trying to compose itself, just declare what it needs:
[Export(typeof(IMyService))]
public class MyService: IMyService
{
private readonly IContext context;
public MyService(
[Import(typeof(IContext),
RequiredCreationPolicy=CreationPolicy.NonShared)]
IContext context)
{
if (context == null)
throw new ArgumentNullException("context");
this.context = context;
}
public void DoTheJob()
{
// Logic goes here
}
}
In a WCF service, I think you should only need to call the container in your ServiceHostFactory implementation. I'm not really familiar with WCF though.