Есть ли хороший / правильный способ решения проблемы цикла инъекций зависимостей в учебнике ASP.NET MVC ContactsManager?

Если вы не знаете, о чем я говорю, либо пройдитесь в учебнике, либо попытайтесь добавить зависимость Injection самостоятельно или попробуйте удачу с моим объяснением проблемы.

Примечание. Эта проблема не входит в frameworks исходного руководства по ASP.NET. В учебном пособии только предполагается, что используемые шаблоны являются дружественными к инъекциям.

Проблема в основном состоит в том, что существует цикл зависимостей между controllerом, ModelStateWrapper и ContactManagerService.

  1. Контактор ContactController принимает IContactManagerService.
  2. Конструктор ContactManagerService использует IContactManagerRepository (не важно) и документ IValidationDictionary (который реализует ModelStateWrapper) .
  3. Конструктор ModelStateWrapper принимает ModelStateDictionary (который является свойством, называемым ModelState) на controllerе) .

Таким образом, цикл зависимостей выглядит так: Controller> Service> ModelStateWrapper> Controller

Если вы попытаетесь добавить инъекцию зависимостей к этому, это не удастся. Поэтому мой вопрос: что мне с этим делать? Другие опубликовали этот вопрос, но ответов мало, разные, и все они кажутся «хаки-иш».

Моим текущим решением является удаление IModelStateWrapper из конструктора IService и добавление метода Initialize вместо этого:

public class ContactController : Controller { private readonly IContactService _contactService; public ContactController(IContactService contactService) { _contactService = contactService; contactService.Initialize(new ModelStateWrapper(ModelState)); } //Class implementation... } public class ContactService : IContactService { private IValidationDictionary _validationDictionary; private readonly IContactRepository _contactRepository; public ContactService(IContactRepository contactRepository) { _contactRepository = contactRepository; } private void Initialize(IValidationDictionary validationDictionary) { if(validationDictionary == null) throw new ArgumentNullException("validationDictionary"); _validationDictionary = validationDictionary; } //Class implementation... } public class ModelStateWrapper : IValidationDictionary { private readonly ModelStateDictionary _modelState; public ModelStateWrapper(ModelStateDictionary modelState) { _modelState = modelState; } //Class implementation... } 

С помощью этой конструкции я могу настроить контейнер единства следующим образом:

 public static void ConfigureUnityContainer() { IUnityContainer container = new UnityContainer(); // Registrations container.RegisterTypeInHttpRequestLifetime(); container.RegisterTypeInHttpRequestLifetime(); ControllerBuilder.Current.SetControllerFactory(new UnityControllerFactory(container)); } 

К сожалению, это означает, что метод «Инициализация» в службе должен быть вызван вручную конструктором controllerа. Есть ли способ лучше? Может быть, где-то я включаю IValidationDictionary в мою конфигурацию единства? Должен ли я переключиться на другой контейнер DI? Я что-то упускаю?

    Как общее соображение, круговые зависимости указывают на дефект дизайна – я думаю, что могу смело сказать это, так как вы не являетесь оригинальным автором кода 🙂

    Я бы не считал метод Initialize хорошим решением. Если вы не имеете дело с сценарием надстройки (которого вы не являетесь), метод Injection не является правильным решением. Вы уже почти поняли это, так как вы считаете неудовлетворительным, что вам нужно вручную вызывать его, потому что ваш контейнер DI не может.

    Если я не ошибаюсь, ContactController не нуждается в экземпляре IValidationDictionary до того, как будут вызваны его действия.

    Если это так, самым простым решением, вероятно, будет определение интерфейса IValidationDictionaryFactory и создание конструктора ContactController для экземпляра этого интерфейса.

    Этот интерфейс можно определить следующим образом:

     public interface IValidationDictionaryFactory { IValidationDictionary Create(Controller controller); } 

    Любой метод Action на controllerе, который нуждается в экземпляре IValidationDictionary, может затем вызвать метод Create для получения экземпляра.

    Реализация по умолчанию будет выглядеть примерно так:

     public class DefaultValidationDictionaryFactory : IValidationDictionaryFactory { public IValidationDictionary Create(Controller controller) { return controller.ModelState; } } 

    Как насчет незначительного изменения / улучшения дизайна примерно так: http://forums.asp.net/t/1486130.aspx

    Каждый controller имеет виртуальный метод Инициализировать, чтобы делать такие вещи.

    Я думаю, что нет лучшего способа, потому что IValidationDictionary – это слой абстракции между вами текущего запроса / controllerа / modelstate и IContactService. Моделирование controllerов инъекций в службу, а затем инжектирование службы в controller просто невозможно с помощью встраивания конструктора. Один должен быть первым.

    Может быть, есть способ использования инъекции свойств? Но я думаю, что это тоже будет сложно.

    Interesting Posts

    Выпускать / обновлять IP-адрес через терминал в OS X

    Выполнение вложений и обновлений с помощью Dapper

    Получить подписи экспортируемых функций в DLL

    Установленная оперативная память: 4 ГБ, но 2.96 ГБ. Полезно … почему?

    Как создать прозрачный демонстрационный экран для Android-приложения?

    Как предоставить ASP.NET доступ к закрытому ключу в сертификате в хранилище сертификатов?

    JSON.net сериализуется непосредственно из oledbconnection

    Как сопоставить имя домена с IP-адресом и портом?

    Существует pmin и pmax, каждый из которых принимает na.rm, почему нет psum?

    Какие файлы, типы файлов и папки исключаются из резервной копии папки пользователя?

    Защита исполняемого файла от обратной инженерии?

    JQGrid: Как обновить выпадающий список после редактирования?

    Как закрыть диалог jQuery в диалоговом окне?

    Почему в C # часто появляется «null! = Variable» вместо «variable! = Null»?

    Как конвертировать книги Kindle в формат PDF?

    Давайте будем гением компьютера.