Question

The problem Membership.GetUser works fine if I use the GUID, but 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 Mysteries

//This works
Int32 count = Membership.GetNumberOfUsersOnline();    

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

The Setup

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

ex:

<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 with no customization or extra keys
  • aspnet_Membership_GetAllUsers runs fine manually from the DB. Redirected output shows the expected results are being returned
  • aspnet_Membership_GetUserByName is working as well from the DB

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

It's almost like there's something wrong inside the Membership.GetUser method. I reflected out the code for the System.Web.Security.SqlMembershipProvider.GetUser 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'm hoping to get some direction from the SO crowd on where I should go next. I figure I could either override this method and put together my own provider just to debug it, or I could just go around the darned thing and call out to the DB myself directly. This seems like a lot of heartache from some basic DB CRUD.

Current Status

  • 3/5/2013: I discovered this morning that my aspnet_Users table has the UserId as an nvarchar(256) instead of a uniqueidentifier. Perhaps the SqlDataReader.GetGuid() is choking there. I'll run some tests this evening to see if that's the problem. I'm wondering if my table structure is outdated, because online documentation shows this field as a uniqueidentifier.
Était-ce utile?

La solution 2

Answer

My aspnet_User and aspnet_Membership tables had the UserId set to a type of nvarchar(256).

Discussion

This appears to have been causing the error during 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 the UserId to a uniqueidentifier, leading me to think I did not (after all) have a standard ASPNET DB.

A little digging in the project's history reveals that this membership database was originally generated via a custom provider for MySql. I can only conclude that it was never regenerated when we switched back to the default provider.

Thanks to everyone for their feedback.

Autres conseils

Why do you use membership.CurrentUserName()? You can just use HttpContext.Current.User.Identity.Name;

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top