Previous: Getting Data to Your Application
Accessing Data through WCF
Visual Studio .NET provides relatively seamless integration of WCF services into your Silverlight application. A huge benefit of leveraging WCF is automatic type serialization and deserialization between the server and client for a wide variety of Types.
Taking advantage of WCF can be factored into several key steps including:
1. Creating business objects which correspond to your data
2. Exposing WCF services for working with those objects
3. Referencing the WCF service from your Silverlight Project and creating proxy classes
4. Accessing the services from your Silverlight Application
Factoring out Business Objects for Your Data
While it might be a foregone conclusion to factor out business objects for many developers who have been working with web services or following formal tiered architectures, many ASP.NET developers choose to include SQL queries directly in their presentation layer and have found no need to do so. If you fall into the latter category, get ready for a major context switch! The time spent making this adjustment is well worth it since your developer skills and the applications you build will be greatly improved.
Since Silverlight does not provide any classes for accessing SQL databases directly you are forced to create a server side layer which exposes the data to the client. While you are free to employ a variety of server side data access technologies, it is strongly advisable to create objects which represent that data which is essential to your application.
This could be as strait forward as creating a set of objects which mirror your SQL table structure, or might be more involved depending on the architecture of your application.
In this example we are going to reuse the Destination object:
public class Destination
{
public string Name { get; set; }
public int Population { get; set; }
public double AverageAirfare { get; set; }
public double AverageHotel { get; set; }
public string BestKnownFor { get; set; }
}
Serialization
At some point WCF is going to need to serialize your types so you should take a moment to consider what is the most appropriate for your applications types. The three built in serialization mechanisms are:
XmlSerializer
DataContractSerializer
NetDataContractSerializer.
By default WCF will uses DataContractSerializer while classic ASMX services defaulted to XmlSerializer. This disconnect may lead to some confusion if you are transitioning between the two service platforms.
If you are using built in types and don’t have particularly complicated objects you should not need to spend much time digging through MSDN’s serialization documentation. One issue that you may encounter involves serialization of automatic properties. In order to ensure that these properties are exposed properly the Destination class requires some extra metadata:
[Serializable]
[DataContract]
publicclass Destination
{
[DataMember]
publicstring Name { get; set; }
[DataMember]
publicint Population { get; set; }
[DataMember]
publicdouble AverageAirfare { get; set; }
[DataMember]
publicdouble AverageHotel { get; set; }
[DataMember]
publicstring BestKnownFor { get; set; }
}
Exposing a WCF Service
Start by adding a new “Silverlight-enabled WCF service” to your web application in Visual Studio. You might be wondering why we selected Silverlight Enabled WCF service instead of creating a standard WCF service. The primary difference is the transport enabled for the service. Silverlight only supports basicHttpBinding and a quick look at your web.config will show that this has been configured automatically for the new service.
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behaviorname="CaribbeanDestinationsWeb.DestinationsServiceBehavior">
<serviceMetadatahttpGetEnabled="true" />
<serviceDebugincludeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironmentaspNetCompatibilityEnabled="true" />
<services>
<servicebehaviorConfiguration="CaribbeanDestinationsWeb.DestinationsServiceBehavior"
name="CaribbeanDestinationsWeb.DestinationsService">
<endpointaddress=""binding="basicHttpBinding"
contract="CaribbeanDestinationsWeb.DestinationsService" />
<endpointaddress="mex"binding="mexHttpBinding"
contract="IMetadataExchange" />
</service>
</services>
</system.serviceModel>
After selecting an appropriate ServiceContract namespace and class name you will want to create a set of methods which are flagged with the OperationContract attribute.
In this case one service is offered for retrieving a list of Destinations.
[ServiceContract(Namespace = "CaribbeanDestinationsWeb")]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
publicclassDestinationsService
{
[OperationContract]
publicList<Destination> GetIslands()
{
List<Destination> destinations = newList<Destination>();
destinations.Add(newDestination
{
Name = "St Croix"
});
destinations.Add(newDestination
{
Name = "St John"
});
destinations.Add(newDestination
{
Name = "St Thomas"
});
return destinations;
}
}
Referencing the WCF Service from Silverlight
Now that you have a WCF service to offer up it is time to set up the hooks so you can access it from the client. To make consuming services easy Visual Studio is capable of generating proxy classes for accessing the service.
This process begins by selecting “Add Service Reference” from the project menu. You can select services by URI or by finding them in other solution projects. Visual Studio’s interface allows you to drill into the service to verify that it exposes the operations you expect.
Take a moment to consider the appropriate namespaces Visual Studio is about to create for consuming and working with the data provided by the service. Once a service is selected, choose a Namespace for the proxy objects through which you will access the service.
A host of advanced options which control the proxy classes which Visual Studio generates are available by selecting the “Advanced …” button. If you are wondering why the return type of collection objects exposed through the service don’t align with what is found in the generated proxy class take a quick look at the Advanced settings. One option that may catch you by surprise is that the proxy class will expose collections offered through service operations as ObservableCollections. Later in this chapter we will discuss the advantages of using this collection when binding a collection to the presentation layer.
Accessing the Service from Silverlight
Having created and exposed a WCF service, you are now set up to consume it from Silverlight. Each time you add a service reference Visual Studio creates several classes for facilitating communication with the service. The ServiceClient is the key class for calling into the service and named the same as the service with “ServiceClient” appended. For example in the Lumos application example AuthenticationServiceClient was created as a proxy class for accessing the AuthenticationService.
The ServiceClient Class
Similarly to the WebClient class, ServiceClient derived classes are architected around asynchronous calls to the server. A quick inspection of the Lumos AuthenticationServiceClient class reveals unique asynchronous methods and matching event handlers for each method in the AuthenticationService. This is pattern you will find in all Service Client classes
To call into a server you need to create a new instance of the ServiceClient, attach on event handler for the method you wish to call and finally invoke the service.
AuthenticationServiceClient client = new AuthenticationServiceClient();
client.LoginCompleted += new
EventHandler<LoginCompletedEventArgs>(authenticationService_LoginCompleted);
client.LoginAsync(this.txtUsername.Text, this.txtPassword.Text, "", true, this.txtUsername.Text);
Waiting for the Service to Respond
The Completed event will be called when the service returns or if an error has occurred. Access to the return data from the service is provided in a strongly typed manner through the Result property of the custom EventArgs objects created for each service method.
void authenticationService_LoginCompleted(object sender, LoginCompletedEventArgs e)
{
// First check if there was an error or null result
if (e.Error != null && e.Result )
{
UserContext.Instance.UserState = e.UserState;
UserContext.Instance.LoggedIn = e.Result;
this.Visibility = Visibility.Collapsed;
}
else
{
//show some type of error
this.btnAttemptLogin.IsEnabled = true;
}
}

RSS

