Я думаю, у вас есть пара изменений:.
Разрешить вашему DI-контейнеру внедрить экземпляр UnitOfWork
в ваши классы Service в их конструкторах и полностью исключить его из вашего контроллера.
Если ваш DI-контейнер поддерживает его (например, Ninject), настройте UnitOfWork
для управления по запросу; таким образом, вашим услугам будет вручаться отдельный UnitOfWork
для каждого запроса, и все готово. Или ...
Если ваш DI-контейнер не поддерживает время жизни для каждого запроса, настройте его так, чтобы он управлял UnitOfWork
как одноэлементным, чтобы каждый класс Service
получал один и тот же экземпляр. Затем обновите ваш UnitOfWork
, чтобы сохранить его Entities
объект в хранилище данных, которое хранит объекты для каждого запроса, например, в HttpContext.Current.Items
, как описано здесь .
Редактировать 1
Относительно того, куда следует вводить UnitOfWork
; Я бы сказал, что Сервисный слой - это правильное место. Если вы представляете свою систему как серию уровней, где внешние уровни имеют дело с взаимодействиями с пользователем, а нижние уровни имеют дело с хранением данных, каждый уровень должен меньше заботиться о пользователях и больше заботиться о хранении данных. UnitOfWork
- это концепция одного из уровней «более низкого уровня», а контроллер - из уровня более высокого уровня; ваш слой Service
помещается между ними. Поэтому имеет смысл поместить UnitOfWork
в класс Service
, а не Controller
.
Редактировать 2
Для уточнения создания UnitOfWork
и его отношения к HttpContext.Current.Items
:
Ваш UnitOfWork
больше не будет содержать ссылку на объект Entities
, что будет сделано через объект HttpContext
, введенный в UnitOfWork
за интерфейсом, подобным этому:
public interface IPerRequestDataStore : IDisposable
{
bool Contains(string key);
void Store<T>(string key, T value);
T Get<T>(string key);
}
Объект HttpContext
будет реализовывать IPerRequestDataStore
следующим образом:
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
, поскольку он использует свойство static HttpContext.Current
; это не идеально для модульного тестирования (еще одна тема), но, по крайней мере, название указывает на характер его зависимости.
Ваш UnitOfWork
затем передает IPerRequestDataStore
, который он дал каждому из его Repository
объектов, чтобы они могли получить доступ к Entities
; это означает, что независимо от того, сколько UnitOfWork
экземпляров вы создадите, вы будете использовать один и тот же объект Entities
в запросе, поскольку он сохраняется и извлекается в IPerRequestDataStore
.
.
У вас была бы абстрактная база Repository
, которая использовала бы ее IPerRequestDataStore
для отложенной загрузки Entities
объекта следующим образом:
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
(например) будет выглядеть так:
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
:
IPerRequestDataStore dataStore = new StaticHttpContextDataStore();
UnitOfWork unitOfWork = new UnitOfWork(dataStore);
PeopleService service = new PeopleService(unitOfWork);
PeopleController controller = new PeopleController(service);
Одна из центральных концепций здесь заключается в том, что объектам вводят свои зависимости через своих конструкторов; Это общепринято как хорошая практика, и вам легче составлять объекты из других объектов.