IoC / DI с атрибутами MVC - PullRequest
       7

IoC / DI с атрибутами MVC

6 голосов
/ 11 октября 2011

Один из моих атрибутов MVC зависит от службы, которую я надеялся внедрить через конструктор.Очевидно, что для атрибута MVC также требуется конструктор без параметров.

    public MyAttribute()
    {
       ... 
    }

    public MyAttribute(IMyService)
    {
      ...
    }

Я думал, что мог бы делать инъекцию свойств, а не конструктор, однако мои контроллеры (и их атрибуты) находятся в отдельной библиотеке классов без ссылки наконтейнер IoC.

Есть ли способ использования службы в фильтре атрибутов без ссылки на контейнер IoC?

Для чего я использую Ninject for MVC3

Спасибо

Ответы [ 2 ]

10 голосов
/ 11 октября 2011

В качестве общего решения (без какой-либо специальной поддержки интеграции вашей структуры DI), MVC3 запрашивает IDependencyResolver для IFilterProvider.Другими словами, хитрость заключается в следующем:

  1. Удалите FilterAttributeFilterProvider из коллекции System.Web.Mvc.FilterProviders.
  2. Зарегистрируйте IDependencyResolver для вашей конкретной структуры DI (если вы 'это еще не сделано).
  3. Зарегистрируйте пользовательский IFilterProvider в своем контейнере, который может внедрить свойства любого запрошенного атрибута.

Это выглядит так:

var container = new [your favorite container];

// 1. Remove the FilterAttributeFilterProvider from the collection.
var providers = FilterProviders.Providers
    .OfType<FilterAttributeFilterProvider>().ToList();

providers.ForEach(p => FilterProviders.Providers.Remove(p));

// 2. Register a IDependencyResolver
DependencyResolver.SetResolver(new YourDiResolver(container));

// 3. Register a customer IFilterProvider.
container.Register<IFilterProvider, YourAttributeFilterProvider>();

YourAttributeFilterProvider будет выглядеть следующим образом:

private class YourAttributeFilterProvider
    : FilterAttributeFilterProvider
{
    private readonly [your favorite container] container;

    public YourAttributeFilterProvider(
        [your favorite container] container)
        : base(false)
    {
        this.container = container;
    }

    public override IEnumerable<Filter> GetFilters(
        ControllerContext controllerContext, 
        ActionDescriptor actionDescriptor)
    {
        var filters = base.GetFilters(controllerContext,
            actionDescriptor).ToList();

        // Inject properties into attribute here.
        filters.ForEach(f => container.InjectProperties(f.Instance));

        return filters;
    }
}

Многие фреймворки, такие как Ninject и Autofac, имеют встроенную поддержку для этого через свои пакеты интеграции MVC.Тем не менее, важно понять, как сделать это вручную.

ПРЕДУПРЕЖДЕНИЕ:

Одно большое предупреждение о внедрении зависимостей в атрибуты фильтра MVC. MVC кэширует атрибуты и повторно использует экземпляры в течение срока действия домена приложения.Это означает, что они практически становятся синглетонами и увлекают за собой свои зависимости.Другими словами: эти зависимости также станут синглетонами, что также известно как проблема зависимостей в неволе .Поэтому убедитесь, что вы только внедряете синглеты в свои атрибуты, потому что ваша производственная система будет обеспокоена ошибками параллелизма, если вы этого не сделаете.

Хотя большинство платформ DI поддерживают внедрение в атрибуты фильтров, ни одна из платформ не помогает в устранении этой проблемы.Так что лучшим решением будет сохранить ваши атрибуты пассивными, как объяснено здесь и здесь .

1 голос
/ 11 октября 2011

Я пытался добиться того же несколько дней назад. Пожалуйста, прочитайте пост здесь Существует встроенная функциональность для фильтров привязки.

...