6

問題 Membership.GetUser は、GUID を使用すると問題なく動作しますが、パラメーターを使用せずに、または名前を使用して試行すると失敗します。

//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 は、DB から手動で正常に実行されます。リダイレクトされた出力は、期待される結果が返されていることを示しています
  • aspnet_Membership_GetUserByName は DB からも機能しています

例外の詳細

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 を直接呼び出すことができると考えています。これは、いくつかの基本的な DB CRUD からの多くの心痛のようです。

現在のステータス

  • 2013 年 3 月 5 日: 今朝、aspnet_Usersテーブルに がUserIdではnvarchar(256)なく としてあることを発見しましたuniqueidentifier。おそらく、SqlDataReader.GetGuid()そこで窒息しているのでしょう。今晩、いくつかのテストを実行して、それが問題かどうかを確認します。オンライン ドキュメントではこのフィールドがuniqueidentifier.
4

2 に答える 2

1

なぜ使うのmembership.CurrentUserName()?あなたはただ使うことができますHttpContext.Current.User.Identity.Name;

于 2013-03-05T19:13:40.593 に答える
1

答え

aspnet_User および aspnet_Membership テーブルUserIdのタイプが に設定されていましたnvarchar(256)

討論

これにより、SqlMembershipProvider.GetUser メソッドの次の行でエラーが発生したようです。

Guid guid = reader.GetGuid(8);

.NET Framework 2 と 4 の両方から aspnet_regsql.exe を実行し、両方とも UserId を uniqueidentifier に設定したため、(結局のところ) 標準の ASPNET DB を持っていないと思いました。

プロジェクトの歴史を少し掘り下げると、このメンバーシップ データベースは、もともとMySqlのカスタム プロバイダーを介して生成されたものであることがわかります。デフォルトのプロバイダーに切り替えたときに再生成されなかったとしか言えません。

フィードバックをお寄せいただきありがとうございます。

于 2013-03-06T00:08:03.390 に答える