Microsoft Silverlight 5: Working with Services

Exclusive offer: get 50% off this eBook here
Microsoft Silverlight 5 Data and Services Cookbook

Microsoft Silverlight 5 Data and Services Cookbook — Save 50%

Over 100 practical recipes for creating rich, data-driven, business applications in Silverlight 5 with this book and ebook

$35.99    $18.00
by Gill Cleeren Kevin Dockx | April 2012 | Microsoft

In this article by Gill Cleeren and Kevin Dockx, authors of Microsoft Silverlight 5 Data and Services Cookbook, we will cover:

  • Connecting and reading from a standardized service
  • Persisting data using a standardized service
  • Configuring cross-domain calls
  • Working cross-domain from a trusted application
  • Reading XML using HttpWebRequest

(For more resources on silverlight, see here.)

Introduction

Looking at the namespaces and classes in the Silverlight assemblies, it's easy to see that there are no ADO.NET-related classes available in Silverlight. Silverlight does not contain a DataReader, a DataSet, or any option to connect to a database directly. Thus, it's not possible to simply define a connection string for a database and let Silverlight applications connect with that database directly.

The solution adds a layer on top of the database in the form of services. The services that talk directly to a database (or, more preferably, to a business and data access layer) can expose the data so that Silverlight can work with it. However, the data that is exposed in this way does not always have to come from a database. It can come from a third-party service, by reading a file, or be the result of an intensive calculation executed on the server.

Silverlight has a wide range of options to connect with services. This is important as it's the main way of getting data into our applications. In this article, we'll look at the concepts of connecting with several types of services and external data.

We'll start our journey by looking at how Silverlight connects and works with a regular service. We'll see the concepts that we use here recur for other types of service communications as well. One of these concepts is cross-domain service access. In other words, this means accessing a service on a domain that is different from the one where the Silverlight application is hosted. We'll see why Microsoft has implemented cross-domain restrictions in Silverlight and what we need to do to access externally hosted services.

Next, we'll talk about working with the Windows Azure Platform. More specifically, we'll talk about how we can get our Silverlight application to get data from a SQL Azure database, how to communicate with a service in the cloud, and even how to host the Silverlight application in the cloud, using a hosted service or serving it from Azure Storage.

Finally, we'll finish this chapter by looking at socket communication. This type of communication is rare and chances are that you'll never have to use it. However, if your application needs the fastest possible access to data, sockets may provide the answer.

Connecting and reading from a standardized service

Applies to Silverlight 3, 4 and 5

If we need data inside a Silverlight application, chances are that this data resides in a database or another data store on the server. Silverlight is a client-side technology, so when we need to connect to data sources, we need to rely on services. Silverlight has a broad spectrum of services to which it can connect.

In this recipe, we'll look at the concepts of connecting with services, which are usually very similar for all types of services Silverlight can connect with. We'll start by creating an ASMX webservice—in other words, a regular web service. We'll then connect to this service from the Silverlight application and invoke and read its response after connecting to it.

Getting ready

In this recipe, we'll build the application from scratch. However, the completed code for this recipe can be found in the Chapter07/SilverlightJackpot_Read_Completed folder in the code bundle that is available on the Packt website.

How to do it...

We'll start to explore the usage of services with Silverlight using the following scenario. Imagine we are building a small game application in which a unique code belonging to a user needs to be checked to find out whether or not it is a winning code for some online lottery. The collection of winning codes is present on the server, perhaps in a database or an XML file. We'll create and invoke a service that will allow us to validate the user's code with the collection on the server. The following are the steps we need to follow:

  1. We'll build this application from scratch. Our first step is creating a new Silverlight application called SilverlightJackpot. As always, let Visual Studio create a hosting website for the Silverlight client by selecting the Host the Silverlight application in a new Web site checkbox in the New Silverlight Application dialog box. This will ensure that we have a website created for us, in which we can create the service as well.
  2. We need to start by creating a service. For the sake of simplicity, we'll create a basic ASMX web service. To do so, right-click on the project node in the SilverlightJackpot. Web project and select Add | New Item... in the menu. In the Add New Item dialog, select the Web Service item. We'll call the new service as JackpotService. Visual Studio creates an ASMX file (JackpotService.asmx) and a code-behind file (JackpotService.asmx.cs).
  3. To keep things simple, we'll mock the data retrieval by hardcoding the winning numbers. We'll do so by creating a new class called CodesRepository.cs in the web project. This class returns a list of winning codes. In real-world scenarios, this code would go out to a database and get the list of winning codes from there. The code in this class is very easy. The following is the code for this class:

    public class CodesRepository
    {
    private List<string> winningCodes;
    public CodesRepository()
    {
    FillWinningCodes();
    }
    private void FillWinningCodes()
    {
    if (winningCodes == null)
    {
    winningCodes = new List<string>();
    winningCodes.Add("12345abc");
    winningCodes.Add("azertyse");
    winningCodes.Add("abcdefgh");
    winningCodes.Add("helloall");
    winningCodes.Add("ohnice11");
    winningCodes.Add("yesigot1");
    winningCodes.Add("superwin");
    }
    }
    public List<string> WinningCodes
    {
    get
    {
    return winningCodes;
    }
    }
    }

  4. At this point, we need only one method in our JackpotService. This method should accept the code sent from the Silverlight application, check it with the list of winning codes, and return whether or not the user is lucky to have a winning code. Only the methods that are marked with the WebMethod attribute are made available over the service. The following is the code for our service:

    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    [System.ComponentModel.ToolboxItem(false)]
    public class JackpotService : System.Web.Services.WebService
    {
    List<string> winningCodes;
    public JackpotService()
    {
    winningCodes = new CodesRepository().WinningCodes;
    }
    [WebMethod]
    public bool IsWinningCode(string code)
    {
    if(winningCodes.Contains(code))
    return true;
    return false;
    }
    }

  5. Build the solution at this point to ensure that our service will compile and can be connected from the client side.
  6. Now that the service is ready and waiting to be invoked, let's focus on the Silverlight application. To make the service known to our application, we need to add a reference to it. This is done by right-clicking on the SilverlightJackpot project node, and selecting the Add Service Reference... item.
  7. In the dialog that appears, we have the option to enter the address of the service ourselves. However, we can click on the Discover button as the service lives in the same solution as the Silverlight application. Visual Studio will search the solution for the available services. If there are no errors, our freshly created service should show up in the list. Select it and rename the Namespace: as JackpotService, as shown in the following screenshot. Visual Studio will now create a proxy class:

  8. The UI for the application is kept quite simple. An image of the UI can be seen a little further ahead. It contains a TextBox, where the user can enter a code, a Button that will invoke a check, and a TextBlock that will display the result. This can be seen in the following code:

    <StackPanel>
    <TextBox x:Name="CodeTextBox"
    Width="100"
    Height="20">
    </TextBox>
    <Button x:Name="CheckForWinButton"
    Content="Check if I'm a winner!"
    Click="CheckForWinButton_Click">
    </Button>
    <TextBlock x:Name="ResultTextBlock">
    </TextBlock>
    </StackPanel>

  9. In the Click event handler, we'll create an instance of the proxy class that was created by Visual Studio as shown in the following code:

    private void CheckForWinButton_Click(object sender,
    RoutedEventArgs e)
    {
    JackpotService.JackpotServiceSoapClient client = new
    SilverlightJackpot.JackpotService.JackpotServiceSoapClient();
    }

  10. All service communications in Silverlight happen asynchronously. Therefore, we need to provide a callback method that will be invoked when the service returns:

    client.IsWinningCodeCompleted += new EventHandler
    <SilverlightJackpot.JackpotService.
    IsWinningCodeCompletedEventArgs>
    (client_IsWinningCodeCompleted);

  11. To actually invoke the service, we need to call the IsWinningCodeAsync method as shown in the following line of code. This method will make the actual call to the service. We pass in the value that the user entered:

    client.IsWinningCodeAsync(CodeTextBox.Text);

  12. Finally, in the callback method, we can work with the result of the service via the Result property of the IsWinningCodeCompletedEventArgs instance. Based on the value, we display another message as shown in the following code:

    void client_IsWinningCodeCompleted(object sender,
    SilverlightJackpot.JackpotService.
    IsWinningCodeCompletedEventArgs e)
    {
    bool result = e.Result;
    if (result)
    ResultTextBlock.Text = "You are a winner! Enter your data
    below and we will contact you!";
    else
    ResultTextBlock.Text = "You lose... Better luck next time!";
    }

  13. We now have a fully working Silverlight application that uses a service for its data needs. The following screenshot shows the result from entering a valid code:

How it works...

As it stands, the current version of Silverlight does not have support for using a local database. Silverlight thus needs to rely on external services for getting external data. Even if we had local database support, we would still need to use services in many scenarios. The sample used in this recipe is a good example of data that would need to reside in a secure location (meaning on the server). In any case, we should never store the winning codes in a local database that would be downloaded to the client side.

Silverlight has the necessary plumbing on board to connect with the most common types of services. Services such as ASMX, WCF, REST, RSS, and so on, don't pose a problem for Silverlight. While the implementation of connecting with different types of services differs, the concepts are similar.

In this recipe, we used a plain old web service. Only the methods that are attributed with the WebMethodAttribute are made available over the service. This means that even if we create a public method on the service, it won't be available to clients if it's not marked as a WebMethod. In this case, we only create a single method called IsWinningCode, which retrieves a list of winning codes from a class called CodesRepository. In real-world applications, this data could be read from a database or an XML file. Thus, this service is the entry point to the data.

For Silverlight to work with the service, we need to add a reference to it. When doing so, Visual Studio will create a proxy class. Visual Studio can do this for us because the service exposes a Web Service Description Language (WSDL) file. This file contains an overview of the methods supported by the service. A proxy can be considered a copy of the server-side service class, but without the implementations. Instead, each copied method contains a call to the actual service method. The proxy creation process carried out by Visual Studio is the same as adding a service reference in a regular .NET application.

However, invoking the service is somewhat different. All communication with services in Silverlight is carried out asynchronously. If this wasn't the case, Silverlight would have had to wait for the service to return its result. In the meantime, the UI thread would be blocked and no interaction with the rest of the application would be possible.

To support the asynchronous service call inside the proxy, the IsWinningCodeAsync method as well as the IsWinningCodeCompleted event is generated. The IsWinningCodeAsync method is used to make the actual call to the service. To get access to the results of a service call, we need to define a callback method. This is where the IsWinningCodeCompleted event comes in. Using this event, we define which method should be called when the service returns (in our case, the client_IsWinningCodeCompleted method). Inside this method, we have access to the results through the Result parameter, which is always of the same type as the return type of the service method.

See also

Apart from reading data, we also have to persist data. In the next recipe, Persisting data using a standardized service, we'll do exactly that.

Microsoft Silverlight 5 Data and Services Cookbook Over 100 practical recipes for creating rich, data-driven, business applications in Silverlight 5 with this book and ebook
Published: April 2012
eBook Price: $35.99
Book Price: $59.99
See more
Select your format and quantity:

(For more resources on silverlight, see here.)

Persisting data using a standardized service

Applies to Silverlight 3, 4 and 5

In the previous recipe, we connected with the service and read the result of the service call. However, we can also send data back to the service as a type known by the service. If a type is used as the type for a parameter or as the return type for a service method, that type will be exposed by the service as well. Through the proxy generation, we have access to this type inside the Silverlight application as well.

In this recipe, we'll add another method to the web service that uses a custom type as the type for its parameter.

Getting ready

This recipe builds on the code from the previous recipe. If you want to follow along with this recipe, you can either continue using your code or use the provided starter solution located in the Chapter07/SilverlightJackpot_Persist_Starter folder in the code bundle that is available on the Packt site. The finished solution for this recipe can be found in the Chapter07/SilverlightJackpot_Persist_Completed folder.

How to do it...

We'll extend the SilverlightJackpot solution that we built in the previous recipe. When the user enters a valid code, a registration form appears that allows the user to enter his or her credentials. We'll extend the service as well, so that it accepts this data and stores it accordingly. Let's look at the way this is done in the following steps:

  1. We will start by adding a new class called Winner in the web project. This class will be used to store the information about a winner:

    public class Winner
    {
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Email { get; set; }
    }

  2. We'll also create another class called WinnerRepository. This class would allow us to store all the winners in a static List. Just as the previous recipe, this data would be stored in a database in real-world scenarios:

    public static class WinnerRepository
    {
    private static List<Winner> winners = new List<Winner>();
    public static void AddWinner(Winner newWinner)
    {
    winners.Add(newWinner);
    }
    }

  3. We can now extend the service (JackpotService.asmx.cs), so that it includes a method (again marked as WebMethod) that accepts a Winner, and stores it in the List of the WinnerRepository class. This is shown in the following code:
    [WebMethod]
    public void SaveWinner(Winner winner)
    {
    WinnerRepository.AddWinner(winner);
    }

  4. Build the solution to make sure that the service works correctly.
  5. To make the new method available in the Silverlight application, we need to right-click on the JackpotService node within the Silverlight project in the Solution Explorer, and select the Update Service Reference item. Visual Studio will reconnect to the service and rebuild the proxy. It will also include our extra method.
  6. We need to add some XAML code to add the fields to collect the required information. For the complete listing, refer to the MainPage.xaml file in the sample code. The following is the most relevant part of the XAML code, as it contains the fields in which the user can enter his/her details:

    <TextBlock x:Name="NameTextBlock"
    Text="Name: ">
    </TextBlock>
    <TextBox x:Name="NameTextBox">
    </TextBox>
    <TextBlock x:Name="FirstNameTextBlock">
    </TextBlock>
    <TextBox x:Name="FirstNameTextBox">
    </TextBox>
    <TextBlock x:Name="EmailTextBlock">
    </TextBlock>
    <TextBox x:Name="EmailTextBox">
    </TextBox>
    <Button x:Name="SubmitButton"
    Click="SubmitButton_Click">
    </Button>
    <TextBlock x:Name="SubmissionResultTextBlock">
    </TextBlock>

  7. In the Click event handler, we start off by creating an instance of the proxy similar to the previous recipe. We'll define the callback method when the service call completes, as well as make the asynchronous call. However, the latter requires an instance of the Winner class, which was originally created on the server. This instance is now sent to the service. In the callback method, we'll update the user interface, so that the result of the service call is shown:

    private void SubmitButton_Click(object sender, RoutedEventArgs e)
    {
    JackpotService.JackpotServiceSoapClient client = new
    SilverlightJackpot.JackpotService.JackpotServiceSoapClient();
    client.SaveWinnerCompleted += new
    EventHandler<System.ComponentModel.AsyncCompletedEventArgs>
    (client_SaveWinnerCompleted);
    client.SaveWinnerAsync(
    new JackpotService.Winner()
    {
    FirstName = FirstNameTextBox.Text,
    LastName = NameTextBox.Text,
    Email = EmailTextBox.Text
    }
    ); } void client_SaveWinnerCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e) { if (e.Error == null) { ResultTextBlock.Text = string.Empty; SubmissionResultTextBlock.Text = "Submission successful!"; UserDetailGrid.Visibility = Visibility.Collapsed; } }

  8. After completing these steps, we have successfully allowed the user to send data from the Silverlight application to the service. In turn, the service can store this data in any data store. The following screenshot shows the expanded fields. The application will bundle the entered information into a Winner object and send it to the service:

How it works...

Apart from reading data, we also need to send data back to a service. Behind this service façade, code can be used to store data into a database or any other data store. An important thing to understand here is that persisting data can be carried out by passing in values for the parameters of a service method.

When the service uses a particular class (such as the Winner class in this recipe) as a parameter type, this class gets sent down the wire to the Silverlight application as well. On generating the proxy based on the WSDL file, a local copy of this class will be generated in the Silverlight application as well. This class can be used in the same way as a normal class. In this sample, we have created an instance of this class using the following code:

client.SaveWinnerAsync(new JackpotService.Winner()
{ FirstName = FirstNameTextBox.Text, LastName = NameTextBox.Text,
Email = EmailTextBox.Text });

This instance is then serialized in a SOAP message (because of the ASMX service), and sent to the service. On the service side, the instance is rebuilt and used as a parameter for the service method through deserialization.

See also

We have looked at connecting with a service and reading data from it in the first recipe of this chapter, Connecting and reading from a standardized service.

Configuring cross-domain calls

Applies to Silverlight 3, 4 and 5

In the previous recipes, we have used services that were hosted within the same website (and consequently the same domain) as the Silverlight application itself. However, more often than not, this will not be the case in real-world scenarios. We may need to connect to a third- party service (such as Flickr's API services) from Silverlight. Even if we wrote the service layer ourselves, it may be hosted on a different domain.

Silverlight imposes restrictions on communication with external services. However, Silverlight allows services to opt-in to allow being called from a Silverlight application. In this recipe, we'll look at the actions we need to take to make it possible to connect to a self-written service that is hosted in a different domain.

Getting ready

To follow along with this recipe, a starter solution is provided in the Chapter07/ SilverlightCrossDomain_Starter folder in the code bundle that is available on the Packt site. The finished solution for this recipe can be found in the Chapter07/ SilverlightCrossDomain_Completed folder.

How to do it...

In this recipe, we'll build a Silverlight application that shows flight information based on the values entered by the user. However, this information is located in a service hosted by the airline companies, which means it runs externally and on a different domain than our Silverlight application. In the following steps, we'll see what we need to change so that Silverlight can access externally hosted services:

  1. Start by opening the solution as outlined in the Getting Ready section. The solution contains two projects: SilverlightCrossDomain (the Silverlight project) and SilverlightCrossDomain.Web (the hosting web project).
  2. In this solution, add a new ASP.NET Web Application and name it as FlightInformation. You can do this by right-clicking on the solution in the Solution Explorer and selecting Add | New Project.... In the dialog that appears, select ASP. NET Web Application under the Visual C# | Web node.
  3. We'll create a WCF service in this web application. Add a new WCF service called FlightInformationService.svc. Visual Studio will create the FlightInformationService.svc file, the IFlightInformationService.cs interface, and the concrete implementation—FlightInformationService.svc.cs.
  4. To make the service accessible from Silverlight, we need to change the binding type from wsHttpBinding to basicHttpBinding in the web.config of the project. The change we need to make is shown in the following code:

    <endpoint address=""
    binding="basicHttpBinding"
    contract="FlightInformation.IFlightInformationService">
    <identity>
    <dns value="localhost" />
    </identity>
    </endpoint>

  5. Let's now define the contract of the service in the IFlightInformationService interface. We'll keep it simple by making it possible for the service to return only a list of Flight instances.

    [ServiceContract]
    public interface IFlightInformationService
    {
    [OperationContract]
    List<Flight> GetFlights(string fromAirport, string toAirport,
    DateTime date);
    }

  6. The Flight class is not yet defined, so we should go ahead and create this class as shown in the following code:

    [DataContract]
    public class Flight
    {
    [DataMember]
    public string Airway { get; set; }
    [DataMember]
    public DateTime DepartureTime { get; set; }
    [DataMember]
    public DateTime ArrivalTime { get; set; }
    [DataMember]
    public double Price { get; set; }
    }

  7. We can now add the implementation method for the service in the FlightInformationService class. For now, we'll create a hard-coded list of Flight instances. In real-world scenarios, this data would come from a real data store, such as a database. The following is the code for the service:
    public class FlightInformationService : IFlightInformationService
    {
    public List<Flight> GetFlights(string fromAirport, string
    toAirport, DateTime date)
    {
    //some data access code here...
    return new List<Flight>()
    {
    new Flight()
    {
    Airway = "Silverlight Airways",
    DepartureTime = DateTime.Now,
    ArrivalTime = DateTime.Now.AddHours(3),
    Price=300
    },
    new Flight()
    {
    Airway = "Packt Airways",
    DepartureTime = DateTime.Now.AddHours(5),
    ArrivalTime = DateTime.Now.AddHours(10),
    Price=1000
    },
    new Flight()
    {
    Airway = "New Airways",
    DepartureTime = DateTime.Now,
    ArrivalTime = DateTime.Now.AddHours(9),
    Price=1200
    },
    new Flight()
    {
    Airway = "Silverlight Airways",
    DepartureTime = DateTime.Now.AddHours(3),
    ArrivalTime = DateTime.Now.AddHours(5),
    Price=200
    }
    };
    }
    }

     

  8. Build the solution at this point.
  9. Now that the external service is ready, we can use it from our Silverlight application. Or can we? Let's try and see how it goes! Add a service reference in the Silverlight application by right-clicking on the Silverlight project in the Solution Explorer and selecting Add Service Reference.... In the dialog, search for the FlightInformationService using the Discover button. Once it's located, set FlightInformationService as the namespace.
  10. In the Silverlight application, we create a basic UI (shown in the image a bit later in this recipe). The most important element of the UI is a ListBox control, which we'll use to bind the flight information. The UI also contains a Button that will trigger a request to the service. Refer to the sample code for the complete listing.
  11. In the Click event of the Button, we perform an asynchronous call to the service. This is shown in the following code:

    private void SearchButton_Click(object sender, RoutedEventArgs e)
    {
    FlightInformationService.FlightInformationServiceClient proxy =
    new SilverlightCrossDomain.FlightInformationService.
    FlightInformationServiceClient();
    proxy.GetFlightsCompleted += new
    EventHandler<SilverlightCrossDomain.
    FlightInformationService.GetFlightsCompletedEventArgs>
    (proxy_GetFlightsCompleted);
    proxy.GetFlightsAsync("New York", "London",
    DateTime.Now.Date);
    }

  12. In the proxy_GetFlightsCompleted event handler, we can read the results from the e.Result property and bind them to the ListBox, as shown in the following code:

    void proxy_GetFlightsCompleted(object sender,
    SilverlightCrossDomain.FlightInformationService.
    GetFlightsCompletedEventArgs e)
    {
    FlightListBox.ItemsSource = e.Result;
    }

  13. On running this code now, we'll get an exception telling us that we're most likely trying to do a cross-domain service call. The exception is of the CommunicationException type.
  14. To solve this, we need to add a file called clientaccesspolicy.xml to our web project (the project where the service resides). Silverlight will check for the existence of this file in the root of the service domain when performing a cross-domain call. The content of this file is shown in the following code:

    <?xml version="1.0" encoding="utf-8"?>
    <access-policy>
    <cross-domain-access>
    <policy>
    <allow-from http-request-headers="*">
    <domain uri="*"/>
    </allow-from>
    <grant-to>
    <resource path="/" include-subpaths="true"/>
    </grant-to>
    </policy>
    </cross-domain-access>
    </access-policy>

  15. When trying to run the code again, Silverlight will make the call to the service and the results are displayed as shown in the following screenshot:

How it works...

When talking to services that are not hosted in the same domain as the Silverlight application, Silverlight is quite restrictive. By default, it does not allow so-called cross-domain calls. This is purely for security reasons. Let's look at what would happen if Silverlight would allow making cross-domain calls.

Let's assume that a website hosted on SomeFriendlySite.com requires the user to log in. The credentials are stored on the user's PC, so that on the next visit they wouldn't need to log in again. This site also exposes a service that contains secret information about the user, which is only accessible when logged in to the site.

An attacker could create a Silverlight application that would try to retrieve this secret information and host this application on SomeFakeSite.com. Unaware of any danger, the user accesses the Silverlight application on SomeFakeSite.com, and thereby installs the hacker's Silverlight application on his machine. This application can now try to make a request to the SomeFriendlySite.com service using the stored credentials and can send the secret information to BadAttackerSite.com. Worst of all, the user would not even know of all this happening as it would take place behind the scenes. This type of attack from Silverlight is comparable to a cross-site scripting attack, in which the same technique is used. To make it impossible for these kinds of attacks to occur, Silverlight does not make a request to an external service; that is, unless this service explicitly allows us to do so (usually because it does not expose any sensitive data).

When making a call to such an external service, Silverlight will first check the existence of a file called clientaccesspolicy.xml. If this file exists, it will be analyzed by Silverlight. If the file allows all domains to call the service (domain uri="*"), or if the domain in which the Silverlight application is running is in the specified list, Silverlight will make the service call. The following listing shows a clientaccesspolicy.xml file, which allows only some domains to call it:

<?xml version="1.0" encoding="utf-8"?>
<access-policy>
<cross-domain-access>
<policy>
<allow-from http-request-headers="*">
<domain uri="http://www.snowball.be"/>
<domain uri="http://api.snowball.be"/>
<domain uri="http://www.codeflakes.com"/>
</allow-from>
<grant-to>
<resource path="/" include-subpaths="true"/>
</grant-to>
</policy>
</cross-domain-access>
</access-policy>

The approach that Silverlight uses here is similar to what Flash does. Flash also does not allow cross-domain calls. When making a request to an external service, it will check for the existence of a file called crossdomain.xml. The following is a sample crossdomain.xml file:

<?xml version="1.0" encoding="utf-8"?>
<cross-domain-policy>
<allow-access-from domain="*" />
</cross-domain-policy>

Silverlight can work with both clientaccesspolicy.xml as well as crossdomain.xml. When calling a service, Silverlight will first check if clientaccesspolicy.xml exists at the root of the domain. If it does not, it will check if crossdomain.xml is located at the root. If neither of the files is present, the request is blocked. The following screenshot shows that Silverlight searched for clientaccesspolicy.xml before allowing the call to the service:

Of course, the need for one of these two files is bad news when we are creating mashups. Mashups are applications that are composed of data coming from different services. However, the good news is that several services (such as, Flickr) expose a file that allows cross-domain calls. That said, some services do not, while others are restrictive (such as Twitter). Nothing is lost in this case, but we are required to do some additional work. We need to create an extra service layer in the same domain as the one in which the Silverlight application is hosted. These services can connect with every service (as this is not a cross- domain call from a client). Thus, when calling the external service, we would actually call the local service from Silverlight, which would in turn call the external service. The local service acts as a pass-through for data.

Please note that while this is a good solution, it will put extra load on the server as every service call will pass by that server.

Working cross-domain from a trusted Silverlight application

Applies to Silverlight 4 and 5

In the previous recipe, we looked at the restrictions enforced by the Silverlight runtime when accessing services that do not live in the same domain as the Silverlight application. These are called cross-domain restrictions. To access a service that lives in another domain, a cross-domain policy file should be in place. If not, Silverlight won't communicate with the service.

Starting with Silverlight 4, a new application model was added, namely trusted applications. A trusted application or an application with elevated permissions is similar to an out- of-browser application. However, it gets more permissions on the system. One of these permissions is accessing services in a cross-domain manner without requiring a cross- domain file to be in place. In Silverlight 5, in-browser applications can also run with elevated permissions. The concepts explained in this recipe therefore apply for both in-browser and out-of-browser trusted applications.

In this recipe, we'll make cross-domain calls from a trusted Silverlight application.

Getting ready

For this recipe, you can use any of the other Silverlight applications. In the following steps, we use the starter solution for this recipe that can be found in the Chapter07/ Silverlight_TrustedCrossDomain_Starter folder in the code bundle that is available on the Packt site. The completed solution can be found in the Chapter07/Silverlight_ TrustedCrossDomain_Completed folder.

How to do it...

To allow a Silverlight application to make cross-domain calls without having a cross-domain file in place, the application should run as an out-of-browser application having elevated permissions. The following are the steps we need to perform to get this working:

  1. Open a Silverlight project (starter solution or your own project) as outlined in the Getting ready section of this recipe.
  2. Right-click on the SilverlightCrossDomain project and select the Properties item to open the Project Properties window.
  3. In this window, select the Enable running application out of the browser option. This will allow us to install the application locally, so that it can run as a standalone application and will not require a browser to be opened:

  4. Running without a browser is not enough; the application should run with elevated permissions. To enable this, click on the Out-of-Browser Settings... button as shown in the previous screenshot, and mark the Require elevated trust when running outside the browser option in the dialog box that appears. This is shown in the following screenshot:

  5. In the FlightInformation project, we don't need the clientaccesspolicy.xml anymore. It can be deleted from the project.
  6. You can now run the application. Make sure that the hosting web application, SilverlightCrossDomain.Web, is set as the startup project for the solution. Before interacting with it, right-click on the interface and choose the second option—Install SilverlightCrossDomain Application onto this computer. As shown in the following screenshot, Silverlight will display a prompt warning that the application requires elevated permissions and thus has access to system resources. Click on the Install button to finish installing the application on the local machine:

  7. Our application now runs as a trusted application and can access the service located on another domain, without cross-domain restrictions preventing us from accessing this service. The running application is shown in the following screenshot:

How it works...

The default behavior of Silverlight is that it will check for the existence of a cross-domain policy file, when accessing services that are hosted on a domain different from the one the Silverlight application itself is hosted on.

Starting with Silverlight 4, a new option was added: an application that runs with elevated permissions. This so-called trusted application has permissions that regular in-browser or regular out-of-browser Silverlight applications don't have. For example, it can access the local filesystem, perform COM interop or P/Invoke calls, and also perform cross-domain service access without checking for the policy file.

COM interop is a technology, part of .NET, that makes it possible to interact with COM objects, directly from .NET code. This way, .NET code can call into existing COM components without these components needing to be changed. Working with Microsoft Office components requires that COM interop code is written.

P/Invoke (short for Platform Invocation Services) is another CLR feature that allows .NET code to invoke native (for example, C++) code.

With Silverlight 5, the concept of trusted applications is extended into the browser: in-browser applications can run with elevated permissions as well. In case you are building this type of application, it will also be able to access a service in a cross-domain manner without a cross-domain file being in place.

See also

In the previous recipe, we looked at the default cross-domain behavior, where Silverlight restricts the access to services that are not hosted in the same domain.

Microsoft Silverlight 5 Data and Services Cookbook Over 100 practical recipes for creating rich, data-driven, business applications in Silverlight 5 with this book and ebook
Published: April 2012
eBook Price: $35.99
Book Price: $59.99
See more
Select your format and quantity:

(For more resources on silverlight, see here.)

Reading XML using HttpWebRequest

Applies to Silverlight 3, 4 and 5

The services we used in the first two recipes of this chapter were self-describing services. By this we mean that the service itself exposes information about its methods and data types by means of a WSDL file.

However, often we might need to access data that is not exposed by such a service. For example, we may need to read out XML data. This data could be available as a physical file on the server. It could perhaps be dumped by a process in a specific location. Alternatively, while sending a request to a specific URL, some services, such as REST services, return XML data.

Whether the XML comes from a REST service or lives in a file on the server, reading out XML is done using the WebClient class most of the time.However, if we need more control over the call, we should use the HttpWebRequest class. Everything we can do with the WebClient class can also be done using the HttpWebRequest class, but not vice-versa.

In this recipe, we'll look at how we can use the HttpWebRequest class to read out the XML data returned by a handler file.

How to do it...

To find out how to work using the HttpWebRequest class, we'll develop a handler that generates an XML string containing news items. Our Silverlight client will create an HttpWebRequest instance to request news items newer than a specified date from the handler and receive a response, the XML literal. We can use such a literal in a data binding scenario by parsing it using LINQ to XML. Following are the steps we need to execute to get the HttpWebRequest class working:

  1. Open the starter solution as outlined in the Getting Ready section of this recipe. In the web project, add a new Generic Handler in the Add new item dialog named NewsHandler.ashx. A handler can be recognized by its .ASHX file extension and is comparable to an ASP.NET webform as both implement the IHttpHandler interface and act like an endpoint. The IHttpHandler interface defines one method (ProcessRequest) and one boolean property (IsReusable). The ProcessRequest method will be executed when sending a request to the handler.
  2. Before we add the code to the handler, let's create a class named NewsRepository that represents a data access layer containing some hardcoded data (which is news items here). This class is located in the NewsRepository.cs file in the web project, and can be found in the samples. The most relevant part is shown in the following code. It contains the GetNewsAsXml method, which accepts the start date parameter. The method will carry out a LINQ query to retrieve the news items and return them in an XML format using the XElement class (part of LINQ to XML). The rest of the code for this class can be found in the completed solution of the code bundle:

    public string GetNewsAsXml(DateTime startDate) { XElement element = new XElement("news"); var result = from n in CreateNews() where n.DatePosted > startDate select n; foreach (var newsItem in result.ToList()) { element.Add(new XElement("newsitem", new XElement("newsitemid", newsItem.NewsItemId), new XElement("title", newsItem.Title), new XElement("content", newsItem.Content), new XElement("dateposted", newsItem.DatePosted), new XElement("image", newsItem.Image) )); } return element.ToString(); }

    For compiling this code, a reference has to be made to the System.Xml.Linq assembly.

  3. Let's now look back at the handler. In the ProcessRequest method, we'll call the previous method, which required a parameter of the DateTime type. We can get access to objects such as Server and Request using the context parameter of the ProcessRequest method. In this case, we'll use it to get the value sent from the client. In the following steps, we'll write the code that passes a DateTime object. Finally, we'll use the same Context instance to send the result back to the caller in an XML format. All this can be achieved using the following code:

    public void ProcessRequest(HttpContext context)
    {
    string news;
    using (System.IO.StreamReader reader = new
    System.IO.StreamReader(context.Request.InputStream))
    {
    string input = reader.ReadToEnd();
    DateTime startDate = DateTime.Parse(input);
    news = new NewsRepository().GetNewsAsXml(startDate);
    }
    context.Response.ContentType = "text/xml";
    context.Response.Write(news);
    }

  4. That's all for the server side! The next stop is the client side. The UI for the application is quite simple. The code can be found in the MainPage.xaml file of the code bundle. It mainly contains a Button that will load the news items into a ListBox when clicked. The ListBox has a DataTemplate applied to it, which uses data binding features to tie the items to the template.
  5. When clicking on the button, we need to send a request to the URI of the handler and later work with the response. We can use the Create method of the HttpWebRequest class to create the request. This method accepts a URI as a parameter and returns a WebRequest instance. We can use this instance to call the service. The following code creates a WebRequest using the Create method of the HttpWebRequest class:

    request.ContentType = "text/xml";
    private void LoadButton_Click(object sender, RoutedEventArgs e) { WebRequest request = HttpWebRequest.Create(new Uri("http://localhost:61639/NewsHandler.ashx", UriKind.Absolute)); }

  6. We need a stream to send data to a service (the start date). Getting this stream is carried out asynchronously using the BeginGetRequestStream method of the request. We also need to specify that we'll be sending data, so we need to set the Method to POST. This is shown in the following code:

    request.ContentType = "text/xml";
    request.Method = "POST";
    request.BeginGetRequestStream(RequestCallback, request);

  7. The callback method implements the AsyncCallback delegate. It has an IAsyncResult parameter. The AsyncState property of the IAsyncResult instance is cast to HttpWebRequest. Using this instance, we retrieve the EndGetRequestStream method to get the request stream. We use a StreamWriter instance to write the current date as shown in the following code:

    void RequestCallback(IAsyncResult result)
    {
    HttpWebRequest request = result.AsyncState as HttpWebRequest;
    Stream stream = request.EndGetRequestStream(result);
    using (StreamWriter writer = new StreamWriter(stream))
    {
    writer.Write(new DateTime(2009, 12, 1));
    }
    }

  8. We can now use the request to invoke the service and get its result asynchronously. This is done using the BeginGetResponse method. The invocation is carried out using the following line of code, which again specifies a callback method— ResponseCallback.

    request.BeginGetResponse(ResponseCallback, request);

  9. The ResponseCallback method is similar to the RequestCallback. It has the same IAsyncResult parameter as the RequestCallback had. We get access to the HttpWebRequest object again using the AsyncState property of the IAsyncResult. On this instance, we call the EndGetResponse to get an HttpWebResponse instance. This is shown in the following code:

    void ResponseCallback(IAsyncResult result)
    {
    HttpWebRequest request = result.AsyncState as HttpWebRequest;
    HttpWebResponse response = request.EndGetResponse(result) as
    HttpWebResponse;
    }

  10. We invoke the GetResponseStream method on the HttpWebResponse instance. This call returns a Stream that can be used in combination with a StreamReader to read out the response from the service. This is shown in the following lines of code:

    using(StreamReader reader = new
    StreamReader(response.GetResponseStream()))
    {
    string responseMessage = reader.ReadToEnd();
    }

  11. This string now contains the XML data as returned from the service. We can parse it and generate instances of a custom class called NewsItem using LINQ to XML. This is shown in the following code:

    public class NewsItem
    {
    public int NewsItemId { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }
    public DateTime DatePosted { get; set; }
    public string NewsImage { get; set; }
    }

  12. The parsing of the XML code generates a List. The code uses the XDocument and the XElement classes that are located in the System.Xml. Linq namespace. This namespace lives in the corresponding System.Xml.Linq assembly to which we need to create a reference. The parsing process is shown in the following lines of code:

    XDocument document = XDocument.Parse(responseMessage);
    var query = from n in document.Descendants("newsitem")
    select n;
    List<NewsItem> newsItems = new List<NewsItem>();
    foreach (XElement element in query)
    {
    NewsItem newsItem = new NewsItem();
    newsItem.NewsItemId = int.Parse
    (element.Descendants("newsitemid").First().Value);
    newsItem.Title = element.Descendants("title").First().Value;
    newsItem.Content = element.Descendants("content").First().Value;
    newsItem.DatePosted = DateTime.Parse
    (element.Descendants("dateposted").First().Value);
    newsItem.NewsImage= element.Descendants("image").First().Value;
    newsItems.Add(newsItem);
    }

  13. Now that we have a collection of items, we want to display them in a ListBox. However, the asynchronous service call operates in the background thread and thus cannot directly access the controls in the UI that live in the UI thread. However, we can use the Dispatcher class to invoke the code in the UI thread from the background thread, as shown in the following line of code:
    this.Dispatcher.BeginInvoke(() => NewsListBox.ItemsSource = 
    newsItems);
  14. At this point, we have successfully communicated with a service using the HttpWebRequest class.

How it works...

Silverlight can connect with several types of services. They can be categorized into two types— services that describe themselves and services that do not describe themselves. The latter can be used from Silverlight by using either the WebClient class or the HttpWebRequest class. Most of the time, the more easy-to-use WebClient class will suffice. It contains all that is needed to carry out communication with most services.

However, if more control is needed over the call to the service, the HttpWebRequest class can be used. It has more options than the WebClient class. In spite of that, the WebClient class does use the HttpWebRequest class under the hood.

All calls carried out using the HttpWebRequest class take place asynchronously. Using the HttpWebRequest class, we can send data to the service using the request as well as read out data using the response.

The request

A WebRequest instance is created using the Create method of the HttpWebRequest class. This method accepts one parameter, which is the URI of the service. On the created WebRequest instance, we can specify the HTTP verb. Silverlight's HttpWebRequest class supports the GET and the POST methods. If we want to send data to the service (for example a search term), we need to get the request stream. This can be done using the BeginGetRequestStream method of the HttpWebRequest class, which starts an asynchronous call to get the request. This method requires two parameters—a callback method and a state. The callback method is executed when the request stream is ready. For the state, we pass in the request itself, so that we have access to it in the callback.

In the callback method, we can get the request by casting the AsyncResult property of the IAsyncState interface back into the HttpWebRequest class. On this instance, we can call the EndGetRequestStream method that gives us access to the request stream. We can write to this stream using a StreamWriter.

The response

The request instance can be used to invoke a service and get back its result. To carry out this invocation, we use the BeginGetResponse method on the request, which is, quite logically, also asynchronous. In the specified callback, we can use the EndGetResponse method, which will give us an HttpWebResponse instance. On this instance, we can use the GetResponseStream method, which returns a stream. This stream can then be used to read the textual response from the server.

Threading headaches

Calls using the HttpWebRequest class take place on the background thread. The code that runs in this thread has no access to the UI and its controls. This means that we can't update the UI from the callback method. Luckily, we can use the Dispatcher class. Using the Dispatcher, we can cross threads quite easily by means of the BeginInvoke method. The Dispatcher.BeginInvoke method allows us to call from the background thread code that will be executed on the UI thread.

Summary

In this chapter, we learned the following:

  • Connecting and reading from a standardized service
  • Persisting data using a standardized service
  • Configuring cross-domain calls
  • Working cross-domain from a trusted application
  • Reading XML using HttpWebRequest

Further resources on this subject:


About the Author :


Gill Cleeren

Gill Cleeren is Microsoft Regional Director (http://www.theregion.com), Silverlight MVP (former ASP.NET MVP) and Telerik MVP. He lives in Belgium where he works as .NET architect at Ordina (http://www.ordina.be/). Passionate about .NET, he’s always playing with the newest bits. In his role as Regional Director, Gill has given many sessions, webcasts and training on new as well as existing technologies, such as Silverlight, ASP.NET and WPF at conferences including TechEd Berlin 2010, TechDays Belgium – Switzerland - Sweden, DevDays NL, NDC Oslo Norway, DevReach Bulgaria, NRW Conference Germany, Spring Conference UK, Telerik Silverlight Roadshow in Sweden, Telerik RoadShow UK. He is the author of Packt’s Microsoft Silverlight 4 Data and Services Cookbook and is also the author of many articles in various developer magazines and for SilverlightShow.net and he organizes the yearly Community Day event in Belgium. He also leads Visug (http://www.visug.be), the largest .NET user group in Belgium. You can find his blog at http://www.snowball.be and on Twitter by following @gillcleeren.

Kevin Dockx

Kevin Dockx lives in Belgium and works at RealDolmen, one of Belgium's biggest ICT companies, where he is a 30-year old technical specialist/project leader on .NET web applications, mainly Silverlight, and a solution manager for Rich Applications (Silverlight, Windows Phone 7, WPF, Surface, HTML5). His main focus is on all things Silverlight, but he still keeps an eye on the new developments concerning other products from the Microsoft .NET (Web) Stack. As a Silverlight enthusiast, he's a regular speaker on various national and international events, like Microsoft DevDays in the Netherlands, Microsoft Techdays in Portugal, NDC Oslo Norway, and Community Day Belgium. He is the author of Packt’s Microsoft Silverlight 4 Data and Services Cookbook and also writes articles for various Silverlight-related sites & magazines. His blog, which contains various tidbits on Silverlight, .NET, and the occasional rambling, can be found at http://blog.kevindockx.com/, and you can find him on Twitter as well: @KevinDockx.

Books From Packt


Microsoft Silverlight 5 and Windows Azure Enterprise Integration
Microsoft Silverlight 5 and Windows Azure Enterprise Integration

Microsoft Silverlight 5: Building Rich Enterprise Dashboards
Microsoft Silverlight 5: Building Rich Enterprise Dashboards

Microsoft Silverlight 4 Data and Services Cookbook
BMicrosoft Silverlight 4 Data and Services Cookbook

Microsoft Silverlight 4 and SharePoint 2010 Integration
Microsoft Silverlight 4 and SharePoint 2010 Integration

Silverlight 4 User Interface Cookbook
Silverlight 4 User Interface Cookbook

Microsoft Silverlight 4 Business Application Development: Beginner’s Guide
Microsoft Silverlight 4 Business Application Development: Beginner’s Guide

Windows Phone 7 Silverlight Cookbook
Windows Phone 7 Silverlight Cookbook

Managing Data and Media in Microsoft Silverlight 4: A mashup of chapters from Packt's bestselling Silverlight books
Managing Data and Media in Microsoft Silverlight 4: A mashup of chapters from Packt's bestselling Silverlight books


Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software