【问题标题】:SqlMembershipProvider Membership.GetUser by name failingSqlMembershipProvider Membership.GetUser 按名称失败
【发布时间】:2013-02-19 09:23:39
【问题描述】:

问题 如果我使用 GUID,Membership.GetUser 可以正常工作,但如果我在没有参数或名称的情况下尝试它会失败:

//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);

其他谜题

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

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

设置

  • MVC
  • .NET 4.0
  • 默认 SQL 成员资格提供程序(无自定义或覆盖)

例如:

<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>
  • 标准 aspnet_* 数据库表,没有自定义或额外键
  • aspnet_Membership_GetAllUsers 从数据库手动运行良好。重定向的输出显示正在返回预期结果
  • aspnet_Membership_GetUserByName 在数据库中也能正常工作

异常详情

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)

想法

这几乎就像 Membership.GetUser 方法内部有问题。我为我的 System.Web.dll(4.0 版)反映了 System.Web.Security.SqlMembershipProvider.GetUser 的代码,我得到以下信息:

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;
  }
}

下一步

我希望从 SO 人群中获得一些关于我下一步应该去哪里的方向。我想我可以重写这个方法并将我自己的提供程序放在一起只是为了调试它,或者我可以绕过该死的东西并自己直接调用数据库。这似乎是一些基本的 DB CRUD 造成的心痛。

当前状态

  • 3/5/2013:今天早上我发现我的aspnet_Users 表有UserId 作为nvarchar(256) 而不是uniqueidentifier。也许SqlDataReader.GetGuid() 在那里窒息。今晚我会进行一些测试,看看是否是问题所在。我想知道我的表结构是否已过时,因为在线文档将此字段显示为uniqueidentifier

【问题讨论】:

  • 它是如何失败的?请提供异常详细信息。
  • 添加了异常详情。这条线: System.Data.SqlClient.SqlDataReader.GetGuid(Int32 i) 确实看起来很奇怪。
  • 另外,如果你要“反映”/逆向工程/反编译以了解代码,你应该查看静态成员资格类上的 GetUser() 方法 -- 成员资格.GetUser() - 在那里对当前用户的身份进行假设。 GetUser() 假设它正在检索 Web 应用程序中有关当前用户的详细信息
  • 好主意,我试过了。 Membership 类具有以下代码:return Membership.GetUser(Membership.GetCurrentUserName(), true); 在“立即”窗口中执行以下操作会产生预期的用户名:System.Web.Security.Membership.GetCurrentUserName() //Good result 但是...System.Web.Security.Membership.GetUser( System.Web.Security.Membership.GetCurrentUserName(), true) 似乎仍然返回 InvalidCast。 :(
  • 如果可以的话,请向我们提供堆栈跟踪...特别是无效的演员表详细信息。

标签: c# asp.net-mvc exception-handling sqlmembershipprovider .net


【解决方案1】:

你为什么使用membership.CurrentUserName()?你可以使用HttpContext.Current.User.Identity.Name;

【讨论】:

    【解决方案2】:

    回答

    我的 aspnet_User 和 aspnet_Membership 表将 UserId 设置为 nvarchar(256) 类型。

    讨论

    这似乎导致了 SqlMembershipProvider.GetUser 方法的以下行中的错误:

    Guid guid = reader.GetGuid(8);
    

    我从 .NET 框架 2 和 4 中运行了 aspnet_regsql.exe,并且都将 UserId 设置为唯一标识符,这让我认为我(毕竟)没有标准的 ASPNET DB。

    稍微挖掘一下项目的历史就会发现,这个成员数据库最初是通过 MySql自定义提供程序 生成的。我只能得出结论,当我们切换回默认提供程序时,它从未重新生成。

    感谢大家的反馈。

    【讨论】:

      猜你喜欢
      • 2019-07-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-06-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多