Pea*_*e87 0 enterprise-library unit-of-work autofac repository-pattern asp.net-mvc-4
我已经实现了工作单元/存储库模式,如此处所述,但我还使用 autofac 和构造函数注入,因此我注册了 UnitOfWork 和 DbContext (PsyProfContext) 类,如下所示:
builder.Register(context => new PsyProfContext()).InstancePerHttpRequest();
builder.RegisterType<UnitOfWork>().As<IUnitOfWork>().InstancePerHttpRequest();
Run Code Online (Sandbox Code Playgroud)
一切都很好!
除了一件事:我还使用企业库日志记录块,并且我已经实现了 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);
}
}
Run Code Online (Sandbox Code Playgroud)
在 CustomTraceListener 类的 Write 方法中,我尝试解析 UnitOfWork:
DependencyResolver.Current.GetService<IUnitOfWork>() as UnitOfWork;
Run Code Online (Sandbox Code Playgroud)
但我得到一个已经被处置的实例!所以我设置了一些断点,发现控制器的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();
}
}
}
Run Code Online (Sandbox Code Playgroud)
但我不喜欢这个解决方案!如果直接访问 DbContext 对象,那么使用 UnitOfWork 和 Repository 模式有什么意义。或者,如果您在某些情况下手动创建注册对象,那么在项目中使用 DI 有何意义。
所以我想听听您的意见,如何处理这种情况?我当前的实现是否良好,或者它肯定是错误的,我应该考虑另一种实现。
任何帮助将不胜感激,欢迎任何想法!
看起来您可能有几个问题。
首先,如果您在控制器中手动处置工作单元对象,则控制器应该Owned<IUnitOfWork>在构造函数中采用 an 。当请求生命周期被处置时,它将自动处置任何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);
}
}
Run Code Online (Sandbox Code Playgroud)
(请注意 Dispose 覆盖中的一个小逻辑修复 - 您需要检查 的值,disposing这样您就不会双重处置您的工作单元。)
或者,您可以将您的工作单元注册为ExternallyOwned,例如
builder
.RegisterType<UnitOfWork>()
.As<IUnitOfWork>()
.ExternallyOwned()
.InstancePerHttpRequest();
Run Code Online (Sandbox Code Playgroud)
ExternallyOwned还告诉 Autofac 您将控制处置。在这种情况下,您的控制器将看起来像它已经一样。(不过,一般来说,我喜欢让 Autofac 来做这项工作,如果可以避免的话,就不要取得所有权。)
事实上,看看事情的设置方式,如果您让 Autofac 为您进行处置,您可能能够完全避免处置问题- 调用DependencyResolver将返回尚未处置的工作单元,并且它'会没事的。
如果这不能解决问题...您可能需要为您的问题添加一些细节。我看到您的控制器在哪里使用工作单元类,但我没有看到它在哪里记录任何内容,也没有在侦听器实现中看到任何使用工作单元的内容。
(另外,正如对您的问题的第一条评论中所指出的,在控制器的构造函数中,您不应该将服务转换为IUnitOfWork-UnitOfWork这破坏了接口首先提供的抽象。)
| 归档时间: |
|
| 查看次数: |
4890 次 |
| 最近记录: |