Ответ 1
Думаю, у вас есть пара изменений:
-
Позвольте вашему контейнеру DI вставить экземпляр
UnitOfWork
в свои классы обслуживания в своих конструкторах и полностью исключить его из вашего контроллера. -
Если ваш контейнер 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
, поскольку он использует статическое свойство 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);
Одно из центральных понятий здесь состоит в том, что объекты имеют свои зависимости, вводимые в них через их конструкторы; это общепринято как хорошая практика и более легко позволяет создавать объекты из других объектов.