The How-To series demo Silverlight accessing Web Services in various configuration. In this post, we will demonstrate a SOAP service consumed by a Silverlight client application. This scenario can be categorized as a D2D scenario with a cross domain policy.
Both the Silverlight and SOAP service are available as an attachment to this post. Since Metro libraries are too large, you will need to copy all jar files from metro\lib\ folder into WebContent\WEB-INF\lib project folder. Steps are described below.
- SOAP services are built with JAX-WS and JAX-B APIs and hosted in Tomcat.
- The Silverlight application is hosted under the Visual Studio embedded Web Server code name “Catalina” (which delivers a subset of the IIS capabilities)
Download the jar file from https://metro.dev.java.net/1.2/ and launch it. A “metro” folder has been created at the jar location. metro\lib folder contains all the needed libraries for the Java SOAP service development and Tomcat configuration. Here is a good link that describes how to configure your Tomcat server http://blogs.sun.com/arungupta/entry/metro_on_tomcat_6_x
Implementing the SOAP / RPC service
- In Eclipse, create a new Dynamic Web Project called “SOAP-SumService”
- copy all jar files from metro\lib\ folder into WebContent\WEB-INF\lib project folder.
- Create a package called “service” and add a new Java class called “ServiceSumImpl” to this package.
- Add a xml file to WebContent\WEB-INF called “sun-jaxws.xml”.
Your project structure now looks like this :
Implementation of the Web Service endpoint
In ServiceSumImpl.java, import the following libraries :
Declare the class as a Web Service endpoint with the following annotations, for more informations about annotations refer to this site.
The only method that our service exposes is getSum. It returns the sum of two integers. But we want this method to be known over the service as “SumTwoInt”. Within the annotations we can configure all these parameters.
- Now build the project to generate the bytecode as the WSGen tool need it.
Generation of the required artifacts for the Web Service deployment and invocation
For this step, Metro provides a generation tool called “wsgen”.
- Open a Windows Command Prompt : Start->Run and type “cmd”
- set a METRO as a path variable to metro\bin folder (in our case it is C:\metro\bin path)
- Go to your build project folder (by default in Eclipse: ProjectName\build\classes). In our example it is the SOAP-SumService\build\classes folder
- Refresh the Project Explorer and observes that two java files have been generated
They represent the message that will be shared in the Web Service process
Configuring the Web Service Deployment
To configure the deployment, we need to instantiate a Servlet that will handles JAX-WS Web Services requests.
In web.xml, add a Servlet element. We use a pre-existing Web Service Servlet :
This servlet will handle every requests on /services/* URI, so let’s map to it with its name:
To provide the right context, we need a listener (which also already exists):
Finally, we need to expose the endpoint ServiceSumImpl within an URI, for example /services/sum.
Edit the sun-jaxws.xml file and add the following elements :
<?xml version="1.0" encoding="UTF-8"?>
<endpoints xmlns="http://java.sun.com/xml/ns/jax-ws/ri/runtime" version="2.0">
- Save all files, then Run the project on the Tomcat Server
Right click on the project node : Run As –> Run on Server
The service is now hosted on Tomcat at http://localhost:8080/SOAP-SumService/services/sum?wsdl
Enabling Cross Domain Access
Since the SOAP service and the Silverlight application reside on different hosts, we need to overpass the Cross Domain Issue. Create at the root of the SOAP service host, a clientaccesspolicy.xml file with the following content :
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<resource include-subpaths="true" path="/"/>
Consuming a SOAP service with Silverlight
Now that the Web Service is exposed, we are going to generate the client proxy to consume the Web Service with Silverlight.
Open Visual Studio 2008 and create a new Silverlight Project called SOAP-Sum and paste the following XAML code in Page.xaml to obtain a simple interface that will manipulate the web service.
<Canvas x:Name="LayoutRoot" Background="White">
<TextBox Text="0" x:Name="_int1" Width="50" Height="20"
Canvas.Top="10" Canvas.Left="30" TextChanged="_TextChanged"/>
<TextBlock Canvas.Top="10" Canvas.Left="95" Text="+"/>
<TextBox Text="0" x:Name="_int2" Width="50" Height="20"
Canvas.Top="10" Canvas.Left="120" TextChanged="_TextChanged"/>
<TextBlock Canvas.Top="10" Canvas.Left="175" Text="="/>
<TextBlock x:Name="_result" Canvas.Top="10" Canvas.Left="190" Text=""/>
- Add a Service Reference
Right click on References then chose Add a Service Reference
- In Address field, type the Sum service address then click Go (it should be http://localhost:8080/SOAP-SumService/services/sum?wsdl).
We actually have the Sum service named ServiceSum and one operation exposed as SumTwoInt, this is exactly what we did parameter in “Implementation of the Web Service endpoint” (see above)
- In Namespace field, type ServiceSum : this is how the service will be accessible through the Silverlight project. Click OK. In the Solution Explorer you see the ServiceSum reference in Service References.
Implementation of the client proxy
In Page.xaml.cs, add an import to SOAP-Sum.ServiceSum reference library.
1: using SOAP_Sum.ServiceSum;
Now we need to handle the TextChanged event in _TextChanged method :
- Instantiate a client proxy
ServiceSumClient client = new ServiceSumClient();
- Add an event handler corresponding to the operation we are going to use so we can get the result
- Use Async operation to send our two integers.
Operations are made asynchronous so Silverlight UI won’t freeze
The whole method looks like this :
1: private void _TextChanged(object sender, TextChangedEventArgs e)
3: // check if fields contain some text
4: if (_int1.Text == "" || _int2.Text == "") return;
6: int a = int.Parse(_int1.Text);
7: int b = int.Parse(_int2.Text);
9: // generate a client proxy to the Web Service
10: ServiceSumClient client = new ServiceSumClient();
11: client.SumTwoIntCompleted += new EventHandler<SumTwoIntCompletedEventArgs>(client_SumTwoIntCompleted);
Then we can process the result in the event handler
void client_SumTwoIntCompleted(object sender, SumTwoIntCompletedEventArgs e)
_result.Text = e.Result.ToString();
Run the project and type some integers in the text boxes : Silverlight is consuming a JAX-WS SOAP service.