我应该在哪里创建 ASP.Net MVC 3 应用程序中的工作单元实例? [英] Where should I create the Unit of Work instance in an ASP.Net MVC 3 application?
问题描述
我已经阅读了尽可能多的关于 Stackoverflow 的帖子,其中关于在其中使用工作单元模式一个包含业务层的 ASP.Net MVC 3 应用程序.但是,我仍然有几个问题关于这个主题,非常感谢人们可以给我的任何反馈.
I have read as many of the posts on Stackoverflow as I can find with regards the use of a Unit of Work pattern within an ASP.Net MVC 3 application which includes a Business Layer. However, I still have a couple of questions with regards this topic and would greatly appreciate any feedback people can give me.
我正在开发一个使用 EF 4.1 的 ASP.Net MVC 3 Web 应用程序.我将同时使用存储库和此项目的工作单元模式类似于它们在 这个很棒的教程
I am developing an ASP.Net MVC 3 Web application which uses EF 4.1. I will be using both the Repository and Unit of Work Patterns with this project similar to how they are used in this great tutorial
我的项目的不同之处在于我还需要包含一个业务层(我的解决方案中的单独项目),以便执行应用程序的各种业务规则.上面提到的教程没有业务层,并且因此从控制器创建一个工作单元类的实例
The difference in my project is that I need to also include a Business Layer (separate project in my solution) in order to carry out the various business rules for the application. The tutorial mentioned above does not have a Business layer, and therefore creates an instance of the Unit of Work class from the controller
public class CourseController : Controller
{
private UnitOfWork unitOfWork = new UnitOfWork();
但是,我的问题是,如果我有业务层,我应该在哪里创建工作单元类的实例?
However, my question is, where should I create the instance of the Unit of Work class if I have a Business Layer?
我个人认为它应该在我的控制器中创建,然后像这样注入到业务层:
I personally think it should be created in my controller and then injected into the Business Layer like so:
public class PeopleController : Controller
{
private readonly IUnitOfWork _UoW;
private IPersonService _personService;
public PeopleController()
{
_UoW = new UnitOfWork();
_personService = new PersonService(_UoW);
}
public PeopleController(IUnitOfWork UoW, IPersonService personService)
{
_UoW = UoW;
_personService = personService;
}
public ActionResult Edit(int id)
{
Person person = _personService.Edit(id);
return View(person);
}
public class UnitOfWork : IUnitOfWork, IDisposable
{
private BlogEntities _context = new BlogEntities();
private PersonRepository personRepository = null;
public IPersonRepository PersonRepository
{
get
{
if (this.personRepository == null)
{
this.personRepository = new PersonRepository(_context);
}
return personRepository;
}
}
public void Save()
{
_context.SaveChanges();
}
public class PersonService : IPersonService
{
private readonly IUnitOfWork _UoW;
public PersonService(IUnitOfWork UoW)
{
_UoW = UoW;
}
public Person Edit(int id)
{
Person person = _UoW.PersonRepository.GetPersonByID(id);
return person;
}
public class PersonRepository : IPersonRepository
{
private readonly BlogEntities _context;
public PersonRepository(BlogEntities context)
{
_context = context;
}
public Person GetPersonByID(int ID)
{
return _context.People.Where(p => p.ID == ID).Single();
}
我读过其他人说工作单元实例化不应在控制器中,而应在服务层中创建反而.我对这种方法不太确定的原因是因为我的 Controller 可能不得不使用几种不同的一个业务事务中的服务层,如果工作单元实例是在每个服务中创建的,它将导致多个正在创建工作单元实例,这违背了目的,即每个业务交易一个工作单元.
I have read others saying that the Unit of Work instantiation should not be in the Controller, but created in the Service Layer instead. The reason why I am not so sure about this approach is because my Controller may have to use several different Service Layers in one business transaction, and if the Unit of Work instance was created inside each Service, it would result in several Unit of Work instances being created, which defeats the purpose, ie, one Unit of Work per business transaction.
也许我上面的解释是错误的,但如果是这样,如果有人能纠正我,我将不胜感激.
Maybe what I have explained above is wrong, but if so, I would greatly appreciate if someone could put me right.
再次感谢您的帮助.
推荐答案
我认为您需要进行一些更改:.
I think you have a couple of changes to make:.
允许您的 DI 容器在其构造函数中将
UnitOfWork
实例注入到您的服务类中,并将其完全保留在您的控制器之外.
Allow your DI container to inject a
UnitOfWork
instance into your Service classes in their constructors, and leave it out of your Controller altogether.
如果您的 DI 容器支持(例如,Ninject 支持),请将您的 UnitOfWork
配置为基于每个请求进行管理;这样,您的服务将为每个请求传递一个不同的 UnitOfWork
,然后就大功告成了.或者...
If your DI container supports it (Ninject does, for example), configure your UnitOfWork
to be managed on a per-request basis; this way your services will be handed a distinct UnitOfWork
for each request, and you're all done. Or...
如果您的 DI 容器不支持每个请求的生命周期,请将其配置为将 UnitOfWork
作为单例进行管理,以便每个 Service
类获得相同的实例.然后更新您的 UnitOfWork
以将其 Entities
对象存储在数据存储中,该数据存储基于每个请求存储对象,例如在 HttpContext.Current.Items代码>,如此处所述.
If your DI container does not support per-request lifetimes, configure it to manage the UnitOfWork
as a singleton, so every Service
class gets the same instance. Then update your UnitOfWork
to store its Entities
object in a data store which stores objects on a per-request basis, for example in HttpContext.Current.Items
, as described here.
编辑 1
关于UnitOfWork
应该注入到哪里;我会说服务层是正确的地方.如果您将系统想象为一系列层,其中外层处理用户交互,下层处理数据存储,那么每一层都应该不那么关心用户,而更关心数据存储.UnitOfWork
是来自较低级别"层之一的概念,而 Controller 来自较高级别;您的 Service
层适合它们.因此,将 UnitOfWork
放入 Service
类而不是 Controller
是有意义的.
Regarding where the UnitOfWork
should be injected; I'd say the Service layer is the correct place. If you imagine your system as a series of layers where the outer layers deal with user interactions and the lower layers deal with data storage, each layer should become less concerned with users and more concerned with data storage. UnitOfWork
is a concept from one of the 'lower-level' layers and Controller is from a higher-level layer; your Service
layer fits between them. It therefore makes sense to put the UnitOfWork
into the Service
class rather than the Controller
.
编辑 2
详细说明UnitOfWork
的创建及其与HttpContext.Current.Items
的关系:
To elaborate on the UnitOfWork
creation and it's relationship to HttpContext.Current.Items
:
您的 UnitOfWork
将不再持有对 Entities
对象的引用,这将通过 HttpContext
对象完成,注入到 UnitOfWork
在这样的界面后面:
Your UnitOfWork
would no longer hold a reference to an Entities
object, that would be done through the HttpContext
object, injected into the UnitOfWork
behind an interface like this:
public interface IPerRequestDataStore : IDisposable
{
bool Contains(string key);
void Store<T>(string key, T value);
T Get<T>(string key);
}
HttpContext
对象会像这样实现 IPerRequestDataStore
:
The HttpContext
object would then implement IPerRequestDataStore
like this:
public class StaticHttpContextPerRequestDataStore : IPerRequestDataStore
{
public bool Contains(string key)
{
return HttpContext.Current.Items.Contains(key);
}
public void Store<T>(string key, T value)
{
HttpContext.Current.Items[key] = value;
}
public T Get<T>(string key)
{
if (!this.Contains(key))
{
return default(T);
}
return (T)HttpContext.Current.Items[key];
}
public void Dispose()
{
var disposables = HttpContext.Current.Items.Values.OfType<IDisposable>();
foreach (var disposable in disposables)
{
disposable.Dispose();
}
}
}
顺便说一句,我将其称为 StaticHttpContextPerRequestDataStore
,因为它使用静态 HttpContext.Current
属性;这对于单元测试来说并不理想(完全是另一个主题),但至少名称表明了其依赖项的性质.
As an aside, I've called it StaticHttpContextPerRequestDataStore
as it uses the static HttpContext.Current
property; that's not ideal for unit testing (another topic altogether), but at least the name indicates the nature of its dependency.
您的 UnitOfWork
然后将它赋予的 IPerRequestDataStore
传递给它的每个 Repository
对象,以便他们可以访问 Entities
>;这意味着无论您创建多少个 UnitOfWork
实例,您都将在整个请求中使用相同的 Entities
对象,因为它在 IPerRequestDataStore
中存储和检索代码>.
Your UnitOfWork
then passes the IPerRequestDataStore
it's given to each of its Repository
objects so they can access the Entities
; this means that no matter how many UnitOfWork
instances you create, you'll use the same Entities
object throughout a request because it's stored and retrieved in the IPerRequestDataStore
.
您将有一个抽象的基础 Repository
,它将使用其 IPerRequestDataStore
延迟加载其 Entities
对象,如下所示:
You'd have an abstract base Repository
which would use its IPerRequestDataStore
to lazy-load its Entities
object like this:
public abstract class RepositoryBase : IDisposable
{
private readonly IPerRequestDataStore _dataStore;
private PersonRepository personRepository;
protected RepositoryBase(IPerRequestDataStore dataStore)
{
this._dataStore = dataStore;
}
protected BlogEntities Context
{
get
{
const string contextKey = "context";
if (!this._dataStore.Contains(contextKey))
{
this._dataStore.Store(contextKey, new BlogEntities());
}
return this._dataStore.Get<BlogEntities>(contextKey);
}
}
public void Dispose()
{
this._dataStore.Dispose();
}
}
您的 PeopleRepository
(例如)看起来像这样:
Your PeopleRepository
(for example) would look like this:
public class PeopleRepository : RepositoryBase, IPersonRepository
{
public PeopleRepository(IPerRequestDataStore dataStore)
: base(dataStore)
{
}
public Person FindById(int personId)
{
return this.Context.Persons.FirstOrDefault(p => p.PersonId == personId);
}
}
最后,这是您的 PeopleController
的创建:
And finally, here's the creation of your PeopleController
:
IPerRequestDataStore dataStore = new StaticHttpContextDataStore();
UnitOfWork unitOfWork = new UnitOfWork(dataStore);
PeopleService service = new PeopleService(unitOfWork);
PeopleController controller = new PeopleController(service);
这里的中心概念之一是对象通过它们的构造函数将它们的依赖注入到它们中;这通常被认为是一种很好的做法,并且更容易让您从其他对象组合对象.
One of the central concepts here is that objects have their dependencies injected into them via their constructors; this is generally accepted as good practice, and more easily allows you to compose objects from other objects.
这篇关于我应该在哪里创建 ASP.Net MVC 3 应用程序中的工作单元实例?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!