0

我已经实现了工作单元/存储库模式,如here所述,但我也使用autofac和构造函数注入,所以我注册了UnitOfWork和DbContext(PsyProfContext)类,如下所示:如何正确处理使用Autofac注册的对象

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

而且一切都很好!

除了一件事情:我也使用enterprise library logging block,我已经实现了CustomTraceListener,它使用Entity Framework将日志条目写入数据库。

我的控制器看起来像这样(它是空的,因为在现阶段,我只是试图验证是否所有的东西(国际奥委会,记录,实体框架)的工作):

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

而在Write方法CustomTraceListener类,我试图解决UnitOfWork:

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

但我得到一个已经处置的实例!所以我已经放了一些断点,发现控制器的Dispose方法在CustomTraceListener类的Write方法之前调用,所以最终我没有发现直接使用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和Repository模式有什么意义。或者如果在某些情况下手动创建注册对象,在项目中使用DI有什么意义。

所以我想听听你的意见,关于如何处理这种情况?我现在的执行情况是否正常,或者肯定是错误的,我应该考虑另一个。

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

+0

这不是相关的,但你为什么要投你的服务?无论如何,你的服务没有解决的原因可能是因为HttpContext在你试图解决的时候是空的。 – maxlego

+1

是否有任何理由需要将登录与工作单元联系起来?通常情况下,如果发生异常或检测到某个验证错误,则不会提交工作单元,但无论如何日志记录都应该成功。事实上,在错误情况下,日志记录最有价值! –

+0

你对铸造完全正确,我没有注意到这一点。 – Peace87

回答

4

看起来你可能有几个问题。首先,如果要手动将工作单元放置在控制器中,则控制器应在构造函数中采用Owned<IUnitOfWork>。处理请求生命周期时,它会自动处理任何IDisposable组件 - 包括控制器和任何已解决的依赖关系 - 除非您指定要以某种方式接管生命周期的所有权。 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); 
    } 
} 

(请注意,在处置未成年人的逻辑修复覆盖有 - 你需要检查的disposing值,所以你不要双击处置您的工作单位。)

或者,你可以注册您的工作单位ExternallyOwned,像

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

ExternallyOwned还告诉Autofac,你会采取处置的控制。在这种情况下,你的控制器看起来就像它已经。 (虽然通常我只想让Autofac做的工作,但如果我能避免它,就不会取得所有权。)

其实,看事情的方式设立,如果你让Autofac你做处理,你可能能够完全避免处置的问题 - 调用DependencyResolver将返回工作单位是还没有处理完毕,它会没事的。

如果不能解决这个问题......您可能需要为您的问题添加一些细节。我看到你的控制器正在使用工作单元类,但我没有看到它在哪里记录任何东西,也没有看到使用工作单元的侦听器实现中的任何内容。 (另外,正如在你的问题的第一个评论中指出的那样,在你的控制器的构造函数中,你不应该把你的服务从IUnitOfWork转换为UnitOfWork--这首先打破了接口提供的抽象。 )

+0

你是对的让Autofac自动摆脱任何IDisposable组件。我不知道这个功能,所以我一定要阅读Autofac wiki。 – Peace87