Click here to Skip to main content
Click here to Skip to main content

Silverlight tutorial: Creating a data centric web app with DataGrid, LINQ, and WCF Web Service

By , 11 Sep 2008
 

You can see a working example of this finished data centric Silverlight 2.0 web application at my web site.

Introduction

This article is a step-by-step tutorial on how to make a data centric Silverlight 2.0 web application. This tutorial will give you practical hands-on experience on all of the following:

  • Silverlight 2.0 DataGrid
  • LINQ
  • Web Services

If you go through this tutorial, I'll think you'll be amazed at how simple, powerful, and elegant these three technologies are. I've really started to feel that Microsoft is on a roll with some of these new technologies.

I will also give you instructions on how to deploy this application to a remote web server, which, in my experience, is probably the most difficult part. The instructions I give specifically apply to my host provider discountasp.net; however, no matter what your hosting provider, you'll probably need to do something similar.

Part 1: Building the application and testing it locally

  1. For this tutorial, you will need access to a web accessible database. As mentioned in the introduction, I use a web hosting account from discountasp.net, with a SQL Server 2008 add-on, but there are many options of hosting providers to choose from. To establish a connection with your remote database, select View from the menu and then Server Explorer. Click on the Connect to Database option, and then fill in the SQL Server name and database login that you can get from your hosting provider. Click Test Connection to confirm that you're set up.
  2. Create a new Silverlight Application called SilverlightClient. Call the solution WcfSqlDemo.
  3. VS 2008 will ask you if you want to add a Web to the solution. Select "Web Application Project" instead of the default "Web Site". Name the web WcfSqlDemoWeb.
  4. Right click on WcfSqlDemoWeb and select Add New Item. Select Data, LINQ to SQL Classes, and leave the name DataClasses1.dbml.
  5. What you should see next is:

  6. If you set up your server at the beginning of the project, you will already have a database in the Server Explorer view as I do (in my case, it's named sql2k801.SQL2008_540970). If you haven't, click on the cylinder with a plus sign icon under Server Explorer to connect to the database.
  7. Right click "Table" on your connected database and select Add New Table. Fill in the table as shown below. Under Properties, name the table DemoTable.
  8. Drag the DataTable onto DataClasses1.dbml.
  9. Set Key as the Primary Key.
  10. View properties for DataClasses1.dml. Set the serialization mode to Unidirectional so that it is compatible with Web Services.
  11. Okay, that takes care of your database. Now let's set up the Web Service. Right click on the WcfSqlDemoWeb project and add a new item. Select the Silverlight-enabled WCF Service template and name it DemoService.svc.
  12. Delete the DoWork method and replace with the two methods below, plus the following using references. By the way, the "var selected_rows = from rows in db.DemoTables select rows" stuff, that's LINQ. It's fantastic. It's a very clean and sensible query language that is built into .NET 3.5 that can be used for querying databases, XML, and even collections. One of the easier ways to figure out what LINQ is, is to look at some examples. I recommend Microsoft's 101 LINQ Samples. The LINQ line that I use in the GetRows method loosely means "Take the table db.DemoTable and assign the elements of that table to the collection rows, then select all those rows and assign them to the collection selected rows".
  13. using System.Collections.Generic;
    using System.Text;

    and also:

    // Return the list of valid data
    [OperationContract]
    public List<demotable> GetRows()
    {
    
        DataClasses1DataContext db = new DataClasses1DataContext();
    
        var selected_rows = from rows in db.DemoTables select rows;
    
        return selected_rows.ToList();
    
    }
    
    // Insert a new data into the database
    [OperationContract]
    public void InsertData(string testItem1,
                           string testItem2)
    {
        DataClasses1DataContext db = new DataClasses1DataContext();
        // Create a new row object.
        DemoTable row = new DemoTable
        {
            Key = Guid.NewGuid(),
            TestItem1 = testItem1,
            TestItem2 = testItem2
        };
    
        // Add the new object to the collection.
        db.DemoTables.InsertOnSubmit(row);
    
        // Submit the change to the database.
        db.SubmitChanges();
    }
  14. Now we need to let our Silverlight client know about the Web Service we've just created. Right click SilverlightClient and select Add Service Reference. Click Discover. VS2008 should find the service from the project. Allow it to be saved in the namespace ServiceReference1.
  15. Open page.xaml in Expression Blend. Make a form that looks something like what I've created below. Name the text boxes TestItem1TxtBox and TestItem2TxtBox.
  16. Now let's add the DataGrid into which the data we retrieve from the Web Service will be placed. The DataGrid control is not a default control of your Silverlight project, so you'll have to add it. Right click on References in SilverlightClient and add a reference to System.Windows.Control.Data. Now go to page.xaml. Add the following attribute to the user control element so we can get access to the DataGrid:
  17. xmlns:my="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"
  18. Now you can go to the asset library and find DataGrid under Custom Controls.
  19. Add a DataGrid to the project and size it. Name the grid ResultsGrid. If you look at the XAML, it should look similar to this:
  20. <my:DataGrid Margin="8,283,51,87" AutoGenerateColumns="True" x:Name="ResultsGrid"/>
  21. Add a button and label it "Get". The end result should be something like this:
  22. Add OnGetBtnClicked and OnSubmitBtnClicked to the clicked events of the respective buttons in Expression Blend. This will add the attributes to the XAML button tags and will wake up VS2008 and add the specified methods to the code-behind file.
  23. Fill in OnSubmitBtnClick and OnGetBtnClick as shown below. Create a call back to handle the GetRowsCompleted event. (By the way, are you noticing how easy this is? Look at how much is getting done with a few lines of code, and look how clean and sensible these few lines are.)
  24. private void OnGetBtnClick(object sender, RoutedEventArgs e)
    {
        DemoServiceClient webService = new DemoServiceClient();
    
        webService.GetRowsCompleted +=
            new EventHandler<getrowscompletedeventargs>(webService_GetRowsCompleted);
    
        webService.GetRowsAsync();
    }
    
    void webService_GetRowsCompleted(object sender, GetRowsCompletedEventArgs e)
    {
        ResultsGrid.ItemsSource = e.Result;
    }
    
    private void OnSubmitBtnClick(object sender, RoutedEventArgs e)
    {
        DemoServiceClient webService = new DemoServiceClient();
    
        webService.InsertDataAsync(TestItem1TxtBox.Text, TestItem2TxtBox.Text);
    }
  25. Build and test. Try submitting a few items and then getting the results. You should see something like the following:
  26. Easy, right? Notice how we didn't have to do anything to get the DataGrid to display our results other than assign our results to the DataGrid's ItemsSource. The only down side to this simplicity is that we're seeing everything returned, including the GUID representing the key. That's not very user friendly. Let's get rid of the auto-generation of columns and create custom ones. Also, it seems I needed to add an explicit size to the DataGrid, or I'd get a funny rendering of the grid when it's empty.
  27. <my:datagrid margin="8,283,51,85" 
       autogeneratecolumns="False" x:name="ResultsGrid"
       width="641" height="232">
        <my:DataGrid.Columns>
            <my:DataGridTextColumn 
                Header="Test Item 1" 
                DisplayMemberBinding="{Binding TestItem1}"/>
            <my:DataGridTextColumn 
                Header="Test Item 2" 
                DisplayMemberBinding="{Binding TestItem2}"/>
        </my:DataGrid.Columns>
    </my:datagrid>
  28. Build and Debug. The results should look exactly like before, except this time, there is no column for Key.
  29. By now, you're probably collecting some garbage in your database, because we have no way to delete any items. Let's change that now. First, let's modify our Web Service to be able to delete items from our database. Add the following to DemoService. Note that we're using more LINQ. The line below written in LINQ loosely means "Take the table db.DemoTable and assign the elements of that table to the collection rows, then select those rows where the key is the passed GUID and assign those selected rows to the collection selectedrow".
  30. // Delete the item specified by the passed key
    [OperationContract]
    public void DeleteRow(Guid key)
    {
    
        DataClasses1DataContext db = new DataClasses1DataContext();
    
        var selected_row = from rows in db.DemoTables where rows.Key==key select rows;
    
        // Delete the selected "rows". There will actual be only one
        // item in this collection because the Guid is unique and is the
        // primary key for the table.
        db.DemoTables.DeleteAllOnSubmit(selected_row);
    
        // Submit the change to the database.
        db.SubmitChanges();
    }
  31. Add a Delete button. When the Delete button is clicked, it will delete whatever item in our DataGrid that was selected.
  32. private void OnDeleteClick(object sender, RoutedEventArgs e)
    {
        DemoTable selectedRow = ResultsGrid.SelectedItem as DemoTable;
    
        // Now access the service to delete the item
        DemoServiceClient webService = new DemoServiceClient();
        webService.DeleteRowAsync(selectedRow.Key);
    
        // Now refresh the grid
        webService.GetRowsCompleted +=
            new EventHandler<getrowscompletedeventargs>(webService_GetRowsCompleted);
    
        webService.GetRowsAsync();
    }
  33. Rebuild and Debug. Now you can select items and delete them.

Part 2: Deploying the web app to a remote server

  1. Publishing the application to the web can be a little difficult. The instructions below have been tried out on my web hosting provider discountasp.net, but you're likely to need to do something similar for other host providers.
  2. To see the difficulty, publish the website. Now, DemoService is located at your server, right? All you might think you would need to do is reconfigure your Silverlight client to reference the service at your website. Go ahead and try it. Right click on ServiceReference1 and select Configure Service Reference. Add the address of the service. In my case, it is http://uiprototype.web702.discountasp.net/DemoService.svc. You'll get the error below and you won't be able to proceed.
  3. Here's the workaround. We're going to override the way the server creates the Service Host. Add the following class to DemoService.svc.cs:
  4. public class MyServiceHostFactory : ServiceHostFactory
    {
        protected override ServiceHost CreateServiceHost(Type serviceType, 
                                       Uri[] baseAddresses) 
        {
    
            // Specify the exact URL of your web service
            Uri webServiceAddress = 
              new Uri("http://uiprototype.web702.discountasp.net/DemoService.svc"); 
            ServiceHost webServiceHost = new ServiceHost(serviceType, webServiceAddress);
    
            return webServiceHost; 
        }
    }
  5. Go to DemoService.svc, right click to view markup, and you'll see this:
  6. <%@ ServiceHost Language="C#" Debug="true" 
        Service="WcfSqlDemoWeb.DemoService" CodeBehind="DemoService.svc.cs" %>

    Add the following attribute:

    Factory="WcfSqlDemoWeb.MyServiceHostFactory"
  7. Now Rebuild All and Publish. Go back to ServiceReference1, right click on ServiceReference1, and select Configure Service Reference. Add the address of the service. In my case, it is http://uiprototype.web702.discountasp.net/DemoService.svc. Now it should accept it.

Part 3: Configuring your application and your remote server so that you can debug in a variety of local and remote configurations

  1. The only problem with the workaround described in Part 2 is that you can't debug your application locally anymore. If you now try to debug your Silverlight page and you click on either of your buttons (thereby attempting to access the Web Service), you'll get an exception saying the Web Service wasn't found. This is due to cross-domain security restrictions. When you debug, your client is hosted on localhost and the Web Service is hosted on your remote server (in my case, discountasp.net). When the localhost hosted Silverlight client reaches out and tries to talk to the DiscountAsp.net hosted Web Service, that's a cross-domain communication and you need to explicitly grant permission for that type of access to your Web Service. To grant this cross-domain access, you'll need to put a crossdomain.xml and clientaccesspolicy.xml on your remote server.
  2. Here's the crossdomain.xml file you'll need to add to your web project:

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

    Here's the clientaccesspolicy.xml file you'll need to add to your web project:

    <?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>
  3. What if you want to go back to debugging both the client and the Web Service from localhost, like we were doing at the beginning of this tutorial? There may be a better way, but here's what I did. Go to your Web.config file and find your appSettings tag. Replace it with the following:
  4. <appSettings>
        <!--<add key="ServiceUri_WcfSqlDemo" 
           value="http://uiprototype.web702.discountasp.net/DemoService.svc"/>-->
        <add key="ServiceUri_WcfSqlDemo" value="http://localhost:49797/DemoService.svc"/>
    </appSettings>
  5. Now go back to DemoService.svc.cs. Add the following using statement:
  6. using System.Configuration;

    Change the URI as follows in your CreateServiceHost method to look up the address in the Web.config file:

    Uri webServiceAddress = 
      new Uri(ConfigurationManager.AppSettings["ServiceUri_WcfSqlDemo"]);
  7. Right click on ServiceReference1 and click on Configure Service Reference. Set the address to http://localhost:49797/DemoService.svc.
  8. Now Rebuild All and Debug. Things should be working as before, except now the Web Service is back to being hosted locally. If you don't believe it, go and delete everything from the server.
  9. Now you can go back and forth by changing the address in ServiceReference1 and Web.config.
  10. That's all!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Mike Dobbles
Software Developer (Senior) SilverlightWebApps.com
United States United States
Member
Mike Dobbles is a freelance software developer specializing in Silverlight and C#. Mike has over 15 years of software development experience.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionNice ArticlememberChandra Sekhar - SQLVERSITY17 Mar '13 - 20:25 
Good Article dude. I am waiting for some more articles from you on Silverlight.
 
But i found some mistakes in this article. Some of the screenshots are misplaced.
 
Please take care of this in your future articles.
 
thank you very much for sharing such a good article.
 
ALL THE BEST.
 
Chandra Sekhar
http://sqlversity.wordpress.com/[^]
Questionvar selected_rows = from rows in db.DemoTables select rows; errormemberSolo12332117 Feb '13 - 6:17 
Error   1   'SilverlightBingMapControl.Web.DataClasses1DataContext' does not contain a definition for 'configuration' and no extension method 'configuration' accepting a first argument of type 'SilverlightBingMapControl.Web.DataClasses1DataContext' could be found (are you missing a using directive or an assembly reference?)   

Suggestionplease add project to source code.membercristaloleg28 Dec '12 - 8:41 
please add project to source code.
Questionjust a requestmembersofiagvaladze8 Nov '12 - 4:03 
i like this example very ,much since i am beginner, please can u do the same but using MVVM pattern? it would be just great.
thank u
GeneralMy vote of 4memberHimanshu Yadav24 Oct '12 - 22:01 
good
GeneralVery good detailed information..memberSujit Bhujbal13 Sep '11 - 21:01 
Hi,
 
Thanks for explaining in detail. I solved my issue using this detailed information.
 
Thanks,
Sujit Bhujbal
 

 http://sujitbhujbal.blogspot.com/

GeneralNeed to get Values in Class/datarowmemberBanuGowri24 Oct '10 - 9:26 
Hi i can able to create the service using List.. how to retrive the values in Class variable or data row.. i think data row is not possible in silverlight.. pls let me know how to retrive the data with out assigning to any list
GeneralThank You!memberpangb8413 Aug '09 - 5:22 
I had many problems till i finally made it work but you helped me a lot understanding the basic structure.
I had to alter the methods a little bit here is what my Page.xaml.cs looks like
 
private void OnSubmitBtnClicked(object sender, System.Windows.RoutedEventArgs e)
        {
        	 ServiceReference1.DemoServiceClient webService = new ServiceReference1.DemoServiceClient();
 
            webService.InsertDataAsync(TestItem1TxtBox.Text, TestItem2TxtBox.Text);
 
        }
		
		void webService_GetRowsCompleted(object sender, GetRowsCompletedEventArgs e)
        {
            ResultsGrid.ItemsSource = e.Result;
        }
 

        private void OnGetBtnClick(object sender, System.Windows.RoutedEventArgs e)
        {
            ServiceReference1.DemoServiceClient webService = new ServiceReference1.DemoServiceClient();
 
            
            webService.GetRowsCompleted += new EventHandler<ServiceReference1.GetRowsCompletedEventArgs>(webService_GetRowsCompleted);
 
            webService.GetRowsAsync();
 
        }
 
 

 
I'm using Silverlight 3 and i even had incompatibilities with the xaml page..
Anyways thanks again your tutorial was exactly what i was looking for thanks again!
 
Ah! and for those struggling to make this work don't forget to add this at the beginning of your Page.xaml.cs!
using SilverlightClient.ServiceReference1;

GeneralDiscountASP.netmemberNeil Richardson10 Jun '09 - 6:51 
Thanks ever so much. Been stuck for quite some time trying to get site to run at DiscountASP.net. This did the trick.
GeneralThank YOumembermbaocha3 May '09 - 8:30 
Cant thank you enough for this tutorial. It was really great and helpful. Silverlight is the way to go.....
 

 
______________________________________________________________________________
Cheap Affordable Web Hosting & Design | Best PHP MySQL Linux Hosting | ASP.NET Windows Hosting
Generalwhymemberchyishan26 Feb '09 - 21:04 
Why have not update datagrid? 能做一下吗?
QuestionError 82 - GetRowsCompletedEventArgs?memberYoonka13 Feb '09 - 18:08 
I've implemented the first set of your demo and the only issue I'm running into is that when I create paste in the codebehind for the buttons in the xaml.cs I get the following error:
 
Error 82 The type or namespace name 'GetRowsCompletedEventArgs' could not be found (are you missing a using directive or an assembly reference?)
 
Here is the codebehind:
 
        private void OnGetBtnClicked(object sender, RoutedEventArgs e)
        {
            Service1Client webService = new Service1Client();
 
            webService.GetRowsCompleted +=
                            new EventHandler(webService_GetRowsCompleted);
 
            webService.GetRowsAsync();
        }
 
        void webService_GetRowsCompleted(object sender, GetRowsCompletedEventArgs e)
        {
            ResultsGrid.ItemsSource = e.Result;
        }
 
Thanks for your help!
 
J
AnswerRe: Error 82 - GetRowsCompletedEventArgs?memberYoonka16 Feb '09 - 4:48 
This solved the problem.
 
        private void OnGetBtnClicked(object sender, RoutedEventArgs e)
        {
            ServiceReference1.Service1Client webService = new dashboard.ServiceReference1.Service1Client();
 
            webService.GetRowsCompleted +=
                            new EventHandler<dashboard.ServiceReference1.GetRowsCompletedEventArgs>(webService_GetRowsCompleted);
 
            webService.GetRowsAsync();
        }
 
        void webService_GetRowsCompleted(object sender, dashboard.ServiceReference1.GetRowsCompletedEventArgs e)
        {
            ResultsGrid.ItemsSource = e.Result;
        }

GeneralListmemberelmidwill27 Nov '08 - 4:26 
I get the following error:
 
Using the generic type 'System.Generic.List'requires'1'type arguments
 
Any suggestions?

GeneralRe: Listmemberelmidwill27 Nov '08 - 4:47 
I followed the breadcrums to http://www.silverlightwebapps.com/Tutorials.aspx and realized my error. As I am new to programming this was a good learning experience.
 
Thanks for the great article.
GeneralRe: ListmemberManishPTIn11 Oct '09 - 21:07 
hi.. in the DemoService.svc.cs file.. When you copy paste those 2 methods, it requires to specify the type for the List to be returned (as its the Generic List<T>)
 
So just change that line
public List GetRows()
To
public List<DemoTable> GetRows()
 
I think this will solve ur prob.
 
manish

GeneralVery good detailed information..memberVetrivel Vaithialingam18 Nov '08 - 19:24 
Hi,
 
Thanks for explaining in detail. I solved my Publish issue using this detailed information.
 
thanks,
Vetri
GeneralSample projectmemberJerry Evans24 Oct '08 - 9:54 
Mike, whilst the walkthrough is really useful, a working sample project would be an invaluabule addition. Any chance of supplying one?
 
Thx++
 
Jerry
GeneralAdd Service ReferencememberTaborskyT15 Sep '08 - 22:12 
I can not Add Service Reference by button Discover. I can only see message "No services found in the solution." What can be reason for it.
GeneralRe: Add Service Referencememberavtar11121 Jan '09 - 22:12 
Visual studio list out only those service which are in the solution,
To add service to your project you can open your service in browser and copy the address and while adding the service in visual studio you can use this address instead of searching......
GeneralUpdate The Data Grid By Code Behindmemberfpatton13 Sep '08 - 11:49 
Is This possible with 2.2

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130523.1 | Last Updated 12 Sep 2008
Article Copyright 2008 by Mike Dobbles
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid