Using WebService Data With Silverlight

Posted Sunday, March 23, 2008 11:58 PM by Kevin

Now, I want to do something a bit more dynamic.  How about we call a web service, get some dynamic data back, and render something based on that data?  In this post, I will build a simple example in order to clearly illustrate the concepts.  But at the end, I will post an example of something a bit more useful to show what can be done!

First off, let's define a simple web service.  I used VS2008's New Item wizard and selected "Web Service" from the dialog.  Then, I replaced HelloWorld() with my own GetData() method.  Here's what the code behind for MyService.asmx looks like:

[WebService(Namespace = "http://tempuri.org/")]

[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]

[ToolboxItem(false)]

// To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line.

[System.Web.Script.Services.ScriptService]

public class MyService : System.Web.Services.WebService

{

    [WebMethod]

    [ScriptMethod]

    public string[] GetData()

    {

        string[] data = new[] { "first data", "second data", "third data" };

        return data;

    }

}

Note I also have uncommented the ScriptService attribute on my class and added a ScriptMethod attribute to my method.  Calling web services from Javascript is a whole lot easier using ASP.NET AJAX.  You'll need to have the ASP.NET AJAX 1.0 Extensions installed for this to work, but it's worth it.  Oh, I'm also using the new array initialization syntax from C# 3.0 in case you've never seen it before.  A real world application would probably query a database or something.

In order to call the web service from Javascript, ASP.NET AJAX requires us to place a ScriptManager on the page with a ServiceReference pointing to the .asmx.  Here's what mine looks like:

<asp:ScriptManager ID="ScriptManager1" runat="server">

    <Services>

        <asp:ServiceReference Path="~/MyService.asmx" />

    </Services>

</asp:ScriptManager>

Thankfully, VS2008's web application project template already set up my web.config to use ASP.NET AJAX.  If you are not using VS2008, you may need to follow the directions at http://asp.net/AJAX/Documentation/Live/ConfiguringASPNETAJAX.aspx to ensure your web.config is set up properly.

At this point, I can call my web service from Javascript and react to whatever data comes back.  The question is - what should it do?  For this post, I think I'll just put up a Silverlight TextBlock and rotate through the web service data when the user clicks on the text.  Here's the XAML:

<Canvas xmlns="http://schemas.microsoft.com/client/2007" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

 

    <TextBlock x:Name="MyTextBlock" FontSize="10" FontFamily="Arial" Canvas.Top="10" Canvas.Left="10" Loaded="MyTextBlockLoaded" MouseLeftButtonDown="MyTextBlockClick" />

 

</Canvas>

First, I will retrieve the data from the web service once the text block has loaded by using the Loaded event.  Let me show you the Javascript and then I will explain it...

var index;

var data;

 

function MyTextBlockLoaded( sender, args )

{

    MyService.GetData( GetDataSuccess, GetDataFailed );

}

 

function GetDataSuccess( result )

{

    data = result;

    index = 0;

    UpdateTextBlock();

}

 

function GetDataFailed()

{

    alert( 'Call to MyService.GetData() failed!' );

}

 

function UpdateTextBlock()

{

    var textblock = document.getElementById( '<%= Silverlight1.ControlId %>' ).content.findName( 'MyTextBlock' );

    textblock.Text = data[index];

}

First I declare a variable to hold the current index into the data array and a variable to hold the data itself.  The implementation of the MyTextBlockLoaded() event handler is calling the web service using the proxy built by ASP.NET AJAX.  Note that because this is an asynchronous call, you have to pass in event handlers for both success and failure - that is where my GetDataSuccess() and GetDataFailed() functions come from.  On success, I store the data, set the initial index to 0, and call the function to set the text in the TextBlock.  Note I'm using document.getElementById() to find the Silverlight viewer.  I'm using some inline server-side script to get the Id of the Silverlight viewer from my control (covered in a previous post) to pass to getElementById().  The viewer object has a content property upon which I can call findName() (also covered in a previous blog post) to get a reference to the TextBlock.

The last thing to do is handle the MouseLeftButtonDown event on the TextBlock so that the text changes when the user clicks on it.  Here's that Javascript function:

function MyTextBlockClick( sender, args )

{

    if ( index >= data.length-1 )

    {

        index = 0;

    }

    else

    {

        index = index + 1;

    }

 

    UpdateTextBlock();

}

Here, I increment the index and when the index reaches the end of the list, I reset it to 0 to go back to the beginning.  Then I call UpdateTextBlock() to display the new text.

You can see this example in action at http://www.killeverything.com/zak/Silverlight1/WebService1.aspx.

At the beginning of this post, I promised to show a more useful example.  How about a Silverlight app that displays headlines from an RSS feed and lets you click through to the articles?  If you've been reading my Silverlight posts, there shouldn't be anything too new going on here.  I have just combined several of the concepts I've been learning and blogging about into a single Silverlight app.  You can see it running here: http://www.killeverything.com/zak/Silverlight1/WebService2.aspx and the code for both the simple example and the RSS headline viewer are attached to this post.  If you're a .NET head, you might want to look at the source for the web service where I used LINQ to XML to make parsing the RSS feed easy as cake.  Oh, and I want to point out the clipping I had to add to the TextBlock.  Support for MaxHeight and MaxWidth may be coming in Silverlight 2.0, but clipping is how it's done for now...

Comments

No Comments