Ninject/NHibernate 配置多个数据库;绑定到提供程序 Ninject.Web.MVC3 和 .NET 4.5 时可以使用多个绑定
Ninject/NHibernate configuring multiple databases; more than one binding available when binding to provider Ninject.Web.MVC3 and .NET 4.5
我在尝试添加第二个数据库连接时遇到问题。
错误:
NinjectConfigurator.cs
当我注释掉 sybase 数据库的绑定时,我没有收到任何错误。我试图在 ISessionFactory
的绑定上添加条件 .WhenClassHas<CLASS>()
但无济于事。
...
container.Bind<ISessionFactory>().ToProvider<MsSqlSessionFactoryProvider>().InSingletonScope().Named("mssql");
container.Bind<ISession>().ToProvider<MsSqlSessionProvider>().WhenClassHas<MsSqlNhibernateSessionAttribute>().InRequestScope();
container.Bind<ISessionFactory>().ToProvider<SybaseSessionFactoryProvider>().InSingletonScope().Named("sybase");
container.Bind<ISession>().ToProvider<SybaseSessionProvider>().WhenClassHas<NhibernateSessionAttribute>().InRequestScope();
container.Bind<ICurrentSessionContextAdapter>().To<CurrentSessionContextAdapter>();
...
MsSqlSessionFactoryProvider.cs
public class MsSqlSessionFactoryProvider : Provider<ISessionFactory>
{
protected override ISessionFactory CreateInstance(IContext context)
{
return FluentNHibernate.Cfg.Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2012.ConnectionString(c => c.FromConnectionStringWithKey("MsSqlDbConnection")))
.CurrentSessionContext("web")
.Mappings(m => m.FluentMappings.AddFromAssemblyOf<SqlCommandFactory>())
.BuildSessionFactory();
}
}
MsSqlSessionProvider.cs
public class MsSqlSessionProvider : Provider<ISession>
{
protected override ISession CreateInstance(IContext context)
{
var sessionFactory = context.Kernel.Get<ISessionFactory>("mssql");
if (!CurrentSessionContext.HasBind(sessionFactory))
{
var session = sessionFactory.OpenSession();
CurrentSessionContext.Bind(session);
}
return sessionFactory.GetCurrentSession();
}
}
SybaseSessionFactoryProvider.cs
public class SybaseSessionFactoryProvider : Provider<ISessionFactory>
{
protected override ISessionFactory CreateInstance(IContext context)
{
return FluentNHibernate.Cfg.Fluently.Configure()
.Database(
OdbcConfiguration.Sybase.ConnectionString(c => c.FromConnectionStringWithKey("dbConnection")))
.ExposeConfiguration(c => c.SetProperty(NHibernate.Cfg.Environment.Hbm2ddlKeyWords, "none"))
.CurrentSessionContext("web")
.Mappings(m => m.FluentMappings.AddFromAssemblyOf<OdbcCommandFactory>())
.BuildSessionFactory();
}
}
SybaseSessionProvider.cs
public class SybaseSessionProvider : Provider<ISession>
{
protected override ISession CreateInstance(IContext context)
{
var sessionFactory = context.Kernel.Get<ISessionFactory>("sybase");
if (!CurrentSessionContext.HasBind(sessionFactory))
{
var session = sessionFactory.OpenSession();
CurrentSessionContext.Bind(session);
}
return sessionFactory.GetCurrentSession();
}
}
更新:
MsSqlNhibernateSessionAttribute.cs
using System.Web.Mvc;
namespace Common
{
public class MsSqlNhibernateSessionAttribute : ActionFilterAttribute/*, IActionFilter*/
{
private readonly IActionTransactionHelper _actionTransactionHelper;
private readonly IActionExceptionHandler _actionExceptionHandler;
public MsSqlNhibernateSessionAttribute()
: this(WebContainerManager.Get<IActionTransactionHelper>(),
WebContainerManager.Get<IActionExceptionHandler>())
{
}
public MsSqlNhibernateSessionAttribute(
IActionTransactionHelper actionTransactionHelper,
IActionExceptionHandler actionExceptionHandler)
{
_actionTransactionHelper = actionTransactionHelper;
_actionExceptionHandler = actionExceptionHandler;
}
public override void OnActionExecuting(ActionExecutingContext actionContext)
{
_actionTransactionHelper.BeginTransaction();
}
public override void OnActionExecuted(ActionExecutedContext actionExecutedContext)
{
_actionTransactionHelper.EndTransaction(actionExecutedContext);
_actionTransactionHelper.CloseSession();
_actionExceptionHandler.HandleException(actionExecutedContext);
}
}
}
NhibernateSessionAttribute.cs
using System.Web.Mvc;
namespace Common
{
public class NhibernateSessionAttribute : ActionFilterAttribute
{
private readonly ISybaseActionTransactionHelper _sybaseActionTransactionHelper;
private readonly IActionExceptionHandler _actionExceptionHandler;
public NhibernateSessionAttribute()
: this(WebContainerManager.Get<ISybaseActionTransactionHelper>(),
WebContainerManager.Get<IActionExceptionHandler>())
{
}
public NhibernateSessionAttribute(
ISybaseActionTransactionHelper actionTransactionHelper,
IActionExceptionHandler actionExceptionHandler)
{
_sybaseActionTransactionHelper = actionTransactionHelper;
_actionExceptionHandler = actionExceptionHandler;
}
public override void OnActionExecuting(ActionExecutingContext actionContext)
{
_sybaseActionTransactionHelper.BeginTransaction();
}
public override void OnActionExecuted(ActionExecutedContext actionExecutedContext)
{
_sybaseActionTransactionHelper.EndTransaction(actionExecutedContext);
_sybaseActionTransactionHelper.CloseSession();
_actionExceptionHandler.HandleException(actionExecutedContext);
}
}
}
我正在将其注入控制器并尝试将其注入 ActionTransactionHelper classes,但是当我这样做时错误变为 "Error activating ISessionFactory. No matching bindings were found..." 我包括控制器和一个 ActionTransactionHelper,因为它们都是相同的实现(我不确定我是否可以拥有一个事务助手 class)。
控制器
using System.Web.Mvc;
using Common;
using Data.SqlServer;
using NHibernate;
using Warehouse.Actions;
using Warehouse.Actions.VendorManagement;
namespace Warehouse.Controllers
{
[MsSqlNhibernateSession]
public class VendorManagementController : Controller
{
private readonly ISession _session;
public VendorManagementController(ISession session)
{
_session = session;
}
// GET: Vendor
public ActionResult Index()
{
ViewVendorManagementAction viewVendorManagementAction = new ViewVendorManagementAction();
return viewVendorManagementAction.Create(_session);
}
public ActionResult Vendor(Vendor vendor)
{
ViewVendorFormAction viewVendorFormAction = new ViewVendorFormAction();
return viewVendorFormAction.Create(Request, _session);
}
public ActionResult SaveVendor(Vendor vendor)
{
SaveVendorAction saveVendorAction = new SaveVendorAction(_session);
var newVendor = saveVendorAction.Save(vendor);
var returnUrl = Url.Action("Vendor") + "?Id=" + newVendor.Id;
return Redirect(returnUrl);
}
public ActionResult UpdateVendor(Vendor vendor)
{
UpdateVendorAction updateVendorAction = new UpdateVendorAction(_session);
updateVendorAction.Update(vendor);
var returnUrl = Url.Action("Vendor") + "?Id=" + vendor.Id;
return Redirect(returnUrl);
}
}
}
ActionTransactionHelper.cs
using System.Web.Mvc;
using NHibernate;
namespace Common
{
public class ActionTransactionHelper : IActionTransactionHelper
{
private readonly ISessionFactory _sessionFactory;
private readonly ICurrentSessionContextAdapter _currentSessionContextAdapter;
public ActionTransactionHelper(
ISessionFactory sessionFactory,
ICurrentSessionContextAdapter currentSessionContextAdapter)
{
_sessionFactory = sessionFactory;
_currentSessionContextAdapter = currentSessionContextAdapter;
}
public void BeginTransaction()
{
var session = _sessionFactory.GetCurrentSession();
if (session != null)
{
session.BeginTransaction();
}
}
public bool TransactionHandled { get; private set; }
public void EndTransaction(ActionExecutedContext filterContext)
{
var session = _sessionFactory.GetCurrentSession();
if (session == null) return;
if (!session.Transaction.IsActive) return;
if (filterContext.Exception == null)
{
session.Flush();
session.Transaction.Commit();
}
else
{
session.Transaction.Rollback();
}
TransactionHandled = true;
}
public bool SessionClosed { get; private set; }
public void CloseSession()
{
if (_currentSessionContextAdapter.HasBind(_sessionFactory))
{
var session = _sessionFactory.GetCurrentSession();
session.Close();
session.Dispose();
_currentSessionContextAdapter.Unbind(_sessionFactory);
SessionClosed = true;
}
}
}
}
WhenClassHas<Attribute>
绑定检查 class X,其中绑定类型 Y 被注入到属性 Z。
例如,当您有绑定时
Bind<IFoo>().To<Foo>().WhenClassHas<MarkerAttribute>();
和:
[Marker]
public class Bar {
public Bar(IFoo foo) ...
}
满足条件
但是,给定:
public class ZZZ
{
public ZZZ(IFoo foo) ..
}
[Marker]
public class YYY {
public YYY(ZZZ zzz) ..
}
这不满足条件。 IFoo
被注入到没有 [Marker]
属性的 ZZZ
中。
此外,当注入 [Marker]
属性本身时,这不满足条件,因为 [Marker]
属性本身在其 [=36= 上没有 [Marker]
属性]声明。
我找到了解决问题的方法。感谢@BatteryBackupUnit 的帮助。结果是我不得不用 [Named("corresponding name from NinjectConfiguration binding to ISessionFactory")] 装饰 ActionTransactionHelper 中的 ISessionFactory 注入。
Ninject Documentation for contextual named bindings
例如:
在配置文件中使用.Named("name")
。
container.Bind<ISessionFactory>().ToProvider<MsSqlSessionFactoryProvider>().InSingletonScope().Named("mssql");
然后在注入时使用 [Named("name")]
获取它
public class ActionTransactionHelper : IActionTransactionHelper
{
private readonly ISessionFactory _sessionFactory;
private readonly ICurrentSessionContextAdapter _currentSessionContextAdapter;
public ActionTransactionHelper(
[Named("mssql")] ISessionFactory sessionFactory,
ICurrentSessionContextAdapter currentSessionContextAdapter)
{
_sessionFactory = sessionFactory;
_currentSessionContextAdapter = currentSessionContextAdapter;
}
}
我在尝试添加第二个数据库连接时遇到问题。
错误:
NinjectConfigurator.cs
当我注释掉 sybase 数据库的绑定时,我没有收到任何错误。我试图在 ISessionFactory
的绑定上添加条件 .WhenClassHas<CLASS>()
但无济于事。
...
container.Bind<ISessionFactory>().ToProvider<MsSqlSessionFactoryProvider>().InSingletonScope().Named("mssql");
container.Bind<ISession>().ToProvider<MsSqlSessionProvider>().WhenClassHas<MsSqlNhibernateSessionAttribute>().InRequestScope();
container.Bind<ISessionFactory>().ToProvider<SybaseSessionFactoryProvider>().InSingletonScope().Named("sybase");
container.Bind<ISession>().ToProvider<SybaseSessionProvider>().WhenClassHas<NhibernateSessionAttribute>().InRequestScope();
container.Bind<ICurrentSessionContextAdapter>().To<CurrentSessionContextAdapter>();
...
MsSqlSessionFactoryProvider.cs
public class MsSqlSessionFactoryProvider : Provider<ISessionFactory>
{
protected override ISessionFactory CreateInstance(IContext context)
{
return FluentNHibernate.Cfg.Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2012.ConnectionString(c => c.FromConnectionStringWithKey("MsSqlDbConnection")))
.CurrentSessionContext("web")
.Mappings(m => m.FluentMappings.AddFromAssemblyOf<SqlCommandFactory>())
.BuildSessionFactory();
}
}
MsSqlSessionProvider.cs
public class MsSqlSessionProvider : Provider<ISession>
{
protected override ISession CreateInstance(IContext context)
{
var sessionFactory = context.Kernel.Get<ISessionFactory>("mssql");
if (!CurrentSessionContext.HasBind(sessionFactory))
{
var session = sessionFactory.OpenSession();
CurrentSessionContext.Bind(session);
}
return sessionFactory.GetCurrentSession();
}
}
SybaseSessionFactoryProvider.cs
public class SybaseSessionFactoryProvider : Provider<ISessionFactory>
{
protected override ISessionFactory CreateInstance(IContext context)
{
return FluentNHibernate.Cfg.Fluently.Configure()
.Database(
OdbcConfiguration.Sybase.ConnectionString(c => c.FromConnectionStringWithKey("dbConnection")))
.ExposeConfiguration(c => c.SetProperty(NHibernate.Cfg.Environment.Hbm2ddlKeyWords, "none"))
.CurrentSessionContext("web")
.Mappings(m => m.FluentMappings.AddFromAssemblyOf<OdbcCommandFactory>())
.BuildSessionFactory();
}
}
SybaseSessionProvider.cs
public class SybaseSessionProvider : Provider<ISession>
{
protected override ISession CreateInstance(IContext context)
{
var sessionFactory = context.Kernel.Get<ISessionFactory>("sybase");
if (!CurrentSessionContext.HasBind(sessionFactory))
{
var session = sessionFactory.OpenSession();
CurrentSessionContext.Bind(session);
}
return sessionFactory.GetCurrentSession();
}
}
更新:
MsSqlNhibernateSessionAttribute.cs
using System.Web.Mvc;
namespace Common
{
public class MsSqlNhibernateSessionAttribute : ActionFilterAttribute/*, IActionFilter*/
{
private readonly IActionTransactionHelper _actionTransactionHelper;
private readonly IActionExceptionHandler _actionExceptionHandler;
public MsSqlNhibernateSessionAttribute()
: this(WebContainerManager.Get<IActionTransactionHelper>(),
WebContainerManager.Get<IActionExceptionHandler>())
{
}
public MsSqlNhibernateSessionAttribute(
IActionTransactionHelper actionTransactionHelper,
IActionExceptionHandler actionExceptionHandler)
{
_actionTransactionHelper = actionTransactionHelper;
_actionExceptionHandler = actionExceptionHandler;
}
public override void OnActionExecuting(ActionExecutingContext actionContext)
{
_actionTransactionHelper.BeginTransaction();
}
public override void OnActionExecuted(ActionExecutedContext actionExecutedContext)
{
_actionTransactionHelper.EndTransaction(actionExecutedContext);
_actionTransactionHelper.CloseSession();
_actionExceptionHandler.HandleException(actionExecutedContext);
}
}
}
NhibernateSessionAttribute.cs
using System.Web.Mvc;
namespace Common
{
public class NhibernateSessionAttribute : ActionFilterAttribute
{
private readonly ISybaseActionTransactionHelper _sybaseActionTransactionHelper;
private readonly IActionExceptionHandler _actionExceptionHandler;
public NhibernateSessionAttribute()
: this(WebContainerManager.Get<ISybaseActionTransactionHelper>(),
WebContainerManager.Get<IActionExceptionHandler>())
{
}
public NhibernateSessionAttribute(
ISybaseActionTransactionHelper actionTransactionHelper,
IActionExceptionHandler actionExceptionHandler)
{
_sybaseActionTransactionHelper = actionTransactionHelper;
_actionExceptionHandler = actionExceptionHandler;
}
public override void OnActionExecuting(ActionExecutingContext actionContext)
{
_sybaseActionTransactionHelper.BeginTransaction();
}
public override void OnActionExecuted(ActionExecutedContext actionExecutedContext)
{
_sybaseActionTransactionHelper.EndTransaction(actionExecutedContext);
_sybaseActionTransactionHelper.CloseSession();
_actionExceptionHandler.HandleException(actionExecutedContext);
}
}
}
我正在将其注入控制器并尝试将其注入 ActionTransactionHelper classes,但是当我这样做时错误变为 "Error activating ISessionFactory. No matching bindings were found..." 我包括控制器和一个 ActionTransactionHelper,因为它们都是相同的实现(我不确定我是否可以拥有一个事务助手 class)。
控制器
using System.Web.Mvc;
using Common;
using Data.SqlServer;
using NHibernate;
using Warehouse.Actions;
using Warehouse.Actions.VendorManagement;
namespace Warehouse.Controllers
{
[MsSqlNhibernateSession]
public class VendorManagementController : Controller
{
private readonly ISession _session;
public VendorManagementController(ISession session)
{
_session = session;
}
// GET: Vendor
public ActionResult Index()
{
ViewVendorManagementAction viewVendorManagementAction = new ViewVendorManagementAction();
return viewVendorManagementAction.Create(_session);
}
public ActionResult Vendor(Vendor vendor)
{
ViewVendorFormAction viewVendorFormAction = new ViewVendorFormAction();
return viewVendorFormAction.Create(Request, _session);
}
public ActionResult SaveVendor(Vendor vendor)
{
SaveVendorAction saveVendorAction = new SaveVendorAction(_session);
var newVendor = saveVendorAction.Save(vendor);
var returnUrl = Url.Action("Vendor") + "?Id=" + newVendor.Id;
return Redirect(returnUrl);
}
public ActionResult UpdateVendor(Vendor vendor)
{
UpdateVendorAction updateVendorAction = new UpdateVendorAction(_session);
updateVendorAction.Update(vendor);
var returnUrl = Url.Action("Vendor") + "?Id=" + vendor.Id;
return Redirect(returnUrl);
}
}
}
ActionTransactionHelper.cs
using System.Web.Mvc;
using NHibernate;
namespace Common
{
public class ActionTransactionHelper : IActionTransactionHelper
{
private readonly ISessionFactory _sessionFactory;
private readonly ICurrentSessionContextAdapter _currentSessionContextAdapter;
public ActionTransactionHelper(
ISessionFactory sessionFactory,
ICurrentSessionContextAdapter currentSessionContextAdapter)
{
_sessionFactory = sessionFactory;
_currentSessionContextAdapter = currentSessionContextAdapter;
}
public void BeginTransaction()
{
var session = _sessionFactory.GetCurrentSession();
if (session != null)
{
session.BeginTransaction();
}
}
public bool TransactionHandled { get; private set; }
public void EndTransaction(ActionExecutedContext filterContext)
{
var session = _sessionFactory.GetCurrentSession();
if (session == null) return;
if (!session.Transaction.IsActive) return;
if (filterContext.Exception == null)
{
session.Flush();
session.Transaction.Commit();
}
else
{
session.Transaction.Rollback();
}
TransactionHandled = true;
}
public bool SessionClosed { get; private set; }
public void CloseSession()
{
if (_currentSessionContextAdapter.HasBind(_sessionFactory))
{
var session = _sessionFactory.GetCurrentSession();
session.Close();
session.Dispose();
_currentSessionContextAdapter.Unbind(_sessionFactory);
SessionClosed = true;
}
}
}
}
WhenClassHas<Attribute>
绑定检查 class X,其中绑定类型 Y 被注入到属性 Z。
例如,当您有绑定时
Bind<IFoo>().To<Foo>().WhenClassHas<MarkerAttribute>();
和:
[Marker]
public class Bar {
public Bar(IFoo foo) ...
}
满足条件
但是,给定:
public class ZZZ
{
public ZZZ(IFoo foo) ..
}
[Marker]
public class YYY {
public YYY(ZZZ zzz) ..
}
这不满足条件。 IFoo
被注入到没有 [Marker]
属性的 ZZZ
中。
此外,当注入 [Marker]
属性本身时,这不满足条件,因为 [Marker]
属性本身在其 [=36= 上没有 [Marker]
属性]声明。
我找到了解决问题的方法。感谢@BatteryBackupUnit 的帮助。结果是我不得不用 [Named("corresponding name from NinjectConfiguration binding to ISessionFactory")] 装饰 ActionTransactionHelper 中的 ISessionFactory 注入。
Ninject Documentation for contextual named bindings
例如:
在配置文件中使用.Named("name")
。
container.Bind<ISessionFactory>().ToProvider<MsSqlSessionFactoryProvider>().InSingletonScope().Named("mssql");
然后在注入时使用 [Named("name")]
获取它public class ActionTransactionHelper : IActionTransactionHelper
{
private readonly ISessionFactory _sessionFactory;
private readonly ICurrentSessionContextAdapter _currentSessionContextAdapter;
public ActionTransactionHelper(
[Named("mssql")] ISessionFactory sessionFactory,
ICurrentSessionContextAdapter currentSessionContextAdapter)
{
_sessionFactory = sessionFactory;
_currentSessionContextAdapter = currentSessionContextAdapter;
}
}