Joy*_*Joy 1 nhibernate aop ninject repository-pattern
我是DI和IoC模式的新手.
public class LazySessionContext
{
private readonly ISessionFactoryImplementor factory;
private const string CurrentSessionContextKey = "NHibernateCurrentSession";
public LazySessionContext(ISessionFactoryImplementor factory)
{
this.factory = factory;
}
/// <summary>
/// Retrieve the current session for the session factory.
/// </summary>
/// <returns></returns>
public ISession CurrentSession()
{
Lazy<ISession> initializer;
var currentSessionFactoryMap = GetCurrentFactoryMap();
if (currentSessionFactoryMap == null ||
!currentSessionFactoryMap.TryGetValue(factory, out initializer))
{
return null;
}
return initializer.Value;
}
/// <summary>
/// Bind a new sessionInitializer to the context of the sessionFactory.
/// </summary>
/// <param name="sessionInitializer"></param>
/// <param name="sessionFactory"></param>
public static void Bind(Lazy<ISession> sessionInitializer, ISessionFactory sessionFactory)
{
var map = GetCurrentFactoryMap();
map[sessionFactory] = sessionInitializer;
}
/// <summary>
/// Unbind the current session of the session factory.
/// </summary>
/// <param name="sessionFactory"></param>
/// <returns></returns>
public static ISession UnBind(ISessionFactory sessionFactory)
{
var map = GetCurrentFactoryMap();
var sessionInitializer = map[sessionFactory];
map[sessionFactory] = null;
if (sessionInitializer == null || !sessionInitializer.IsValueCreated) return null;
return sessionInitializer.Value;
}
/// <summary>
/// Provides the CurrentMap of SessionFactories.
/// If there is no map create/store and return a new one.
/// </summary>
/// <returns></returns>
private static IDictionary<ISessionFactory, Lazy<ISession>> GetCurrentFactoryMap()
{
var currentFactoryMap = (IDictionary<ISessionFactory, Lazy<ISession>>)
HttpContext.Current.Items[CurrentSessionContextKey];
if (currentFactoryMap == null)
{
currentFactoryMap = new Dictionary<ISessionFactory, Lazy<ISession>>();
HttpContext.Current.Items[CurrentSessionContextKey] = currentFactoryMap;
}
return currentFactoryMap;
}
}
public interface ISessionFactoryProvider
{
IEnumerable<ISessionFactory> GetSessionFactories();
}
public class SessionFactoryProvider
{
public const string Key = "NHibernateSessionFactoryProvider";
}
public class NHibernateSessionModule : IHttpModule
{
private HttpApplication app;
public void Init(HttpApplication context)
{
app = context;
context.BeginRequest += ContextBeginRequest;
context.EndRequest += ContextEndRequest;
context.Error += ContextError;
}
private void ContextBeginRequest(object sender, EventArgs e)
{
var sfp = (ISessionFactoryProvider)app.Context.Application[SessionFactoryProvider.Key];
foreach (var sf in sfp.GetSessionFactories())
{
var localFactory = sf;
LazySessionContext.Bind(
new Lazy<ISession>(() => BeginSession(localFactory)),
sf);
}
}
private static ISession BeginSession(ISessionFactory sf)
{
var session = sf.OpenSession();
session.BeginTransaction();
return session;
}
private void ContextEndRequest(object sender, EventArgs e)
{
var sfp = (ISessionFactoryProvider)app.Context.Application[SessionFactoryProvider.Key];
var sessionsToEnd = sfp.GetSessionFactories()
.Select(LazySessionContext.UnBind)
.Where(session => session != null);
foreach (var session in sessionsToEnd)
{
EndSession(session);
}
}
private void ContextError(object sender, EventArgs e)
{
var sfp = (ISessionFactoryProvider)app.Context.Application[SessionFactoryProvider.Key];
var sessionstoAbort = sfp.GetSessionFactories()
.Select(LazySessionContext.UnBind)
.Where(session => session != null);
foreach (var session in sessionstoAbort)
{
EndSession(session, true);
}
}
private static void EndSession(ISession session, bool abort = false)
{
if (session.Transaction != null && session.Transaction.IsActive)
{
if (abort)
{
session.Transaction.Rollback();
}
else
{
session.Transaction.Commit();
}
}
session.Dispose();
}
public void Dispose()
{
app.BeginRequest -= ContextBeginRequest;
app.EndRequest -= ContextEndRequest;
app.Error -= ContextError;
}
}
Run Code Online (Sandbox Code Playgroud)
我从GitHub的chinooknugets和jfmarillo那里得到了这个样本.从上面的代码我将会话注入存储库并通过IHttpmodule控制事务.现在我有两个问题:
如果我通过上面的代码实现事务管理,只要有请求就会调用它,它会为该请求打开一个会话.这是实现"按请求进行会话"方法的唯一目的.但是,如果我的所有控制器方法中只有一个实际使用存储库的方法,那么每次我发出请求时都不想打开会话.仅在控制器中由Transaction属性标记的操作期间才会处理该事务.
我会发出请求,只有在存储库请求时才会打开会话,因此可以通过任何IoC容器实现.
我仍然希望httpcontext事件处理事务,以便context + = BegingRequest和context + = EndRequest.并且该事务将在httpsodule内部处理,并根据请求提供httpcontext.但我不想实现IhttpModule并放入web.config.这种方法还有其他选择吗?
会话打开和关闭只能在那些httpcontext中完成,但是我想通过IoC容器(最好是ninject)来管理它,但只有当存储库正在请求该会话时.请注意,可以在调用控制器时初始化存储库,但不应该在该存储库中打开会话.当实际存储库执行任何临时操作时,会话应该打开.
有人会澄清我应该遵循这种情况的做法吗?我正在使用带有ninject和nhibernate的Mvc 3.
1,2)Ninject允许使用Ninject.Extensions.Factory 3.0.0创建Lazy对象
class MyController
{
public MyController(Lazy<SomeRepository> repository) { ... }
}
Run Code Online (Sandbox Code Playgroud)
这样就可以在使用时创建存储库(和上下文).
3)为什么要为此使用HttpModule?有更简单的方法,例如:
kernel.Bind<ISession>()
.ToMethod(ctx => ctx.Kernel.Get<ISessionFactory().OpenSession())
.InRequestScope()
.OnActivation(session => OpenTransaction(session))
.OnDeactivation(session => EndTransaction(session));
Run Code Online (Sandbox Code Playgroud)
从Ninject 3.0.0开始,您可以为HttpModules添加绑定,而不是在web.config中注册它们,并为它们使用construcotr注入.但由于HttpModule不知道是否使用了上下文,因此您必须为所有请求打开事务.
| 归档时间: |
|
| 查看次数: |
1416 次 |
| 最近记录: |