Silverlight 2 Beta 2 - Doing Data Part I

This is the first in a series of articles focusing on working with Data and Databinding with Silverlight 2 Beta 2. Each article in this series will focus on a simple "task" in an easy-to-understand progression of working with Data via ASMX and WCF web service, WebClient, and other modalities, and using Silverlight Controls.

The future is here. It's just not widely distributed yet.  - William Gibson

To start, I'll lay out some groundwork so you can understand how the article projects will be set up, and why. First, I do all my ASP.NET web projects as "Web Application Projects" running under IIS (not the built-in web dev server).  I do this because the WAP under IIS is the closest you can get to an actual deployed app in production. Many developers and authors use the Web Site model, and use SQLEXPRESS with User Instance connection strings that point to the MDF database file in the App_Data folder. While this arrangement is very handy, I have seen that it also causes a great deal of confusion with newer developers when they attempt to deploy these, as "real life" hosted IIS accounts don't play well at all with these arrangements. All my databases are full SQL Server databases that are attached; no User Instance connections are employed.

Each solution in this series will uses a subset of my Quotations database. This "stripped down" database has 1000 famous quotations arranged in three tables (my original has 44,000 quotations, a little too big for a sample download!):

The database also includes a series of stored procedures sufficient to build a complete "Quotations" web site or Silverlight app. The SQL Script to create this database is in the /SQL subfolder of the solution.  So first, you'll want to create a new SQL Server database named "QUOTES", and run the SQL Script to populate everything.

For our first solution, we will create an ASMX WebService with a GetRandomQuote WebMethod. The method will accept two parameters, an int "numberofquotes" to return, and an optional string subject that corresponds to the Subject column in the Subjects table. We will then create a Silverlight app that consumes this webservice and binds the returned data to a DataGrid.

Create a new ASP.NET Web Application. Now Add a  Web Service (ASMX) to it with "Add, New Item". Now lets create a Quotation class that will mirror and contain the data returned from the database:

using System;
using System.Data;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;

namespace SilverlightWeb
{
    [Serializable]
    public class Quotation
    {
        public string AuthorName { get; set; }
        public string Subject { get; set; }
        public string AuthorInfo { get; set; }
        public string Quote { get; set; }
        public Quotation(  string authorName,  string subject, string quote, string authorInfo)
        {
            this.AuthorName = authorName;
            this.Subject = subject;
            this.Quote = quote;
            this.AuthorInfo = authorInfo;
        }

        public Quotation()
        {
        }
    }
}
Now, lets set up the WebMethod to retrieve our data, populate a List of Quotation objects, and return it:
[WebMethod]
        public List GetRandomQuote(int numQuotes, string subject)
        {
            var cnString = ConfigurationManager.ConnectionStrings["quotes"].ConnectionString;
            SqlDataReader rdr = PAB.Data.Utils.SqlHelper.ExecuteReader(cnString,
               "dbo.GetRandomQuote", numQuotes,  subject);
            var quotes = new List();           

            while (rdr.Read())
            {                 
                var AuthorName = (string)rdr["AuthorFirstName"] + " " +(string)rdr["AuthorLastname"];
                var authorInfo = (string)rdr["AuthorInfo"];
                var theQuote = (string)rdr["quotation"];
                var subj = (string)rdr["Subject"];
                var quote = new Quotation(AuthorName,  subj, theQuote,authorInfo);
                quotes.Add(quote);
            }
            rdr.Close();
            return quotes;
        }

Note that I'm using the handy SqlHelper class here. In later articles, we'll be using the LINQ to SQL generators. But for now, let's just keep it simple in order to get to "First Base".

Your WebService is now complete. Of course, you can look at the stored procs in the database and add additional WebMethods later. Test your WebService by right-clicking on the Service1.asmx page and selecting "View in Browser". You should see the standard ASMX webservice discovery page listing our one method. We are now ready to create our Silverlight Consumer App.

Add a new Silverlight Application to your Solution and accept the offer to add the Silverlight Test page to your existing Web Application. I called my app "quoter".  Now let's add a Service Reference to our SL App. In Solution Explorer, under Service References, right-click and "Add Service Reference". You should be able to Discover the existing WebService in the solution and the ServiceReference1 will be added.

Now we will consume and display the results of the GetRandomQuote WebMethod in a Silverlight DataGrid. In your Page.xaml markup, add the following code inside the default Grid usercontrol:

<Controls:DataGrid x:Name="Grid1"  Width="900" AutoGenerateColumns="True" Margin="0,0,0,0"  >
</Controls:DataGrid>
Now in our Page.xaml.cs codebehind, here is how we can consume the results:
public partial class Page : UserControl
    {
        public Page()
        {
            InitializeComponent();
            var c = new WebService1SoapClient();
            c.GetRandomQuoteCompleted += new EventHandler(c_GetRandomQuoteCompleted);
            c.GetRandomQuoteAsync(2, "");
        }

        void c_GetRandomQuoteCompleted(object sender, GetRandomQuoteCompletedEventArgs e)
        {
            ObservableCollection q = e.Result;
            this.Grid1.ItemsSource = q;
        } 
    }

In the Page constructor, we create an instance of the WebServiceSoapClient proxy. Then we set the GetRandomQuoteCompleted callback (you can type "+=" and hit the Tab key to stub this out automatically). Then we call the method, passing in a 2 to get 2 random quotes, and a null string for the subject, meaning "any subject".

In the callback method, we are going to get an ObservableCollection from our Generic List in the WebMethod. If your DataGrid has AutoGenerateColumns set, you can bind this directly to the DataGrid's ItemsSource property, and you are done!

The display should look something like this:

Incidentally, this works great in Firefox 3 RC1 on my machines.  In the next installment of the series, we'll add a ListBox of the Subjects and a Button to retrieve the results, and we'll switch to a WCF Service to get our data, plus a couple of other nice surprises.

D00ds, I CAN HAS SILVERLIGHT is within your grasp! KTHXBYE!

You can download the complete Visual Studio 2008 Solution here. Don't forget to change the connection string in the web.config to match your environment!
See Part II of this series.
By Peter Bromberg   Popularity  (2646 Views)