Asp.net MVC RouteBase и IoC - PullRequest
       5

Asp.net MVC RouteBase и IoC

1 голос
/ 27 декабря 2010

Я создаю собственный маршрут, создав подкласс RouteBase. У меня есть зависимость, которую я хотел бы подключить к IoC. Метод GetRouteData просто принимает HttpContext, но я также хочу добавить в свою единицу работы .... каким-то образом.

Я использую StructureMap, но информация о том, как вы будете это делать с любой платформой IoC, будет полезна.

Ответы [ 2 ]

4 голосов
/ 28 декабря 2010

Ну, вот наше решение. Многие мелкие детали могут быть опущены, но общая идея здесь. Этот ответ может быть своего рода оффтопом к первоначальному вопросу, но он описывает общее решение проблемы.

Я попытаюсь объяснить ту часть, которая отвечает за простые пользовательские HTML-страницы, которые создаются пользователями во время выполнения и поэтому не могут иметь свой собственный контроллер / действие. Таким образом, маршруты должны быть либо каким-либо образом построены во время выполнения, либо быть «универсальными» с помощью пользовательского IRouteConstraint.

Прежде всего, давайте изложим некоторые факты и требования.

  • У нас есть некоторые данные и некоторые метаданные о наших страницах, хранящиеся в БД;
  • Мы не хотим заранее (гипотетически) создавать целый миллион маршрутов для всех существующих страниц (т. Е. При запуске приложения), потому что что-то может измениться во время приложения, и мы не хотим сталкиваться с продвижением изменений в глобальном масштабе. RouteCollection; * +1010 *

Итак, мы делаем это так:

1. PageController

Да, специальный контроллер, который отвечает за все наши контентные страницы. И есть единственное действие, которое Display(int id) (на самом деле у нас есть специальный ViewModel в качестве параметра, но я использовал int id для простоты.

Страница со всеми данными разрешается по идентификатору внутри этого Display() метода. Сам метод возвращает либо ViewResult (строго типизированный после PageViewModel), либо NotFoundResult в случае, если страница не найдена.

2. Пользовательская IRouteConstraint

Нам нужно где-то определить, ссылается ли фактически запрошенный пользователь URL на одну из наших пользовательских страниц. Для этого у нас есть специальный IsPageConstraint, который реализует интерфейс IRouteConstraint. В методе Match() нашего ограничения мы просто вызываем наш PageRepository, чтобы проверить, существует ли страница, соответствующая нашему запрошенному URL. У нас есть наш PageRepository, добавленный StructureMap. Если мы находим страницу, то добавляем этот параметр «id» (со значением) в словарь RouteData, и он автоматически связывается с PageController.Display(int id) на DefaultModelBinder.

Но для проверки нам нужен параметр RouteData. Где мы это получили? Вот идет ...

3. Отображение маршрута с параметром «поймать все»

Важное примечание: этот маршрут определен в самом конце списка отображений маршрутов, потому что он очень общий, а не конкретный. Сначала мы проверяем все наши явно определенные маршруты, а затем проверяем наличие Page (которое легко изменить при необходимости).

Мы просто наносим на карту наш маршрут так:

routes.MapRoute("ContentPages", 
                "{*pagePath}", 
                new { controller = "Page", action = "Display" }
                new { pagePath = new DependencyRouteConstraint<IsPageConstraint>() });

Стоп! Что это за вещь DependencyRouteConstraint появилась в картографии? Ну, вот что делает трюк.

4. DependencyRouteConstraint класс

Это просто еще одна универсальная реализация IRouteConstraint, которая принимает "real" IRouteConstraint (IsPageConstraint) и разрешает его (данный TConstraint) только при вызове метода Match(). Он использует внедрение зависимостей, поэтому в нашем экземпляре IsPageConstraint вставлены все фактические зависимости!

Наш DependencyRouteConstraint затем просто вызывает dependentConstraint.Match(), предоставляя все параметры, таким образом просто делегируя фактическое "соответствие" "реальному" IRouteConstraint.

Примечание: этот класс фактически зависит от ServiceLocator.

Резюме

Таким образом, у нас есть:

  • Наши Route чистые и чистые;
  • Единственный класс, который зависит от Service Locator, - это DependencyRouteConstraint;
  • Любой пользовательский IRouteConstraint использует внедрение зависимостей при необходимости;
  • ???
  • PROFIT!

Надеюсь, это поможет.

1 голос
/ 27 декабря 2010

Итак, проблема в следующем:

  • Маршрут должен быть определен заранее, во время запуска приложения
  • Маршрут ответственностьсопоставить шаблон входящего URL-адреса с нужным контроллером / действием для выполнения некоторой задачи по запросу.И наоборот - генерировать ссылки с использованием этих картографических данных.Период.Все остальное является нарушением «принципа единой ответственности», которое фактически привело к вашей проблеме.
  • Но UoW зависимости (например, NHibernate ISession или EF ObjectContext) должны быть разрешены во время выполнения.1015 *

    И именно поэтому я не вижу детей класса RouteBase как хорошее место для некоторой зависимости от работы с БД.Это делает все тесно связанным и не масштабируемым.На самом деле невозможно выполнить Dependency Injection.

    С этого момента (я думаю, что есть какая-то уже работающая система), у вас фактически есть только одна более или менее жизнеспособная опция:

    • Чтобы использовать шаблон Service Locator: разрешите свой экземпляр UoW прямо внутри метода GetRouteData (используйте CommonServiceLocator при поддержке StructureMap IContainer).Это простая, но не очень приятная вещь, потому что таким образом вы получаете зависимость от статического Service Locator в вашем Route.

    . С CSL вам нужно просто звонить внутри GetRouteData:

    var uow = ServiceLocator.Current.GetService<IUnitOfWork>();
    

    или только с StructureMap (без CSL-фасада):

    var uow = ObjectFactory.GetInstance<IUnitOfWork>();
    

    и все готово.Быстро и грязно.И ключевое слово «грязный» на самом деле:)

    Конечно, есть гораздо более гибкое решение, но оно требует нескольких архитектурных изменений.Если вы предоставите более подробную информацию о том, какие именно данные вы получаете в своих маршрутах, я могу попытаться объяснить, как мы решили нашу проблему маршрутизации Pages (используя DI и пользовательские IRouteConstraint).

...