Asp.net mvc 在ASP.NET(MVC)中使用Autofac的NHibernate:ITransaction

Asp.net mvc 在ASP.NET(MVC)中使用Autofac的NHibernate:ITransaction,asp.net-mvc,nhibernate,transactions,autofac,Asp.net Mvc,Nhibernate,Transactions,Autofac,在web应用程序中使用Autofac管理NHibernate事务的最佳方法是什么 我的治疗方法是 builder.Register(c => c.Resolve<ISessionFactory>().OpenSession()) .ContainerScoped(); builder.Register(c=>c.Resolve().OpenSession()) .集装箱镜检(); 对于ITransaction,我使用了Google代码,但它在决定是否回滚时依赖

在web应用程序中使用Autofac管理NHibernate事务的最佳方法是什么

我的治疗方法是

builder.Register(c => c.Resolve<ISessionFactory>().OpenSession())
       .ContainerScoped();
builder.Register(c=>c.Resolve().OpenSession())
.集装箱镜检();
对于
ITransaction
,我使用了Google代码,但它在决定是否回滚时依赖于
HttpContext.Current.Error


有更好的解决办法吗?以及NHibernate事务应该有什么范围?

我通常自己管理事务

public ActionResult Edit(Question q){
try {
 using (var t = repo.BeginTransaction()){
  repo.Save(q);
  t.Commit();
  return View();
 }
 catch (Exception e){
  ...
 }
}

我不久前发布了以下内容:

已修改,因此拦截器具有日志功能,[Transaction]属性也可用于类

[global::System.AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
public class TransactionAttribute : Attribute
{
}


public class ServicesInterceptor : Castle.Core.Interceptor.IInterceptor
{
    private readonly ISession db;
    private ITransaction transaction = null;

    public ServicesInterceptor(ISession db)
    {
        this.db = db;
    }

    public void Intercept(IInvocation invocation)
    {
        ILog log = LogManager.GetLogger(string.Format("{0}.{1}", invocation.Method.DeclaringType.FullName, invocation.Method.Name));

        bool isTransactional = IsTransactional(invocation.Method);
        bool iAmTheFirst = false;

        if (transaction == null && isTransactional)
        {
            transaction = db.BeginTransaction();
            iAmTheFirst = true;
        }

        try
        {
            invocation.Proceed();

            if (iAmTheFirst)
            {
                iAmTheFirst = false;

                transaction.Commit();
                transaction = null;
            }
        }
        catch (Exception ex)
        {
            if (iAmTheFirst)
            {
                iAmTheFirst = false;

                transaction.Rollback();
                db.Clear();
                transaction = null;
            }

            log.Error(ex);
            throw ex;
        }
    }

    private bool IsTransactional(MethodInfo mi)
    {
        var atrClass = mi.DeclaringType.GetCustomAttributes(false);

        foreach (var a in atrClass)
            if (a is TransactionAttribute)
                return true;

        var atrMethod = mi.GetCustomAttributes(false);

        foreach (var a in atrMethod)
            if (a is TransactionAttribute)
                return true;

        return false;
    }
}

当我使用autofac时,我使用相同的容器范围的方法,但不是将相同的会话传递给我的存储库/DAO对象,而是传递一个容器范围的UnitOfWork。工作单元在构造函数中具有此功能

    private readonly ISession _session;
    private ITransaction _transaction;

    public UnitOfWork(ISession session)
    {
        _session = session;
        _transaction = session.BeginTransaction();
    }
最重要的是:

    public void Dispose()
    {
        try
        {
            if (_transaction != null &&
                            !_transaction.WasCommitted &&
                            !_transaction.WasRolledBack)
                _transaction.Commit();
            _transaction = null;
        }
        catch (Exception)
        {
            Rollback();
            throw;
        }

    }
我(ab)使用autofac中的确定性处理工具来管理它,我有点喜欢它

另一件事是,我基本上只针对ASPNet环境,并有意识地决定将事务绑定到web请求。因此,每个web请求的事务模式

因此,我可以在IHTTP模块中执行以下错误处理代码:

    void context_Error(object sender, System.EventArgs e)
    {
        _containerProvider.RequestContainer.Resolve<IUnitOfWork>().Rollback();
    }
void context\u错误(对象发送方,System.EventArgs e)
{
_containerProvider.RequestContainer.Resolve().Rollback();
}

我还没有看过NHibernate。挖得太近了,但我确信有某种东西可以完成大部分工作。

这是最简单的解决方案,但有点繁琐,会给整个方法增加缩进。当然,2行和一个缩进,但是有一天你会意识到你必须在同一个请求或类似的事情中做两个事务..我喜欢这个解决方案。然而,另一个问题是我应该应用什么方法[事务]?根据这一点,如果我有一个会话,我似乎应该总是有一个事务,但是这个解决方案要求我在使用会话的任何地方手动添加[transaction]。请检查修改后的版本。您可能知道如何从那里修改它。您还可以完全跳过[Transaction]属性并始终启动事务。这是你的选择。我需要这个属性,因为有时候我需要在不同的事务中做两件事。我是这样做的://No transaction属性public virtual void CallThis(){Trans1();//commits Trans2();//commits}[transaction]public virtual void Trans1(){}[transaction]public virtual void Trans2(){}您能解释两个事务的用例吗?这一点很重要,因为如果我也遇到类似的用例,我会以不同的方式看待问题。当用户尝试使用证书登录时,我必须在数据库中进行一些选择和更新(这是第一个事务)。如果由于某种原因用户无法登录(被阻止的帐户、网络中的错误等等),我必须对我所做的一切进行回滚,并(在新的事务中)更新一个“失败的登录计数”(达到5后,帐户被阻止)。我想我现在理解了上下文。我可以自动启动和提交事务,但一个好的解决方案需要允许手动回滚和手动重启。我会再考虑一下,但现在我接受你的回答。谢谢。你的想法和Autofac非常相似,我非常喜欢。不幸的是,我不能接受两个答案,所以我会选择第一个答案(同样,dmonlord的声誉也要差得多)。