0

我已经实现了工作单元/存储库模式,如此所述,但我也在使用 autofac 和构造函数注入,所以我注册了 UnitOfWork 和 DbContext (PsyProfContext) 类,如下所示:

 builder.Register(context => new PsyProfContext()).InstancePerHttpRequest();
 builder.RegisterType<UnitOfWork>().As<IUnitOfWork>().InstancePerHttpRequest();

一切都很好!

除了一件事:我也在使用企业库日志记录块,并且我已经实现了使用实体框架将日志条目写入数据库的 CustomTraceListener。

我的控制器看起来像这样(它是空的,因为目前我只是试图验证所有东西(IoC、日志记录、实体框架)是否都在工作):

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);
    }
}

在 CustomTraceListener 类的 Write 方法中,我尝试解决 UnitOfWork:

DependencyResolver.Current.GetService<IUnitOfWork>() as UnitOfWork;

但是我得到了一个已经被处理的实例!所以我放了一些断点,发现在CustomTraceListener类的Write方法之前调用了控制器的Dispose方法,所以最后我没有找到直接使用DbContext(PsyProfContext)的其他解决方案:

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();
            }
        }
    }

但我不喜欢这个解决方案!如果您直接访问 DbContext 对象,那么使用 UnitOfWork 和存储库模式有什么意义。或者,如果您在某些情况下手动创建注册对象,那么在项目中使用 DI 有什么意义。

所以我想听听你的意见,关于如何处理这种情况?我目前的实施是否良好,或者肯定是错误的,我应该考虑另一个。

任何帮助将不胜感激,欢迎任何想法!

4

1 回答 1

4

看起来你可能有几个问题。

首先,如果您在控制器中手动处理工作单元对象,您的控制器应该Owned<IUnitOfWork>在构造函数中使用一个。当请求生命周期被释放时,它将自动释放任何IDisposable组件 - 包括控制器和任何已解决的依赖项 - 除非您以某种方式指定您将接管生命周期的所有权。您可以使用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);
  }
}

(请注意那里的 Dispose 覆盖中的一个小逻辑修复 - 您需要检查 的值,disposing这样您就不会重复处理您的工作单元。)

或者,您可以将您的工作单元注册为ExternallyOwned,例如

builder
  .RegisterType<UnitOfWork>()
  .As<IUnitOfWork>()
  .ExternallyOwned()
  .InstancePerHttpRequest();

ExternallyOwned还告诉 Autofac 您将控制处置。在这种情况下,您的控制器看起来就像它已经完成的那样。(不过,一般来说,我喜欢让 Autofac 完成工作,如果可以避免的话,不要拥有所有权。)

事实上,看看事情的设置方式,如果您让 Autofac 为您进行处理,您可能可以完全避免处理问题- 调用DependencyResolver将返回尚未处理的工作单元,并且它没关系。

如果这不能解决问题......您可能想为您的问题添加一些细节。我看到您的控制器在哪里使用工作单元类,但我没有看到它在哪里记录任何内容,也没有看到侦听器实现中使用工作单元的任何内容。

(另外,正如对您的问题的第一条评论中所述,在您的控制器的构造函数中,您不应该将您的服务从IUnitOfWorkto转换为UnitOfWork- 这首先破坏了接口提供的抽象。)

于 2013-04-01T15:33:23.000 回答