- PR -

[ASP.NET 2.0] - Membershipuser.ProviderUserKeyが取得できない(Nothingになる)

1
投稿者投稿内容
Youme
会議室デビュー日: 2008/02/26
投稿数: 7
お住まい・勤務地: Lexington, KY
投稿日時: 2008-03-01 04:03
こんにちは。
[現状]
ASP.NET 2.0 にて認証フォームを開発しております。
aspnet_regsql.exe ツールを利用して、メンバシップ データベースを作成し、Loginコントロール、CreateUserWizerdコントロールでユーザの登録、認証を行う処理はうまく実装する事ができております。

構築中のシステムでは、ユーザの登録時にLoginコントロールで登録される情報の他に、ユーザの情報を登録できるようにしたいのです(例えば、電話番号や出身地など)。
これを実現する為に、データベースに以下のようなテーブルを追加しました。

T_Users
--------------------------
UserId [uniqueidentifier]
PhoneNumber [varchar(50)]
Prefecture [varchar(50)]

そして、CreateUserWizardコントロールのCreatedUser イベントに次のコードを記述し、T_Usersテーブルにユーザ情報の登録を試みております。

Protected Sub CreateUserWizard_CreatedUser(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles CreateUserWizard.CreatedUser
If Me.User.Identity.IsAuthenticated Then
Dim memberUser As MembershipUser = Membership.GetUser()
  '--- memberUser.ProviderUserKeyがNothingのため↓ここでエラーになる。
Dim userId As Guid = DirectCast(memberUser.ProviderUserKey, Guid)
Dim phoneNumber As String = txbPhoneNumber.Text.Trim()
Dim Prefecture As String = txbPrefecture.Text.Trim()
SqlDatabase.InsertData(userId, phoneNumber, prefecture)
End If
End Sub

[参考にしたサイト]
MSDN - MembershipUser.ProviderUserKey プロパティ
http://msdn2.microsoft.com/ja-jp/library/system.web.security.membershipuser.provideruserkey.aspx

MSDN - How To: ASP.NET 2.0 でメンバシップを使用する方法
http://www.microsoft.com/japan/msdn/enterprise/pag/securityguidance/paght000022.aspx#paght000022_usingthesqlmembershipprovider

[問題点]
MembershipUser.ProviderUserKey の値がNothing になっており、IDを取得する事ができません。プログラムコードのコメント部
Global.asax のApplication_AuthorizeRequest イベントにも同様のコードを記述しましたが、同じ結果になりました。
その他、aspnet_regsql.exe を実行して作成される aspnet_Users からデータを取得するストアドプロシージャを作成して、コールしてみましたがやはり、Membershipuser.ProviderUserKeyはNothingでした。
個人サイトの情報も参考にさせてもらっているのですが、私のような事例は見つからず、皆さんKeyを取得出来ている様子です。

web.configかMachine.configの設定の問題ではないかな?
とニラんでいるのですが、具体的な解決方法が見つからず困っております。
Keyを取得するために必要な設定、方法等 アドバイス頂けないでしょうか?

また、情報が不足している場合は、ご指導いただければ幸いです。
よろしくお願いいたします。

最後にweb.configのソースも提示しておきます。
接続文字列等、公開できない部分は適当に変更しています。
ご了承ください。

---------------------------------------------------
<?xml version="1.0" encoding="utf-8"?><configuration>
<appSettings/>
<connectionStrings>
<remove name="LocalSqlServer"/>
<add name="LocalSqlServer" connectionString="Data Source=SQLSERVER2005;Initial Catalog=DatabaseName;Integrated Security=True;Pooling=False" providerName="System.Data.SqlClient"/>
</connectionStrings>

<system.web>
<!--
デバッグ シンボルをコンパイルされたページに挿入するに
は、compilation debug="true" に設定します。この設
定はパフォーマンスに影響するため、開発時のみこの値
を true に設定してください。

Visual Basic オプション:
データの損失が発生する可能性のあるすべてのデータ型
の変換を無効にするには、strict="true" に設定します。
すべての変数の定義を強制するためには、explicit="true"
に設定します。
-->
<roleManager enabled="true"/>
<compilation debug="true" strict="false" explicit="true">
<assemblies>
<add assembly="System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/>
<add assembly="System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
<add assembly="System.Configuration, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/>
<add assembly="System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/>
<add assembly="System.Xml, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
<add assembly="System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
<add assembly="System.Web.Services, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/>
<add assembly="System.DirectoryServices, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/>
<add assembly="System.DirectoryServices.Protocols, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/>
<add assembly="System.EnterpriseServices, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/>
<add assembly="System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/>
<add assembly="System.ServiceProcess, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/>
<add assembly="System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
<add assembly="System.Web.RegularExpressions, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/></assemblies></compilation>
<pages>
<namespaces>
<clear/>
<add namespace="System"/>
<add namespace="System.Collections"/>
<add namespace="System.Collections.Specialized"/>
<add namespace="System.Configuration"/>
<add namespace="System.Text"/>
<add namespace="System.Text.RegularExpressions"/>
<add namespace="System.Web"/>
<add namespace="System.Web.Caching"/>
<add namespace="System.Web.SessionState"/>
<add namespace="System.Web.Security"/>
<add namespace="System.Web.Profile"/>
<add namespace="System.Web.UI"/>
<add namespace="System.Web.UI.WebControls"/>
<add namespace="System.Web.UI.WebControls.WebParts"/>
<add namespace="System.Web.UI.HtmlControls"/>
</namespaces>
</pages>
<!--
<authentication> セクションは、ユーザーを識別するため
に、ASP.NET で使用されるセキュリティ認証モードの構成
を有効にします。
-->
<authentication mode="Forms">
<forms loginUrl="/login.aspx" />
</authentication>
<!--

<customErrors> セクションは、要求の実行中にハンドル
されていないエラーが発生した場合の処理方法の構成を
有効にします。具体的には、開発者が HTML エラー ペ
ージをスタック トレースのエラーの代わりに表示するように構
成することを可能にします。

<customErrors mode="RemoteOnly" defaultRedirect="GenericErrorPage.htm">
<error statusCode="403" redirect="NoAccess.htm" />
<error statusCode="404" redirect="FileNotFound.htm" />
</customErrors>
-->
<trace enabled="true" localOnly="true" pageOutput="true"/>
</system.web>
<system.net>
<mailSettings>
<smtp deliveryMethod="Network">
<network host="mailhost" port="25" defaultCredentials="true"/>
</smtp>
</mailSettings>
</system.net>
</configuration>
くまっち
大ベテラン
会議室デビュー日: 2008/01/18
投稿数: 169
お住まい・勤務地: 茨城県のどこか。
投稿日時: 2008-03-01 05:16
質問に対する答えではないのですが・・・

任意の値を追加する場合、通常カスタムメンバシップを実装することになります。
MSDN:カスタム メンバシップ ユーザーの実装

今のままですと、追加した値はMembershipクラスからでは取得できないですし
ここで正しい実装に修正したほうが良いのではないでしょうか。
Youme
会議室デビュー日: 2008/02/26
投稿数: 7
お住まい・勤務地: Lexington, KY
投稿日時: 2008-03-01 07:56
くまっちさん。
ご助言ありがとうございます。

教えて頂いたページを参考に、カスタムメンバシップを作成しました。
これからCreateUserWizard に手を加えるところなのですが、
こちらはちょっと大変そうですね。
MSDNの読み解きたいと思います。

ASP.NET を使った開発は初めてなので、勉強になります。
くまっち
大ベテラン
会議室デビュー日: 2008/01/18
投稿数: 169
お住まい・勤務地: 茨城県のどこか。
投稿日時: 2008-03-01 08:25
その解説ページは、説明&完全なサンプルコードという
初めて触れる場合でも即役立つ、MSDNにしては珍しい(私的印象)ページです。

ざっと確認した程度ですが、必要な情報へのリンクはページ中に全てあると思います。

頑張って乗り越えれば、ユーザーに関する情報は
全てカスタムクラスにて一元管理できるので
ビックなお宝目指して頑張ってください。
どっとねっとふぁん
ぬし
会議室デビュー日: 2005/02/23
投稿数: 935
投稿日時: 2008-03-03 11:55
カスタムメンバーシップを作りこむのが一番すっきりするとは思いますが。
もうちょっと手軽にプロファイルを使う方法でこんなやり方もあります。
http://weblogs.asp.net/scottgu/archive/2005/10/18/427754.aspx

ご参考まで。
Youme
会議室デビュー日: 2008/02/26
投稿数: 7
お住まい・勤務地: Lexington, KY
投稿日時: 2008-03-03 15:31
どっとねっとふぁんさん
こんにちは。ご紹介ありがとうございます。

今日は目を通せなかったのですが、明日拝読させていただきます。
取り急ぎ、お礼を述べさせていただきます。

くまっちさん、どっとねっとふぁんさん から御助言頂いて、
一歩進歩できたことに感謝しております。

タイトルの問題についても、解決したく思っておりますので、
引き続き、ご意見を募りたく思います。
どうぞよろしくお願いいたします。
Youme
会議室デビュー日: 2008/02/26
投稿数: 7
お住まい・勤務地: Lexington, KY
投稿日時: 2008-03-08 08:53
こんにちは。
くまっちさんに教えて頂いたMSDNの記事を参考に、引き続き実装を行っております。
カスタム メンバシップの作成まで終了し、テストを行っているのですが、1点解決できないことがあります。カスタムメンバーシップのソースコードは、

MSDN: 方法 : サンプル メンバシップ プロバイダを実装する
http://msdn2.microsoft.com/ja-jp/library/6tc47t75.aspx
に掲載されているコードをベースにしています。

カスタムメンバーシップユーザーのクラス名は、SqlMembershipUser としています。

問題: GetUserメソッド内で、cmd.ExecuteReader() をコールした時にエラーが発生する
状況: エラーはSqlExeptionでメッセージは 「'?' 付近に不適切な構文があります。」です。 ExecuteReader()でコールされるSQL文は次のようになります。サンプルのコードCompanyIdというint型のデータが加えられています。

SELECT
PKID, Username, Email, PasswordQuestion, Comment, IsApproved, IsLockedOut,
CreationDate, LastLoginDate, LastActivityDate, LastPasswordChangedDate,
LastLockedOutDate, CompanyId
FROM aspnet_Membership
WHERE Username = ? AND ApplicationName = ?"

その後、
cmd.Parameters.Add("@Username", SqlDbType.NVarChar, 255).Value = username
cmd.Parameters.Add("@ApplicationName", SqlDbType.NVarChar, 255).Value = pApplicationName

でパラメータを追加して、接続->Executeの流れになります。
ステップ実行で確認したところ、@Usernameには取得したいユーザの名前が入っているの
が、@ApplicationNameは、Nothing になっていました。

[不明点]
ApplicationName = Nothingが原因で、エラーになっていると思うのですが、AppliationName を正しい値を取得する方法が判明していません。
ProfileManager.ApplicationName で値の取得を試みたのですが、 「/」というデータが入っているのみで、同じくエラーになってしまいます。

最後にカスタムメンバシッププロバイダのソースをアップ致します。

Public Overrides Function GetUser(ByVal username As String, ByVal userIsOnline As Boolean) As MembershipUser
Dim conn As SqlConnection = New SqlConnection(connectionString)
Dim cmd As SqlCommand = New SqlCommand("SELECT PKID, Username, Email, PasswordQuestion," & _
" Comment, IsApproved, IsLockedOut, CreationDate, LastLoginDate," & _
" LastActivityDate, LastPasswordChangedDate, LastLockedOutDate, CompanyId" & _
" FROM aspnet_Membership WHERE Username = ? AND ApplicationName = ?", conn)
cmd.Parameters.Add("@Username", SqlDbType.NVarChar, 255).Value = username
cmd.Parameters.Add("@ApplicationName", SqlDbType.NVarChar, 255).Value = pApplicationName

Dim u As SqlMembershipUser = Nothing
Dim reader As SqlDataReader = Nothing

Try
conn.Open()
'↓ここでエラーが発生します。
reader = cmd.ExecuteReader()

If reader.HasRows Then
reader.Read()
u = GetUserFromReader(reader)

If userIsOnline Then
Dim updateCmd As SqlCommand = New SqlCommand("UPDATE aspnet_Membership " & _
"SET LastActivityDate = ? " & _
"WHERE Username = ? AND Applicationname = ?", conn)

updateCmd.Parameters.Add("@LastActivityDate", SqlDbType.DateTime).Value = DateTime.Now
updateCmd.Parameters.Add("@Username", SqlDbType.NVarChar, 255).Value = username
updateCmd.Parameters.Add("@ApplicationName", SqlDbType.NVarChar, 255).Value = pApplicationName

updateCmd.ExecuteNonQuery()
End If
End If
Catch e As SqlException
If WriteExceptionsToEventLog Then
WriteToEventLog(e, "GetUser(String, Boolean)")

Throw New ProviderException(exceptionMessage)
Else
Throw e
End If
Finally
If Not reader Is Nothing Then reader.Close()

conn.Close()
End Try

Return u
End Function
1

スキルアップ/キャリアアップ(JOB@IT)