Проектирование сервисного уровня и репозиториев в Microsoft MVC

#asp.net-mvc #linq #design-patterns #repository

#asp.net-mvc #linq #шаблоны проектирования #репозиторий

Вопрос:

У меня следующая проблема — или, скорее, срочная потребность в ценном совете — с Microsoft MVC. Определенное действие со стороны клиента приводит к созданию:

  • Замечание в таблице Примечания
  • Запись в таблице для часовой регистрации
  • Запись в журнале изменений для заявок

Я использую сервисный уровень для бизнес-действий и репозитории для действий CRUD. Проблема в том, что мне иногда нужно подключать объекты из разных DataContexts, поэтому я полагаю, что использую некорректный дизайн. Недавно мы начали удалять всю бизнес-логику из наших контроллеров и репозиториев, и это одна из первых вещей, с которыми я сталкиваюсь.

Пример:

 BLogic.AddRemarks(Ticket t, ...)
{
  Remark r = _remarksRepository.Create();
  r.Ticket = t;
  _remarksRepository.Add(r);
  _remarksRepository.Save();
}
  

Это запускает kBOOM, поскольку запрос извлекается в контроллере с использованием репозитория. Таким образом, замечание r и запрос t не используют один и тот же контекст данных.

Я могу изменить сигнатуру метода и предоставить int TicketID, но это кажется неправильным. Кроме того, затем я получаю аналогичные проблемы в дальнейшем.

Мои репозитории создаются в конструкторе класса service. Возможно, я должен создать их в начале метода? Даже тогда мне часто приходится передавать идентификаторы вместо истинных объектов.

Ответ №1:

Мое предложение заключается в использовании dependeny injection (или инверсии управления — зависит от того, как бы вы хотели это назвать). Я сам использую castle windor. Действительно простая интеграция с mvc.net . читать дальше

Когда IoC запущен, создайте ContextManager. Что-то вроде этого:

 public class ContextManager : IContextManager
{
    private XContext context;

    public XContext GetContext()
    {
        return context ?? (context = XContext.Create());
    }
}
  

Задайте IContextManager стиль жизни в соответствии с perwebrequest, и вы получите собственный контекст, к которому сможете получить доступ из репозиториев и служб. и это то же самое для одного запроса.

Редактировать

Вам также необходимо создать свой собственный ControllerFactory

затем вы можете использовать свои сервисы и репозитории следующим образом:

 public class MyController : Controller
{
    public ISomeService SomeService { get; set; }
    public IContextManager ContextManager { get; set; }

...

}
  

Вам не нужно создавать новые экземпляры для сервисов и репозиториев, и вы можете управлять образом жизни этих объектов из конфигурации. Наиболее разумным было бы singleton

Комментарии:

1. Термины DI и IoC не взаимозаменяемы и означают две разные вещи. Вы достигаете IoC с помощью DI. Windsor, Unity, Ninject — это фреймворки DI, которые вы используете для инвертирования управления. 😉

2. Итак, в начале действия контроллера я должен инициализировать контекстный менеджер и извлечь из него необходимые объекты? Могу ли я получить доступ к context manager с сервисного уровня без явного указания его там? Или это скорее решение на уровне сервиса, поскольку затем я могу создавать репозитории, используя требуемый datacontext.

3. @Paul используйте конструктор контроллера для включения зависимости ContextManager. Проделайте то же самое с классом service layer. Не создавайте экземпляр ContextManager в вашем методе.

4. Спасибо за ваши ответы! В настоящее время я думаю, что наиболее разумным решением действительно является создание datacontext в контроллере. Оттуда я могу инициализировать сервисный уровень. Сервисный уровень может инициализировать репозитории. Таким образом, вся «цепочка» будет использовать один и тот же datacontext.