Published
Monday, June 30, 2008 11:35 AM
by
mtaulty
Someone mailed me to ask whether I had a video on how to put together Silverlight and ADO.NET Data Services.
I don't at the time of writing and I've also got a cold right now ( thank you, Microsoft Manchester office :-) ) so I thought I'd write something rather than record it.
Let's run through a step-by-step thing.
Visual Studio 2008 - File->New->Web Site. I'm going for the filesystem and C# as below;
Now, to make it easy to work with ADO.NET Data Services, I'm going to add in an ADO.NET Entity Data Model for Northwind. That is ... Website->Add->New Item;
I say "yes" to add it to my app_code folder, then select;

and then I can go and add a new ADO.NET Data Service ( again via Website->Add New Item );
and then I can update my service code to read;
public class Service : DataService<NorthwindEntities>
{
// This method is called only once to initialize service-wide policies.
public static void InitializeService(IDataServiceConfiguration config)
{
config.SetEntitySetAccessRule("*", EntitySetRights.All);
}
}
and I'm also going to reconfigure my project so that the built-in web server uses a particular port rather than a randomly selected one by selecting the website's properties and changing it;
Then I can add a new Silverlight 2 project here by doing File->Add New Project;
and then accepting the defaults for the Silverlight options;
Now, I need my Silverlight project to call the ADO.NET Data Service from my other project so I do a quick "view on browser" on my Service.svc file just to spin up the web server. Then I can drop to a command line in my c:\demo\BlogPostSL folder and use the datasvcutil.exe tool to generate some proxy code for my Silverlight project;
Then I can pop back to Visual Studio and add this as an existing item to my Silverlight project. I also need to add a reference to;
System.Data.Services.Client
in order to make that project ( with the new proxy code ) compile.
Now, I want to build a little bit of UI for Silverlight to display some data. I want to use the DataGrid so the first thing that I need to do is to add a reference to pick up the DataGrid assembly as well. So, that's another reference to the Silverlight project;
System.Windows.Controls.Data
Now I can go and edit some XAML and build up a little piece of UI;
<UserControl
x:Class="BlogPostSL.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data">
<Grid x:Name="LayoutRoot" Background="White">
<Grid.RowDefinitions>
<RowDefinition
Height="8*" />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<data:DataGrid
x:Name="dataGrid"
Margin="10"
AutoGenerateColumns="True"
ItemsSource="{Binding}" />
<Button
Margin="10"
Content="Get Data"
Grid.Row="1"
Click="OnGetData" />
</Grid>
</UserControl>
and then drop some code behind it;
public partial class Page : UserControl
{
public Page()
{
InitializeComponent();
this.Loaded += OnLoaded;
}
void OnLoaded(object sender, RoutedEventArgs e)
{
proxy = new NorthwindEntities(
new Uri("http://localhost:32767/BlogPost/Service.svc", UriKind.Absolute));
}
void OnGetData(object sender, EventArgs args)
{
// I don't think that we can use LINQ here because there's no way then
// to make it asynchronous. So, let's use the manual way of doing things.
DataServiceQuery<Customers> query =
proxy.CreateQuery<Customers>("Customers?$filter=Country eq 'UK'");
query.BeginExecute((asyncResult) =>
{
try
{
IEnumerable<Customers> result = query.EndExecute(asyncResult);
// Doubt if we're on the UI thread so...
Dispatcher.BeginInvoke(() =>
{
ObservableCollection<Customers> data = new ObservableCollection<Customers>();
foreach (Customers c in result)
{
data.Add(c);
}
dataGrid.DataContext = data;
});
}
catch (Exception ex)
{
// TODO
Debugger.Break();
}
}, null);
}
NorthwindEntities proxy;
}
and now clicking on my "Get Data" button gets me some data;
Now, that Orders column isn't really something that I want so I guess the easiest thing to do there is to hide it. I still want the grid to automatically generate columns though so perhaps I can just get this one removed?
public Page()
{
InitializeComponent();
this.Loaded += OnLoaded;
dataGrid.AutoGeneratingColumn += OnGeneratedColumn;
}
void OnGeneratedColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
{
if (e.Property.Name == "Orders")
{
e.Cancel = true;
}
}
That's a bit better in that I've got some data on the screen.
As an aside, where I said in that code above that we "can't write this query with LINQ". That wasn't strictly true. I can write something like;
var query = (DataServiceQuery<Customers>)
from c in proxy.Customers
where c.Country == "UK"
select c;
query.BeginExecute((asyncResult) =>
{ // .......
and that looks to work fine once you get over the cast.
I'll look at updating, inserting, deleting in subsequent posts otherwise this gets very long very quickly.