# Walkthrough: Using Authentication Service with Silverlight Navigation Application

\[ **This document was written for WCF Services Version 1 Service Pack 2 and might not be up to date** \
&#x20;Please see [Release Notes](https://github.com/OpenRIAServices/OpenRiaServices/releases) or [Changelog](https://github.com/OpenRIAServices/OpenRiaServices/blob/main/Changelog.md) for a list of changes since WCF RIA Services ]

In this walkthrough, you learn how to set up your server and client projects in an Open Ria Services solution to work with an authentication service. When you create a solution with the Silverlight Navigation Application template and enable Open Ria Services, you can access the ASP.NET Membership framework by adding an authentication service. The authentication service exposes authentication, roles, and profiles from the server project to the client project. You use the authentication service to validate user credentials, restrict access to resources based on roles, and store profile properties.

{% hint style="info" %}
**Note:** The Silverlight Business Application automatically implements the authentication service. For more information, see [Walkthrough: Using Authentication Service with Silverlight Business Application](https://github.com/OpenRIAServices/OpenRiaServices/tree/82784ac86a5b1cdd95b784ccdb3a00baefcaa7de/docs/ee942449\(v=vs.91\).md).
{% endhint %}

## Prerequisites

This and the other walkthroughs presented in the Open Ria Services documentation require several prerequisite programs, such as Visual Studio and the Silverlight Developer Runtime and SDK, be installed and configured properly, in addition to Open Ria Services and the Open Ria Services Toolkit. They also require installing and configuring SQL Server 2008 R2 Express with Advanced Services and installing the AdventureWorks OLTP and LT database.

Detailed instructions for the satisfaction of each of these prerequisites are provided by the topics within the [Prerequisites for Open Ria Services](https://openriaservices.gitbook.io/openriaservices/gg512106) node. Follow the instructions provided there before proceeding with this walkthrough to ensure that you encounter as few problems as possible when working through this Open Ria Services walkthroughs.

## Configuring the Server Project for Authentication, Roles, and Profiles

To use the authentication service from a Silverlight application, you must configure the authentication on the server project. You configure authentication in the Web.config file. After configuring authentication, you can also configure roles and profiles on the server project, if you want to use those features from the Silverlight application. In this walkthrough, you will configure all three features. Finally, you add an authentication service which exposes the enabled features to the client.

### To configure the server project

1. In Visual Studio, select **File**, **New**, and then **Project**.

   The **New Project** dialog box appears.
2. Select the **Silverlight** project type.
3. Select the **Silverlight Navigation Application** template and name the application ExampleNavigationApplication.
4. Click **OK**.

   The **New Silverlight Application** dialog box appears.
5. Make sure that the **Host the Silverlight application in a new Web site** check box is selected and that the New Web project type is set to **ASP.NET Web Application Project**.
6. Select the **Enable Open Ria Services** check box.
7. Click **OK** to create the solution.
8. In the server project (ExampleBusinessApplication.Web), open the Web.config file.
9. In the \ element, add an \ element and set the mode property to Forms.

   ```csharp
   <authentication mode="Forms"></authentication>
   ```
10. In the \ element, add a \ element and set the enabled property to true.

    ```csharp
    <roleManager enabled="true"></roleManager>
    ```
11. In the \ element, add a \ element, set the enabled property to true, and include a profile property named DefaultRows.

    ```csharp
    <profile enabled="true">
      <properties>
        <add type="System.Int32" defaultValue="10" name="DefaultRows"/>
      </properties>
    </profile>
    ```

    The completed \ element should include the following elements.

    ```csharp
    <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>
    ```
12. Save the Web.config file.
13. In the **Solution Explorer**, right-click the server project, select **Add** and then **New Item.**

    The **Add New Item** dialog box appears.
14. Select the **Authentication Domain Service** template and name it AuthenticationDomainService.

    ![RIA\_ServicesAddAuth](https://1585985709-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M_5pS6LfA6GSEBmCbd9%2Fsync%2F00bac6ac85ef5a1d4bd52755d1dd7210be3f0153.png?generation=1620474363446185\&alt=media)
15. Click **Add**.
16. Open the authentication service code file (AuthenticationDomainService.cs or AuthenticationDomainService.vb) and add the DefaultRows property that you defined in the Web.config file to the User class.

    ```
    <EnableClientAccess()> _
    Public Class AuthenticationDomainService
        Inherits AuthenticationBase(Of User)

    End Class

    Public Class User
        Inherits UserBase

        Public Property DefaultRows As Integer

    End Class
    ```

    ```csharp
    [EnableClientAccess]
    public class AuthenticationDomainService : AuthenticationBase<User>
    {
    }

    public class User : UserBase
    {
        public int DefaultRows { get; set; }
    }
    ```
17. Build the solution.

In this section, you will use the ASP.NET Web Site Administration Tool to create a user and role. You will login as this user in a later section.

### To add users with the ASP.NET Web Site Administration Tool

1. To open the ASP.NET Web Site Administration Tool, first select the server project in the **Solution Explorer**.
2. On the **Project** menu, select **ASP.NET Configuration**.

   If you do not see the ASP.NET Configuration option in the Project menu, it may be because you have selected the client project.

   ![RIA\_OpenAdminTool](https://1585985709-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M_5pS6LfA6GSEBmCbd9%2Fsync%2F5b5f3f595c825ec67822b9dd187ff8d1a99ccaac.png?generation=1620474374182009\&alt=media)
3. Select the **Security** tab in ASP.NET Web Site Administration Tool.

   ![RIA\_WebAdminSecurity](https://1585985709-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M_5pS6LfA6GSEBmCbd9%2Fsync%2F3a97e3a103552a615bd9424aab78d42c3a784fe2.png?generation=1620474374949152\&alt=media)
4. In the **Roles** section, click the **Create or Mange roles** link.
5. Add a new role named Managers and click the **Add Role** button.

   ![WebAdmin\_CreateRole](https://1585985709-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M_5pS6LfA6GSEBmCbd9%2Fsync%2F74143ee7848d1fc7268cad082e55e903615e2113.png?generation=1620474374612337\&alt=media)
6. In the lower-right corner, click the **Back** button.
7. In the **Users** section, click the **Create user** link.
8. Create a new user with the following values and select the Managers role check box.

   User Name: CustomerManager

   Password: P\@ssword

   E-mail: <someone@example.com>

   Security Question: Favorite color?

   Security Answer: Blue

   Managers role: selected

   ![WebAdmin\_CreateUser](https://1585985709-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M_5pS6LfA6GSEBmCbd9%2Fsync%2F482e9f73a2dafc7f60526b6add08a98f0f6114c3.png?generation=1620474373359752\&alt=media)
9. Click the **Create User** button.
10. Close the ASP.NET Web Site Administration Tool.

## Configuring the Client for Authentication

You must configure the client project to use the authentication mode that matches the authentication mode you configured in the server project.

### To configure the client project

1. In the client project, open the code-behind file for the App.xaml file (App.xaml.cs or App.xaml.vb).
2. In the constructor, create a new instance of the WebContext class.
3. Set the [Authentication](https://github.com/OpenRIAServices/OpenRiaServices/tree/82784ac86a5b1cdd95b784ccdb3a00baefcaa7de/docs/ff457819.md) property to a new instance of the [FormsAuthentication](https://github.com/OpenRIAServices/OpenRiaServices/tree/82784ac86a5b1cdd95b784ccdb3a00baefcaa7de/docs/ff457803.md) class, and add the WebContext instance to the ApplicationLifetimeObjects.

   ```
   Public Sub New()
       InitializeComponent()

       Dim webcontext As New WebContext
       webcontext.Authentication = New OpenRiaServices.Client.Authentication.FormsAuthentication
       Me.ApplicationLifetimeObjects.Add(webcontext)
   End Sub
   ```

   ```csharp
   public App()
   {
       this.Startup += this.Application_Startup;
       this.UnhandledException += this.Application_UnhandledException;

       InitializeComponent();

       WebContext webcontext = new WebContext();
       webcontext.Authentication = new OpenRiaServices.Client.Authentication.FormsAuthentication();
       this.ApplicationLifetimeObjects.Add(webcontext);
   }
   ```

## Adding Login Functionality to the Client

In this section, you will add Silverlight controls that enable the user to provide user name and password for logging in. You will add code that calls the [Login](https://github.com/OpenRIAServices/OpenRiaServices/tree/82784ac86a5b1cdd95b784ccdb3a00baefcaa7de/docs/ff457850.md) method with the user's credentials. You will also set which controls are visible based on whether the user is logged in.

For simplicity, the login user interface is added to the Home page in this walkthrough. In your application, you may want to create a separate login page.

### To login and logout a user

1. In **Solution Explorer**, expand the Views folder in the client project.
2. Open the Home.xaml file.
3. After the TextBlock named ContentText, add the following XAML.

   The XAML includes a TextBox for providing a user name, a PasswordBox for providing a password, a Button for submitting the login request, and a TextBlock and HyperlinkButton for logging out which are only displayed after the user has logged in.

   ```
   <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>
   ```
4. Open the code-behind file for the home page (Home.xaml.cs or Home.xaml.vb).
5. Add a using or an Imports statement for the [OpenRiaServices.Client.Authentication](https://github.com/OpenRIAServices/OpenRiaServices/tree/82784ac86a5b1cdd95b784ccdb3a00baefcaa7de/docs/ff457765.md) namespace.
6. Add the following code to the Home class.

   The code includes event handlers for logging in and logging out, callback methods for completed login and logout operations, and a method that set the visibility of controls based on whether the user is authenticated.

   ```
   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
   ```

   ```csharp
   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();
       }
   }
   ```
7. Run the solution.

   ![RS\_CustomLoginNav](https://1585985709-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M_5pS6LfA6GSEBmCbd9%2Fsync%2F54dab2c05edfcaa48fa679e588de82b9d6c1c6af.png?generation=1620474377158652\&alt=media)
8. Log in as CustomerManager with P\@ssword for the password.

   Notice that the Login area is no longer displayed, but the welcome text and logout link are now displayed.

   ![RIA\_CustomLoggedInNav](https://1585985709-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M_5pS6LfA6GSEBmCbd9%2Fsync%2Fe20b5a251a1c78716d4d24c38978e7a2ec948861.png?generation=1620474377575261\&alt=media)
9. Click **Logout** link and close Web browser.

## Adding New Users from the Client

The authentication service does not contain an operation to create new users. To register a new user, you create an empty domain service and add an operation for adding a user to the ASP.NET Membership framework.

### To configure the server project for adding a new user

1. In the server project, add a new class file named NewUser.
2. Define the properties for registering a new user by adding the following code to the NewUser class.

   ```
   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
   ```

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

   The ConfirmPassword property in the previous step is defined with a CustomValidationAttribute attribute. In the attribute, it specifies a RegistrationValidator class and a method named IsPasswordConfirmed. You must now define this custom validation class.
3. Add a new class named RegistrationValidator.shared.cs or RegistrationValidator.shared.vb.
4. Add the following code to the RegistrationValidator.shared file.

   ```
   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
   ```

   ```csharp
   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.");
               }
           }
       }
   }
   ```
5. Add a new item to the server project and select the Domain Service Class template.
6. Name the file RegistrationDomainService.cs or RegistrationDomainService.vb and then click the **Add** button.
7. In the Add New Domain Service Class dialog box, select **\\** from the **Available DataContexts/ObjectContexts** list.
8. Click **OK**.
9. To create a domain operation that adds a new user through the Membership framework and saves a profile property, add the following code to the RegistrationDomainService class.

   The GetUsers method must be included to ensure that the NewUser entity class is generated for the client project. Only classes that are exposed through a public query operation are generated in the client project.

   After creating the user, the profile property named DefaultRows is set. In this case, the profile property is set as part of the domain operation for creating a user. In a later section, you will add code to set the profile property from the client project.

   ```
   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 OpenRiaServices.Hosting
   Imports OpenRiaServices.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
   ```

   \`\`\` csharp namespace ExampleNavigationApplication.Web { using System; using System.Collections.Generic; using OpenRiaServices.Hosting; using OpenRiaServices.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();
        }
    }  
}
```
````

### To configure the client project for adding new users

1. Open the Home.xaml file.
2. After the end tag for the LoginBorderBorder control, add the following XAML to create a second Border control with input controls to collect information for creating new users.

   The controls accept values for user name, password, password confirmation, e-mail address, security question, security answer, and the number of records to show on reports. The number of records to display will be saved as a profile property. All of the other values are used to create the user through ASP.NET Membership framework.

   ```
   <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>
   ```
3. Open the Home.xaml.cs (or Home.xaml.vb) code-behind file.
4. Add a using or an Imports statement for the [OpenRiaServices.Client](https://github.com/OpenRIAServices/OpenRiaServices/tree/82784ac86a5b1cdd95b784ccdb3a00baefcaa7de/docs/ff422479.md), System.ComponentModel.DataAnnotations, and ExampleNavigationApplication.Web namespaces.
5. Add an event handler for the register button click event and add a callback method for domain operation. The callback method includes code to login the user after successfully creating the user account.

   ```
   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
   ```

   ```csharp
   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;
   }
   ```
6. Modify the SetControlVisibility method to set the visibility of RegisterBorder, as shown in the following code.

   ```
   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
   ```

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

   The following shows the complete code-behind file.

   ```
   Imports OpenRiaServices.Client.Authentication
   Imports OpenRiaServices.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
   ```

   ```csharp
   using System;
   using System.Windows;
   using System.Windows.Controls;
   using System.Windows.Navigation;
   using OpenRiaServices.Client.Authentication;
   using OpenRiaServices.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;
           }
       }
   }
   ```
7. Run the solution.

   ![RIA\_LoginandRegister](https://1585985709-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M_5pS6LfA6GSEBmCbd9%2Fsync%2F057d808743ecd490d94650f6065114b089f91f25.png?generation=1620474376164741\&alt=media)
8. Provide values to register a new user.
9. Close the Web browser.

## Restricting Access to Domain Operations

You restrict access to a domain operation by applying either the [RequiresAuthenticationAttribute](https://github.com/OpenRIAServices/OpenRiaServices/tree/82784ac86a5b1cdd95b784ccdb3a00baefcaa7de/docs/ff423107.md) attribute or the [RequiresRoleAttribute](https://github.com/OpenRIAServices/OpenRiaServices/tree/82784ac86a5b1cdd95b784ccdb3a00baefcaa7de/docs/ff422065.md) attribute to the domain operation. Domain operations without an attribute are available to all users. Applying an attribute to domain operation does not prevent the user from calling the domain operation; however, users without the required credentials will receive an exception.

### To restrict displayed data by roles

1. In **Solution Explorer**, select the server project and click the **Show All Files** button.
2. Right-click the App\_Data folder and select **Include in Project**.
3. Right-click the App\_Data folder, select **Add** and then **Existing Item**.
4. In the **Add Existing Item** dialog box, add the AdventureWorksLT sample database.
5. In the server project, add a new item and select the **ADO.NET Entity Data Model** template.
6. Name the model AdventureWorksModel.edmx and click **Add**.

   The **Entity Data Model** Wizard appears.
7. Select the **Generate from database** option and then click **Next**.
8. Select the AdventureWorksLT database and then click **Next**.
9. From the list of database objects, select the Customer, Product, and SalesOrderHeader tables, and then click **Finish**.

   The entity data model appears in the designer.
10. Build the solution.
11. In the server project, add a new item and select the **Domain Service Class** template.
12. Name the domain service AdventureWorksDomainService and then click **Add**.
13. In the **Add New Domain Service Class** dialog box, select the Customer, Product, and SalesOrderHeader entities.

    ![RIA\_CreateDSForAuth](https://1585985709-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M_5pS6LfA6GSEBmCbd9%2Fsync%2F7fc4a2c6d66b14c3a4f8df1baeccb2597fdcc1cc.png?generation=1620474373935873\&alt=media)
14. Click **OK** to finish creating the domain service.
15. In the AdventureWorksDomainService class file, add the [RequiresAuthenticationAttribute](https://github.com/OpenRIAServices/OpenRiaServices/tree/82784ac86a5b1cdd95b784ccdb3a00baefcaa7de/docs/ff423107.md) attribute to GetSalesOrderHeader method.

    ```
    <RequiresAuthentication()> _
    Public Function GetSalesOrderHeaders() As IQueryable(Of SalesOrderHeader)
        Return Me.ObjectContext.SalesOrderHeaders
    End Function
    ```

    ```csharp
    [RequiresAuthentication()]
    public IQueryable<SalesOrderHeader> GetSalesOrderHeaders()
    {
        return this.ObjectContext.SalesOrderHeaders;
    }
    ```
16. Add the [RequiresRoleAttribute](https://github.com/OpenRIAServices/OpenRiaServices/tree/82784ac86a5b1cdd95b784ccdb3a00baefcaa7de/docs/ff422065.md) attribute to the GetCustomers method, and set the name of the required role to "Managers".

    ```
    <RequiresRole("Managers")> _
    Public Function GetCustomers() As IQueryable(Of Customer)
        Return Me.ObjectContext.Customers
    End Function
    ```

    ```csharp
    [RequiresRole("Managers")]
    public IQueryable<Customer> GetCustomers()
    {
        return this.ObjectContext.Customers;
    }
    ```

    The GetProducts domain operation is available to any user, GetSalesOrderHeaders is available to authenticated users, and GetCustomers is available to only users in the Managers role.

    The following shows the complete domain service.

    ```
    <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
    ```

    ```csharp
    [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;
        }
    }
    ```

## Using the Authentication Service from the Client

Before calling a domain operation with restricted permissions, you should check that the user has the required credentials; otherwise, an exception is thrown. In this section, you will check the user's credentials and populate from one to three DataGrid controls based on the user's credentials. You will also retrieve the number of records based on a property in the user profile. A default value of 10 is used for users that are not authenticated. This section does not include a way for users to set the DefaultRows profile property, but you will add that in a later section.

### To add a Silverlight Page for displaying data

1. In the client project, add a new item to the Views folder.
2. Select the **Silverlight Page** template and name the new page Reports.xaml.
3. Open the MainPage.xaml file and add a link for the Reports page by adding the following XAML after the HyperlinkButton named Link2 that links to the About page.

   ```
    <Rectangle x:Name="Divider2" Style="{StaticResource DividerStyle}"/>

    <HyperlinkButton x:Name="Link3" Style="{StaticResource LinkStyle}" 
   NavigateUri="/Reports" TargetName="ContentFrame" Content="reports"/>
   ```
4. Open the Reports.xaml file, and add the following XAML inside the Grid tags to match the formatting of the other pages in the site, and to include a HyperlinkButton control that will launch a window for editing a profile property.

   ```
   <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>
   ```
5. Drag three DataGrid controls from the **Toolbox** to just before the end tag of the stack panel named ContentStackPanel.

   When you drag the DataGrid controls from the **Toolbox**, a reference to the System.Windows.Controls.Data assembly is added to the project and a prefix for the System.Windows.Controls namespace is added to the page.
6. Name the DataGrid controls ProductsGrid, SalesOrdersGrid, and CustomersGrid and set Margin to 5.

   The following example shows the complete Reports.xaml file.

   ```
   <navigation:Page 
         x:Class="ExampleNavigationApplication.Views.Reports"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
         xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"
         xmlns:mc="http://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>
   ```
7. Open the Reports.xaml.cs or Reports.xaml.vb file and add using or Imports statements for the OpenRiaServices.Client and ExampleNavigationApplication.Web namespaces.
8. Create an instance of the AdventureWorksDomainContext named context, and create a variable named numberOfRows that contains the number of rows to retrieve.

   ```
   Private context As New AdventureWorksDomainContext
   Private numberOfRows As Integer = 10
   ```

   ```csharp
   private AdventureWorksDomainContext context = new AdventureWorksDomainContext();
   int numberOfRows = 10;
   ```
9. Add a method named LoadRestrictedReports that calls the GetSalesOrderHeaderQuery method and the GetCustomersQuery method, if the user belongs to the Managers role, and populates the corresponding data grids with the results.

   If you call a domain operation when the user does not have the required credentials, the domain operation returns an exception. You can avoid this situation by checking the credentials before calling the domain operation.

   ```
   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
   ```

   ```csharp
   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;
       }
   }
   ```
10. Add a method named LoadReports that checks whether the user is authenticated and, if so, calls LoadRestrictedReports method. It also retrieves the profile property named DefaultRows and adds an event handler for the PropertyChanged event on the User object. Finally, it calls the GetProductsQuery method for all users.

    ```
    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
    ```

    ```csharp
    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;
    }
    ```
11. Add an event handler for the [PropertyChanged](https://github.com/OpenRIAServices/OpenRiaServices/tree/82784ac86a5b1cdd95b784ccdb3a00baefcaa7de/docs/ff422749.md) event that calls LoadReports if the property DefaultRows has changed.

    ```
    Private Sub User_PropertyChanged(ByVal sender As Object, ByVal e As System.ComponentModel.PropertyChangedEventArgs)
        If (e.PropertyName = "DefaultRows") Then
            LoadReports()
        End If
    End Sub
    ```

    ```csharp
    void User_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
    {
        if (e.PropertyName == "DefaultRows")
        {
            LoadReports();
        }
    }
    ```
12. Add the following code to the constructor. This code loads the reports and makes the settings link visible for authenticated users.

    ```
    Public Sub New()
        InitializeComponent()
        LoadReports()
        If (WebContext.Current.User.IsAuthenticated) Then
            SettingsButton.Visibility = System.Windows.Visibility.Visible
        End If
    End Sub
    ```

    ```csharp
    public Reports()
    {
        InitializeComponent();
        LoadReports();
        if (WebContext.Current.User.IsAuthenticated)
        {
            SettingsButton.Visibility = System.Windows.Visibility.Visible;
        }
    }
    ```
13. Add an event handler for the Click event on the settings link.

    The ProfileWindow will be added in a later step.

    ```
    Private Sub SettingsButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
        Dim settingsWindow = New ProfileWindow()
        settingsWindow.Show()
    End Sub
    ```

    ```csharp
    private void SettingsButton_Click(object sender, RoutedEventArgs e)
    {
        Views.ProfileWindow settingsWindow = new Views.ProfileWindow();
        settingsWindow.Show();
    }
    ```

    The following shows the complete code file.

    ```
    Imports OpenRiaServices.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
    ```

    ```csharp
    using System;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Navigation;
    using OpenRiaServices.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();
            }
        }
    }
    ```

You can allow users to edit the DefaultRows profile property by adding child window. When the value is changed, you call the [SaveUser](https://github.com/OpenRIAServices/OpenRiaServices/tree/82784ac86a5b1cdd95b784ccdb3a00baefcaa7de/docs/ff457896.md) method to save the value in the data source. You retrieve the current value through the properties on the User object of the current WebContext instance.

### To add a window for setting profile property

1. In the client project, add a new item to the Views folder.
2. Select the **Silverlight Child Window** template and name it ProfileWindow\.xaml.

   ![Add Child Window](https://1585985709-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M_5pS6LfA6GSEBmCbd9%2Fsync%2F6326bf76b42e621d9204e36a309d55fae7f537be.png?generation=1620474374749760\&alt=media)
3. Click the **Add** button.
4. In the ProfileWindow\.xaml file, add the following XAML to include a ComboBox for selecting the number of rows to display in the reports.

   ```
   <controls:ChildWindow x:Class="ExampleNavigationApplication.Views.ProfileWindow"
              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
              xmlns:x="http://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>
   ```
5. In the ProfileWindow\.xaml.cs or ProfileWindow\.xaml.vb code-behind file, add the following code to retrieve and set the profile property.

   ```
   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
   ```

   ```csharp
   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;
       }
   }
   ```
6. Run the solution.
7. Click the **reports** link.

   Notice that when the site starts and you are not logged in, only the products table is displayed on the Reports page.
8. On the Home page, register and log in as a new user.
9. Click the **reports** link.

   Notice that the tables for products and sales orders are displayed.
10. Log out, and log in as CustomerManager.

    Notice that the tables for products, sales orders, and customers are displayed.
11. Click the **Adjust Settings** link and set the default number of rows to show for the reports.

    ![RIA\_ShowProfileSettings](https://1585985709-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M_5pS6LfA6GSEBmCbd9%2Fsync%2F8c5a5bd9ffba09c2fc14d4f489e7fff664179074.png?generation=1620474375526538\&alt=media)

    Notice that the DataGrid now contains the number of rows you selected.
12. Close the Web browser.

## See Also

#### Tasks

[Walkthrough: Using Authentication Service with Silverlight Business Application](https://openriaservices.gitbook.io/openriaservices/ee707361/ee942449)
