Consuming services asynchronously

Services (and most notably web services) are a main ingredient in today's LOB applications. Nowadays, you'll have a hard time finding an application that doesn't require access to data. While Silverlight doesn't offer a native client-side database solution (though you can find some great third-party solutions for that, such as Sterling DB), web services are your main route to access data.

Microsoft made sure that Silverlight is well equipped for the task of accessing data. Silverlight is able to consume services of ASMX, WCF, REST, POX, RSS, and others. Just like any other .NET language, Visual Studio will automatically generate a proxy class in our project when working with an ASMX or WCF service. This proxy class is in charge of making the actual connection to the service, and send and receive data to and from it. The one big difference between Silverlight and other .NET languages is that all communication in Silverlight happens asynchronously. This is a very logical functionality, because it makes sure that Silverlight's UI thread won't be locked down while waiting for a response from a service, which can happen in a synchronous model.

Now that we understand all the background information of the consuming services, let's get down to action and consume our first web service!

Adding your first service reference

Fire up Visual Studio 2010 and open the Chapter4-ConsumeService project from the downloadable book files from the Packt website. The project contains a Silverlight application and a WCF service, which reside inside the web project.

Note

We won't be discussing the details about the WCF service itself, as this is not the focus of our book, but I highly recommend you to pick up Microsoft Windows Communication Foundation 4.0 Cookbook for Developing SOA by Packt if you are interested in the subject.

Open the MainPage.xaml file and inspect it. You'll notice we have a DataGrid control added to the page. Once we hook up the web service to the project, the DataGrid control will display its result. To know what we are dealing with, open up the ContactsService.svc file in the web project. The service consists of a single method called GetEmployees and a class to represent the data we are displaying. Our Silverlight application will call this method and get back an IEnumerable control with a list of employees.

To add a service to your Silverlight project, simply right-click on the Service References folder under your Silverlight project and choose Add Service Reference.

We are now presented with two possible ways to add a service—enter its URL or let Visual Studio discover the service on its own. Visual Studio can only discover services that are added within the solution, and as our service is added under the web project, it fits into this term.

Click on Discover. You should get a screen similar to the following screenshot:

Adding your first service reference

The service details are listed under the Services area. If you click on the little arrow to the left-hand side of the service file name, you'll be able to drill down and up until the point you can see all the available methods the service exposes.

Under Namespace, you can enter a string value that will represent the service class namespace in the project.

Change the default ServiceReference1 namespace to something more meaningful such as EmployeesService and click on OK.

Now that we have our service added, it's time to use it! Add the following line of code just above the constructor of MainPage in the MainPage.xaml.cs file:

private EmployeesService.ContactsServiceClient proxy = new EmployeesService.ContactsServiceClient();

We can now use our new variable—proxy, to communicate with the web service. Silverlight web services only work asynchronously, so we have to declare a completed event handler, for when the method we wish to run finishes. The completed event name will always consist of the name of the method and Completed in the end. For example, in our web service we have a method called GetEmployees, therefore to attach an event handler for its completed event we will attach the GetEmployeesCompleted event handler. Add the following line of code inside the constructor of MainPage:

proxy.GetEmployeesCompleted += new EventHandler<EmployeesService.GetEmployeesCompletedEventArgs>(proxy_GetEmployeesCompleted);

We have attached a new event handler called proxy_GetEmployeesCompleted to the completed event of our desired method. In our example, there is only one action we wish to perform when the method finishes, and that is to set its result to the lonely DataGrid control that we added to MainPage.xaml. Add the following code snippet in the proxy_GetEmployeesCompleted event hander, so the method will look as follows:

void proxy_GetEmployeesCompleted(object sender, EmployeesService.GetEmployeesCompletedEventArgs e)
{
ContactsGrid.ItemsSource = e.Result;
}

As can be seen from the preceding code, we bind the ItemsSource property of DataGrid to the Result property of the e object. This e object holds many properties in the context of our request. Other than Result, you have the Error property, which holds details about what went wrong during the asynchronous operation, or the Canceled property, which is a Boolean property that indicates whether the operation got canceled.

If we recap what we have done so far, we have added a service, attached an event handler for its completed event, and bound the results of the operation to a DataGrid control that was added to the UI layer. There is still one thing missing from our application that prevents it from actually doing something—calling the method on the web service. Calling a method is as simple as the following line of code:

proxy.GetEmployeesAsync();

Add the preceding line of code just after the event handler declaration and run your application. You should get the result, as shown in the following screenshot:

Adding your first service reference

We have successfully added a service reference and handled its completed event.

Configuring service endpoint

In almost any work environment nowadays, you have a testing and production environment. When you deploy your solution to the testing environment, you will usually reference a service that runs in that environment. But what happens when you move your application to the production environment? You probably guessed it—the services you reference no longer exist. This is exactly the case that service endpoints come to solve. Whenever you add a new service reference via the Add Service Reference option in Visual Studio 2010, a new file named ServiceReferences.ClientConfig gets created in your Silverlight project. This file contains binding and endpoint configurations for the service you added. If you switch back to Visual Studio and open the ServiceReferences.CliengConfig file in the last project we worked on, you will get something similar to the following code snippet:

<client>
<endpoint address="http://localhost:53985/ContactsService.svc"
binding="customBinding" bindingConfiguration="CustomBinding_ContactsService"
contract="EmployeesService.ContactsService" name="CustomBinding_ContactsService" />
</client>

The preceding code snippet shows us the default endpoint that Visual Studio creates for us when we add a service reference, but that doesn't mean we can't interfere with the file a bit by ourselves. We know this endpoint represents our testing environment, so let's add an endpoint for our production environment too! Add the following code snippet just before the closing client element in your file:

<endpoint address="http://localhost:53985/ContactsService.svc"
binding="customBinding" bindingConfiguration="CustomBinding_ContactsService"
contract="EmployeesService.ContactsService" name="ContactsService_Production" />

While in our example the address is exactly the same, in real environments it would be different. Now that we have the new entry in the configuration file, how do we get Silverlight to act on it? Well, do you remember the code we used to initiate our service in the last example?

private EmployeesService.ContactsServiceClient proxy = new EmployeesService.ContactsServiceClient();

The constructor for ContractsServiceClient is overloaded so it can accept parameters, as well as empty initiation. Change this code in your project to the following code snippet:

private EmployeesService.ContactsServiceClient proxy = new EmployeesService.ContactsServiceClient("ContactsService_Production");

Build and run your application, and you'll notice that nothing has changed. Your application works just the same, but this time it uses the production service reference.

In a real project, you'll probably want a better solution than to hardcode these properties in your code. In this case, you can use Visual Studio's Configuration Build Manager to create new profiles but this is out of the scope for this book. If you are interested in the subject, take a look at the MSDN documentation for working with the configuration manager at http://msdn.microsoft.com/en-us/library/kwybya3w(v=VS.100).aspx.

Handling timeouts

The default timeout for a service call in Silverlight 4 is 30 seconds. While 30 seconds should be more than enough time for your request to return, sometimes you need a little more. To change the default timeout property, we set the OperationalTimeOut property of the web service proxy element's InnerChannel. The property accepts a TimeSpan value and sets it as the service request timeout. To change our service to a one minute timeout, add the following line of code just above the call to the GetEmployees method in your constructor:

proxy.InnerChannel.OperationTimeout = new TimeSpan(0, 1, 0);

Now your application will wait for a minute before it throws a time-out exception.

Cross-domain networking

Silverlight implements a strict cross-domain policy when accessing assets like web services over the network. In order to appear more secure, Silverlight, just like Adobe Flash, restricts the network connections to only be able to connect to resources on the same domain as the Silverlight application. For example, if our application runs on http://intranet/, it will only be able to consume web services that run on that exact domain.

The one exemption to this rule is services that host what is known as a policy file. This policy file is basically an XML file that defines resources, the services expose to the domains they trust. The clientaccesspolicy.xml file defines these policies and has to be placed at the root folder of the hosting domain. The file is only a valid policy file if placed in the root folder. Any other location will be ignored by Silverlight. A simple implementation of this file looks like the following code snippet:

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

The preceding code snippet is in an example of a minimum security clientaccesspolicy.xml file as it allows access to any resource on the server to any requesting domain. You can adjust the file to fit your security needs quite easily using the provided properties. You can read more about the clientaccesspolicy.xml file over at MSDN—http://msdn.microsoft.com/en-us/library/cc645032(v=vs.95).aspx.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.118.2.240