Exercise 1: Single Sign on, Claims-Driven Experience and Service Authorization for In-Browser Silverlight applications

In the first exercise of the lab you will deal with a Silverlight application designed to be hosted in a browser. The application has been developer for Fabrikam Gym, a health club franchise, and is intended to enhance the experience of the club members and help them to get the most from their membership. Identity is central to the application, as summarized by the three requirements below:

  • You need to ensure that only club members can use the application
  • The application look & feel must reflect the characteristic of the current user, so that every member has the feeling that is custom-tailored to his or her needs
  • What can be done with the application must reflect the membership level: gold members pay a premium, hence they enjoy a wider range of features

All those activities would normally require you to write a great deal of code, both difficult to develop and maintain. With claims-based identity, however, you can avoid the problem by literally telling your application to outsource the authentication operations to some external entity (called identity provider, or IP, in identity jargon) that has your trust. Claims-based identity describes standard ways of exposing authentication operations and data, which can be consumed by one application just like a printer driver can be used for printing pages (even without really knowing the details of the specific printer model available). Windows Identity Foundation (WIF) is what enables you, the developer, to tap into the claims-based identity model without really having to know the details of the underlying security protocols. As of today WIF and Silverlight are not entirely integrated, hence the abstractions boundaries aren’t perfect: however the lab provides some ready code tor taking care of the bulk of the work.

Your first job is to create a Silverlight application and outsource its authentication to the Fabrikam IP. With the authentication taken care of, you will learn how to use the claims from the IP to drive the behavior of the application UI. Finally, you will use the same information on the application services for enforcing authorization criteria without having to touch the services authorization logic.

Figure 2

A visual summary of the scenario you will build in Exercise 1

Task 1 – Creating a Silverlight Application

In the first task you will create a Silverlight application. This is mainly for providing the project structure: later in the lab we will supply you with a ready UI.

  1. Open Microsoft Visual Studio 2010 with administrator privileges. From Start | All Programs | Microsoft Visual Studio 2010, right-click on Microsoft Visual Studio 2010 and select Run as administrator.
  2. In the File menu, choose Open and then Project/Solution.
  3. In the Open Project dialog, navigate to Ex1-InBrowserApplications\Begin folder inside the Source folder of this lab. Select the InBrowserApplications.sln file and click Open.

    Figure 3

    Opening Ex01 Begin Solution

  4. The initial solution looks like the following:

    Figure 4

    Begin Solution structure

    Note:
    You start exercise 1 with three initial assets. Here there’s an explanation of what they contains: note that for the purposes of completing the lab you don’t need to understand (or even know) what is in there, although you can feel free to take a peek if you are curious about the internals. As the integration between WIF and Silverlight goes forward, the need for the last two assets will wane.

    GymFabrikamP_Sts represents, in identity jargon, Fabrikam’s identity provider (IP). One IP is one web service or web site which knows about a set of users, is able to authenticate them and make statements about them (claims). Claims can be literally anything that defines the user in the context, from personal attributes such as name and address to traditional roles. The IP exposes those capabilities through a standard programmatic interface endpoint, commonly called Security Token Service (STS). Having an IP factors out authentication management from all the applications that are used by the user population it serves: now every application can outsource authentication to it, instead of having to write its own code. That’s exactly what you are going to do in this exercise. Thanks to WIF tooling it will be really easy!

    SL.IdentityModel is an assembly containing the claims object model you will use from your application. WIF’s assembly DLL is not present in Silverlight, hence for the purpose of this exercise we provided a provisional assembly that allows you to use a subset of the same programming model

    SL.IdentityModel.Server is another assembly which contains logic that can trigger authentication when necessary and handles communications with the website hosting the Silverlight application

  5. You will now create the “GYM Fabrikam” website that will host the Silverlight client. Right-click the solution and select Add | New Web Site.
  6. In the Add New Web Site dialog, select the ASP.NETEmpty Web Site template, set the location to https://localhost/GymFabrikamClientWebEx01 and press OK.

    Figure 5

    Creating an empty Web Site

  7. Right-click the solution again, but this time, select Add | New Project.
  8. In the AddNew Project dialog, expand Visual C# in the project types list and select Silverlight.
  9. In the Templates list, select Silverlight application. Enter GymFabrikamClient as project name and click OK to create the project.

    Figure 6

    Adding a new Silverlight application

  10. In the New Silverlight application dialog, select the GymFabrikamClientWebEx01 web site to host the Silverlight application. Also, make sure that the Silverlight Version is Silverlight 4. Click OK to add the new Silverlight application to the solution.

    Figure 7

    Configuring Silverlight application to be hosted on GymFabrikamClientWebEx01

  11. Add a reference to the SL.IdentityModel.Server project on the https://localhost/GymFabrikamClientWebEx01 project. To do this, right-click it in the Solution Explorer and select Add Reference. In the Add Reference dialog, click the Projects tab, select the SL.IdentityModel.Server project and press OK.

    Figure 8

    Adding a reference to SL.IdentityModel.Server on https://localhost/GymFabrikamClientWebEx01

  12. Add a reference to the SL.IdentityModel project but this time, on the GymFabrikamClient project. To do this, right-click the GymFabrikamClient project in the Solution Explorer and select Add Reference. In the Add Reference dialog, click the Projects tab, select the SL.IdentityModel project and press OK.

    Figure 9

    Adding a reference to SL.IdentityModel on GymFabrikamClient

  13. In the https://localhost/GymFabrikamClientWebEx01 project, delete the GymFabrikamClientTestPage.html page. To do this, right-click it, select Delete and confirm the deletion dialog.
  14. Right-click the GymFabrikamClientTestPage.aspx page and select Rename. Set the new name to Default.aspx and press Enter.

Task 2 - Externalizing Authentication to an Identity Provider

You are now going to use the WIF tooling for configuring your application to outsource authentication to the Fabrikam identity provider, represented by the https://localhost/GymFabrikamP_Sts web site. To be more precise, you will apply the configuration to the web site which hosts the application, https://localhost/GymFabrikamClientWebEx01.

  1. Right-click the https://localhost/GymFabrikamClientWebEx01 project and select Add STS reference.
  2. The Federation Utility wizard window will be displayed. Leave the default values on the first screen, which are simply references to which configuration file will be modified, and press Next.

    Figure 10

    Federation Utility Welcome page

    Note:
    Note through the wizard you will encounter many options for which we are simply going to accept the defaults and move forward. We are not going to give details about those: if you are interested in a deeper discussion about those, please consider going through the Web Sites and Identity and Web Services and Identity labs in the Identity Developer Training Kit.

  3. A ready-to-use IP was provided as part of the initial solution, hence you need to select the Use an Existing STS option. Set the metadata document location to https://localhost/GymFabrikamP_Sts and press Next.

    Figure 11

    Using existing STS to federate https://localhost/GymFabrikamClientWebEx01

  4. In Security token encryption, choose No encryption and press Next to continue with the wizard.

    Figure 12

    Configuring No encryption for the communication with the STS

  5. Press Next in the Offered Claims Wizard step.

    Figure 13

    Showing Offered claims by the STS

    Note:
    Those are the claims we are going to get about the current user, upon successful authentication. The identity provider knows the value of those attributes for every user, and packages them into claims that are delivered to the application as soon as the user successfully authenticated. That means that you don’t need to store any user profile if you don’t want to, since everything the application needs to know about the user is provided at every logon.

  6. Check the Wizard summary, and press Finish.

    Figure 14

    Checking the Federation Utility Summary

  7. Open the web.config file of the https://localhost/GymFabrikamClientWebEx01/ project by double-clicking it in the Solution Explorer.
  8. Add the following validation element inside the system.webServer section:

    XML

    <configuration>
    FakePre-1f5b24733ef8483a8e411a78bc7e77a6-f096b5e3a9af447f85a3d313f31ecd4eFakePre-6450471487e34cd39c282626b6805588-b808adb712fa4083b3ae341f2c9b02f4 <validation validateIntegratedModeConfiguration=”false” />FakePre-293e380a495f47eb965411f80e68d32f-11064f1309e246eb896cb0ec8c95385eFakePre-b1da0a8062f842bda1a6e7bab7d19294-67b3ca2cc19240ccbe8c3286b83fba7fFakePre-5a69ac30fdbf4405bd5de01334f350f3-ec3e621a457743bca2680c0ebacfb0e3FakePre-53f7d623ca9b491c9317b32823d10358-4c50b07144dd43d69f01c5a41cad0703FakePre-04fc970427a14502aa435c636394484d-7aa16e9cdac64e49b682680725af8749FakePre-2b3191d5799e42b4b182b91e2ec66f90-9b33c340612a49b685d7e2d0d7d50459

  9. At this point, your solution should look like the following:

    Figure 15

    Current solution structure

  10. You have finished configuring the https://localhost/GymFabrikamClientWebEx01 project to be federated with the Gym Fabrikam STS. To test how it works, right-click the https://localhost/GymFabrikamClientWebEx01 project and select Set as StartUp Project.
  11. Press Ctrl +F5 to run the web site. Your default browser should be launched displaying the STS’s login page. Leave the default credentials (john) and press Submit.

    Figure 16

    STS’s login page

    Note:
    The wizard you just went through configured the website to redirect unauthenticated users to the STS pages. Here the STS can do whatever it deems necessary for authenticating the user, in this case the auto-generated STS presents a fake username/password form. Once the user successfully authenticated, the outcome of the authentication and the claims are packaged and sent back to the original site. Here they are verified, and if everything looks OK the user is granted access to the page and its content (including the Silverlight application).

  12. You will be redirected to the Default.aspx page of the https://localhost/GymFabrikamClientWebEx01 web site which hosts the Silverlight application. Since it is not implemented yet, you will see a blank page.

    Figure 17

    The empty UI of the Silverlight application inside the Default.aspx page

  13. Close the browser.

Task 3 – Making Claim Values Available to the Silverlight Application

There is a little catch in what we have done so far. The Federation Utility Wizard configured the website hosting the Silverlight application to outsource authentication to the Fabrikam’s IP; and given the fact that without authenticating to the web site you can’t get to the Silverlight app, the latter ends up being protected by the same mechanism. However that means that the claims about the user, issued by the IP upon successful authentication, are sent to the web site rather than the Silverlight client. Claims travel in specialized structures, called Security Tokens, which may be encrypted; in that case the intended recipient, the web site, can decipher the token and read the claim but for anybody else (including the Silverlight app) those are unreadable gibberish. That works well when the consumer of the claims is a traditional web site or web service, but that’s not our case here.

If we want to have access to the claim values from the Silverlight app, we have to ask to the web site (the actual recipient of the claims) to communicate them back to the client. That’s what you are going to do in this task.

  1. Right-click the https://localhost/GymFabrikamClientWebEx01 project and select Add New Item. In the Add New Item dialog, select the Silverlight-enabled WCF Service template, set the name to AuthenticationService.svc and click Add.

    Figure 18

    Adding the AuthenticationService Silverlight-enabled WCF Service

  2. The SL.IdentityModel.Server project provides as initial asset contains a class which will be used as implementation of the AuthenticationService service. In this case, the service will be used by the Silverlight app for obtaining the value of the user claims from the web site. Double-click the AuthenticationService.svc file inside the https://localhost/GymFabrikamClientWebEx01 project and replace its content with the following code:

    XML

      <%@ ServiceHost Language="C#" Debug="true" Service="AuthenticationService" CodeBehind="~/App_Code/AuthenticationService.cs" %>
    
    <%@ ServiceHost Language="C#" Debug="true" Factory="SL.IdentityModel.Server.AuthenticationServiceServiceHostFactory" Service="SL.IdentityModel.Server.SL.IdentityModel.Server" %>

  3. When you added a new service, Visual Studio created the AuthenticationService.cs file inside the App_Code folder of the https://localhost/GymFabrikamClientWebEx01 project. Normally you would use AuthenticationService.cs for implementing the service logic, however AuthenticationService.svc points to the service implementation provided in the SL.IdentityModel.Server project, hence you don’t need the .cs file anymore. Right-click on AuthenticationService.cs inside the App_code folder, select Delete and confirm the deletion dialog.

    Figure 19

    Deleting the AuthenticationService.cs file

  4. Enable anonymous access to the AuthenticationService service by adding the following element on the web.config file of the https://localhost/GymFabrikamClientWebEx01 project.

    (Code Snippet – SilverlightAndIdentity Lab - Ex01 AuthenticationService location element)

    XML

    <connectionStrings />
    FakePre-0af995447113422a9e1d468d9849c587-cf18fd82f45f4b8584173f80d222edb5FakePre-858ba6c30e3b4cd5b25d8b10be190b7b-8f0031759a6d498d9821fbf19765b65aFakePre-50d4248cbe804462bcd522583c2c538b-685bfbcb89734b898268bb936336df1a<location path="AuthenticationService.svc"> <system.web> <authorization> <allow users="*"/> </authorization> </system.web> </location>FakePre-dea3f59e8f614b8d9a8c9fb541f58aa3-5bfc9d82cf4a4f39b88e77aace775b84FakePre-c22736dc06ff4361a15391756cd9dc37-c08b8ef280924a5bb866f3a57fbfe8fdFakePre-d77922f8c00349029d0aa2057cb8e37d-921da57f9eac474c9a177d2cdb0717a3

  5. Inside the GymFabrikamClient project, open the App.xaml file by double-clicking it in the Solution Explorer.
  6. Update the content to use the SL.IdentityModel.Services namespace.

    Note:
    As it was explained on the overview, code snippets for XAML have a different header specifying the path of a txt file that contains the code that you should add to the solution.

    To use them, navigate to the folder that the header specifies, open the txt file, copy the content and paste it on Visual Studio.

    (Source\Assets\XAML Code Snippets\Ex01 SL.IdentityModel.Services namespace.txt)

    XAML

    <Application xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    FakePre-6d6c242699cb4d46804eceee4bf1dddc-e9834cec794b4e2ea20b24147f7ec9b4FakePre-722daa816b1148d6af81874940c30658-ee885e356989454d9bc1ff31b4efe7e9 xmlns:id="clr-namespace:SL.IdentityModel.Services;assembly=SL.IdentityModel">FakePre-4e4d6f2ffaff42209fd0c7d916b87734-d1bf0a2766c143c4b0ea1f7e762d8578FakePre-a55c764fdb5a485890b4c0bc5a94b30a-defc2034ca05443488cbfc9202e2c2c7FakePre-7d066619cea14af5996649b22c0c1344-40e4ddcc700845e4ab1e73032e945b5cFakePre-0be1c1d71852427ab936c31d3eb158e0-cacb0f88df0f4993a5b5dc696952127e

  7. Add a ClaimsIdentitySessionManager application service inside the Application.ApplicationLifetimeObjects section.

    (Source\Assets\XAML Code Snippets\Ex01 ClaimsIdentitySessionManager for Passive STS.txt)

    XAML

    <Application xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    FakePre-e58e7049437c46bf84809c424cb97c08-731a099144364eedadbc803dce2cec31FakePre-642352c93cb44f969ae3b12931f18867-5fdaf473142f439f9e941b723e0543e8FakePre-206b2faae02b4216bd0f0688a7d3c191-e6c5bff4b8074250b0a94dae3350b570FakePre-8c4aedd8bbad4ac5b108e184e34f61d5-9fc5de84d93c45edb189c0919efc386cFakePre-a8f53df2064a4fb6a8ad56c33fcb6fbd-990d4253bf1d4f009bbfa800ca3af0fcFakePre-61371fb0ba0b4711a25a6c0e01450d37-34b1bdb283ff44428714640cbf3ceda4FakePre-c7b39f00abb44f359b4b8af1e0f6c47b-458934e4f2e44516bb8f3442f785662a <Application.ApplicationLifetimeObjects> <id:ClaimsIdentitySessionManager> <id:ClaimsIdentitySessionManager.IdentityProvider> <id:WSFederationSecurityTokenService/> </id:ClaimsIdentitySessionManager.IdentityProvider> </id:ClaimsIdentitySessionManager> </Application.ApplicationLifetimeObjects>FakePre-43709327699946d6a22e0dfa677073c3-886ae531a1f446c79eb5366711b49f60
    Note:
    The ClaimsIdentitySessionManager class registers an object in the application resources which will be used for accessing claims from anywhere in the app. The property IdentityProvider indicates from where we expect claims to originate from. In this case, we expect the hosting web site to take care of outsourcing authentication to the identity provider; later in the lab the Silverlight application will have to handle the relationship with the IP directly, in which case the IdentityProvider property will be set to an object which contains more information about the IP.

  8. You will now replace the current MainPage.xaml file with one provided with the lab, already predisposed to take advantage in the UI of the claims about the user. Delete the current MainPage.xaml file by right-clicking it inside the GymFabrikamClient project, selecting Delete and confirming the deletion dialog.
  9. Add the new MainPage.xaml from the Assets folder of this lab. Right-click the GymFabrikamClient project and select Add | Existing Item. In the Add Existing Item dialog, navigate to the Assets\GymFabrikamClient folder and select the MainPage.xaml file. Press Add to include it in the project.

    Figure 20

    Adding the improved MainPage.xaml version

  10. The improved version of the Mainpage.xaml file uses some images that should be placed inside an Images folder. Right-click the GymFabrikamClient project and select Add | New Folder. Set its name to Images and press Enter.
  11. Add the required images by the Gym Application’s UI to the recently created folder. To do this, right-click the Images folder and select Add | Existing Item. In the Add Existing Item dialog, navigate to the Assets\GymFabrikamClient\Images folder and select all the files available there. Press Add to include them inside your Images folder.

    Figure 21

    Adding the required images for the improved UI

  12. Open the MainPage.xaml Code-Behind. To do this, right-click the MainPage.xaml file inside the GymFabrikamClient project and select View Code.
  13. Add the following code to the ShowUserInfo method to update the UI based on the user’s gender and show his/her name.

    (Code Snippet – SilverlightAndIdentity Lab - Ex01 ShowUserInfo method 1)

    C#

    private void ShowUserInfo()
    FakePre-925f9b0452ab4670804a70662ccecf50-721b97747e1248c888dc0e5427a5953e if (ClaimsIdentitySessionManager.Current.User.Identity.IsAuthenticated) { // Gender Claim genderClaim = ClaimsIdentitySessionManager.Current .User .ClaimsIdentity .Claims .Where<Claim>(c => c.ClaimType == ClaimType.Gender) .SingleOrDefault(); this.UpdateBackgroundColor(genderClaim.Value); // User name string userName = ClaimsIdentitySessionManager.Current.User.Identity.Name; this.userNameLabel.Text = string.Format("Hi {0}!", userName); }FakePre-d5455bc190ab4ad695fe97649ae0d63f-c1659b6c11d54263affd987c1f40383cFakePre-629b4269af264fca8f2e42d19e632556-eddb69c409bf426cb31a23091d63c01dFakePre-2159eb4dd32442749077c0d1eb9a6031-ee026c2c87344cc1a163a372b16787b8
    Note:
    The Current_GetClaimsIdentityComplete handler fires when all the claims have been received. Claims contain information about your user, which you can easily use for customizing the appearance of the UI and deliver a personalized experience. The current implementation calls directly to the ShowUserInfo method.

    The first line of the ShowUserInfo method shows how you can use a LINQ query on the claims collection for extracting a specific attribute, in this case the gender of the user, and drives the background color with that. Note that here you are not exposed to any of the details of how the user authenticated, or which protocol was used to obtain the claim values: your code is decoupled from those details, saving you from the hassle of having to know about security and making your application resilient to external changes. There’s more: this is practically the same code you would write in other kind of applications, like web sites or web services. Once you learn how to use claims, you can reuse the skill practically everywhere.

    The last two lines show how certain claims, like the name, can be accessed directly.

  14. Now that you understand how to work with claims, let’s make things more interesting. Insert the following code below the last line inserted above to show the user’s picture, heart rate at rest, maximum lift and enable the trainingSessionsButton button only if the current user is purchased a Gold membership to the gym.

    (Code Snippet – SilverlightAndIdentity Lab - Ex01 ShowUserInfo method 2)

    C#

    private void ShowUserInfo()
    FakePre-c2cbe05389b344d288c72b628c56f0db-0ad58b24a7534153be181679f03caf44FakePre-08d1342fbba44cf2a4e2f35b32c17b49-398f9621cc584d87accfbda6e8c2c4dcFakePre-3dc697f840b747d6990dae09fca08df3-d45b7d405574463c8e395e6dcff59c04FakePre-c422984b0d0146a5acd63e3f9e59ba41-00fc24ad81714c329ddafb4b7f4747c8FakePre-7155904e649f4177b0b23948154220ad-69f6d643f16b4bfd9a27b1ab97b8a519FakePre-5d6bf6a7465d4641a1c2c623c2499ceb-841ddca839af4d6085e6424cf9a7b72c // User picture Claim userPictureClaim = ClaimsIdentitySessionManager.Current .User .ClaimsIdentity .Claims .Where<Claim>(c => c.ClaimType == UserPictureClaimType) .SingleOrDefault(); this.userImage.Source = GetBitmapSourceFromBase64(userPictureClaim.Value); // Heart Rate at Rest Claim hrRestClaim = ClaimsIdentitySessionManager.Current .User .ClaimsIdentity .Claims .Where<Claim>(c => c.ClaimType == HeartRateAtRestClaimType) .SingleOrDefault(); this.hrRestLabel.Text = string.Format("HRrest = {0} bpm", hrRestClaim.Value); // Maximum Lift Claim maximumLiftClaim = ClaimsIdentitySessionManager.Current .User .ClaimsIdentity .Claims .Where<Claim>(c => c.ClaimType == MaximumLiftClaimType) .SingleOrDefault(); this.UpdateMaximumLiftInfo(int.Parse(maximumLiftClaim.Value)); // Membership Claim membershipLevelClaim = ClaimsIdentitySessionManager.Current .User .ClaimsIdentity .Claims .Where<Claim>(c => c.ClaimType == MembershipLevelClaimType) .SingleOrDefault(); if (membershipLevelClaim.Value == "gold") { this.trainingSessionsButton.IsEnabled = true; } else { this.goldMembershipOnlyLabel.Visibility = Visibility.Visible; } this.ShowControls();FakePre-af927726f9664621b405bdb9ce3bde51-a7cd70385fa14335aea0246ab310b920FakePre-4778e9341c7f419180afa7e5f7c7a056-cba63b5daffc4db68085e8e515a0d32aFakePre-3557a12ba8c640f9b284dfaccb2477f6-6d4c016a9dc04953a46a9ecaacf3b03fFakePre-765ea245e25e4d2e92e69dd3e322b001-53e4b33a490d493490f2c20c7ef40251FakePre-631ee8c1718b43a8a9d129eed6a3e2c0-bfe44fdaaf7d4a2b9524e40dea13dc8d
    Note:
    Do not think, even for a small second, that disabling the trainingSessionsButton button is equivalent to perform authorization! The reason for which we do that is that we want to guide the user though the application experience, and we want to make sure that he or she is aware of the fact that the corresponding operation is not available. However you still need to enforce the gold membership condition at the service, otherwise something as simple as creating a different client (or somehow fooling the UI) would suffice for circumventing the condition.

  15. Your Silverlight application is ready to run. You will verify it by running again the Web site that host the Silverlight application. Press Ctrl +F5 to run the Web Site. In the STS’s login page, press Submit to login as “john”.

    Figure 22

    Login as “john” on the STS’s login page.

  16. The improved Silverlight application will be shown and it is automatically customized based on the john’s claims. Also, since John is a gold member of Gym Fabrikam, he is able to click the Get Training Sessions. The button has still no effect, we will be providing the associated implementation a bit later.

    Figure 23

    Silverlight application customized based on John’s claims.

    Note:
    This time the appearance of the application reflects the user attributes, as established by the claim processing code you wrote. There is quite a lot of activity under the hood leading to that; for the ones who are interested in understanding how the process unfolds, here there’s quick summary. The ClaimsIdentitySessionManager detects that successful authentication took place. It is configured with the WSFederationSecurityTokenService type of IP, which implies that the token with the claims is available at the web site which hosts the Silverlight application. Hence ClaimsIdentitySessionManager invokes the AuthenticationService you previously added to the web site, and uses it for retrieving the claim values. Once the claim values are successfully retrieved, the GetClaimsIdentityComplete event is raised, giving you a chance to use the claims in your application as shown in step 12.

  17. Close the browser and press Ctrl+F5 again to start a new instance of the Web Site. In the STS’s login page, set the User name to “mary” and press Submit.

    Figure 24

    Login as “mary” on the STS’s login page

  18. The Silverlight application will be shown again but this time you will notice how the UI changed based on the claims issued for Mary: the background is pink, the dumbbell icon is different, and so on. The Get Training Sessions button is disabled, since Mary is not a gold member.

    Figure 25

    Silverlight application customized based on Mary’s claims

  19. Close the browser.

Task 4 – Creating a Silverlight-Enabled WCF Service and Consume It from the Silverlight application

Our presentation layer is practically ready. What is still missing is the service layer, that is to say the server-side logic which implements the actual application behavior.

As mentioned in the exercise introduction, the purpose of the application is to help members to get the most from their gym experience. In order to achieve that, the application is going to provide the following functionalities:

  • Show news about the gym in a sort of digital corkboard
  • Only for gold members, show the recordings of their heart rate for every training session (on the treadmill and outdoor) so that they can track their progress

Both functions are implemented by exposing a Silverlight-enabled WCF service, hosted in the same web site as the Silverlight application. We will need to flow identity information, so that the appropriate authorization enforcement can take place.

  1. Right-click the https://localhost/GymFabrikamClientWebEx01 project and select Add New Item. In the Add New Item dialog, select the Silverlight-enabled WCF Service template, set the name to GymService.svc and click Add.

    Figure 26

    Adding the GymService Silverlight-enabled WCF Service

  2. In the interest of time, one implementation for the service is provided for you as lab asset. Remove the GymService.cs file inside the App_Code folder of the https://localhost/GymFabrikamClientWebEx01 project. Right-click GymService.cs, select Delete and confirm the deletion dialog.
  3. Right-click the App_Code folder inside the https://localhost/GymFabrikamClientWebEx01 project and select Add Existing Item. In the Add Existing Item dialog, navigate to the Assets\GymFabrikamClientWebEx01 folder inside the Source folder of this lab. Select the GymService.cs and Contracts.cs files and press Add.

    Figure 27

    Adding the GymService implementation and its contracts

  4. Double-click the GymService.cs file that you just added to the App_Code folder. Check the implementation and notice that there is not authentication code inside the different methods.

    C#

    [ServiceContract] [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)] public class GymService { [OperationContract] public IEnumerable<TrainingSession> GetTrainingSessions() { List<TrainingSession> trainingSessions = new List<TrainingSession>(); trainingSessions.Add( new TrainingSession { SessionId = new Guid("8EF3B2A8-88E2-45fc-8F4C-AE97B6D588C7"), SessionDate = DateTime.Now.AddDays(-1).AddHours(5).AddMinutes(4).AddSeconds(3), Time = TimeSpan.FromMinutes(60), Distance = 5.44, AverageHR = 137, MaxHR = 151, HrGraph = }); ... return trainingSessions.OrderByDescending(s => s.SessionDate); } [OperationContract] public IEnumerable<Announcement> GetAnnouncements() { List<Announcement> announcements = new List<Announcement>(); announcements.Add( new Announcement { Title = "Save up to 40% on your gym membership", Date = DateTime.Now.AddDays(-5).AddHours(8).AddMinutes(10).AddSeconds(25), Description = "New Year is the time when many people decide to join a gym, or revisit a neglected gym membership, so now is a good time to return to GYMFabrikam and get 40% off." }); ... return announcements.OrderByDescending(a => a.Date); } }
    Note:
    The service serves back some hardcoded data. The most notable thing is that… there is nothing notable! The service does not contain ANY logic for enforcing authorization checks, and just performs the business function it has been designed to: serving a list of announcements and a list of training sessions recordings. As service developer you don’t need to worry about authorization details: they will be taken care of outside of the proper service code, as you will see few steps ahead. Another obvious advantage of this approach is that the authorization policies can be changed to adapt to different deployments and changing requirements without having to touch the service code itself.

  5. The provided version of the GymService uses some images as heart rate graphs that should be placed inside a Graphs folder. Right-click the https://localhost/GymFabrikamClientWebEx01 project and select New Folder. Set its name to Graphs and press Enter.
  6. Add the required images by the GymService to the recently created folder. To do this, right-click the Graphs folder and select Add Existing Item. In the Add Existing Item dialog, navigate to the Assets\GymFabrikamClientWebEx01\Graphs folder and select all the files available there. If you don’t find the images inside the folder, make sure that the Image Files filter is selected. Press Add to include them inside your Graphs folder.

    Figure 28

    Adding the required images for the GymService

  7. Update the service binding to use https and allow cookies. To do this, Open the web.config file inside the https://localhost/GymFabrikamClientWebEx01 project and replace the httpTransport element for an httpsTransport allowing cookies inside the binding named GymService.customBinding0 like is shown below.

    (Code Snippet – SilverlightAndIdentity Lab - Ex01 httpsTransport element)

    XML

    <system.serviceModel>
    FakePre-d3125a34915a4f91946232a69b26f6d4-371c92a80ab54e828acf6ddc2cc4c412FakePre-768b702841e343ffb8e0699f1a648dd8-c3a853fca64d4cbfa394a4923fa427f6FakePre-f1da68aa6a614e9cb33a4b404500244f-b8f62d0900c1449796344ad8a3cf403bFakePre-4b65129afd554ffcaad035284b4df578-7f803a593a9c4488b62c518cec02fd7bFakePre-67df6e179e164699b8520aab670399a5-0d20213c71a74a76a8f5dbdb4ea2451aFakePre-766997f2916a4957b024e37586bc3a75-1c49a34947a74c9f8893f93d16bfbac6FakePre-28c9d0273d7143de9099a8d4b52b5f91-9201fd46fb1245c5949fa26428e6585aFakePre-83e63dddfb9348c682d38b8896e90b93-bb539bc2685e445a95f241f06281f14bFakePre-f777370a23f545d6badd42a0d7bc974f-b2de4ce760ec491da327847e1bc39033FakePre-0a32ab652b47463ca0501f377a084c30-f2154124817049cd8d372f6f838227b0FakePre-b524f5601dfd4aeb8beb0ad18f6c54cb-f1c4e4d8d1f74baeac0b043e1dac5befFakePre-c6e749fc542043d0b35577523e100d75-9bfda766c5b04112b053a0a9656980e6 <httpsTransport allowCookies="True"/>FakePre-c967f6b672c64f3c831bca174ac22c74-5748218eb42b47aca6567fbe145fbfa9FakePre-c19e03c1c1684b618222249de1b783b5-d7df95ce855446a989dd95efebea8e8fFakePre-669466a2049f4c6b9541136d0011c690-2e87df5a18614decad3a599bcf9ea44eFakePre-0fffc1189d604e1c8fd5448e43fbcfd4-92e4c0a0daea4606840b4dfd62b13be4FakePre-c0c955040af74957a80877071188cb82-ef10181ef4d247fe9fdad51f89f08541
    Note:
    We need HTTPS for obvious reasons, the application is handling personally identifiable information (PII) hence we need to protect data in transit. We allow cookies for a different reason. When a user obtains a security token and presents it to the web site at authentication time, WIF generates a cookie which is used to maintain the security session. The cookie contains, among other things, the claims obtained from the IP. Enabling cookies allows the WCF services hosted on the same websites to have access to the same cookie, hence to the claim values; in turn, this makes possible for WIF to enforce authorization conditions on service access according to claim values, exactly what we wanted to obtain.

  8. In analogy to what you did for the AuthenticationService service, enable anonymous access to the GymService service by adding the following location element.

    (Code Snippet – SilverlightAndIdentity Lab - Ex01 GymService location element)

    XML

    <connectionStrings />
    FakePre-98129c20c9144614881f4ae51e388df7-455512eb373645ed8337f1671fc89b39FakePre-04850156845749cd84b51907c380c682-33860e0cee224e378ead2171d6e45543FakePre-c682f63615da4d0b9523d1cf4d27bf43-cb0eebad84bb490caff72bee6588c5caFakePre-fb03e9df0aea49c38811023e73168115-a91f9433768249c59b000d977d2ae277FakePre-6648dc7de1624dfdbeb55df4af2325f0-06bf2c0bf9a9431ba6a7afaf10fa42ccFakePre-84a499b4757443ba93bda0b33166d3eb-1e3c60878fcc4089aa7bcde235da7b7b<location path="GymService.svc"> <system.web> <authorization> <allow users="*"/> </authorization> </system.web> </location>FakePre-1382182e7fda4ad3b5e32c3fc7c6bea6-33a37a48668241589be0cb7ca9052967FakePre-0b506480d14c46afb5f0268505210c35-81b653ebc11d44b7aeb02ffb84b5ccebFakePre-5da7e4505f2647159ecb261041c7a0ea-b7b710cfc96341ba860a2d6ca9d9b811

  9. Change the GymService service to use a new behavior configuration called GymServiceBehavior as it is shown below:

    XML

    <system.serviceModel>
    FakePre-1a52d403a025478bbc7454c9d715608f-16d364e0c95041e9a6ab816496e08f5cFakePre-1a72c1b8d8244282b30705e739c9acdd-d7cd81ab2f324c519384ef6ced9f6017FakePre-3e367a95e8594e68bfd6b89469a4e75e-0403d063b6ca47d49710a6174b2f3b98FakePre-61b65d789eb042a5b5b75db483b33d37-ce73f9ac5ed24edb885c6a1897a525fcFakePre-fac9e6d6e63d420d9d38e29bffec0fd9-a6ef929c8f7b4bf7b4cc6a264c1b50dbFakePre-bcae681ad3ef4a4db5f1a64c39e91af8-cc26ffb7153344a48094d8c9cb03fd7fbehaviorConfiguration=”GymServiceBehavior”>FakePre-41b08334d5564c5db1477e80c81811ee-be272b498c0c4d7c852165c80742a0ceFakePre-5e0fbef0ecf34fa6beebbc5d66b696d3-f6b2c6fd8b2142ae81bbf558c1dc414fFakePre-b4ae24388f2c4a3fab599241fd1dbd16-38925846b8814cf881732104f005e7f5FakePre-2c95e4b0d000499caa11aab93556a047-3b05b9362b0f46fe827613f928d64d67FakePre-03e49404b64d46a3908ec03b1431c9d9-258cab3779194ab58d50d8587fdeb4aeFakePre-bd3467f26e0f4e22ad16c8ca336d4272-5058baff210045cfa80ea87a0799c50e

  10. Change the endpoint address of the GymService to be https://localhost/GymFabrikamClientWebEx01/GymService.svc

    XML

    <system.serviceModel>
    FakePre-7e896ab9348640769b9a0ceca3982fc3-ee3c12ae551649d988cb420117ca1f8cFakePre-71df8d12456746ab89d229167919b253-07eacf43b3d54a218b3c559548972166FakePre-eaecc45d97f44d28b48fb177db1c0732-01c3983f2e6841a4ae2f4a741dadda11FakePre-35b54651d3ce4ee5be88d488584c2310-605318ec921b4269b7832d89c3363508FakePre-8421d13d09eb4624835f559e4c6c15b2-d142c345304349b7a2bde7a04d3e7a64FakePre-cc2ca8593cd545bbada3e6700f8fca1a-17bd7db35f0342d78efe93eb94a8eac9FakePre-2815841665ce4f8bbc19623a4b7a5afb-0237059cfa6949e7a735e8a5bafaad7a <endpoint address="https://localhost/GymFabrikamClientWebEx01/GymService.svc"FakePre-ae85706646a046558d88e4fa6bcd0da3-82d5798c4c37426aa4032e388a9089f5FakePre-caa2560c865c425b972c8ea011c3c3d2-e38b1257a790464b9e2d7a4bc56e2c92FakePre-36472db1e12d478eae67a1ab6c3d674a-4770e03607e34a56b0a9adafaab2c67dFakePre-bc091e5c13f64e4191ad2a3ec636703d-ca896e1a9df04cacbcac30be80bcf845FakePre-9e1b0627ff41495cb5c2c9c26590348e-828f42d60a6b4e058f5d37f1e71654ab

  11. At this point the service is ready to serve requests; however we still need to do something for ensuring that our authorization logic is enforced. You will include an existing class inside the Assets folder that allows limiting the access to the GymService based on the user membership. To do this, right-click App_Code folder of the https://localhost/GymFabrikamClientWebEx01 project and select Add Existing Item.
  12. In the Add Existing Item dialog, navigate to the Assets\GymFabrikamClientWebEx01 folder inside the Source folder of this lab and select the MyClaimsAuthorizationManager.cs file. Press Add to include it inside the App_Code folder.

    Figure 29

    Adding the MyClaimsAuthorizationManager class to the GymFabrikamClientWebEx01 project

    Note:
    The MyClaimsAuthorizationManager file you just added to the project contains one implementation of the ClaimsAuthorizationManager class. ClaimsAuthorizationManager is the mechanism that WIF offers you for integrating your authorization logic in the request processing pipeline: you derive from ClaimsAuthorizationManager, embed authorization logic in a method override, write some code to read the access policy associated to the resources you want to protect and you are done. Once you have that class, you can easily insert it in the processing pipeline by editing the configuration. If your development focus area is not security, chances are that you’d receive this class ready to use from your security colleagues in your company: at that point you’d just follow the same steps described here. If you are interested in knowing more about how to write your own ClaimsAuthorizationManager please refer to the other labs in the Identity Training Kit.

  13. Add inside the Web.config file the required configuration so the WIF runtime can instantiate the custom ClaimsAuthorizationManager class to check access to the GymService. Open the web.config file of the https://localhost/GymFabrikamClientWebEx01 project and update the microsoft.identityModel section to define a “GymService” service section specifying the custom ClaimsAuthorizationManager class and the policies that it should take into account.

    (Code Snippet – SilverlightAndIdentity Lab - Ex01 GymService service element)

    XML

    <microsoft.identityModel>
    <service name="GymService"> <claimsAuthorizationManager type="ClaimsBasedAuthorization.MyClaimsAuthorizationManager"> <policy resource="https://localhost/GymFabrikamClientWebEx01/GymService.svc" action="https://tempuri.org/GymService/GetTrainingSessions"> <claim claimType="https://gym.fabrikam.com/2010/03/identity/claims/membershiplevel" claimValue="gold"/> </policy> <policy resource="https://localhost/GymFabrikamClientWebEx01/GymService.svc" action="https://tempuri.org/GymService/GetAnnouncements"> <or> <claim claimType="https://gym.fabrikam.com/2010/03/identity/claims/membershiplevel" claimValue="gold"/> <claim claimType="https://gym.fabrikam.com/2010/03/identity/claims/membershiplevel" claimValue="silver"/> </or> </policy> </claimsAuthorizationManager> </service>FakePre-fc4bbb69e9754c6dad1522930beb02a5-30f259695cdd415eaf533580b1e75576FakePre-ac47527445f94bc6b9cbe4c024f783f8-246075d5db0c40c198ddcca04b5ccf2aFakePre-56851c857c3247bfb5dfdd5c0380d836-f87db9c7e9604f8c9a3d62e71119727bFakePre-7ad7f287ca2e44fbb33532c9b79c6f57-f2e776e9f4724c2bab7272dc7ed37ba7FakePre-1904730d161346a3b8ed31da24d57aaf-798cd809dafb418aae5bab7043fcb5f6FakePre-fe79d495b7f84d12931c240d53d85212-c7646fc818954acb867c2c70381ecc20FakePre-da58ff5a5a2d4c2c897d86b4078723eb-7022bd2d49ec468d8c53bf1e1da35d1e
    Note:
    The policy above is pretty straightforward: calling the method GetTrainingSessions requires the current user to present a claim of type https://gym.fabrikam.com/2010/03/identity/claims/membershiplevel with value “gold”, while the method GetAnnouncements can be invoked both by gold and silver members.

  14. Add an extensions section to system.serviceModel to define a behavior extension that allows define which service definition inside microsoft.identityModel should be used by the service. To do this, add the following element to system.serviceModel below the behaviors section.

    (Code Snippet – SilverlightAndIdentity Lab - Ex01 system.serviceModel extensions section)

    XML

    <system.serviceModel>
    FakePre-b97383cad87243009fddbcc4950d16ab-64012fc2e16943fca7c73a67a00c5882FakePre-0b2c4b89b29e4a8b8af4008fb5c1bc15-7ca293bac0624450907f045053fbb262FakePre-455909d7a6194cbc98ce76fe4198a0e7-f69d36d49d28498ba40e6432aed64099 <extensions> <behaviorExtensions> <add name="federatedServiceHostConfiguration" type="Microsoft.IdentityModel.Configuration.ConfigureServiceHostBehaviorExtensionElement, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" /> </behaviorExtensions> </extensions>FakePre-5c8b5654ac56425280d7f6d5f0e5e1d5-34751517d74a4f7a9e8e291d0aa7ae43FakePre-b82dfd59a9024b6dafcc5f6b55b309e1-73edddef236043cb9d3aa2e2abd36e68FakePre-bb39f26754ee4a6f834c599459ad183d-13d0f8766b3040c98d329ab1ff0b6276FakePre-958c94e9817747ce876b7c8bbaeee5c5-d81a0ffbcad04dcc9818df23ecf9da91

  15. Add a service behavior named “GymServiceBehavior” to configure the GymService to use the new service defined in the microsoft.identityModel section. To do this, add the following behavior element on the servicebehaviors definition.

    (Code Snippet – SilverlightAndIdentity Lab - Ex01 GymServiceBehavior binding element)

    XML

    <system.serviceModel>
    FakePre-5929197250a548cbb59c261c2417a909-180ef871871d4d898186f41623ea1ab4FakePre-2ef876918e41455bb27589c4343292db-b0f113ed4f7243569900e7c900a802d7FakePre-e80e34c056204b2a89a2b9735c6061b8-570a008a2b244fbcb1109024c02333c7FakePre-a4753f134aa3440aa789320c585ce47c-ef9c5757a20d482da425414ab35e4ca6FakePre-4c4a9bba0b0e48428943f4e8aa90e0e7-7d1365b9f3614979a2683082be029dd8 <behavior name="GymServiceBehavior"> <serviceMetadata httpGetEnabled="true" /> <serviceDebug includeExceptionDetailInFaults="false" /> <federatedServiceHostConfiguration name="GymService" /> </behavior>FakePre-358ec1fbb56240c184da9ee385b5cb99-bb917523833f429fa18662a5544a0312FakePre-33420eef78894d068349d20721a15487-848da95b83cf4d699d95237b0fd5ce54FakePre-653ed29d0dfb4f2b964365ef1bd3879a-25502a3074d34bf68da16908e055625bFakePre-e90ac5745bb34deb92117f831ebb1fc8-ee139772acb4492e9dbcfbfd5be283d5FakePre-d2ffc0576d2e4c6585d7dbe8e3c1b06e-39870c80188941a9a7ebaec038303d5bFakePre-87e28d29b83f41f29d1c39ae9b517237-7a169ca425b54e28a5d0fd671b9c5868FakePre-f139769192034bdfb66a976f8705242c-3343e2eeaad046d18f628d46bfe74143

  16. Disable multisite bindings to avoid problems when the service is hosted. To do this, update the multipleSiteBindingsEnabled attribute to false inside the system.serviceModel/serviceHostingEnvironment element.

    XML

    <system.serviceModel>
    FakePre-28989ae76c794de7be5961bf5c81826e-b86b5d14557148729dd9651aab93287eFakePre-1983690945074fdd8ffcb33f87a793ca-fb5a673b534a455db96c401e29a35bb2FakePre-0083bd2637c145fb89f271c9cfd3041a-60b8ed66b09b49dbb0466817a171aa07FakePre-05df819b4a2646ada06c7a85ee8a9f3d-aa713d9b2d4a435abb50e9d45bcb35b0 multipleSiteBindingsEnabled="false" />FakePre-343dcb4599dd44739df4c9524b2cd4df-b53dd6c432f849c78ff3210f6ecb521cFakePre-e81bf72772124db2abbe7a119e63387a-1625b512f02c4d789558dd2d2d3e43b9FakePre-8c44ff94b4d84dfcac40b4f3f509b5bf-ec1fa5ba26894ae28cde6908fd980ebbFakePre-0a520c20585746d3ae2b417ebdd1530c-cc0a57457af94ccd94c9f78922ee8834FakePre-f659faa45da14d67b6b2064aa03a454e-d482321157e544bdaf4e07554260f990

  17. Press Ctrl + Shift + B to compile the solution.
  18. Now the GymService service is truly ready. It’s time to hook the Silverlight application to it: we are going to do it just like we would with any other service. Right-click the GymFabrikamClient project and select Add Service Reference.
  19. On the Add Service Reference dialog, press Discover to list the different available services in the solution. Select the GymFabrikamClientWebEx01/GymService.svc service, change the namespace to GymServiceReference and press OK.

    Figure 30

    Adding a reference to the GymService service from the Silverlight application

    Note:
    If you get a warning saying that your certificate name does not match the DNS server name of your machine, press Yes.

  20. Only if you were prompted with the warning shown in the note above, open the ServiceReferences.ClientConfig file inside the GymFabrikamClient project and replace the address for the GymService with localhost instead of the full name of your machine, as shown below.

    XML

    <configuration>
    FakePre-739d62bed805492ca112ca1c5dae11fc-b6f48f22ad854a5083699acfc3adf5a5FakePre-ba5038614de146a8ab11a35212e86ed0-855127c2e8ab4421bd3593dee101737fFakePre-944aa343117148db916bfd25fb439532-c6ec5e0a9404451ab5d6f7e7de2941e7FakePre-63f3a2014d194a1885fd480ff4e08d9e-be588d7be83d4d7caaab80dbd22bfc47FakePre-26bfa873929b4510b35c05bd474f41d7-5e2fe068be854fbbb84593eb5857c4ccFakePre-10920eb0ad4244ef86f57fba9cb8afbd-969f662a8f7d4f77aecb1431df1d35b6FakePre-6fa405ee42894da68c943d5eb3c12c89-d2df939153b3495aafbd590961a657cfFakePre-543677d546af49079c96d6fd3919eff4-858dd9155a294240bb76153cac20a075FakePre-34d348e2ddec43dd9085e84e40b55f93-e10ead5b00cc43fa84808138526aa179FakePre-6e536d551b85450b9d9ba61f6424f99e-fc1bf68e573149babc6170960ad7c912FakePre-7c694820d2884617b19cbffae5431f64-8aef9a6a831c424f8f7c84bb30c7f2d0FakePre-64d5d4adb5324ff685c2723dbfba4beb-945810c1c90e4983b99e15936ab011ffaddress="https://localhost/GymFabrikamClientWebEx01/GymService.svc"FakePre-610b1ac51b5348699f0b3ef21d98ed67-c829ea19f4dd44dabebbf2e812defb13FakePre-d096a193b0f04c50a17659249dc6d137-77294cc6da0e449eace1236a33545e12FakePre-af0614b5301e4a86bd37003564406e9f-52ee239fb03d43d981c524a347022a5bFakePre-395cb8f3efb94990833847defb6ff6a0-dd954376aa41458faf78996db2f3fb26FakePre-8926929d57dd44e9a1ee951d593ecce9-f5c9a823acf6424d80e8f2d60277cb31
    Note:
    If your machine is domain-joined, sometimes the Add Service Reference operation will resolve your full machine name, which does not match with the localhost certificate you use in the lab. Changing the endpoint address back to localhost will avoid any certificate conflicts.

  21. On previous steps, you enabled anonymous access to the GymService service to be able to add a service reference to it. Now that you did it, remove the GymService.svc location element from the web.config file of the https://localhost/GymFabrikamClientWebEx01 project.

    XML

    <connectionStrings /> <location path="FederationMetadata"> ... </location> <location path="AuthenticationService.svc"> ... </location> <location path="GymService.svc"> <system.web> <authorization> <allow users="*"/> </authorization> </system.web> </location> <system.web> ... </system.web>

  22. Open the MainPage.xaml Code-Behind in the GymFabrikamClient project. To do this, right-click the MainPage.xaml file inside the GymFabrikamClient project and select View Code.
  23. Add a namespace directive to the GymServiceReference at the top of the class:

    C#

    using GymFabrikamClient.GymServiceReference;

  24. Implement the call to the GymService service to retrieve the list of announcements at the bottom of the ShowUserInfo method.

    (Code Snippet – SilverlightAndIdentity Lab - Ex01 ShowUserInfo Announcements)

    C#

    private void ShowUserInfo()
    FakePre-8f6800b1792a4a6e832db20bc826bc3e-3b6e0661aab0437fbae4f0ed50cc543cFakePre-5679e64ef8eb45eeb40b70b4afc9811f-0881d837b3e8418cb51f513b3b438cdaFakePre-8370ef95c7f04b08b6a796631bf0fb15-d35a9cf3494f45ca88d13ff7f18c7f38FakePre-5e6d3920e1554a7da1a21bbc0afc424d-af5dd79eae304383840887030948b5a9FakePre-e8c2e0c6b0c4443ab0ce9409a7bade49-839f0e94b3314fdb9215d2ccc7e9ae6fFakePre-5b1d6f24a7394497b49875057e2fbf24-4b2de7e999e24d6eb71ad257ee48f3d3FakePre-4164aa1a351f4c508d48390852239fce-59633fad52474c429f672b003bf74736FakePre-997dd7ffb2e64b9eabbb14c8beed9a63-9760e1b69d5c4e95a98bd9f566f54f94FakePre-50a08de2d7554ea495e73c6774943997-ce35fa87031e42daa764c0a6ba8dbdf9FakePre-566a90ed99bb421580effb893ad95499-33d68a72107e4beca41b7d043b4f7fedFakePre-e67d45a0dd874efd89a3ac7bfbb398b4-d69b446d27654c0db5a4faf876180b27FakePre-ebb7570f6c084183b9ad2360e846e39f-e91ab8f368cc49338b1388ce972f0a6aFakePre-48fa41663d5741339788d19e0c5d3f25-037af58d56f4496b8d47c6f824b7e89fFakePre-7ab530eb9c1943818df56cd270186cd1-bdba92e98dc04b69839e51b63996171cFakePre-4472ef1f0a3343949cc584089173a4c4-a6094541597143d998cd20fbb26a2235FakePre-c24d26a1427d471eb93265171bbe24e4-a69648e65c6446d3a0ecebbd8d1e6aa9 // Announcements GymServiceClient client = new GymServiceClient(); client.GetAnnouncementsCompleted += new EventHandler<GetAnnouncementsCompletedEventArgs>(this.Client_GetAnnouncementsCompleted); client.GetAnnouncementsAsync();FakePre-f56e5cd010af46c291a4a2f9e3dba910-45f2369c9f204f718a0920df98bf6766FakePre-2a6cccf9d3b24bf791d9bdf276d71d32-42a642408e474edbabb9f7297199ed01

  25. Implement the call to the GymService service on the TrainingSessionsButton_Click method.

    (Code Snippet – SilverlightAndIdentity Lab - Ex01 TrainingSessionsButton_Click method)

    C#

    private void TrainingSessionsButton_Click(object sender, RoutedEventArgs e)
    FakePre-6ad63575874e48ceac06e1ff239c4df8-d06fae088a5c409fa734f554c4dac91b GymServiceClient client = new GymServiceClient(); client.GetTrainingSessionsCompleted += new EventHandler<GetTrainingSessionsCompletedEventArgs>(this.Client_GetTrainingSessionsCompleted); this.announcementsList.Visibility = Visibility.Collapsed; this.goldMembersArea.Visibility = Visibility.Visible; try { client.GetTrainingSessionsAsync(); } catch { this.trainingSessionsArea.Visibility = Visibility.Collapsed; }FakePre-3a84c407724c43aa9cb288e34d0c1ffd-633b1d1b919e4adebffee2628a4c8c16FakePre-fb174079b9ad40ceb475fdc712ca4c1d-d5dd7d8aabcc4eb399ec90160fc9b0d2FakePre-afa14e1370bc4dd8924aaeec40a03f6e-e9906d1e1ebb4b0c8586bd25b7d89cd3

  26. That’s pretty much it for what concerns the call. Next, you will implement the logic to change the Training Session image when the user selects a different entry in the training sessions list. Add the following code on the TrainingSessionsList_SelectionChanged method.

    (Code Snippet – SilverlightAndIdentity Lab - Ex01 TrainingSessionsList_SelectionChanged)

    C#

    private void TrainingSessionsList_SelectionChanged(object sender, SelectionChangedEventArgs e)
    FakePre-7eee9b5ca06b4aa98f3ab4b1d4cd1e9a-73457ea2098c44ffbbfbc71ac75f3dfb if (e.AddedItems.Count == 0) { return; } var selectedItem = (TrainingSession)e.AddedItems[0]; this.heartRateImage.Source = GetBitmapSourceFromBase64(selectedItem.HrGraph);FakePre-9deb28f139f04014bb3ec3ffad528807-c7e8c6779e0a4a76b824190e7020301dFakePre-2566f8814f18432c8b14f82d1c826b36-123e2f73cfd3401d9241d4b5ae971efeFakePre-f3fc529b50c6400988606e11560a3e9b-2c7975f78da84872875c869f54cea0c6

  27. Add the Client_GetTrainingSessionsCompleted and Client_GetAnnouncementsCompleted methods which will bind the information retrieved from the Gym Service to the different lists.

    (Code Snippet – SilverlightAndIdentity Lab - Ex01 Data Binding methods)

    C#

    private void Client_GetTrainingSessionsCompleted(object sender, GetTrainingSessionsCompletedEventArgs e) { if (e.Error == null) { this.trainingSessionsList.ItemsSource = e.Result; this.trainingSessionsList.SelectedIndex = 0; } } private void Client_GetAnnouncementsCompleted(object sender, GetAnnouncementsCompletedEventArgs e) { if (e.Error == null) { this.announcementsList.ItemsSource = e.Result; } }

Exercise 1 – Verification

That’s it: the service is ready to serve content according to the user’s membership level, and the client application is wired up to call the service as intended. All that’s left is giving it a spin and verify that it behaves as expected.

  1. Make sure that the https://localhost/GymFabrikamClientWebEx01 project is the StartUp Project by right-clicking the https://localhost/GymFabrikamClientWebEx01 project and selecting Set as StartUp Project.
  2. Press Ctrl +F5 to run the Web Site. In the STS’s login page, press Submit to login as “john”.

    Figure 31

    Login as “john” on the STS’s login page

    The Gym Fabrikam Silverlight application will be displayed inside the browser. Notice that a list of Notes is displayed at the bottom of the page, a telltale sign that the call to the GetAnnouncements method of GymService succeeded.

    Figure 32

    Improved UI showing notes from the Gym Service

  3. John is a gold member of Gym Fabrikam, hence he is able to click the Get Training Sessions button and get the list of his recorded training sessions. Click some item in the list and observe that the associated Heart Rate graphic changes accordingly.

    Figure 33

    Showing Training Sessions is a privilege reserved to gold members

    Note:
    Pressing the Get Training Sessionss button triggers the service call you coded earlier. The service verifies that the caller has indeed an active gold membership by checking the claims in the session cookie: upon successful authorization, the service returns a list of hardcoded sessions with associated heart rate graphs.

  4. Close the browser. For extra credits, repeat the verification process by signing in as Mary: you will discover that Mary can see the news on the main page, but her membership level prevents her from accessing the session recording features.