34

I am in the process of creating a custom membership provider for an ASP.Net MVC website. The provider is being created as a separate class as part of a bigger library. There is a need for the back-end data store to be flexible as it could be an Xml File or SQL database. My initial thought was to create an interface for the data store and inject this into provider using dependency injection.

The end result is required is that a developer can inherit the data store interface and provide the required methods to update the data, which will then be used by the custom membership providers.

However through my own lack of skill I can't figure out how to inject the class into the membership provider when adding it to the website? What needs to be done to link the data store to the provider? What would be the simplest way to enable this in the website?

BinaryMisfit
  • 26,461
  • 2
  • 35
  • 43
  • Do you familiar with any dependency injection frameworks? – Restuta Oct 11 '09 at 19:21
  • @Restuta - No. I am not looking for a framework. A simple interface will be enough for this specific requirement. Developers should be able to create their own back-end stores by simply inheriting the interface. – BinaryMisfit Oct 11 '09 at 19:25
  • 1
    I think framework can save you a lot of time. It will be used for injecting specific realization into you custom Membership provider, this task is most complex, cos you can't control provider initialization. – Restuta Oct 11 '09 at 19:34
  • @Restuta - Fair comment however not what I am looking for. First prize is doing it using the method I have in mind above. I prefer not to be dependant on external frameworks that provide more then what I need. – BinaryMisfit Oct 11 '09 at 19:39

3 Answers3

33

If you are configuring the custom membership providers via the <membership> element in the Web.config file, then I can see the issues you will have with dependency injection.

The providers are constructed and managed by the framework, and there is no opportunity for you to intercept that construction to provide additional dependency injection for the IDataStore interface.

If my assumption is correct, then what you can do is override the Initialize() method in your custom provider, and do the dependency injection there. You can have a custom name/value setting in the provider configuration which points to a type that implements IDataStore, which is passed as part of a dictionary to the Initialize() method.

Then, you activate an instance of the data store type and set it on the appropriate property:

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() will be called by the framework after it constructs an instance of your provider, so that is the perfect place to do any additional setup work such as this.

For testing scenarios, you just set the data store property on the provider instance itself, as you will be constructing it directly in your tests.

Sam
  • 5,907
  • 25
  • 35
  • There is a fix done in a similar way found here: http://bugsquash.blogspot.com.au/2010/11/windsor-managed-membershipproviders.html It basically implements the Decorator Design Pattern to wrap the instance created by your DI container. – Mark Whitfeld Jan 10 '14 at 11:31
20

Isn't this better? I use it with MVC3 and ninject. It's enough to add a property to your custom membership provider class. Remember to add "using System.Web.Mvc;" on top.

public IRepository Repository
{
    get
    {
        return DependencyResolver.Current.GetService<IRepository>();
    }
}
Michal B.
  • 5,497
  • 6
  • 39
  • 65
  • Possibly. I haven't looked at this in a while, and at the time the question was asked it was still MVC 1.0 – BinaryMisfit Dec 04 '11 at 15:37
  • 1
    It works for me. The downside is that it's a variation of the "Service Locator" anti-pattern, but sometimes you have to make architectural compromises. (See http://stackoverflow.com/questions/22795459/is-servicelocator-anti-pattern.) I don't know if they're supposed to fix this in ASP.NET vNext, but hopefully. – Ken Smith Mar 16 '15 at 20:09
2

The simplest way to do dependency injection that I've seen (and actually the only one I've used so far...) is to have a constructor of your dependent class take the interface as a parameter, and assign it to a private field. If you want, you can also add a "default" constructor, which chains to the first one with a default value.

Simplified, it would look something like this:

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()) { }
}

The concept is called "Constructor chaining", and there's a lot of articles on the web on how to do it. I find this tutorial very explanatory of the DI pattern.

Tomas Aschan
  • 53,075
  • 51
  • 214
  • 362
  • Thanks. I use DI quite often so I am pretty comfortable with this part. My problem is specific to the membership provider which gets configured in the web.config. Sam's solution solves this problem. – BinaryMisfit Oct 12 '09 at 08:35
  • @Sleeper: He says he's using ASP.NET MVC, which means that it *is possible* to resolve the class through a container. I suggest that he should. And by the way, you don't have to scream. – Tomas Aschan Mar 09 '11 at 13:38