34

Я нахожусь в создании пользовательского поставщика членства для веб-сайта ASP.Net MVC. Поставщик создается как отдельный класс как часть большей библиотеки. Существует потребность в том, чтобы хранилище данных было гибким, так как это может быть база данных XML или SQL. Моя первоначальная мысль заключалась в том, чтобы создать интерфейс для хранилища данных и ввести его в провайдер, используя инъекцию зависимостей.Зависимость впрыска и провайдеры членства ASP.Net

Конечным результатом является то, что разработчик может наследовать интерфейс хранилища данных и предоставлять необходимые методы для обновления данных, которые затем будут использоваться сторонними поставщиками членства.

Однако, по собственному недостатку мастерства, я не могу понять, как вводить класс в членский провайдер при добавлении его на сайт? Что нужно сделать, чтобы связать хранилище данных с провайдером? Каким будет самый простой способ включить это на веб-сайте?

+0

Вы знакомы с любыми каркасами инъекций зависимостей? – Restuta

+0

@ Restuta - Нет. Я не ищу рамки. Для этого конкретного требования достаточно простого интерфейса.Разработчики должны иметь возможность создавать собственные собственные серверы, просто наследуя интерфейс. – BinaryMisfit

+1

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

ответ

31

Если вы настраиваете поставщиков пользовательского членства через элемент членства < в файле Web.config, я могу увидеть проблемы, которые могут возникнуть при инъекции зависимостей.

Поставщики создаются и управляются инфраструктурой, и нет возможности перехватить эту конструкцию для обеспечения дополнительной инъекции зависимостей для интерфейса IDataStore.

Если мое предположение верно, то то, что вы можете сделать, это переопределить метод Initialize() в вашем пользовательском поставщике и выполнить там инъекцию зависимости. У вас может быть настраиваемое имя/значение в конфигурации поставщика, которое указывает на тип, который реализует IDataStore, который передается как часть словаря в метод Initialize().

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

public class MyMembershipProvider : MembershipProvider 
{ 
    public IDataStore DataStore 
    { 
     get; 
     set; 
    } 

    public override Initialize(string name, NameValueCollection config) 
    { 
     var dataStoreType = config["dataStoreProvider"]; 
     if (!String.IsNullOrEmpty(dataStoreType)) 
     { 
      var type = Type.GetType(dataStoreType); 
      DataStore = (IDataStore) Activator.CreateInstance(type); 
     } 
    } 
} 

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

Для тестирования сценариев вы просто устанавливаете свойство хранилища данных в самом экземпляре поставщика, так как вы будете строить его непосредственно в своих тестах.

+1

Отлично. Код, который я искал. Спасибо! – BinaryMisfit

+0

Существует исправление, выполненное аналогичным образом: http://bugsquash.blogspot.com.au/2010/11/windsor-managed-membershipproviders.html. Он в основном реализует шаблон оформления Decorator, чтобы обернуть экземпляр, созданный вашим DI контейнер. –

+0

Это больше не работает в .Net 4.6.2 – IronSean

2

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

упрощенный, это будет выглядеть примерно так:

public class DependentClass 
{ 
    private IDataStore _store; 

    // Use this constructor when you want strict control of the implementation 
    public DependentClass(IDataStore store) 
    { 
     this._store = store; 
    } 

    // Use this constructor when you don't want to create an IDataStore instance 
    // manually every time you create a DependentClass instance 
    public DependentClass() : this(new DefaultDataStore()) { } 
} 

Концепция называется «Конструктор цепочки», и есть много статей в Интернете о том, как это сделать. Я нахожу this tutorial очень подробный образец DI.

+0

Спасибо. Я часто использую DI, поэтому мне очень нравится эта часть. Моя проблема специфична для поставщика членства, который настраивается в файле web.config. Решение Сэма решает эту проблему. – BinaryMisfit

+0

@Sleeper: Он говорит, что использует ASP.NET MVC, что означает, что он * можно * разрешить класс через контейнер. Я предлагаю ему это сделать. И, кстати, вам не нужно кричать. –

20

Разве это не лучше? Я использую его с MVC3 и ninject. Достаточно добавить свойство в свой пользовательский класс поставщика членства. Не забудьте добавить «using System.Web.Mvc;» наверху.

public IRepository Repository 
{ 
    get 
    { 
     return DependencyResolver.Current.GetService<IRepository>(); 
    } 
} 
+0

Возможно. Я не смотрел на это некоторое время, и в то время, когда вопрос был задан, он все еще был MVC 1.0 – BinaryMisfit

+1

Это работает для меня. Недостатком является то, что это вариация анти-шаблона «Locator», но иногда вам приходится делать архитектурные компромиссы. (См. Http://stackoverflow.com/questions/22795459/is-servicelocator-anti-pattern.) Я не знаю, должны ли они исправить это в ASP.NET vNext, но, надеюсь. –

Смежные вопросы