チュートリアル: Silverlight ナビゲーション アプリケーションでの認証サービスの使用
このチュートリアルでは、認証サービスを使用するように WCF RIA サービス ソリューションのサーバー プロジェクトとクライアント プロジェクトを設定する方法について説明します。Silverlight ナビゲーション アプリケーション テンプレートを使用してソリューションを作成し、RIA サービス を有効にすると、認証サービスを追加することで ASP.NET メンバーシップ フレームワークにアクセスできます。認証サービスは、サーバー プロジェクトからクライアント プロジェクトに対して認証、ロール、およびプロファイルを公開します。ユーザーの資格情報の検証、ロールに基づいたリソースへのアクセス制限、およびプロファイル プロパティの格納を実行するには、認証サービスを使用します。
注 : |
---|
Silverlight ビジネス アプリケーションでは、認証サービスが自動的に実装されます。詳細については、「チュートリアル: Silverlight ビジネス アプリケーションでの認証サービスの使用」を参照してください。 |
前提条件
このチュートリアル、および RIA サービス のドキュメントで紹介されている他のチュートリアルでは、WCF RIA サービス および WCF RIA サービス Toolkit に加え、Visual Studio 2010 や Silverlight の開発者向けランタイムと SDK など、前提条件となっているいくつかのプログラムが適切にインストールおよび構成されている必要があります。また、SQL Server 2008 R2 Express with Advanced Services をインストールして構成し、AdventureWorks OLTP と LT データベースをインストールすることも必要です。
これらの各前提条件を満たしているかどうかを確認するための詳細な手順については、「WCF RIA Services の前提条件」ノード内のトピックを参照してください。このチュートリアルを進める前に、トピックに記載されている手順に従って、この RIA サービス チュートリアルを実行するときに発生する問題をできるだけ最小限に抑えるようにします。
認証、ロール、およびプロファイル用のサーバー プロジェクトの構成
Silverlight アプリケーションから認証サービスを使用するには、サーバー プロジェクトで認証を構成する必要があります。認証は、Web.config ファイルで構成します。認証を構成した後、ロールおよびプロファイルを Silverlight アプリケーションから使用する場合は、サーバー プロジェクトでこれらの機能も構成することができます。このチュートリアルでは、3 つの機能すべてを構成します。最後に、有効になった機能をクライアントに公開する認証サービスを追加します。
サーバー プロジェクトを構成するには
Visual Studio 2010 で、[ファイル]、[新規作成]、[プロジェクト] の順に選択します。
[新しいプロジェクト] ダイアログ ボックスが表示されます。
プロジェクトの種類に [Silverlight] を選択します。
[Silverlight ナビゲーション アプリケーション] テンプレートをクリックし、アプリケーションに ExampleNavigationApplication という名前を付けます。
[OK] をクリックします。
[新しい Silverlight アプリケーション] ダイアログ ボックスが表示されます。
[Silverlight アプリケーションを新しい Web サイトでホストする] チェック ボックスがオンになっていること、および [新しい Web プロジェクトの種類] が [ASP.NET Web アプリケーション プロジェクト] に設定されていることを確認します。
[WCF RIA サービスを有効にする] チェック ボックスをオンにします。
[OK] をクリックして、ソリューションを作成します。
サーバー プロジェクト (ExampleBusinessApplication.Web) で、Web.config ファイルを開きます。
<system.web>
要素で、<authentication>
要素を追加し、mode
プロパティを Forms に設定します。<authentication mode="Forms"></authentication>
<system.web>
要素で、<roleManager>
要素を追加し、enabled
プロパティを true に設定します。<roleManager enabled="true"></roleManager>
<system.web>
要素で、<profile>
要素を追加し、enabled
プロパティを true に設定して、DefaultRows という名前のprofile
プロパティを含めます。<profile enabled="true"> <properties> <add type="System.Int32" defaultValue="10" name="DefaultRows"/> </properties> </profile>
完成した
<system.web>
要素には、次の要素が含まれています。<system.web> <compilation debug="true" targetFramework="4.0" /> <authentication mode="Forms"></authentication> <roleManager enabled="true"></roleManager> <profile enabled="true"> <properties> <add type="System.Int32" defaultValue="10" name="DefaultRows"/> </properties> </profile> </system.web>
Web.config ファイルを保存します。
ソリューション エクスプローラーで、サーバー プロジェクトを右クリックし、[追加] をポイントして、[新しい項目] をクリックします。
[新しい項目の追加] ダイアログ ボックスが表示されます。
[認証 DomainService] テンプレートをクリックし、AuthenticationDomainService という名前を付けます。
[追加] をクリックします。
認証サービスのコード ファイル (AuthenticationDomainService.cs または AuthenticationDomainService.vb) を開き、Web.config ファイルで定義した DefaultRows プロパティを User クラスに追加します。
<EnableClientAccess()> _ Public Class AuthenticationDomainService Inherits AuthenticationBase(Of User) End Class Public Class User Inherits UserBase Public Property DefaultRows As Integer End Class
[EnableClientAccess] public class AuthenticationDomainService : AuthenticationBase<User> { } public class User : UserBase { public int DefaultRows { get; set; } }
ソリューションをビルドします。
ここでは、ASP.NET Web サイト管理ツールを使用してユーザーおよびロールを作成します。後のセクションでは、このユーザーとしてログインします。
ASP.NET Web サイト管理ツールを使用してユーザーを追加するには
ASP.NET Web サイト管理ツールを開くには、最初にソリューション エクスプローラーでサーバー プロジェクトを選択します。
[プロジェクト] メニューの [ASP.NET 構成] をクリックします。
[プロジェクト] メニューに [ASP.NET 構成] オプションが表示されていない場合は、クライアント プロジェクトを選択している可能性があります。
ASP.NET Web サイト管理ツールの [セキュリティ] タブをクリックします。
[ロール] セクションで、[ロールの作成または管理] リンクをクリックします。
Managers という名前の新しいロールを追加し、[ロールの追加] をクリックします。
右下隅の [戻る] をクリックします。
[ユーザー] セクションで、[ユーザーの作成] リンクをクリックします。
次の値を使用して新しいユーザーを作成し、Managers ロールのチェック ボックスをオンにします。
ユーザー名: CustomerManager
パスワード: P@ssword
電子メール: someone@example.com
秘密の質問: 好きな色は?
秘密の答え: 青
Managers ロール: オン
[ユーザーの作成] をクリックします。
ASP.NET Web サイト管理ツールを閉じます。
認証用のクライアントの構成
サーバー プロジェクトで構成した認証モードと一致する認証モードを使用するように、クライアント プロジェクトを構成する必要があります。
クライアント プロジェクトを構成するには
クライアント プロジェクトで、App.xaml ファイルの分離コード ファイル (App.xaml.cs または App.xaml.vb) を開きます。
コンストラクターで、WebContext クラスの新しいインスタンスを作成します。
Authentication プロパティを FormsAuthentication クラスの新しいインスタンスに設定し、WebContext インスタンスを ApplicationLifetimeObjects に追加します。
Public Sub New() InitializeComponent() Dim webcontext As New WebContext webcontext.Authentication = New System.ServiceModel.DomainServices.Client.ApplicationServices.FormsAuthentication Me.ApplicationLifetimeObjects.Add(webcontext) End Sub
public App() { this.Startup += this.Application_Startup; this.UnhandledException += this.Application_UnhandledException; InitializeComponent(); WebContext webcontext = new WebContext(); webcontext.Authentication = new System.ServiceModel.DomainServices.Client.ApplicationServices.FormsAuthentication(); this.ApplicationLifetimeObjects.Add(webcontext); }
クライアントへのログイン機能の追加
このセクションでは、ユーザーがログイン時にユーザー名とパスワードを指定できるようにする Silverlight コントロールを追加します。ユーザーの資格情報を使用して Login メソッドを呼び出すコードを追加します。また、ユーザーがログインしているかどうかに基づいて表示されるコントロールを設定することもできます。
わかりやすくするために、ログイン ユーザー インターフェイスはチュートリアルのホーム ページに追加されます。アプリケーションでは、別のログイン ページを作成することもできます。
ユーザーのログインおよびログアウトを実行するには
ソリューション エクスプローラーで、クライアント プロジェクトの Views フォルダーを展開します。
Home.xaml ファイルを開きます。
ContentText
という名前の TextBlock の後に、次の XAML を追加します。XAML には、ユーザー名を指定するための TextBox、パスワードを指定するための PasswordBox、ログイン要求を送信するための Button、およびユーザーがログインした後のみに表示される、ログアウト用の TextBlock と HyperlinkButton が含まれています。
<TextBlock x:Name="WelcomeText" Style="{StaticResource ContentTextStyle}" Visibility="Collapsed"></TextBlock> <HyperlinkButton x:Name="LogoutButton" Content="Logout" Click="LogoutButton_Click" Visibility="Collapsed"> </HyperlinkButton> <Border x:Name="LoginBorder" Margin="10,10,0,0" BorderThickness="2" BorderBrush="Black" HorizontalAlignment="Left" CornerRadius="15" Padding="10" Background="BlanchedAlmond" Width="300"> <Grid HorizontalAlignment="Left"> <Grid.RowDefinitions> <RowDefinition></RowDefinition> <RowDefinition Height="30" ></RowDefinition> <RowDefinition Height="30"></RowDefinition> <RowDefinition></RowDefinition> <RowDefinition></RowDefinition> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition></ColumnDefinition> <ColumnDefinition></ColumnDefinition> </Grid.ColumnDefinitions> <TextBlock Grid.Row="0" Grid.ColumnSpan="2" Grid.Column="0" FontWeight="Bold" HorizontalAlignment="Left" VerticalAlignment="Center" Text="Log In Existing User"> </TextBlock> <TextBlock Grid.Row="1" Grid.Column="0" HorizontalAlignment="Right" VerticalAlignment="Center" Text="User Name: "> </TextBlock> <TextBox x:Name="UserName" VerticalAlignment="Center" Grid.Row="1" Grid.Column="1" Width="100"> </TextBox> <TextBlock Grid.Row="2" HorizontalAlignment="Right" Grid.Column="0" VerticalAlignment="Center" Text="Password: "> </TextBlock> <PasswordBox x:Name="Password" VerticalAlignment="Center" Grid.Row="2" Grid.Column="1" Width="100"> </PasswordBox> <TextBlock x:Name="LoginResult" TextWrapping="Wrap" Visibility="Collapsed" Grid.Row="3" Grid.ColumnSpan="2" Foreground="Red"> </TextBlock> <Button x:Name="LoginButton" Margin="0,5,0,0" Grid.Row="4" Grid.Column="1" Content="Log In" Click="LoginButton_Click"> </Button> </Grid> </Border>
ホーム ページの分離コード ファイル (Home.xaml.cs または Home.xaml.vb) を開きます。
System.ServiceModel.DomainServices.Client.ApplicationServices 名前空間の using ステートメントまたは Imports ステートメントを追加します。
次のコードをホーム クラスに追加します。
コードには、ログインとログアウト用のイベント ハンドラー、完了したログイン操作とログアウト操作のコールバック メソッド、およびユーザーが認証されているかどうかに基づいてコントロールを表示するかどうかを設定するメソッドが含まれています。
Protected Overrides Sub OnNavigatedTo(ByVal e As System.Windows.Navigation.NavigationEventArgs) SetControlVisibility(WebContext.Current.User.IsAuthenticated) End Sub Private Sub LoginButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs) Dim lp As LoginParameters = New LoginParameters(UserName.Text, Password.Password) WebContext.Current.Authentication.Login(lp, AddressOf Me.LoginOperation_Completed, Nothing) LoginButton.IsEnabled = False LoginResult.Text = "" End Sub Private Sub LoginOperation_Completed(ByVal lo As LoginOperation) If (lo.HasError) Then LoginResult.Text = lo.Error.Message LoginResult.Visibility = System.Windows.Visibility.Visible lo.MarkErrorAsHandled() ElseIf (lo.LoginSuccess = False) Then LoginResult.Text = "Login failed. Please check user name and password." LoginResult.Visibility = System.Windows.Visibility.Visible ElseIf (lo.LoginSuccess = True) Then SetControlVisibility(True) End If LoginButton.IsEnabled = True End Sub Private Sub SetControlVisibility(ByVal isAuthenticated As Boolean) If (isAuthenticated) Then LoginBorder.Visibility = System.Windows.Visibility.Collapsed WelcomeText.Text = "Welcome " + WebContext.Current.User.Name WelcomeText.Visibility = System.Windows.Visibility.Visible LogoutButton.Visibility = System.Windows.Visibility.Visible Else LoginBorder.Visibility = System.Windows.Visibility.Visible WelcomeText.Visibility = System.Windows.Visibility.Collapsed LogoutButton.Visibility = System.Windows.Visibility.Collapsed End If End Sub Private Sub LogoutButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs) WebContext.Current.Authentication.Logout(AddressOf Me.LogoutOperation_Completed, Nothing) End Sub Private Sub LogoutOperation_Completed(ByVal lo As LogoutOperation) If (Not (lo.HasError)) Then SetControlVisibility(False) Else Dim ew As ErrorWindow = New ErrorWindow("Logout failed.", "Please try logging out again.") ew.Show() lo.MarkErrorAsHandled() End If End Sub
protected override void OnNavigatedTo(NavigationEventArgs e) { SetControlVisibility(WebContext.Current.User.IsAuthenticated); } private void LoginButton_Click(object sender, RoutedEventArgs e) { LoginParameters lp = new LoginParameters(UserName.Text, Password.Password); WebContext.Current.Authentication.Login(lp, this.LoginOperation_Completed, null); LoginButton.IsEnabled = false; LoginResult.Text = ""; } private void LoginOperation_Completed(LoginOperation lo) { if (lo.HasError) { LoginResult.Text = lo.Error.Message; LoginResult.Visibility = System.Windows.Visibility.Visible; lo.MarkErrorAsHandled(); } else if (lo.LoginSuccess == false) { LoginResult.Text = "Login failed. Please check user name and password."; LoginResult.Visibility = System.Windows.Visibility.Visible; } else if (lo.LoginSuccess == true) { SetControlVisibility(true); } LoginButton.IsEnabled = true; } private void SetControlVisibility(bool isAuthenticated) { if (isAuthenticated) { LoginBorder.Visibility = System.Windows.Visibility.Collapsed; WelcomeText.Text = "Welcome " + WebContext.Current.User.Name; WelcomeText.Visibility = System.Windows.Visibility.Visible; LogoutButton.Visibility = System.Windows.Visibility.Visible; } else { LoginBorder.Visibility = System.Windows.Visibility.Visible; WelcomeText.Visibility = System.Windows.Visibility.Collapsed; LogoutButton.Visibility = System.Windows.Visibility.Collapsed; } } private void LogoutButton_Click(object sender, RoutedEventArgs e) { WebContext.Current.Authentication.Logout(this.LogoutOperation_Completed, null); } private void LogoutOperation_Completed(LogoutOperation lo) { if (!lo.HasError) { SetControlVisibility(false); } else { ErrorWindow ew = new ErrorWindow("Logout failed.", "Please try logging out again."); ew.Show(); lo.MarkErrorAsHandled(); } }
ソリューションを実行します。
パスワードに P@ssword を使用して CustomerManager としてログインします。
ログイン領域が表示されなくなり、開始テキストとログアウト リンクが表示されています。
[ログアウト] リンクをクリックし、Web ブラウザーを閉じます。
クライアントからの新しいユーザーの追加
認証サービスには、新しいユーザーを作成する操作が含まれていません。新しいユーザーを登録するには、空のドメイン サービスを作成し、ASP.NET メンバーシップ フレームワークにユーザーを追加するための操作を追加します。
新しいユーザーを追加するためにサーバー プロジェクトを構成するには
サーバー プロジェクトに、NewUser という名前の新しいクラス ファイルを追加します。
NewUser クラスに次のコードを追加して、新しいユーザーを登録するためのプロパティを定義します。
Imports System.ComponentModel.DataAnnotations Public Class NewUser <Key()> _ <Required()> _ <RegularExpression("^[a-zA-Z0-9_]*$", ErrorMessage:="Invalid user name. It must contain only alphanumeric characters")> _ Public Property UserName As String <Key()> _ <Required()> _ <RegularExpression("^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$", ErrorMessage:="Invalid email. An email must use the format username@mycompany.com")> _ Public Property Email As String <Required()> _ <RegularExpression("^.*[^a-zA-Z0-9].*$", ErrorMessage:="A password needs to contain at least one special character e.g. @ or #")> _ <StringLength(50, MinimumLength:=7, ErrorMessage:="Invalid password. It must be contain at least 7 characters and no more than 50 characters.")> _ Public Property Password As String <Required()> _ <CustomValidation(GetType(RegistrationValidator), "IsPasswordConfirmed")> _ Public Property ConfirmPassword As String <Range(1, 20)> _ Public Property RecordsToShow As Integer <Required()> _ Public Property SecurityQuestion As String <Required()> _ Public Property SecurityAnswer As String End Class
using System; using System.ComponentModel.DataAnnotations; namespace ExampleNavigationApplication.Web { public class NewUser { [Key] [Required()] [RegularExpression("^[a-zA-Z0-9_]*$", ErrorMessage="Invalid user name. It must contain only alphanumeric characters")] public string UserName { get; set; } [Key] [Required()] [RegularExpression(@"^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$", ErrorMessage="Invalid email. An email must use the format username@mycompany.com")] public string Email { get; set; } [Required()] [RegularExpression("^.*[^a-zA-Z0-9].*$", ErrorMessage="A password needs to contain at least one special character e.g. @ or #")] [StringLength(50, MinimumLength = 7, ErrorMessage="Invalid password. It must be contain at least 7 characters and no more than 50 characters.")] public string Password { get; set; } [Required()] [CustomValidation(typeof(RegistrationValidator), "IsPasswordConfirmed")] public string ConfirmPassword { get; set; } [Range(1, 20)] public int RecordsToShow { get; set; } [Required()] public string SecurityQuestion { get; set; } [Required()] public string SecurityAnswer { get; set; } } }
前の手順の ConfirmPassword プロパティは、CustomValidationAttribute 属性を使用して定義されています。この属性で、RegistrationValidator クラスと、IsPasswordConfirmed という名前のメソッドを指定します。ここで、このカスタム検証クラスを定義する必要があります。
RegistrationValidator.shared.cs または RegistrationValidator.shared.vb という名前の新しいクラスを追加します。
RegistrationValidator.shared ファイルに次のコードを追加します。
Imports System.ComponentModel.DataAnnotations Public Class RegistrationValidator Public Shared Function IsPasswordConfirmed(ByVal confirmPassword As String, ByVal context As ValidationContext) As ValidationResult Dim data As Web.NewUser = CType(context.ObjectInstance, Web.NewUser) If (data.Password = confirmPassword) Then Return ValidationResult.Success Else Return New ValidationResult("Please confirm your password by providing it again.") End If End Function End Class
using System.ComponentModel.DataAnnotations; namespace ExampleNavigationApplication.Web { public class RegistrationValidator { public static ValidationResult IsPasswordConfirmed(string confirmPassword, ValidationContext context) { NewUser data = (NewUser)context.ObjectInstance; if (data.Password == confirmPassword) { return ValidationResult.Success; } else { return new ValidationResult("Please confirm your password by providing it again."); } } } }
サーバー プロジェクトに新しい項目を追加し、[DomainService クラス] テンプレートをクリックします。
ファイルに RegistrationDomainService.cs または RegistrationDomainService.vb という名前を付け、[追加] をクリックします。
[新しいドメイン サービス クラスの追加] ダイアログ ボックスで、[使用できる DataContext/ObjectContext クラス] ボックスの一覧の [<空のドメイン サービス クラス>] を選択します。
[OK] をクリックします。
メンバーシップ フレームワークを使用して新しいユーザーを追加し、プロファイル プロパティを保存するドメイン操作を作成するには、RegistrationDomainService クラスに次のコードを追加します。
クライアント プロジェクトに対して NewUser エンティティ クラスが生成されるように、GetUsers メソッドを含める必要があります。パブリック クエリ操作を通じて公開されるクラスのみがクライアント プロジェクトに生成されます。
ユーザーを作成すると、DefaultRows という名前のプロファイル プロパティが設定されます。この場合、プロファイル プロパティは、ユーザーを作成するためのドメイン操作の一環として設定されます。後のセクションで、クライアント プロジェクトからプロファイル プロパティを設定するコードを追加します。
Option Compare Binary Option Infer On Option Strict On Option Explicit On Imports System Imports System.Collections.Generic Imports System.ComponentModel Imports System.ComponentModel.DataAnnotations Imports System.Linq Imports System.ServiceModel.DomainServices.Hosting Imports System.ServiceModel.DomainServices.Server Imports System.Web.Profile <EnableClientAccess()> _ Public Class RegistrationDomainService Inherits DomainService Public Sub AddUser(ByVal user As NewUser) Dim createStatus As MembershipCreateStatus Membership.CreateUser(user.UserName, user.Password, user.Email, user.SecurityQuestion, user.SecurityAnswer, True, Nothing, createStatus) If (createStatus <> MembershipCreateStatus.Success) Then Throw New DomainException(createStatus.ToString()) End If Dim profile = ProfileBase.Create(user.UserName, True) profile.SetPropertyValue("DefaultRows", user.RecordsToShow) profile.Save() End Sub Public Function GetUsers() As IEnumerable(Of NewUser) Throw New NotSupportedException() End Function End Class
namespace ExampleNavigationApplication.Web { using System; using System.Collections.Generic; using System.ServiceModel.DomainServices.Hosting; using System.ServiceModel.DomainServices.Server; using System.Web.Security; using System.Web.Profile; [EnableClientAccess()] public class RegistrationDomainService : DomainService { public void AddUser(NewUser user) { MembershipCreateStatus createStatus; Membership.CreateUser(user.UserName, user.Password, user.Email, user.SecurityQuestion, user.SecurityAnswer, true, null, out createStatus); if (createStatus != MembershipCreateStatus.Success) { throw new DomainException(createStatus.ToString()); } ProfileBase profile = ProfileBase.Create(user.UserName, true); profile.SetPropertyValue("DefaultRows", user.RecordsToShow); profile.Save(); } public IEnumerable<NewUser> GetUsers() { throw new NotSupportedException(); } } }
新しいユーザーを追加するためにクライアント プロジェクトを構成するには
Home.xaml ファイルを開きます。
LoginBorder
Border コントロールの終了タグの後に、次の XAML を追加して、新しいユーザーを作成するための情報を収集する入力コントロールを含むもう 1 つの Border コントロールを作成します。このコントロールでは、ユーザー名、パスワード、パスワードの確認、電子メール アドレス、秘密の質問、秘密の答え、およびレポートに表示するレコード数の各値をそのまま使用します。表示するレコードの数は、プロファイル プロパティとして保存されます。その他すべての値は、ASP.NET メンバーシップ フレームワークを通じてユーザーを作成する際に使用されます。
<Border x:Name="RegisterBorder" Margin="10,10,0,0" BorderThickness="2" BorderBrush="Black" HorizontalAlignment="Left" CornerRadius="15" Padding="10" Background="BurlyWood" Width="400"> <Grid HorizontalAlignment="Left"> <Grid.RowDefinitions> <RowDefinition></RowDefinition> <RowDefinition Height="30" ></RowDefinition> <RowDefinition Height="30"></RowDefinition> <RowDefinition Height="30"></RowDefinition> <RowDefinition Height="30"></RowDefinition> <RowDefinition Height="30"></RowDefinition> <RowDefinition Height="30"></RowDefinition> <RowDefinition Height="30"></RowDefinition> <RowDefinition></RowDefinition> <RowDefinition></RowDefinition> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition></ColumnDefinition> <ColumnDefinition></ColumnDefinition> </Grid.ColumnDefinitions> <TextBlock Grid.Row="0" Grid.ColumnSpan="2" Grid.Column="0" FontWeight="Bold" HorizontalAlignment="Left" VerticalAlignment="Center" Text="Register New User"> </TextBlock> <TextBlock Grid.Row="1" Grid.Column="0" HorizontalAlignment="Right" VerticalAlignment="Center" Text="User Name: "> </TextBlock> <TextBox x:Name="NewUsername" VerticalAlignment="Center" HorizontalAlignment="Left" Grid.Row="1" Grid.Column="1" Width="100"> </TextBox> <TextBlock Grid.Row="2" HorizontalAlignment="Right" Grid.Column="0" VerticalAlignment="Center" Text="Password: "> </TextBlock> <PasswordBox x:Name="NewPassword" VerticalAlignment="Center" HorizontalAlignment="Left" Grid.Row="2" Grid.Column="1" Width="100"> </PasswordBox> <TextBlock Grid.Row="3" HorizontalAlignment="Right" Grid.Column="0" VerticalAlignment="Center" Text="Confirm Password: "> </TextBlock> <PasswordBox x:Name="NewConfirmPassword" HorizontalAlignment="Left" VerticalAlignment="Center" Grid.Row="3" Grid.Column="1" Width="100"> </PasswordBox> <TextBlock Grid.Row="4" HorizontalAlignment="Right" Grid.Column="0" VerticalAlignment="Center" Text="Email: "> </TextBlock> <TextBox x:Name="NewEmail" VerticalAlignment="Center" Grid.Row="4" Grid.Column="1" Width="200"> </TextBox> <TextBlock Grid.Row="5" HorizontalAlignment="Right" Grid.Column="0" VerticalAlignment="Center" Text="Records to show: "> </TextBlock> <ComboBox Grid.Row="5" Grid.Column="1" x:Name="DefaultRows" HorizontalAlignment="Left" Width="50" Height="20" VerticalAlignment="Center"> <ComboBoxItem Content="1"></ComboBoxItem> <ComboBoxItem Content="3"></ComboBoxItem> <ComboBoxItem Content="5"></ComboBoxItem> <ComboBoxItem Content="10" IsSelected="True"></ComboBoxItem> <ComboBoxItem Content="15"></ComboBoxItem> <ComboBoxItem Content="20"></ComboBoxItem> </ComboBox> <TextBlock Grid.Row="6" HorizontalAlignment="Right" Grid.Column="0" VerticalAlignment="Center" Text="Security Question: "> </TextBlock> <TextBox x:Name="SecurityQuestion" VerticalAlignment="Center" Grid.Row="6" Grid.Column="1" Width="200"> </TextBox> <TextBlock Grid.Row="7" HorizontalAlignment="Right" Grid.Column="0" VerticalAlignment="Center" Text="Security Answer: "> </TextBlock> <TextBox x:Name="SecurityAnswer" VerticalAlignment="Center" Grid.Row="7" Grid.Column="1" Width="200"> </TextBox> <TextBlock x:Name="registerResult" TextWrapping="Wrap" Visibility="Collapsed" Grid.Row="8" Grid.ColumnSpan="2" Foreground="Red"> </TextBlock> <Button x:Name="RegisterButton" Click="RegisterButton_Click" Margin="0,5,0,0" Grid.Row="9" Grid.Column="1" Content="Register" > </Button> </Grid> </Border>
Home.xaml.cs (または Home.xaml.vb) 分離コード ファイルを開きます。
System.ServiceModel.DomainServices.Client、System.ComponentModel.DataAnnotations、および ExampleNavigationApplication.Web の各名前空間の using ステートメントまたは Imports ステートメントを追加します。
登録ボタン クリック イベントのイベント ハンドラーを追加し、ドメイン操作のコールバック メソッドを追加します。コールバック メソッドには、ユーザー アカウントの作成に成功した後にユーザーをログインするためのコードが含まれています。
Private Sub RegisterButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs) RegisterButton.IsEnabled = False Dim context = New RegistrationDomainContext() Dim nu = New NewUser() Try nu.UserName = NewUsername.Text nu.Password = NewPassword.Password nu.Email = NewEmail.Text nu.ConfirmPassword = NewConfirmPassword.Password nu.RecordsToShow = Integer.Parse(DefaultRows.SelectionBoxItem.ToString()) nu.SecurityQuestion = SecurityQuestion.Text nu.SecurityAnswer = SecurityAnswer.Text context.NewUsers.Add(nu) context.SubmitChanges(AddressOf RegisterUser_Completed, Nothing) Catch ve As ValidationException registerResult.Visibility = System.Windows.Visibility.Visible registerResult.Text = ve.Message RegisterButton.IsEnabled = True End Try End Sub Private Sub RegisterUser_Completed(ByVal so As SubmitOperation) If (so.HasError) Then Dim ew = New ErrorWindow("Registration failed.", "Please try registering again.") ew.Show() so.MarkErrorAsHandled() Else Dim lp = New LoginParameters(NewUsername.Text, NewPassword.Password) WebContext.Current.Authentication.Login(lp, AddressOf Me.LoginOperation_Completed, Nothing) NewUsername.Text = "" NewPassword.Password = "" NewConfirmPassword.Password = "" NewEmail.Text = "" DefaultRows.SelectedIndex = 0 SecurityQuestion.Text = "" SecurityAnswer.Text = "" End If RegisterButton.IsEnabled = True End Sub
private void RegisterButton_Click(object sender, RoutedEventArgs e) { RegisterButton.IsEnabled = false; RegistrationDomainContext context = new RegistrationDomainContext(); NewUser nu = new NewUser(); try { nu.UserName = NewUsername.Text; nu.Password = NewPassword.Password; nu.Email = NewEmail.Text; nu.ConfirmPassword = NewConfirmPassword.Password; nu.RecordsToShow = int.Parse(DefaultRows.SelectionBoxItem.ToString()); nu.SecurityQuestion = SecurityQuestion.Text; nu.SecurityAnswer = SecurityAnswer.Text; context.NewUsers.Add(nu); context.SubmitChanges(RegisterUser_Completed, null); } catch (ValidationException ve) { registerResult.Visibility = System.Windows.Visibility.Visible; registerResult.Text = ve.Message; RegisterButton.IsEnabled = true; } } private void RegisterUser_Completed(SubmitOperation so) { if (so.HasError) { ErrorWindow ew = new ErrorWindow("Registration failed.", "Please try registering again."); ew.Show(); so.MarkErrorAsHandled(); } else { LoginParameters lp = new LoginParameters(NewUsername.Text, NewPassword.Password); WebContext.Current.Authentication.Login(lp, this.LoginOperation_Completed, null); NewUsername.Text = ""; NewPassword.Password = ""; NewConfirmPassword.Password = ""; NewEmail.Text = ""; DefaultRows.SelectedIndex = 0; SecurityQuestion.Text = ""; SecurityAnswer.Text = ""; } RegisterButton.IsEnabled = true; }
次のコードに示すように、RegisterBorder の可視性を設定するように SetControlVisibility メソッドを変更します。
Private Sub SetControlVisibility(ByVal isAuthenticated As Boolean) If (isAuthenticated) Then LoginBorder.Visibility = System.Windows.Visibility.Collapsed RegisterBorder.Visibility = Windows.Visibility.Collapsed WelcomeText.Text = "Welcome " + WebContext.Current.User.Name WelcomeText.Visibility = System.Windows.Visibility.Visible LogoutButton.Visibility = System.Windows.Visibility.Visible Else LoginBorder.Visibility = System.Windows.Visibility.Visible RegisterBorder.Visibility = Windows.Visibility.Visible WelcomeText.Visibility = System.Windows.Visibility.Collapsed LogoutButton.Visibility = System.Windows.Visibility.Collapsed End If End Sub
private void SetControlVisibility(bool isAuthenticated) { if (isAuthenticated) { LoginBorder.Visibility = System.Windows.Visibility.Collapsed; RegisterBorder.Visibility = System.Windows.Visibility.Collapsed; WelcomeText.Text = "Welcome " + WebContext.Current.User.Name; WelcomeText.Visibility = System.Windows.Visibility.Visible; LogoutButton.Visibility = System.Windows.Visibility.Visible; } else { LoginBorder.Visibility = System.Windows.Visibility.Visible; RegisterBorder.Visibility = System.Windows.Visibility.Visible; WelcomeText.Visibility = System.Windows.Visibility.Collapsed; LogoutButton.Visibility = System.Windows.Visibility.Collapsed; } }
完全な分離コード ファイルを次に示します。
Imports System.ServiceModel.DomainServices.Client.ApplicationServices Imports System.ServiceModel.DomainServices.Client Imports System.ComponentModel.DataAnnotations Partial Public Class Home Inherits Page Public Sub New() InitializeComponent() End Sub Protected Overrides Sub OnNavigatedTo(ByVal e As System.Windows.Navigation.NavigationEventArgs) SetControlVisibility(WebContext.Current.User.IsAuthenticated) End Sub Private Sub LoginButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs) Dim lp As LoginParameters = New LoginParameters(UserName.Text, Password.Password) WebContext.Current.Authentication.Login(lp, AddressOf Me.LoginOperation_Completed, Nothing) LoginButton.IsEnabled = False LoginResult.Text = "" End Sub Private Sub LoginOperation_Completed(ByVal lo As LoginOperation) If (lo.HasError) Then LoginResult.Text = lo.Error.Message LoginResult.Visibility = System.Windows.Visibility.Visible lo.MarkErrorAsHandled() ElseIf (lo.LoginSuccess = False) Then LoginResult.Text = "Login failed. Please check user name and password." LoginResult.Visibility = System.Windows.Visibility.Visible ElseIf (lo.LoginSuccess = True) Then SetControlVisibility(True) End If LoginButton.IsEnabled = True End Sub Private Sub SetControlVisibility(ByVal isAuthenticated As Boolean) If (isAuthenticated) Then LoginBorder.Visibility = System.Windows.Visibility.Collapsed RegisterBorder.Visibility = Windows.Visibility.Collapsed WelcomeText.Text = "Welcome " + WebContext.Current.User.Name WelcomeText.Visibility = System.Windows.Visibility.Visible LogoutButton.Visibility = System.Windows.Visibility.Visible Else LoginBorder.Visibility = System.Windows.Visibility.Visible RegisterBorder.Visibility = Windows.Visibility.Visible WelcomeText.Visibility = System.Windows.Visibility.Collapsed LogoutButton.Visibility = System.Windows.Visibility.Collapsed End If End Sub Private Sub LogoutButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs) WebContext.Current.Authentication.Logout(AddressOf Me.LogoutOperation_Completed, Nothing) End Sub Private Sub LogoutOperation_Completed(ByVal lo As LogoutOperation) If (Not (lo.HasError)) Then SetControlVisibility(False) Else Dim ew As ErrorWindow = New ErrorWindow("Logout failed.", "Please try logging out again.") ew.Show() lo.MarkErrorAsHandled() End If End Sub Private Sub RegisterButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs) RegisterButton.IsEnabled = False Dim context = New RegistrationDomainContext() Dim nu = New NewUser() Try nu.UserName = NewUsername.Text nu.Password = NewPassword.Password nu.Email = NewEmail.Text nu.ConfirmPassword = NewConfirmPassword.Password nu.RecordsToShow = Integer.Parse(DefaultRows.SelectionBoxItem.ToString()) nu.SecurityQuestion = SecurityQuestion.Text nu.SecurityAnswer = SecurityAnswer.Text context.NewUsers.Add(nu) context.SubmitChanges(AddressOf RegisterUser_Completed, Nothing) Catch ve As ValidationException registerResult.Visibility = System.Windows.Visibility.Visible registerResult.Text = ve.Message RegisterButton.IsEnabled = True End Try End Sub Private Sub RegisterUser_Completed(ByVal so As SubmitOperation) If (so.HasError) Then Dim ew = New ErrorWindow("Registration failed.", "Please try registering again.") ew.Show() so.MarkErrorAsHandled() Else Dim lp = New LoginParameters(NewUsername.Text, NewPassword.Password) WebContext.Current.Authentication.Login(lp, AddressOf Me.LoginOperation_Completed, Nothing) NewUsername.Text = "" NewPassword.Password = "" NewConfirmPassword.Password = "" NewEmail.Text = "" DefaultRows.SelectedIndex = 0 SecurityQuestion.Text = "" SecurityAnswer.Text = "" End If RegisterButton.IsEnabled = True End Sub End Class
using System; using System.Windows; using System.Windows.Controls; using System.Windows.Navigation; using System.ServiceModel.DomainServices.Client.ApplicationServices; using System.ServiceModel.DomainServices.Client; using System.ComponentModel.DataAnnotations; using ExampleNavigationApplication.Web; namespace ExampleNavigationApplication { public partial class Home : Page { public Home() { InitializeComponent(); } // Executes when the user navigates to this page. protected override void OnNavigatedTo(NavigationEventArgs e) { SetControlVisibility(WebContext.Current.User.IsAuthenticated); } private void LoginButton_Click(object sender, RoutedEventArgs e) { LoginParameters lp = new LoginParameters(UserName.Text, Password.Password); WebContext.Current.Authentication.Login(lp, this.LoginOperation_Completed, null); LoginButton.IsEnabled = false; LoginResult.Text = ""; } private void LoginOperation_Completed(LoginOperation lo) { if (lo.HasError) { LoginResult.Text = lo.Error.Message; LoginResult.Visibility = System.Windows.Visibility.Visible; lo.MarkErrorAsHandled(); } else if (lo.LoginSuccess == false) { LoginResult.Text = "Login failed. Please check user name and password."; LoginResult.Visibility = System.Windows.Visibility.Visible; } else if (lo.LoginSuccess == true) { SetControlVisibility(true); } LoginButton.IsEnabled = true; } private void SetControlVisibility(bool isAuthenticated) { if (isAuthenticated) { LoginBorder.Visibility = System.Windows.Visibility.Collapsed; RegisterBorder.Visibility = System.Windows.Visibility.Collapsed; WelcomeText.Text = "Welcome " + WebContext.Current.User.Name; WelcomeText.Visibility = System.Windows.Visibility.Visible; LogoutButton.Visibility = System.Windows.Visibility.Visible; } else { LoginBorder.Visibility = System.Windows.Visibility.Visible; RegisterBorder.Visibility = System.Windows.Visibility.Visible; WelcomeText.Visibility = System.Windows.Visibility.Collapsed; LogoutButton.Visibility = System.Windows.Visibility.Collapsed; } } private void LogoutButton_Click(object sender, RoutedEventArgs e) { WebContext.Current.Authentication.Logout(this.LogoutOperation_Completed, null); } private void LogoutOperation_Completed(LogoutOperation lo) { if (!lo.HasError) { SetControlVisibility(false); } else { ErrorWindow ew = new ErrorWindow("Logout failed.", "Please try logging out again."); ew.Show(); lo.MarkErrorAsHandled(); } } private void RegisterButton_Click(object sender, RoutedEventArgs e) { RegisterButton.IsEnabled = false; RegistrationDomainContext context = new RegistrationDomainContext(); NewUser nu = new NewUser(); try { nu.UserName = NewUsername.Text; nu.Password = NewPassword.Password; nu.Email = NewEmail.Text; nu.ConfirmPassword = NewConfirmPassword.Password; nu.RecordsToShow = int.Parse(DefaultRows.SelectionBoxItem.ToString()); nu.SecurityQuestion = SecurityQuestion.Text; nu.SecurityAnswer = SecurityAnswer.Text; context.NewUsers.Add(nu); context.SubmitChanges(RegisterUser_Completed, null); } catch (ValidationException ve) { registerResult.Visibility = System.Windows.Visibility.Visible; registerResult.Text = ve.Message; RegisterButton.IsEnabled = true; } } private void RegisterUser_Completed(SubmitOperation so) { if (so.HasError) { ErrorWindow ew = new ErrorWindow("Registration failed.", "Please try registering again."); ew.Show(); so.MarkErrorAsHandled(); } else { LoginParameters lp = new LoginParameters(NewUsername.Text, NewPassword.Password); WebContext.Current.Authentication.Login(lp, this.LoginOperation_Completed, null); NewUsername.Text = ""; NewPassword.Password = ""; NewConfirmPassword.Password = ""; NewEmail.Text = ""; DefaultRows.SelectedIndex = 0; SecurityQuestion.Text = ""; SecurityAnswer.Text = ""; } RegisterButton.IsEnabled = true; } } }
ソリューションを実行します。
新しいユーザーを登録するための値を指定します。
Web ブラウザーを閉じます。
ドメイン操作へのアクセスの制限
ドメイン操作へのアクセスを制限するには、ドメイン操作に RequiresAuthenticationAttribute 属性または RequiresRoleAttribute 属性を適用します。属性を持たないドメイン操作は、すべてのユーザーが使用できます。属性をドメイン操作に適用しても、ユーザーがドメイン操作を呼び出せなくなることはありませんが、必要な資格情報を持っていないユーザーの場合は、例外が発生します。
ロール別に表示データを制限するには
ソリューション エクスプローラーで、サーバー プロジェクトを選択し、[すべてのファイルを表示] をクリックします。
App_Data フォルダーを右クリックし、[プロジェクトに含める] をクリックします。
App_Data フォルダーを右クリックし、[追加] をポイントして、[既存の項目] をクリックします。
[既存項目の追加] ダイアログ ボックスで、AdventureWorksLT サンプル データベースを追加します。
サーバー プロジェクトで、新しい項目を追加し、[ADO.NET エンティティ データ モデル] テンプレートをクリックします。
モデルに AdventureWorksModel.edmx という名前を付けて、[追加] をクリックします。
Entity Data Model ウィザードが表示されます。
[データベースから生成] を選択し、[次へ] をクリックします。
AdventureWorksLT データベースを選択し、[次へ] をクリックします。
データベース オブジェクトの一覧から、Customer、Product、および SalesOrderHeader の各テーブルを選択し、[完了] をクリックします。
エンティティ データ モデルがデザイナーに表示されます。
ソリューションをビルドします。
サーバー プロジェクトで、新しい項目を追加し、[DomainService クラス] テンプレートをクリックします。
ドメイン サービスに AdventureWorksDomainService という名前を付けて、[追加] をクリックします。
[新しいドメイン サービス クラスの追加] ダイアログ ボックスで、Customer、Product、および SalesOrderHeader エンティティを選択します。
[OK] をクリックして、ドメイン サービスの作成を完了します。
AdventureWorksDomainService クラス ファイルで、RequiresAuthenticationAttribute 属性を
GetSalesOrderHeader
メソッドに追加します。<RequiresAuthentication()> _ Public Function GetSalesOrderHeaders() As IQueryable(Of SalesOrderHeader) Return Me.ObjectContext.SalesOrderHeaders End Function
[RequiresAuthentication()] public IQueryable<SalesOrderHeader> GetSalesOrderHeaders() { return this.ObjectContext.SalesOrderHeaders; }
RequiresRoleAttribute 属性を
GetCustomers
メソッドに追加し、必要なロールの名前を "Managers" に設定します。<RequiresRole("Managers")> _ Public Function GetCustomers() As IQueryable(Of Customer) Return Me.ObjectContext.Customers End Function
[RequiresRole("Managers")] public IQueryable<Customer> GetCustomers() { return this.ObjectContext.Customers; }
GetProducts
ドメイン操作は、すべてのユーザーが使用できます。GetSalesOrderHeaders
は認証済みユーザー、GetCustomers
は Managers ロールのユーザーのみが使用できます。完全なドメイン サービスを次に示します。
<EnableClientAccess()> _ Public Class AdventureWorksDomainService Inherits LinqToEntitiesDomainService(Of AdventureWorksLT_DataEntities) <RequiresRole("Managers")> _ Public Function GetCustomers() As IQueryable(Of Customer) Return Me.ObjectContext.Customers End Function Public Function GetProducts() As IQueryable(Of Product) Return Me.ObjectContext.Products End Function <RequiresAuthentication()> _ Public Function GetSalesOrderHeaders() As IQueryable(Of SalesOrderHeader) Return Me.ObjectContext.SalesOrderHeaders End Function End Class
[EnableClientAccess()] public class AdventureWorksDomainService : LinqToEntitiesDomainService<AdventureWorksLT_DataEntities> { [RequiresRole("Managers")] public IQueryable<Customer> GetCustomers() { return this.ObjectContext.Customers; } public IQueryable<Product> GetProducts() { return this.ObjectContext.Products; } [RequiresAuthentication()] public IQueryable<SalesOrderHeader> GetSalesOrderHeaders() { return this.ObjectContext.SalesOrderHeaders; } }
クライアントからの認証サービスの使用
アクセス許可が制限されたドメイン操作を呼び出す前に、ユーザーに必要な資格情報があることを確認する必要があります。必要な資格情報がない場合は、例外がスローされます。ここでは、ユーザーの資格情報を確認し、ユーザーの資格情報に基づいて 1 ~ 3 個の DataGrid コントロールを設定します。また、ユーザー プロファイルのプロパティに基づいてレコードの数を取得します。既定値の 10 は、認証されていないユーザーに使用されます。このセクションでは、ユーザーが DefaultRows プロファイル プロパティを設定するための方法は説明しませんが、このプロファイル プロパティは後のセクションで追加します。
データを表示するための Silverlight ページを追加するには
クライアント プロジェクトで、Views フォルダーに新しい項目を追加します。
[Silverlight ページ] テンプレートを選択し、新しいページに Reports.xaml という名前を付けます。
MainPage.xaml ファイルを開き、バージョン情報ページにリンクする
Link2
という名前の HyperlinkButton の後に次の XAML を追加して、Reports ページのリンクを追加します。<Rectangle x:Name="Divider2" Style="{StaticResource DividerStyle}"/> <HyperlinkButton x:Name="Link3" Style="{StaticResource LinkStyle}" NavigateUri="/Reports" TargetName="ContentFrame" Content="reports"/>
Reports.xaml ファイルを開き、
Grid
タグ内に次の XAML を追加し、サイト内の他のページの書式設定と一致させ、プロファイル プロパティを編集するためのウィンドウを起動する HyperlinkButton コントロールを追加します。<ScrollViewer x:Name="PageScrollViewer" Style="{StaticResource PageScrollViewerStyle}"> <StackPanel x:Name="ContentStackPanel"> <TextBlock x:Name="HeaderText" Style="{StaticResource HeaderTextStyle}" Text="Reports"/> <TextBlock x:Name="ContentText" Style="{StaticResource ContentTextStyle}" Text="Display reports based on user permissions"/> <HyperlinkButton x:Name="SettingsButton" Content="Adjust Settings" Click="SettingsButton_Click" Visibility="Collapsed"> </HyperlinkButton> </StackPanel> </ScrollViewer>
ContentStackPanel
という名前のスタック パネルの終了タグの直前に、ツールボックスから 3 つの DataGrid コントロールをドラッグします。ツールボックスから DataGrid コントロールをドラッグすると、System.Windows.Controls.Data アセンブリへの参照がプロジェクトに追加され、System.Windows.Controls 名前空間のプレフィックスがページに追加されます。
DataGrid コントロールに
ProductsGrid
、SalesOrdersGrid
、およびCustomersGrid
という名前を付け、Margin
を 5 に設定します。完全な Reports.xaml ファイルの例を次に示します。
<navigation:Page x:Class="ExampleNavigationApplication.Views.Reports" xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="https://schemas.microsoft.com/expression/blend/2008" xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data" xmlns:mc="https://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation" d:DesignWidth="640" d:DesignHeight="480" Title="Reports Page"> <Grid x:Name="LayoutRoot"> <ScrollViewer x:Name="PageScrollViewer" Style="{StaticResource PageScrollViewerStyle}"> <StackPanel x:Name="ContentStackPanel"> <TextBlock x:Name="HeaderText" Style="{StaticResource HeaderTextStyle}" Text="Reports"/> <TextBlock x:Name="ContentText" Style="{StaticResource ContentTextStyle}" Text="Display reports based on user permissions"/> <HyperlinkButton x:Name="SettingsButton" Content="Adjust Settings" Click="SettingsButton_Click" Visibility="Collapsed"> </HyperlinkButton> <data:DataGrid Name="ProductsGrid" Margin="5" /> <data:DataGrid Name="SalesOrdersGrid" Margin="5" /> <data:DataGrid Name="CustomersGrid" Margin="5" /> </StackPanel> </ScrollViewer> </Grid> </navigation:Page>
Reports.xaml.cs ファイルまたは Reports.xaml.vb ファイルを開き、System.ServiceModel.DomainServices.Client 名前空間および ExampleNavigationApplication.Web 名前空間の using ステートメントまたは Imports ステートメントを追加します。
context という名前の AdventureWorksDomainContext のインスタンスを作成し、取得する行数を含む numberOfRows という名前の変数を作成します。
Private context As New AdventureWorksDomainContext Private numberOfRows As Integer = 10
private AdventureWorksDomainContext context = new AdventureWorksDomainContext(); int numberOfRows = 10;
ユーザーが Managers ロールに属しており、対応するデータ グリッドに結果を読み込む場合は、
GetSalesOrderHeaderQuery
メソッドおよびGetCustomersQuery
メソッドを呼び出す、LoadRestrictedReports
という名前のメソッドを追加します。ユーザーが必要な資格情報を持っていない場合にドメイン操作を呼び出すと、ドメイン操作は例外を返します。ドメイン操作を呼び出す前に資格情報を確認することで、この状況を回避できます。
Private Sub LoadRestrictedReports() Dim loadSales = context.Load(context.GetSalesOrderHeadersQuery().Take(numberOfRows)) SalesOrdersGrid.ItemsSource = loadSales.Entities SalesOrdersGrid.Visibility = System.Windows.Visibility.Visible If (WebContext.Current.User.IsInRole("Managers")) Then Dim loadCustomers = context.Load(context.GetCustomersQuery().Take(numberOfRows)) CustomersGrid.ItemsSource = loadCustomers.Entities CustomersGrid.Visibility = System.Windows.Visibility.Visible Else CustomersGrid.Visibility = System.Windows.Visibility.Collapsed End If End Sub
private void LoadRestrictedReports() { LoadOperation<SalesOrderHeader> loadSales = context.Load(context.GetSalesOrderHeadersQuery().Take(numberOfRows)); SalesOrdersGrid.ItemsSource = loadSales.Entities; SalesOrdersGrid.Visibility = System.Windows.Visibility.Visible; if (WebContext.Current.User.IsInRole("Managers")) { LoadOperation<Customer> loadCustomers = context.Load(context.GetCustomersQuery().Take(numberOfRows)); CustomersGrid.ItemsSource = loadCustomers.Entities; CustomersGrid.Visibility = System.Windows.Visibility.Visible; } else { CustomersGrid.Visibility = System.Windows.Visibility.Collapsed; } }
ユーザーが認証されているかどうかを確認し、認証されている場合は
LoadRestrictedReports
メソッドを呼び出す、LoadReports
という名前のメソッドを追加します。また、DefaultRows
という名前のプロファイル プロパティを取得し、ユーザー オブジェクトに PropertyChanged イベントのハンドラーを追加します。最後に、すべてのユーザーに対してGetProductsQuery
メソッドを呼び出します。Private Sub LoadReports() If (WebContext.Current.User.IsAuthenticated) Then numberOfRows = WebContext.Current.User.DefaultRows AddHandler WebContext.Current.User.PropertyChanged, AddressOf User_PropertyChanged LoadRestrictedReports() Else CustomersGrid.Visibility = System.Windows.Visibility.Collapsed SalesOrdersGrid.Visibility = System.Windows.Visibility.Collapsed End If Dim loadProducts = context.Load(context.GetProductsQuery().Take(numberOfRows)) ProductsGrid.ItemsSource = loadProducts.Entities End Sub
private void LoadReports() { if (WebContext.Current.User.IsAuthenticated) { numberOfRows = WebContext.Current.User.DefaultRows; WebContext.Current.User.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(User_PropertyChanged); LoadRestrictedReports(); } else { CustomersGrid.Visibility = System.Windows.Visibility.Collapsed; SalesOrdersGrid.Visibility = System.Windows.Visibility.Collapsed; } LoadOperation<Product> loadProducts = context.Load(context.GetProductsQuery().Take(numberOfRows)); ProductsGrid.ItemsSource = loadProducts.Entities; }
プロパティ
DefaultRows
が変更された場合にLoadReports
を呼び出す PropertyChanged イベントのイベント ハンドラーを追加します。Private Sub User_PropertyChanged(ByVal sender As Object, ByVal e As System.ComponentModel.PropertyChangedEventArgs) If (e.PropertyName = "DefaultRows") Then LoadReports() End If End Sub
void User_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) { if (e.PropertyName == "DefaultRows") { LoadReports(); } }
次のコードをコンストラクターに追加します。このコードにより、レポートが読み込まれ、設定リンクが認証済みユーザーに表示されます。
Public Sub New() InitializeComponent() LoadReports() If (WebContext.Current.User.IsAuthenticated) Then SettingsButton.Visibility = System.Windows.Visibility.Visible End If End Sub
public Reports() { InitializeComponent(); LoadReports(); if (WebContext.Current.User.IsAuthenticated) { SettingsButton.Visibility = System.Windows.Visibility.Visible; } }
設定リンクに Click イベントのイベント ハンドラーを追加します。
ProfileWindow
は後の手順で追加されます。Private Sub SettingsButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs) Dim settingsWindow = New ProfileWindow() settingsWindow.Show() End Sub
private void SettingsButton_Click(object sender, RoutedEventArgs e) { Views.ProfileWindow settingsWindow = new Views.ProfileWindow(); settingsWindow.Show(); }
完全なコード ファイルを次に示します。
Imports System.ServiceModel.DomainServices.Client Imports ExampleNavigationApplication.Web Partial Public Class Reports Inherits Page Private context As New AdventureWorksDomainContext Private numberOfRows As Integer = 10 Public Sub New() InitializeComponent() LoadReports() If (WebContext.Current.User.IsAuthenticated) Then SettingsButton.Visibility = System.Windows.Visibility.Visible End If End Sub Private Sub LoadReports() If (WebContext.Current.User.IsAuthenticated) Then numberOfRows = WebContext.Current.User.DefaultRows AddHandler WebContext.Current.User.PropertyChanged, AddressOf User_PropertyChanged LoadRestrictedReports() Else CustomersGrid.Visibility = System.Windows.Visibility.Collapsed SalesOrdersGrid.Visibility = System.Windows.Visibility.Collapsed End If Dim loadProducts = context.Load(context.GetProductsQuery().Take(numberOfRows)) ProductsGrid.ItemsSource = loadProducts.Entities End Sub Private Sub LoadRestrictedReports() Dim loadSales = context.Load(context.GetSalesOrderHeadersQuery().Take(numberOfRows)) SalesOrdersGrid.ItemsSource = loadSales.Entities SalesOrdersGrid.Visibility = System.Windows.Visibility.Visible If (WebContext.Current.User.IsInRole("Managers")) Then Dim loadCustomers = context.Load(context.GetCustomersQuery().Take(numberOfRows)) CustomersGrid.ItemsSource = loadCustomers.Entities CustomersGrid.Visibility = System.Windows.Visibility.Visible Else CustomersGrid.Visibility = System.Windows.Visibility.Collapsed End If End Sub Private Sub User_PropertyChanged(ByVal sender As Object, ByVal e As System.ComponentModel.PropertyChangedEventArgs) If (e.PropertyName = "DefaultRows") Then LoadReports() End If End Sub Private Sub SettingsButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs) Dim settingsWindow = New ProfileWindow() settingsWindow.Show() End Sub End Class
using System; using System.Windows; using System.Windows.Controls; using System.Windows.Navigation; using System.ServiceModel.DomainServices.Client; using ExampleNavigationApplication.Web; namespace ExampleNavigationApplication.Views { public partial class Reports : Page { private AdventureWorksDomainContext context = new AdventureWorksDomainContext(); int numberOfRows = 10; public Reports() { InitializeComponent(); LoadReports(); if (WebContext.Current.User.IsAuthenticated) { SettingsButton.Visibility = System.Windows.Visibility.Visible; } } private void LoadReports() { if (WebContext.Current.User.IsAuthenticated) { numberOfRows = WebContext.Current.User.DefaultRows; WebContext.Current.User.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(User_PropertyChanged); LoadRestrictedReports(); } else { CustomersGrid.Visibility = System.Windows.Visibility.Collapsed; SalesOrdersGrid.Visibility = System.Windows.Visibility.Collapsed; } LoadOperation<Product> loadProducts = context.Load(context.GetProductsQuery().Take(numberOfRows)); ProductsGrid.ItemsSource = loadProducts.Entities; } private void LoadRestrictedReports() { LoadOperation<SalesOrderHeader> loadSales = context.Load(context.GetSalesOrderHeadersQuery().Take(numberOfRows)); SalesOrdersGrid.ItemsSource = loadSales.Entities; SalesOrdersGrid.Visibility = System.Windows.Visibility.Visible; if (WebContext.Current.User.IsInRole("Managers")) { LoadOperation<Customer> loadCustomers = context.Load(context.GetCustomersQuery().Take(numberOfRows)); CustomersGrid.ItemsSource = loadCustomers.Entities; CustomersGrid.Visibility = System.Windows.Visibility.Visible; } else { CustomersGrid.Visibility = System.Windows.Visibility.Collapsed; } } void User_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) { if (e.PropertyName == "DefaultRows") { LoadReports(); } } private void SettingsButton_Click(object sender, RoutedEventArgs e) { Views.ProfileWindow settingsWindow = new Views.ProfileWindow(); settingsWindow.Show(); } } }
子ウィンドウを追加することで、ユーザーが DefaultRows プロファイル プロパティを編集できるようにすることができます。値を変更した場合は、SaveUser メソッドを呼び出して、値をデータ ソースに保存します。現在の WebContext インスタンスのユーザー オブジェクトのプロパティを使用して、現在の値を取得します。
プロファイル プロパティを設定するためのウィンドウを追加するには
クライアント プロジェクトで、Views フォルダーに新しい項目を追加します。
[Silverlight 子ウィンドウ] テンプレートを選択し、名前を ProfileWindow.xaml に設定します。
[追加] をクリックします。
ProfileWindow.xaml ファイルで、レポートに表示する行数を選択するための ComboBox を追加するために次の XAML を追加します。
<controls:ChildWindow x:Class="ExampleNavigationApplication.Views.ProfileWindow" xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml" xmlns:controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls" Width="300" Height="200" Title="ProfileWindow"> <Grid x:Name="LayoutRoot" Margin="2"> <Grid.RowDefinitions> <RowDefinition /> <RowDefinition Height="Auto" /> </Grid.RowDefinitions> <StackPanel Orientation="Horizontal" Grid.Row="0"> <TextBlock Text="Number of rows to display for reports: "></TextBlock> <ComboBox x:Name="defaultRows" Height="20" VerticalAlignment="Top"> <ComboBoxItem Content="1"></ComboBoxItem> <ComboBoxItem Content="3"></ComboBoxItem> <ComboBoxItem Content="5"></ComboBoxItem> <ComboBoxItem Content="10"></ComboBoxItem> <ComboBoxItem Content="15"></ComboBoxItem> <ComboBoxItem Content="20"></ComboBoxItem> </ComboBox> </StackPanel> <Button x:Name="CancelButton" Content="Cancel" Click="CancelButton_Click" Width="75" Height="23" HorizontalAlignment="Right" Margin="0,12,0,0" Grid.Row="1" /> <Button x:Name="OKButton" Content="OK" Click="OKButton_Click" Width="75" Height="23" HorizontalAlignment="Right" Margin="0,12,79,0" Grid.Row="1" /> </Grid> </controls:ChildWindow>
ProfileWindow.xaml.cs 分離コード ファイルまたは ProfileWindow.xaml.vb 分離コード ファイルで、次のコードを追加して、プロファイル プロパティを取得および設定します。
Partial Public Class ProfileWindow Inherits ChildWindow Public Sub New() InitializeComponent() Dim userDefaultRows = WebContext.Current.User.DefaultRows.ToString() For Each cbi As ComboBoxItem In defaultRows.Items If (cbi.Content.ToString() = userDefaultRows) Then defaultRows.SelectedItem = cbi Exit For End If Next End Sub Private Sub OKButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs) Handles OKButton.Click Dim newSelection = Integer.Parse(defaultRows.SelectionBoxItem.ToString()) If (newSelection <> WebContext.Current.User.DefaultRows) Then WebContext.Current.User.DefaultRows = newSelection WebContext.Current.Authentication.SaveUser(True) End If Me.DialogResult = True End Sub Private Sub CancelButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs) Handles CancelButton.Click Me.DialogResult = False End Sub End Class
public partial class ProfileWindow : ChildWindow { public ProfileWindow() { InitializeComponent(); string userDefaultRows = WebContext.Current.User.DefaultRows.ToString(); foreach (ComboBoxItem cbi in defaultRows.Items) { if (cbi.Content.ToString() == userDefaultRows) { defaultRows.SelectedItem = cbi; break; } } } private void OKButton_Click(object sender, RoutedEventArgs e) { int newSelection = int.Parse(defaultRows.SelectionBoxItem.ToString()); if (newSelection != WebContext.Current.User.DefaultRows) { WebContext.Current.User.DefaultRows = newSelection; WebContext.Current.Authentication.SaveUser(true); } this.DialogResult = true; } private void CancelButton_Click(object sender, RoutedEventArgs e) { this.DialogResult = false; } }
ソリューションを実行します。
[レポート] リンクをクリックします。
サイトが開かれたときにログインしていない場合は、Reports ページに製品テーブルのみが表示されます。
ホーム ページで、新しいユーザーを登録し、そのユーザーとしてログインします。
[レポート] リンクをクリックします。
製品および販売注文に関するテーブルが表示されます。
ログアウトして、CustomerManager としてログインします。
製品、販売注文、および顧客に関するテーブルが表示されます。
[設定の調整] リンクをクリックし、レポートに表示する既定の行数を設定します。
選択した行数が DataGrid に含まれていることを確認します。
Web ブラウザーを閉じます。