views:

2786

answers:

8

Hi There,

I have read through all the related questions, but I still unable to get the right solution for some reason, something is not right on my side, but not sure what's causing it.

I have created a Custom Membership Provider, also changed my web.config to :

   <membership defaultProvider="MyMemberShipProvider">
      <providers>
        <clear />
        <add name="MyMemberShipProvider" 
                  type="MyNameSpace.MyMemberShipProvider" 
                  connectionStringName="ApplicationServices" 
                  enablePasswordRetrieval="false" 
                  enablePasswordReset="true" 
                  requiresQuestionAndAnswer="false" 
                  requiresUniqueEmail="false" 
                  passwordFormat="Hashed" 
                  maxInvalidPasswordAttempts="5" 
                  minRequiredPasswordLength="6" 
                  minRequiredNonalphanumericCharacters="0" 
                  passwordAttemptWindow="10" 
                  passwordStrengthRegularExpression="" 
                  applicationName="MyApplication" />
      </providers>
    </membership>

Here is the code for my Initialize method:

public override void Initialize(string name, NameValueCollection config)
{
    if (config == null)
    { throw new ArgumentNullException("config"); }

    if (string.IsNullOrEmpty(name))
    { name = "MyMemberShipProvider"; }

    if (string.IsNullOrEmpty(config["description"]))
    {
        config.Remove("description");
        config.Add("description", "My Membership Provider");
    }

    base.Initialize(name, config);

    _applicationName = GetConfigValue(config["applicationName"], System.Web.Hosting.HostingEnvironment.ApplicationVirtualPath);
    _maxInvalidPasswordAttempts = Convert.ToInt32(GetConfigValue(config["maxInvalidPasswordAttempts"], "5"));
    _passwordAttemptWindow = Convert.ToInt32(GetConfigValue(config["passwordAttemptWindow"], "10"));
    _minRequiredNonAlphaNumericCharacters = Convert.ToInt32(GetConfigValue(config["minRequiredAlphaNumericCharacters"], "1"));
    _minRequiredPasswordLength = Convert.ToInt32(GetConfigValue(config["minRequiredPasswordLength"], "7"));
    _passwordStregthRegularExpression = Convert.ToString(GetConfigValue(config["passwordStrengthRegularExpression"], String.Empty));
    _enablePasswordReset = Convert.ToBoolean(GetConfigValue(config["enablePasswordReset"], "true"));
    _enablePasswordRetrieval = Convert.ToBoolean(GetConfigValue(config["enablePasswordRetrieval"], "true"));
    _requiredQuestionAndAnswer = Convert.ToBoolean(GetConfigValue(config["requiresQuestionAndAnswer"], "false"));
    _requiredUniqueEmail = Convert.ToBoolean(GetConfigValue(config["requiresUniqueEmail"], "true"));

    string temp_format = config["passwordFormat"];
    if (temp_format == null)
    {
        temp_format = "Hashed";
    }

    switch (temp_format)
    {
        case "Hashed":
            _passwordFormat = MembershipPasswordFormat.Hashed;
            break;
        case "Encrypted":
            _passwordFormat = MembershipPasswordFormat.Encrypted;
            break;
        case "Clear":
            _passwordFormat = MembershipPasswordFormat.Clear;
            break;
        default:
            throw new ProviderException("Password format not supported.");
    }

    ConnectionStringSettings _connectionStringSettings = ConfigurationManager.ConnectionStrings[config["connectionStringName"]];

    if (_connectionStringSettings == null || _connectionStringSettings.ConnectionString.Length == 0)
    {
        throw new ProviderException("Connection String Cannot Be Blank.");
    }

    _connectionString = _connectionStringSettings.ConnectionString;

    //Get Encryption and Decryption Key Information From the Information.

    System.Configuration.Configuration cfg = WebConfigurationManager.OpenWebConfiguration(System.Web.Hosting.HostingEnvironment.ApplicationVirtualPath);
    _machinekey = cfg.GetSection("system.web/machineKey") as MachineKeySection;

    if (_machinekey.ValidationKey.Contains("AutoGenerate"))
    {
        if (PasswordFormat != MembershipPasswordFormat.Clear)
        {
            throw new ProviderException("Hashed or Encrypted passwords are not supported with auto-generated keys.");
        }
    }

}

And I have noticed that the Initialize method was not called, I read through the questions here and the people were saying I do not have to call that manually, if I have wired up my web.config correctly, I don't have to do anything, but I do tried to call that manually, but it gave me an InvalidCastException when I was trying to cast NameValueCollection.

Can anyone help me? Thanks

+1  A: 

It's true your Initialize method should be called automatically so long as your provider is configured correctly (as it seems to be in your code sample).

You'll need to clarify how you 'called it manually', and where you tried to cast NameValueCollection. Did it happen inside Initialize?

Perhaps you should show us your Initialize method (you didn't forget the override keyword, did you? ;-)

Edit: Well, the Initialize method seems fine too.

Keep in mind: Membership is a static class, and it loads and initializes the configured providers in a lazy manner. So the construction of your provider, and the call to its Initialize method, will not occur until a call is made to either the Membership.Provider or the Membership.Providers property. Most of the other static methods (such as GetUser()) will do this, but the conclusion is that your Initialize method will not be called until the Membership API is actually used.

Have you done this, either explicitly or by using a Login control or suchlike?

Tor Haugen
I have put the Initialize code onto my question already, and I do have override keyword on, and it does not fire, not sure why.
PlayKid
You are right, it is static, not a singleton in this case, I'll edit my post. Thanks!
ray247
A: 

Basically the flow goes like this,

Membership class (a static class) calls and uses MembershipProvider (an abstract class derived from ProviderBase) which SqlMembershipProvider implements (in your case MyMemberShipProvider), thus you gave the your implementation of the data accessing code to your data source in MyMemberShipProvider but you don't call the initialize yourself.

The Initialize() is virtual method on ProviderBase, when you create your MyMemberShipProvider you override it like below

class MyMemberShipProvider : MembershipProvider
{
    private string _connectionStringName;

    public override void Initialize(string name, NameValueCollection config)
    {
       // see the config parameter passed in is of type NameValueCollection 
       // it gives you the chance to get the properties in your web.config
       // for example, one of the properties is connectionStringName

        if (config["connectionStringName"] == null)
        {
            config["connectionStringName"] = "ApplicationServices";
        }
        _connectionStringName = config["connectionStringName"];
        config.Remove("connectionStringName");          
    }
}

Without see your code, when you say have an exception that has to do with NameValueCollection, it reminds me of this method above.

Hope this helps, Ray.

ray247
I have included my code on my question, it is similar to yours, but problem is it never fire.
PlayKid
Actually, Membership is not a singleton - it is static.
Tor Haugen
You are right, it is static, not a singleton in this case, I'll edit my post. Thanks!
ray247
A: 

Custom Membership provider is initialized automatically and it is not intended to do so manually.

In my implementation, there is the Initialize metod like below:

public override void Initialize(string name, NameValueCollection config)
{
    if (config == null)
        throw new ArgumentNullException("config");


    // Initialize the abstract base class.
    base.Initialize(name, config);
}

Keep in mind, that the base.Initialize method is in ProviderBase class which has the following exceptions defined:

Exceptions:

  • System.ArgumentNullException: The name of the provider is null.
  • System.ArgumentException: The name of the provider has a length of zero.

  • System.InvalidOperationException: An attempt is made to call System.Configuration.Provider.ProviderBase.Initialize(System.String,System.Collections.Specialized.NameValueCollection) on a provider after the provider has already been initialized.

Isn't the last exception the one you get?

twk
No, the problem is Initialize did not fire, so what I did is I put a method as public MyMembershipProvider() and it work, but I don't think that's the right way to do.
PlayKid
Make sure, you have the following in your web.config:<membership defaultProvider="MyMemberShipProvider">
twk
Make sure, you have the 'type' attribute contains 2 parts:type="MyNameSpace.MyMemberShipProvider, MyNameSpace"where "MyNameSpace" is the dll name of your provider class.
twk
I do have the 'type' attribute and the defaultProvider in the correct syntax, that's why i am not sure why it does not run properly.
PlayKid
A: 

Since the Initialize method isn't called, I guess the next question is whether your provider being instantiated? If you don't already have one, try adding a public parameterless constructor and putting a break-point on it to confirm that it's called.

Dave Cluderay
A: 

If I'm not mistaken, a provider won't be created or initialized until it's actually used. Have you tried using the provider? If so, did that produce an error?

Marnix van Valen
+1  A: 

I am trying to work out what you have done.... I think you have proceeded as follows:

  • Created a custom class called MyMembershipProvider by inheriting from MembershipProvider
  • Configured web.config (looks correct to me)
  • Created a web control that fires an event to do something (e.g. to authenticate a login) Then...
  • Within this event, you have tried to do something like this and wondering why Initialize() isn't called while stepping through your code:

    MyNameSpace.MyMemberShipProvider msp = new MyNameSpace.MyMemberShipProvider();
    bool IsAuthorised = msp.ValidateUser(txtLogin, txtPass);

Solution: - Use this instead:

bool IsAuthorised = Membership.ValidateUser(txtLogin, txtPass);
  • Don't create an instance of your class by yourself, instead let .NET do this for you by using the Membership static class, which ensures that only one instance of MyMemberShipProvider exists throughout the lifetime of the application. If you instantiate your own class and call Initialize(), your code will not be thread safe.
+4  A: 

For Initialize() to be called, you will need to instantiate your custom membership provider a certain way. Like so:

MyCustomMembershipProvider myProvider = (MyCustomMembershipProvider)Membership.Providers["NameOfMembershipProviderInConfig"];

Now when you use myProvider, Initialize() from your custom provider will be called.

LordHits
This should be marked as the answer. Worked for me!
sestocker
+1 as I just ran in to a problem with Custom Membership and this saved me.
Barry
A: 

oThis may sound too easy, but I just went through the exact same thing and realized that I didn't have this:

Region "Structs"

Public Sub New()
End Sub

End Region

As soon as I added it, it went straight in to hit the Initialize Function.

HOpe that helps!

briandus