다음을 통해 공유


연습: Silverlight 비즈니스 응용 프로그램에서 인증 서비스 사용

Silverlight 비즈니스 응용 프로그램 템플릿은 인증(인증 모드를 위한 폼 인증 포함), 역할 및 프로필을 자동으로 사용하는 솔루션을 만듭니다. 이 솔루션에는 기존 사용자를 로그인하고 새 사용자를 등록하기 위한 데이터 폼이 포함됩니다. 추가 코드를 작성하지 않고 이러한 기능을 사용할 수 있습니다. 역할 및 프로필 속성을 정의하여 솔루션을 사용자 지정할 수 있습니다.

이 연습에서는 Silverlight 비즈니스 응용 프로그램에서 인증, 역할 및 프로필을 사용하는 방법을 배웁니다. 사용자 자격 증명을 기준으로 특정 도메인 작업에 대한 액세스를 제한하고 사용자 기본 설정을 기준으로 사용자 인터페이스를 사용자 지정합니다. ASP.NET 웹 사이트 관리 도구를 사용하여 사이트의 역할과 사용자를 관리합니다.

필수 구성 요소

RIA Services 설명서에서 제공하는 이 연습 및 다른 연습을 실행하려면 WCF RIA Services 및 WCF RIA Services 도구 키트 외에도 Visual Studio 2010, Silverlight Developer 런타임 및 SDK 등의 몇 가지 필수 구성 요소 프로그램을 올바르게 설치하고 구성해야 합니다. 또한 SQL Server 2008 R2 Express with Advanced Services를 설치하고 구성해야 하며 AdventureWorks OLTP 및 LT 데이터베이스를 설치해야 합니다.

이러한 각 필수 구성 요소를 충족하기 위한 자세한 지침은 WCF RIA Services의 사전 요구 사항 노드의 항목에서 제공합니다. 이 RIA Services 연습을 수행할 때 발생할 수 있는 문제를 최소화하려면 이 연습을 진행하기 전에 여기서 제공하는 지침을 따르십시오.

사용자 및 역할 만들기

Silverlight 비즈니스 응용 프로그램에서 제공하는 기능을 사용하여 인증을 빠르게 구현할 수 있습니다. 다음 단원에서는 ASP.NET 구성 도구를 사용하여 사용자와 역할을 만든 다음 해당 사용자로 로그인합니다. Silverlight 비즈니스 응용 프로그램에서 제공하는 등록 양식을 통해 새 사용자를 등록합니다.

사이트, 역할 및 사용자를 만들려면

  1. Visual Studio 2010에서 파일, 새로 만들기, 프로젝트를 차례로 선택합니다.

    새 프로젝트 대화 상자가 나타납니다.

  2. Silverlight 프로젝트 형식을 선택합니다.

  3. Silverlight 비즈니스 응용 프로그램 템플릿을 선택하고 응용 프로그램의 이름을 ExampleBusinessApplication으로 지정합니다.

    RIA_ServicesCreateBizApp

  4. 확인을 클릭합니다.

    만들어진 프로젝트 구조를 확인합니다. Silverlight 클라이언트 프로젝트의 Views 폴더에 있는 Silverlight 페이지에서 사용자를 로그인하고 새 사용자를 등록할 수 있습니다.

  5. ASP.NET 웹 사이트 관리 도구를 열려면 먼저 솔루션 탐색기에서 서비스 프로젝트(ExampleBusinessApplication.Web)를 선택하고 ASP.NET 구성 도구를 엽니다.

  6. 프로젝트 메뉴에서 ASP.NET 구성을 선택합니다.

    프로젝트 메뉴에 ASP.NET 구성 옵션이 보이지 않는 경우 클라이언트 프로젝트를 선택했기 때문일 수 있습니다.

    RIA_OpenAdminTool

  7. ASP.NET 웹 사이트 관리 도구에서 보안 탭을 선택합니다.

    RIA_WebAdminSecurity

  8. 역할 섹션에서 역할 만들기 또는 관리 링크를 클릭합니다.

  9. Managers라는 새 역할을 추가하고 역할 추가 단추를 선택합니다.

    WebAdmin_CreateRole

  10. 오른쪽 아래 모퉁이에서 뒤로 단추를 클릭합니다.

  11. 사용자 섹션에서 사용자 만들기 링크를 클릭합니다.

  12. 다음 값을 사용하여 새 사용자를 만들고 Managers 역할 확인란을 선택합니다.

    사용자 이름: CustomerManager

    암호: P@ssword

    전자 메일: someone@example.com

    보안 질문: 가장 좋아하는 색깔은?

    보안 대답: 파랑

    Managers 역할: 선택

    WebAdmin_CreateUser

  13. 사용자 만들기 단추를 클릭합니다.

  14. ASP.NET 웹 사이트 관리 도구를 닫습니다.

  15. 솔루션을 실행합니다.

    응용 프로그램의 홈 페이지가 웹 브라우저에 나타납니다.

  16. 페이지의 오른쪽 위 모퉁이에서 로그인 링크를 클릭합니다.

    로그인 대화 상자가 나타납니다.

  17. 사용자 이름에 CustomerManager를 입력하고 암호에 P@ssword를 입력한 다음 확인 단추를 클릭합니다.

    RIA_LoginManager

    이제 해당 사용자로 로그인됩니다. 오른쪽 위 모퉁이에 "시작 CustomerManager" 텍스트를 확인합니다.

  18. 로그아웃 링크를 클릭합니다.

    이제 CustomerManager로 로그인되어 있지 않습니다. 다음 단계에서는 등록 양식을 통해 새 사용자를 만듭니다.

  19. 로그인 링크를 다시 클릭합니다.

  20. 로그인 대화 상자에서 지금 등록 링크를 클릭합니다.

    이제 등록 양식이 표시됩니다.

  21. 다음 값으로 등록 양식을 작성하여 새 사용자 계정을 만듭니다.

    사용자 이름: SalesUser

    표시 이름: SalesUser

    전자 메일: someone@example.com

    암호: P@ssword

    보안 질문: 처음 구입한 차의 색상은 무엇입니까?

    보안 대답: 녹색

    RIA_RegisterUser

  22. 확인을 클릭하여 새 사용자를 만듭니다.

    이제 SalesUser로 로그인됩니다.

  23. 브라우저를 닫습니다.

  24. ASP.NET 웹 사이트 관리 도구를 다시 열고 보안 탭을 클릭합니다.

    이제 두 명의 사용자가 사이트에 있으며 하나의 역할만 만들었지만 두 개의 역할이 존재합니다.

  25. 역할 만들기 또는 관리를 클릭하고 Managers 역할과 Registered Users를 확인합니다.

    Registered Users 역할은 비즈니스 응용 프로그램 템플릿에서 자동으로 만들어졌습니다.

    RIA_ManageRoles

  26. Registered Users에 대한 관리 링크를 클릭합니다.

    응용 프로그램을 통해 추가한 SalesUser라는 사용자가 Registered Users 역할에 속하는지 확인합니다.

  27. ASP.NET 웹 사이트 관리 도구를 닫습니다.

액세스 및 프로필 속성 정의

RequiresAuthenticationAttribute 특성 또는 RequiresRoleAttribute 특성을 도메인 작업에 적용하여 도메인 작업에 대한 액세스를 제한합니다. 특성이 없는 도메인 작업은 모든 사용자가 이용할 수 있습니다. 특성을 도메인 작업에 적용해도 사용자가 도메인 작업을 호출할 수 있지만 필수 자격 증명이 없는 사용자의 경우 예외가 발생합니다.

역할에 따라 표시되는 데이터 제한

  1. 솔루션 탐색기에서 서버 프로젝트의 App_Data 폴더를 마우스 오른쪽 단추로 클릭하고 추가를 선택한 다음 기존 항목을 선택합니다.

  2. 기존 항목 추가 대화 상자에서 AdventureWorksLT 샘플 데이터베이스를 추가합니다.

  3. 서버 프로젝트에서 새 항목을 추가하고 데이터 템플릿에서 ADO.NET 엔터티 데이터 모델 템플릿을 선택합니다.

  4. 모델의 이름을 AdventureWorksModel.edmx로 지정하고 추가를 클릭합니다.

    엔터티 데이터 모델 마법사가 나타납니다.

  5. 데이터베이스에서 생성 옵션을 선택하고 다음을 클릭합니다.

  6. AdventureWorksLT 데이터베이스를 선택하고 다음을 클릭합니다.

  7. 데이터베이스 개체 목록에서 Customer, Product 및 SalesOrderHeader 테이블을 선택한 다음 마침을 클릭합니다.

    엔터티 데이터 모델이 디자이너에 나타납니다.

  8. 솔루션을 빌드합니다.

  9. 서버 프로젝트에서 새 항목을 추가하고 템플릿에서 도메인 서비스 클래스 템플릿을 선택합니다.

  10. 도메인 서비스의 이름을 AdventureWorksDomainService로 지정하고 추가를 클릭합니다.

  11. 새 도메인 서비스 클래스 추가 대화 상자에서 Customer, Product 및 SalesOrderHeader 엔터티를 선택합니다.

    RIA_CreateDSForAuth

  12. 확인을 클릭하여 도메인 서비스 만들기를 마칩니다.

  13. AdventureWorksDomainService 클래스 파일에서 GetSalesOrderHeader 메서드에 RequiresAuthenticationAttribute 특성을 추가합니다.

    <RequiresAuthentication()> _
    Public Function GetSalesOrderHeaders() As IQueryable(Of SalesOrderHeader)
        Return Me.ObjectContext.SalesOrderHeaders
    End Function
    
    [RequiresAuthentication()]
    public IQueryable<SalesOrderHeader> GetSalesOrderHeaders()
    {
        return this.ObjectContext.SalesOrderHeaders;
    }
    
  14. GetCustomers 메서드에 RequiresRoleAttribute 특성을 추가하고 필수 역할의 이름을 "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;
        }
    }
    

Web.config 파일에 프로필 속성을 정의합니다. 서버의 User 클래스에 속성을 추가하면 클라이언트 프로젝트에 대해 해당 속성이 생성됩니다.

프로필 속성 추가

  1. 서버 프로젝트에서 Web.config 파일을 엽니다.

  2. <profile> 요소에서 DefaultRows라는 프로필 속성을 추가합니다. 이 속성에는 표시할 행 수에 대한 사용자 기본 설정이 포함됩니다.

    다음은 Web.config 파일의 profile 섹션을 보여 줍니다.

    <profile>
      <properties>
        <add name="FriendlyName" />
        <add type="System.Int32" defaultValue="10" name="DefaultRows"/>
      </properties>
    </profile>
    
  3. Web.config 파일을 저장합니다.

  4. 서버 프로젝트에서 Models 폴더를 확장합니다.

  5. User.cs 또는 User.vb 파일을 열고 DefaultRows라는 속성을 추가합니다.

    Imports System.ServiceModel.DomainServices.Server.ApplicationServices
    Imports System.Runtime.Serialization
    Namespace Web
        Partial Public Class User
            Inherits UserBase
    
            Public Property FriendlyName As String
    
            Public Property DefaultRows As Integer
    
        End Class
    End Namespace
    
    namespace ExampleBusinessApplication.Web
    {
        using System.Runtime.Serialization;
        using System.ServiceModel.DomainServices.Server.ApplicationServices;
    
        public partial class User : UserBase
        {
            public string FriendlyName { get; set; }
    
            public int DefaultRows { get; set; }
        }
    }
    

클라이언트에서 인증 서비스 사용

제한된 권한으로 도메인 작업을 호출하기 전에 사용자에게 필수 자격 증명이 있는지 확인해야 합니다. 그렇지 않으면 예외가 throw됩니다. 다음 단원에서는 사용자의 자격 증명을 확인하고 사용자의 자격 증명을 기준으로 1~3개의 DataGrid 컨트롤을 채웁니다. 사용자 프로필의 속성을 기준으로 레코드 수도 검색합니다. 인증되지 않은 사용자에 대해서는 기본값 10이 사용됩니다. 이 단원에는 사용자가 DefaultRows 프로필 속성을 설정하는 방법이 나와 있지 않지만 이후 단원에서 이 속성을 추가합니다.

데이터를 표시하기 위해 Silverlight 페이지 추가

  1. 클라이언트 프로젝트에서 새 항목을 Views 폴더에 추가합니다.

  2. Silverlight 페이지 템플릿을 선택하고 새 페이지의 이름을 Reports.xaml로 지정합니다.

  3. MainPage.xaml 파일을 열고 About 페이지에 연결하는 Link2라는 HyperlinkButton 뒤에 다음 XAML을 추가하여 Reports 페이지에 대한 링크를 추가합니다.

    <Rectangle x:Name="Divider2" Style="{StaticResource DividerStyle}"/>
    
    <HyperlinkButton x:Name="Link3" Style="{StaticResource LinkStyle}" 
           NavigateUri="/Reports" TargetName="ContentFrame" Content="{Binding Path=ApplicationStrings.ReportsPageTitle, Source={StaticResource ResourceWrapper}}"/>
    
  4. Assets\Resources 폴더에서 ApplicationStrings.resx 파일을 엽니다.

  5. 값이 Reports인 ReportsPageTitle이라는 새 문자열 리소스를 추가합니다.

    RIA_AddReportResource

  6. ApplicationStrings.resx 파일을 저장하고 닫습니다.

  7. Reports.xaml 파일을 열고 사이트에 있는 다른 페이지의 서식과 일치하도록 Grid 요소에 다음 XAML을 추가합니다.

    <ScrollViewer x:Name="PageScrollViewer" Style="{StaticResource PageScrollViewerStyle}">
        <StackPanel x:Name="ContentStackPanel" Style="{StaticResource ContentStackPanelStyle}">
            <TextBlock x:Name="HeaderText" Style="{StaticResource HeaderTextStyle}"
                       Text="{Binding Path=ApplicationStrings.ReportsPageTitle, Source={StaticResource ResourceWrapper}}"/>
            <TextBlock x:Name="ContentText" Style="{StaticResource ContentTextStyle}"
                       Text="Display reports based on user permissions"/>
    
        </StackPanel>
    </ScrollViewer>
    
  8. 도구 상자에서 ContentStackPanel이라는 스택 패널의 끝 태그 바로 앞으로 세 개의 DataGrid 컨트롤을 끌어옵니다.

    도구 상자에서 DataGrid 컨트롤을 끌어오면 System.Windows.Controls.Data 어셈블리에 대한 참조가 프로젝트에 추가되고 System.Windows.Controls 네임스페이스에 대한 접두사가 페이지에 추가됩니다.

  9. DataGrid 컨트롤의 이름을 ProductsGrid, SalesOrdersGridCustomersGrid로 지정합니다.

  10. DataGrid 컨트롤에 대해 Margin 속성을 5로 설정합니다.

    다음 예제에서는 전체 Reports.xaml 파일을 보여 줍니다.

    <navigation:Page x:Class="ExampleBusinessApplication.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:mc="https://schemas.openxmlformats.org/markup-compatibility/2006"
               xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"
               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" Style="{StaticResource ContentStackPanelStyle}">
                    <TextBlock x:Name="HeaderText" Style="{StaticResource HeaderTextStyle}"
                               Text="{Binding Path=ApplicationStrings.ReportsPageTitle, Source={StaticResource ResourceWrapper}}"/>
                    <TextBlock x:Name="ContentText" Style="{StaticResource ContentTextStyle}"
                               Text="Display reports based on user permissions"/>
                    <data:DataGrid Name="ProductsGrid" Margin="5" />
                    <data:DataGrid Name="SalesOrdersGrid" Margin="5" />
                    <data:DataGrid Name="CustomersGrid" Margin="5" />
                </StackPanel>
            </ScrollViewer>
        </Grid>
    </navigation:Page>
    
  11. Reports.xaml.cs 또는 Reports.xaml.vb 파일을 엽니다.

  12. C#의 경우 System.ServiceModel.DomainServices.Client, System.ServiceModel.DomainServices.Client.ApplicationServicesExampleBusinessApplication.Web 네임스페이스에 대해 using 문을 추가합니다. Visual Basic의 경우 System.ServiceModel.DomainServices.Client, System.ServiceModel.DomainServices.Client.ApplicationServices, System.Windows.ControlsExampleBusinessApplication.Web 네임스페이스에 대해 Imports 문을 추가합니다.

  13. 컨텍스트라는 AdventureWorksDomainContext의 인스턴스를 만들고 검색할 행 수가 들어 있는 numberOfRows라는 변수를 만듭니다.

    Private context As New AdventureWorksDomainContext
    Private numberOfRows As Integer = 10
    
    private AdventureWorksDomainContext context = new AdventureWorksDomainContext();
    int numberOfRows = 10;
    
  14. 사용자가 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;
        }
    }
    
  15. 사용자가 인증되는지 확인하고 인증되는 경우 LoadRestrictedReports 메서드를 호출하는 LoadReports라는 메서드를 추가합니다. 또한 이 메서드는 DefaultRows라는 프로필 속성을 검색하고 User 개체의 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;
    }
    
  16. 속성 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();
        }
    }
    
  17. 사용자 인증 자격 증명의 변경 내용을 기준으로 데이터를 로드하거나 숨기는 LoggedInLoggedOut 이벤트에 대한 이벤트 처리기를 추가합니다.

    Private Sub Authentication_LoggedIn(ByVal sender As Object, ByVal e As ApplicationServices.AuthenticationEventArgs)
        LoadReports()
    End Sub
    
    Private Sub Authentication_LoggedOut(ByVal sender As Object, ByVal e As ApplicationServices.AuthenticationEventArgs)
        CustomersGrid.Visibility = System.Windows.Visibility.Collapsed
        SalesOrdersGrid.Visibility = System.Windows.Visibility.Collapsed
    End Sub
    
    void Authentication_LoggedIn(object sender, AuthenticationEventArgs e)
    {
        LoadReports();
    }
    
    void Authentication_LoggedOut(object sender, AuthenticationEventArgs e)
    {
        CustomersGrid.Visibility = System.Windows.Visibility.Collapsed;
        SalesOrdersGrid.Visibility = System.Windows.Visibility.Collapsed;
    }
    
  18. 다음 코드를 생성자에 추가합니다. 이 코드는 처리기를 로드하고 LoadReports를 호출합니다.

    Public Sub New()
        InitializeComponent()
    
        Me.Title = ApplicationStrings.ReportsPageTitle
    
        AddHandler WebContext.Current.Authentication.LoggedIn, AddressOf Authentication_LoggedIn
        AddHandler WebContext.Current.Authentication.LoggedOut, AddressOf Authentication_LoggedOut
    
        LoadReports()
    End Sub
    
    public Reports()
    {
        InitializeComponent();
    
        this.Title = ApplicationStrings.ReportsPageTitle;
    
        WebContext.Current.Authentication.LoggedIn += new System.EventHandler<AuthenticationEventArgs>(Authentication_LoggedIn);
        WebContext.Current.Authentication.LoggedOut += new System.EventHandler<AuthenticationEventArgs>(Authentication_LoggedOut);
    
        LoadReports();
    }
    

    전체 코드 파일은 다음과 같습니다.

    Imports System.Windows.Navigation
    Imports System.Windows.Controls
    Imports System.ServiceModel.DomainServices.Client
    Imports System.ServiceModel.DomainServices.Client.ApplicationServices
    Imports ExampleBusinessApplication.Web
    
    Partial Public Class Reports
        Inherits Page
    
        Private context As New AdventureWorksDomainContext
        Private numberOfRows As Integer = 10
    
        Public Sub New()
            InitializeComponent()
    
            Me.Title = ApplicationStrings.ReportsPageTitle
    
            AddHandler WebContext.Current.Authentication.LoggedIn, AddressOf Authentication_LoggedIn
            AddHandler WebContext.Current.Authentication.LoggedOut, AddressOf Authentication_LoggedOut
    
            LoadReports()
        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 Authentication_LoggedIn(ByVal sender As Object, ByVal e As ApplicationServices.AuthenticationEventArgs)
            LoadReports()
        End Sub
    
        Private Sub Authentication_LoggedOut(ByVal sender As Object, ByVal e As ApplicationServices.AuthenticationEventArgs)
            CustomersGrid.Visibility = System.Windows.Visibility.Collapsed
            SalesOrdersGrid.Visibility = System.Windows.Visibility.Collapsed
        End Sub
    End Class
    
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Animation;
    using System.Windows.Shapes;
    using System.Windows.Navigation;
    using System.ServiceModel.DomainServices.Client;
    using System.ServiceModel.DomainServices.Client.ApplicationServices;
    using ExampleBusinessApplication.Web;
    
    namespace ExampleBusinessApplication.Views
    {
        public partial class Reports : Page
        {
            private AdventureWorksDomainContext context = new AdventureWorksDomainContext();
            int numberOfRows = 10;
    
            public Reports()
            {
                InitializeComponent();
    
                this.Title = ApplicationStrings.ReportsPageTitle;
    
                WebContext.Current.Authentication.LoggedIn += new System.EventHandler<AuthenticationEventArgs>(Authentication_LoggedIn);
                WebContext.Current.Authentication.LoggedOut += new System.EventHandler<AuthenticationEventArgs>(Authentication_LoggedOut);
    
                LoadReports();
            }
    
            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 Authentication_LoggedIn(object sender, AuthenticationEventArgs e)
            {
                LoadReports();
            }
    
            void Authentication_LoggedOut(object sender, AuthenticationEventArgs e)
            {
                CustomersGrid.Visibility = System.Windows.Visibility.Collapsed;
                SalesOrdersGrid.Visibility = System.Windows.Visibility.Collapsed;
            }
    
            void User_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
            {
                if (e.PropertyName == "DefaultRows")
                {
                    LoadReports();
                }
            }
        }
    }
    
  19. 솔루션을 실행합니다.

  20. Reports 링크를 클릭합니다.

    사용자가 로그인하지 않은 경우 products 테이블만 Reports 페이지에 표시됩니다.

  21. 로그인 링크를 클릭하고 SalesUser로 로그인합니다.

    제품 및 판매 주문에 대한 테이블이 표시됩니다.

    RIA_DisplayReports

  22. 로그아웃하고 CustomerManager로 로그인합니다.

    제품, 판매 주문 및 고객에 대한 테이블이 표시됩니다.

  23. 웹 브라우저를 닫습니다.

자식 창을 추가하여 사용자가 DefaultRows 프로필 속성을 편집하도록 허용할 수 있습니다. 값이 변경되면 SaveUser 메서드를 호출하여 데이터 원본에 값을 저장합니다. 현재 WebContext 인스턴스의 User 개체 속성을 통해 현재 값을 검색합니다.

프로필 속성을 설정하기 위한 창 추가

  1. 클라이언트 프로젝트에서 Views 폴더에 새 항목을 추가합니다.

  2. Silverlight 자식 창 템플릿을 선택하고 자식 창의 이름을 ProfileWindow.xaml로 지정합니다.

    자식 창 추가

  3. 추가 단추를 클릭합니다.

  4. ProfileWindow.xaml 파일에서 다음 XAML을 Grid.RowDefinitions 요소 뒤에 추가하여 보고서에 표시할 행 수를 선택하기 위한 ComboBox를 포함합니다.

    <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="2"></ComboBoxItem>
            <ComboBoxItem Content="3"></ComboBoxItem>
            <ComboBoxItem Content="4"></ComboBoxItem>
            <ComboBoxItem Content="5"></ComboBoxItem>
            <ComboBoxItem Content="6"></ComboBoxItem>
            <ComboBoxItem Content="7"></ComboBoxItem>
            <ComboBoxItem Content="8"></ComboBoxItem>
            <ComboBoxItem Content="9"></ComboBoxItem>
            <ComboBoxItem Content="10"></ComboBoxItem>
            <ComboBoxItem Content="15"></ComboBoxItem>
            <ComboBoxItem Content="20"></ComboBoxItem>
        </ComboBox>
    </StackPanel>
    
  5. ChildWindow에서 Title 속성을 Select Preferences로 설정합니다.

  6. ProfileWindow.xaml.cs 또는 ProfileWindow.xaml.vb 파일에서 다음 코드를 추가하여 프로필 속성을 검색하고 설정합니다.

    Imports System.Windows.Controls
    Imports System.Windows
    
    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;
        }
    }
    
  7. Visual Basic의 경우 System.Windows.ControlsSystem.Windows 네임스페이스에 대해 Imports 문을 추가합니다.

  8. Views\Login 폴더를 확장하고 LoginStatus.xaml 파일을 엽니다.

  9. 설정 링크를 프로필 창에 추가하려면 다음 XAML을 로그아웃 단추 앞에 추가합니다.

    <Button x:Name="SettingsButton" Click="SettingsButton_Click" Content="settings" Style="{StaticResource LoginRegisterLinkStyle}" Margin="0,0,0,0"></Button>
    <TextBlock Text="  |  " Style="{StaticResource SpacerStyle}"/>
    
  10. LoginStatus.xaml.cs 또는 LoginStatus.xaml.vb 파일에서 설정 링크에 대해 다음 클릭 이벤트 처리기를 추가합니다.

    Private Sub SettingsButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
        Dim settingsWindow As New ProfileWindow
        settingsWindow.Show()
    End Sub
    
    private void SettingsButton_Click(object sender, RoutedEventArgs e)
    {
        ExampleBusinessApplication.Views.ProfileWindow settingsWindow = new ExampleBusinessApplication.Views.ProfileWindow();
        settingsWindow.Show();
    }
    
  11. 솔루션을 실행합니다.

  12. CustomerManager 또는 SalesUser로 로그인하고 로그인 상태 표시줄에 설정에 대한 링크가 포함되는지 확인합니다.

    RIA_NewLoginStatusBar

  13. 설정 링크를 클릭하고 보고서에 표시할 기본 행 수를 설정합니다.

    RIA_ShowProfileSettings

  14. Reports 페이지를 열고 DataGrid에 선택한 행 수가 포함되는지 확인합니다.