I am using Castle Windsor for my IoC along with NHIbernate in an ASP.NET MVC app. It works great registered as follows (with one exception):
container.Register(Component.For<ISessionFactoryBuilder.().ImplementedBy<SessionFactoryBuilder>().LifestyleSingleton());
// Register the NHibernate session factory as a singleton using custom SessionFactoryBuilder.BuildSessionFactory method.
container.Register(Component.For<ISessionFactory>().UsingFactoryMethod(k => k.Resolve<ISessionFactoryBuilder>().BuildSessionFactory("ApplicationServices")).LifestyleSingleton());
container.Register(Component.For<IInterceptor>().ImplementedBy<ChangeAuditInfoInterceptor>().LifestylePerWebRequest());
container.Register(Component.For<ISession>().UsingFactoryMethod(k => k.Resolve<ISessionFactory>()
.OpenSession(container.Resolve<IInterceptor>())).LifestylePerWebRequest());
All is good except that for my ChangeAuditInterceptor in turn has an IAccountSession service injected which in turn has an NHibernate ISession injected...which leads to the following circular dependency exception:
Dependency cycle has been detected when trying to resolve component
'Late bound NHibernate.ISession'. The resolution tree that resulted in
the cycle is the following: Component 'Late bound NHibernate.ISession'
resolved as dependency of component
'Blah.Core.Services.AccountSession' resolved as dependency of
component 'Blah.Core.Infrastructure.Data.ChangeAuditInfoInterceptor'
resolved as dependency of component
'Blah.Core.Infrastructure.Installers.SessionFactoryBuilder' resolved
as dependency of component 'Late bound NHibernate.ISessionFactory'
resolved as dependency of component 'Late bound NHibernate.ISession'
which is the root component being resolved.
For the past couple years I've usually run with an NHibernateSessionManager which took care of plunking in the IInterceptor without causing this circular dependency issue (as opposed to this usage of a SessionFactoryBuilder which uses Castle Windsor's UsingFactoryMethod functionality).
Any suggestions for how to resolve this circular dependency? Short of starting to hack in the ISession for the AccountSession via some other means (i.e. property injection which skirts around the issue and smells as a result). I've switched the ISession injection to property injection for the AccountSession service and it works fine, but I don't like the implicit contract vs. the constructor explicit contract.
public class AccountSession : IAccountSession
{
private readonly ISession _session;
public AccountSession(ISession session)
{
_session = session;
}
public Account GetCurrentAccount() // Called by a method in ChangeAuditInterceptor
{
...
}
...etc.
Try to add a dependency on Func< ISession > in your interceptor class
public class CustomInterceptor : EmptyInterceptor
{
private readonly Func<ISession> sessionFunc;
private ISession session;
protected ISession Session
{
get
{
return session ?? (session = sessionFunc());
}
}
public CustomInterceptor(Func<ISession> sessionFunc)
{
this.sessionFunc = sessionFunc;
}
}
And registration:
container.Register(Component.For<ISession>().
LifestylePerWebRequest()
.UsingFactoryMethod(container =>
{
var interceptor = container.Resolve<IInterceptor>();
return container.Resolve<ISessionFactory>.OpenSession(interceptor);
}));
container.Register(Component.For<Func<ISession>>()
.LifestylePerWebRequest()
.UsingFactoryMethod(container =>
{
Func<ISession> func = container.Resolve<ISession>;
return func;
}));
Related
I have configured my .net-core 2.1 service with a database-context in the start-up method.
services.AddDbContext<DatabaseContext>(options => options.UseSqlServer(Configuration.GetConnectionString(nameof(DatabaseContext))));
Now i could do the following to get my database-context in my controller:
var context = serviceProvider.GetService<DatabaseContext>();
This works very well. But how could i access the Database-Context in a normal class something like this sould be done:
public class MyAccessClass{
public MyAccessClass(){
//Access the ServiceProvider or get the Database-Context class anywhere else
}
}
I don't want to pass the database-context object through the constructor or to initialize the DatbaseContext Class again.
Thanks for your help.
You should take your dependencies through the constructor, preferrably an interface, e.g. IDatabaseContext, but code sample below based on your code. If you add MyAccessClass as a service, e.g. services.AddTransient<MyAccessClass>(), and then use dependency injection in your controller, the database context would be automatically injected in the constructor by the default IoC container in ASP.NET Core.
You shouldn't have it rely on IServiceProvider, the reasoning is that your class wants to make no assumption of implementations, it just needs the database context. Having it rely on IServiceProvider would assume this context, and any possible future dependencies, comes from the IoC in ASP.NET Core which may not be the case (what if you just want to release this as a class library later on?). It would make the MyAccessClass class hard to test and use outside of a controller.
You say in your comment:
"...or get the Database-Context class anywhere else"
That anywhere else is completely flexible by simply accepting the context into the constructor since your class doesn't know where anywhere else is but whatever is creating your class does know!
Example of DI in ASP.NET Core
Take context as a dependency through constructor
public class MyAccessClass{
private readonly DatabaseContext databaseContext;
public MyAccessClass(DatabaseContext databaseContext) {
this.databaseContext = databaseContext;
}
}
Add as service
public void ConfigureServices(IServiceCollection services)
{
services.AddTransient<MyAccessClass>();
}
Inject into a controller
public class MyController : Controller
{
private readonly MyAccessClass myAccessClass;
//Happily injected through DI
public MyController(MyAccessClass myAccessClass)
{
this.myAccessClass = myAccessClass;
}
}
Or inject straight into an action
public class MyController : Controller
{
public MyController()
{
}
public IActionResult MyAction([FromServices] MyAccessClass myAccessClass)
{
}
}
I've implemented Unit of Work/Repository pattern, as described here, but I'm also using autofac and constructor injection, so I registered UnitOfWork and DbContext (PsyProfContext) class like this:
builder.Register(context => new PsyProfContext()).InstancePerHttpRequest();
builder.RegisterType<UnitOfWork>().As<IUnitOfWork>().InstancePerHttpRequest();
And everything works great!
Except for one thing: I'm also using enterprise library logging block, and I have implemented CustomTraceListener which is using Entity Framework to write log entry into the database.
My controller looks like this (it is empty because at the moment I just tried to verify if all the things (IoC, logging, entity framework) are working):
public class HomeController : Controller
{
private readonly UnitOfWork unitOfWork;
public HomeController(IUnitOfWork unitOfWork)
{
this.unitOfWork = (UnitOfWork) unitOfWork;
}
//
// GET: /Home/
public ActionResult Index()
{
throw new HttpException();
return View();
}
protected override void Dispose(bool disposing)
{
unitOfWork.Dispose();
base.Dispose(disposing);
}
}
And in the Write method of the CustomTraceListener class, I've tried to Resolve UnitOfWork:
DependencyResolver.Current.GetService<IUnitOfWork>() as UnitOfWork;
But I get an instance which is already disposed! so I've put some breakpoints and found out that Dispose method of the controller is called before the Write method of the CustomTraceListener class, so in the end I didn't found other solution than using DbContext (PsyProfContext) directly:
public override void Write(object o)
{
using (var conext = new PsyProfContext())
{
var customLogEntry = o as CustomLogEntry;
if (customLogEntry != null)
{
var logEntry = new LogEntry
{
//a bunch of properties
};
conext.Exceptions.Add(logEntry);
conext.SaveChanges();
}
}
}
But I don't like this solution! What's the point to use UnitOfWork and Repository pattern if you access DbContext object directly. Or what's the point in using DI in project if you create a registered object manually in some cases.
So I wanted to hear your opinion, about how to deal with this kind of situations? Is my current implementation fine, or it is definitely wrong and I should think about another one.
Any help will be greatly appreciated and any ideas are welcome!
It looks like you may have a couple of problems.
First, if you're manually disposing the unit of work object in your controller, your controller should take an Owned<IUnitOfWork> in the constructor. When the request lifetime is disposed it will automatically dispose of any IDisposable components - including the controller and any resolved dependencies - unless you specify somehow that you're going to take over ownership of the lifetime. You can do that by using Owned<T>.
public class HomeController : Controller
{
Owned<IUnitOfWork> _uow;
public HomeController(Owned<IUnitOfWork> uow)
{
this._uow = uow;
}
protected override void Dispose(bool disposing)
{
if(disposing)
{
this._uow.Dispose();
}
base.Dispose(disposing);
}
}
(Note a minor logic fix in the Dispose override there - you need to check the value of disposing so you don't double-dispose your unit of work.)
Alternatively, you could register your units of work as ExternallyOwned, like
builder
.RegisterType<UnitOfWork>()
.As<IUnitOfWork>()
.ExternallyOwned()
.InstancePerHttpRequest();
ExternallyOwned also tells Autofac that you'll take control of disposal. In that case, your controller will look like it does already. (Generally I like to just let Autofac do the work, though, and not take ownership if I can avoid it.)
In fact, looking at the way things are set up, you might be able to avoid the disposal problem altogether if you let Autofac do the disposal for you - the call to DependencyResolver would return the unit of work that isn't disposed yet and it'd be OK.
If that doesn't fix it... you may want to add some detail to your question. I see where your controller is using the unit of work class, but I don't see where it logs anything, nor do I see anything in the listener implementation that's using the unit of work.
(Also, as noted in the first comment on your question, in the constructor of your controller you shouldn't be casting your service from IUnitOfWork to UnitOfWork - that's breaking the abstraction that the interface was offering in the first place.)
Grabbed this from a sample:
protected override ObjectContext CreateDataSource()
{
NorthwindContext nw = new NorthwindContext();
// Configure DbContext before we provide it to the
// data services runtime.
nw.Configuration.ValidateOnSaveEnabled = false;
// Get the underlying ObjectContext for the DbContext.
var context = ((IObjectContextAdapter)nw).ObjectContext;
// Return the underlying context.
return context;
}
Modified it to use the DbContext class that I have in my project.
EDIT: Clarifying that I am casting from a DbContext class just as the sample does:
public class NorthwindContext : DbContext
{
// Use the constructor to target a specific named connection string
public NorthwindContext()
: base("name=NorthwindEntities")
{
// Disable proxy creation as this messes up the data service.
this.Configuration.ProxyCreationEnabled = false;
// Create Northwind if it doesn't already exist.
this.Database.CreateIfNotExists();
}
Running the code gives me an error on the line casting the DbContext:
Unable to cast object of type 'MyProject.MyDbContext' to type 'System.Data.Entity.Infrastructure.IObjectContextAdapter'.
Despite the fact that DbContext implements IObjectContextAdapter:
public class DbContext : IDisposable, IObjectContextAdapter
I've found several questions here on SO and other googled sources, but no solutions I have found work.
I'm using Entity Framework 4.2, attempted to update to the 4.3 beta and I'm not sure if that stuck.
Overall goal is to serve data in WCF as a DataService.
Update: Digging deeper I find that there is an ambiguity issue between what my DbContext was (From EntityFramework.dll ) and the type in the WCF project (from Microsoft.data.Entity.CTP)
Not sure how to get what I want from both here....
Just a reminder, the issue here was that an ambiguity between EntityFramework.dll and Microsoft.Data.Entity.CTP was causing the DataInitializer I had for my DbContext to lose functionality.
I solved this issue by replacing my Initializer here:
public class MyDataInitializer : RecreateDatabaseIfModelChanges<MyData>
{
public void Seed(MyData context)
To:
public class MyDataInitializer : IDatabaseInitializer<MyData>
{
public void InitializeDatabase(MyData context)
And I can now access my DataService.
Just one
UPDATE
I've accepted my answer since I believe that the OnePerRequest module shouldn't clear out the cache until all other modules have had a chance to run. However, after we port the rest of our pages to MVC I will be reworking our Unit of Work implementation to be more in line with Remo's suggestion.
I just upgraded from Ninject 2.0 to Ninject 2.1 and I'm now having issues with my NHibernate UnitOfWork implementation.
My implementation is as follows. I have an HttpModule that subscribes to BeginRequest and EndRequest and has the following code.
public void BeginRequest(object sender, EventArgs e)
{
var app = (WebApplication)sender;
var repository = app.Kernel.Get<IRepository>();
repository.BeginRequest();
}
public void EndRequest(object sender, EventArgs e)
{
var app = (WebApplication)sender;
var repository = app.Kernel.Get<IRepository>();
repository.EndRequest();
}
The IRepository implementation takes an NHibernate ISession as a dependency. Here are the two bindings.
Bind<ISession>().ToMethod(context => NHibernateSessionFactory.Instance.OpenSession()).InRequestScope();
Bind<IRepository>().To<NHibernateRepository>().InTransientScope();
NHibernate repository opens up a transaction in BeginRequest and commits it in EndRequest. With the upgrade to Ninject 2.1. The OnePerRequestModule is now interfering with this code. Since it is attached to the EndRequest event first it fires before my DataModule and clears the ISession from the Kernel cache. This means that the IRepository gets a brand new ISession and thus can't commit the transaction. Complicating matters is the fact that OnePerRequestModule registers with the Kernel not once, but twice. Once in the KernelBase constructor and once again in the Application_Start method in the NinjectHttpApplication.
So it's pretty convoluted and one of the ways I've found to turn this functionality off is to call OnePerRequestModule.StopManaging(Kernel);
twice in the OnApplicationStarted method in my Global.asax.cs. Does anyone have any suggestions in regards to how to handle this? I'm assuming there's a reason OnePerRequestModule was introduced, but it would be nice to keep with my UnitOfWork implementation.
I think that's not a good implementation. You should rather call BeginRequest in a activation action and CloseRequest in the dispose of the repository. That way you do not have thes too service locator like get calls on the kernel.
I've rewritten my UnitOfWork implementation as we have rewritten our WebForms app to MVC. I now have a FilterAttribute that is applied to every data encapsulated action that looks like this:
public class UnitOfWorkAttribute : FilterAttribute, IActionFilter
{
[Inject]
public IUnitOfWork UnitOfWork { get; set; }
public UnitOfWorkAttribute()
{
Order = 0;
}
public void OnActionExecuting(ActionExecutingContext filterContext)
{
UnitOfWork.Begin();
}
public void OnActionExecuted(ActionExecutedContext filterContext)
{
UnitOfWork.End();
}
}
I've decided to edit the Ninject.Web.Mvc project to fix this. In the NinjectHttpApplication class. I've moved this statement this.onePerRequestModule.Init(this); from the constructor to the Init method. This ensures that the onePerRequestModule registers its event handler last.
here is my problem: I'm building a desktop application, with the following tools:
Caliburn
Ninject
NHibernate
All my view models and repositories are instanciated with Ninject. My repositories all need an ISession in their constructor.
I'd like to follow ayende's advice concerning the ViewModels: each ViewModel opens a new session.
Is it possible to configure Ninject to open a new session when a ViewModel is created, and use this session inside the repositories used by this view model?
I had a look to the InScope function of Ninject, as well as the ICurrentSessionContext interface in NHibernate, but I don't know how to model all of that to get what I want...
Did someone make something like that before?
Thanks in advance
Mike
I solved a similar scenario leveraging the ViewModel lifecycle: I created an ISessionAware interface (with a SetSession method) to be implemented by repositories, then I initialized the repositories through ISessionAware in the OnInitialize method of the ViewModel (which is enforced by Caliburn when the VM is managed by a ScreenConductor).
Using reflection to inspect the properties holding the repositories, I could put all the infrastructure on a BaseDataVM class.
Using a scope in the container would be more elegant, I think, but I don't know Ninject.
I have a very similar project (except I'm not using Caliburn) and have been trying to figure out how to do this as well. I did come up with one method that works well for constructor injection using Ninject's InScope() method.
I have a static class called IoC that wraps access to Ninject's kernel. Since the dependencies are all injected into the constructor, the context is only relevant when the object is being created. So it doesn't matter what is supplied for context, but a Guid feels like the safe choice. Program.OpenSession() is a static method to open a new ISession.
public static class Ioc
{
private static readonly IKernel _kernel;
static IoC()
{
_kernel = new StandardKernel();
_kernel.Load(new ContextModule());
}
private static object _context;
public static T ResolveInContext<T>(object context)
{
_context = context;
var result = _kernel.Get<T>();
_context = null;
return result;
}
private class ContextModule : NinjectModule
{
public override void Load()
{
Bind<ISession>().ToMethod(x => Program.OpenSession()).InScope(x => _context);
Bind<frmCompanyViewer>().ToSelf().InScope(x => _context);
}
}
}
Usage is:
var frm = IoC.ResolveInContext<frmCompanyViewer>(Guid.NewGuid());
The form's constructor signature is:
public frmCompanyViewer(ISession session, ICompanyRepository companyRepository)
I verified that with InScope on the bindings, the same ISession that is used to construct frmCompanyViewer is also used to construct companyRepository. If I remove InScope then two ISessions are used.
Edited to add: This would also work, see comments. This should be made thread safe for a real application. I changed the method name to ConstructInContext to clarify that the context only applies during object construction.
public static T ConstructInContext<T>()
{
_context = Guid.NewGuid();
var result = _kernel.Get<T>();
_context = null;
return result;
}
We have this with AOP, in unhaddins.
Is called "Conversation per Business Transaction".
search in google
here you have ;)
http://groups.google.com/group/unhaddins/browse_thread/thread/29eca74a83df5faf/d9fab4062d4cb4c4?lnk=gst&q=ninject#d9fab4062d4cb4c4
Well, I've found a solution thanks to the ninject group.
The solution here is to use the function InScope when I bind ISession, and browse in the IContext variable to inspect the services. If one service in the request hierarchy is assignable to the base class of my view models, I use the context as scope.
So the first time an ISession will be injected in the constructor of my ViewModel, a new scope is used. And all subsequent calls to ISession inside the constructor of the ViewModel will be resolved with the same scope. And then only one session is created for my ViewModel.
Here is the code:
Bind<ISession>().ToMethod(ctx =>
{
var session = ctx.Kernel.Get<INHibernateSessionFactoryBuilder>()
.GetSessionFactory()
.OpenSession();
session.FlushMode = FlushMode.Commit;
return session;
})
.InScope(ctx =>
{
var request = ctx.Request;
if (request.Service is IScreen)
return request;
while ((request = request.ParentRequest) != null)
if (typeof(IScreen).IsAssignableFrom(request.Service))
return request;
return new object();
});
And the constructor of the viewmodel must contains all the injected dependencies which rely on the ISession:
[Inject]
public PlayersManagementViewModel(ISession session, IPlayersRepository playersRepository)
{
}
Hope that helps