Shahar Mosek
Shahar Mosek

Reputation: 1982

Programmatically adding a Membership Provider

I have a .Net application that uses an arbitrary number of Membership providers. I will not go into the reasons, but I do not want these to be pre-configured, but I want to create and add them programmatically. Is there anyway to do this? I have no problem creating the providers, but Membership.Providers is readonly, so I can't add them.

Upvotes: 3

Views: 2963

Answers (3)

Shlomi Borovitz
Shlomi Borovitz

Reputation: 1

I know its already irrelevant, but for future readers I'll add my solution for a similar problem.

I've wanted to create provider that would add some functionality upon any other provider (decorator pattern), so I wanted to add the inner provider to the providers collection (for the one above me - it won't work, because if the provider isn't in the providers collection - it won't be able to create users).

I didn't like the reflection solution for two reasons:

The obvious one - it breaks encapsulation.

The second one - the code should run without reflection permissions, otherwise, any piece of code would be able to add provider of its own - so any security would be compromised.

The (simple) solution I've found was to register both providers in the web.config, set the default provider to my provider, and load the second provider in runtime from the providers collection.

For the first question - if you can know which providers you will need before runtime, it would be better to register them in web.config, and maybe change their properties in runtime.

Another solution (that would be still "right", but slow) would be to delegate the security check to a little exe, change it's app.config, run it, and return the result as an output (your provider can do this). DPAPI can provide security for password delivery.

Upvotes: 0

Doug
Doug

Reputation: 5338

Late, late answer, but you can use reflection:

public static class ProviderUtil
{
    static private FieldInfo providerCollectionReadOnlyField;

    static ProviderUtil()
    {
        Type t = typeof(ProviderCollection);
        providerCollectionReadOnlyField = t.GetField("_ReadOnly", BindingFlags.Instance | BindingFlags.NonPublic);
    }

    static public void AddTo(this ProviderBase provider, ProviderCollection pc)
    {
        bool prevValue = (bool)providerCollectionReadOnlyField.GetValue(pc);
        if (prevValue)
            providerCollectionReadOnlyField.SetValue(pc, false);

        pc.Add(provider);

        if (prevValue)
            providerCollectionReadOnlyField.SetValue(pc, true);
    }
}

Then, in your code, you can do something like this:

MyMembershipProvider provider = new MyMembershipProvider();
NameValueCollection config = new NameValueCollection();
// Configure your provider here.  For example,
config["username"] = "myUsername";
config["password"] = "myPassword";
provider.Initialize("MyProvider", config); 

// Add your provider to the membership provider list
provider.AddTo(Membership.Providers);

It's a hack, because we're using reflection to set the "_ReadOnly" private field, but it seems to work.

Here's a great post about this issue: http://elegantcode.com/2008/04/17/testing-a-membership-provider/

Another good post: http://www.endswithsaurus.com/2010/03/inserting-membershipprovider-into.html

Pay special attention to the warnings of using _ReadOnly in those posts, as you'll want to weigh the downsides of manipulating a readonly collection vs. your project requirements and what you're trying to accomplish.

Regards,

-Doug

Upvotes: 6

Lex Li
Lex Li

Reputation: 63264

An easy hack is to create a custom membership provider (as wrapper) first and hook it in web.config. Then you implement this provider to be able to authenticate users against a list of real membership providers.

As the wrapper is owned by you, you are only limited by your imagination.

Upvotes: 1

Related Questions