SqlMembershipProvider Memberhip.GetUser by name not working

Memberhip.GetUser problem works fine if I use the GUID, but it fails if I try it without parameters or with the name:

//This works and adds records to aspnet_user & aspnet_Membership tables MembershipUser membershipUser = Membership.CreateUser(_name, _pwd, _email, null, null, true, null, out createStatus); //These fail with an InvalidCastException MembershipUser membershipUser2 = Membership.GetUser(_name, true); MembershipUser membershipUser3 = Membership.GetUser(); //If I go look up the GUID for this user (userId), this works! MembershipUser membershipUser4 = Membership.GetUser(new Guid("E1428CD3-CF17-494E-AB77-CF8F6010F585"), true); 

Other secrets

 //This works Int32 count = Membership.GetNumberOfUsersOnline(); //this fails (but totalRecords has the right value) Int32 totalRecords; MembershipUserCollection col = Membership.GetAllUsers(0,100, out totalRecords); 

Customization

  • MVC
  • .NET 4.0
  • Default Membership Provider (no custom or overrides)

Example:

 <membership defaultProvider="SqlProvider"> <providers> <clear /> <add name="SqlProvider" type="System.Web.Security.SqlMembershipProvider" connectionStringName="MyDB" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" applicationName="myapp" requiresUniqueEmail="false" passwordFormat="Hashed" maxInvalidPasswordAttempts="5" minRequiredPasswordLength="2" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10" passwordStrengthRegularExpression="" /> </providers> </membership> 
  • Standard aspnet_ * database tables without configuration or additional keys
  • aspnet_Membership_GetAllUsers works fine manually from the database. Redirected output shows expected results.
  • aspnet_Membership_GetUserByName also works from the database

Exception Details

 Specified cast is not valid. at System.Data.SqlClient.SqlBuffer.get_SqlGuid() at System.Data.SqlClient.SqlDataReader.GetGuid(Int32 i) at System.Web.Security.SqlMembershipProvider.GetUser(String username, Boolean userIsOnline) at System.Web.Security.Membership.GetUser(String username, Boolean userIsOnline) 

Thoughts

This is almost something wrong inside the Membership.GetUser method. I flipped the System.Web.Security.SqlMembershipProvider.GetUser code for my System.Web.dll (version 4.0) and I get the following:

 public override MembershipUser GetUser(string username, bool userIsOnline) { SecUtility.CheckParameter(ref username, true, false, true, 256, "username"); SqlDataReader reader = (SqlDataReader) null; try { SqlConnectionHolder connectionHolder = (SqlConnectionHolder) null; try { connectionHolder = SqlConnectionHelper.GetConnection(this._sqlConnectionString, true); this.CheckSchemaVersion(connectionHolder.Connection); SqlCommand sqlCommand = new SqlCommand("dbo.aspnet_Membership_GetUserByName", connectionHolder.Connection); sqlCommand.CommandTimeout = this.CommandTimeout; sqlCommand.CommandType = CommandType.StoredProcedure; sqlCommand.Parameters.Add(this.CreateInputParam("@ApplicationName", SqlDbType.NVarChar, (object) this.ApplicationName)); sqlCommand.Parameters.Add(this.CreateInputParam("@UserName", SqlDbType.NVarChar, (object) username)); sqlCommand.Parameters.Add(this.CreateInputParam("@UpdateLastActivity", SqlDbType.Bit, (object) (bool) (userIsOnline ? 1 : 0))); sqlCommand.Parameters.Add(this.CreateInputParam("@CurrentTimeUtc", SqlDbType.DateTime, (object) DateTime.UtcNow)); SqlParameter sqlParameter = new SqlParameter("@ReturnValue", SqlDbType.Int); sqlParameter.Direction = ParameterDirection.ReturnValue; sqlCommand.Parameters.Add(sqlParameter); reader = sqlCommand.ExecuteReader(); if (!reader.Read()) return (MembershipUser) null; string nullableString1 = this.GetNullableString(reader, 0); string nullableString2 = this.GetNullableString(reader, 1); string nullableString3 = this.GetNullableString(reader, 2); bool boolean1 = reader.GetBoolean(3); DateTime creationDate = reader.GetDateTime(4).ToLocalTime(); DateTime lastLoginDate = reader.GetDateTime(5).ToLocalTime(); DateTime lastActivityDate = reader.GetDateTime(6).ToLocalTime(); DateTime lastPasswordChangedDate = reader.GetDateTime(7).ToLocalTime(); Guid guid = reader.GetGuid(8); bool boolean2 = reader.GetBoolean(9); DateTime lastLockoutDate = reader.GetDateTime(10).ToLocalTime(); return new MembershipUser(this.Name, username, (object) guid, nullableString1, nullableString2, nullableString3, boolean1, boolean2, creationDate, lastLoginDate, lastActivityDate, lastPasswordChangedDate, lastLockoutDate); } finally { if (reader != null) reader.Close(); if (connectionHolder != null) connectionHolder.Close(); } } catch { throw; } } 

Next step

I hope to get some direction from the SO crowd, where I should move on. I believe that I can either override this method, or assemble my own provider to debug it, or I could just bypass the damn thing and directly access the database. This seems like a lot of suffering from the base DB CRUD.

Current status

  • 3/5/2013: in the morning, I found that the aspnet_Users table has a UserId as nvarchar(256) instead of a uniqueidentifier . Perhaps SqlDataReader.GetGuid() choking. I'll do some tests tonight to see if this is a problem. I am wondering if my table structure is out of date because the online documentation shows this field as uniqueidentifier .
+6
source share
2 answers

Answer

In my aspnet_User and aspnet_Membership tables, the UserId type nvarchar(256) .

Discussion

It seems that this caused an error in the following line from the SqlMembershipProvider.GetUser method:

 Guid guid = reader.GetGuid(8); 

I ran aspnet_regsql.exe from both .NET frameworks 2 and 4, and both set UserId to a uniqueidentifier, which made me think that I did not (after all) have a standard ASPNET database.

A little digging into the project history shows that this membership database was originally generated using a custom provider for MySql . I can only conclude that it never recovered when we returned to the default provider.

Thank you all for your feedback.

+1
source

Why are you using membership.CurrentUserName() ? You can simply use HttpContext.Current.User.Identity.Name;

+1
source

All Articles