Uploading with Silveright 2 Beta 1 and WCF

By: Brad McKelvie

SourceCode Download : Upload.zip

This is a guest post by Brad McKelvie. (Thank a lot, Brad!) If you like to share some tips/tricks, articles or tutorials, please let me know.

This method allows the upload of any file type to a WCF Service which then stores it on the server. While researching uploading I came across the following Silverlight 2 Beta 1 limitations that led to my solution:

BassicHttpBinding.TransferMode property is not accessible to Stream data
BassicHttpBinding.MessageEncoding property is not accessible to set it as MTOM

Due to the above I elected to convert a Stream into a byte[] array, and then send it over to the Service.

By default the largest message that can be sent to a service from the client is 8124 bytes, and the largest message that can be received on the WCF service is 65536. Changing these settings and how to get this all working is explained below.

Creating the WCF Service to consume uploaded files

1. Create a new WCF Service. I have named it, Upload.svc.

2. Create a DataContract for the file being sent to the server. In this Contract the file’s name needs to also be sent if you want to keep the original name when saving to the server’s file system.

[DataContract]
public class FileUpload
{
[DataMember]
public string Name;

[DataMember]
public byte[] File;
}

3. Create an Interface for the Service in IUpload.cs and add an OperationContract for the StoreFile function.

[ServiceContract]
public interface IUpload
{
[OperationContract]
void StoreFile(FileUpload UploadedFile);
}
1

4. Create the Service function that consumes an uploaded file and stores it to the file system

1
public void StoreFile(FileUpload UploadedFile)
{

FileStream FileStream = new FileStream(HttpContext.Current.Server.MapPath(ConfigurationManager.AppSettings["FileUploadLocation"]) + UploadedFile.Name, FileMode.Create);
FileStream.Write(UploadedFile.File, 0, UploadedFile.File.Length);

FileStream.Close();
FileStream.Dispose();
}

5. Setup your Web.Config to accept files bigger than 65536 bytes. For this example I have a size of 2 MB. To be safe I set all the properties to 2 MB as I didn’t want to run into any problems later.

Edit the binding configuration for BasicHttpBinding:

<bindings>
<basicHttpBinding>
<binding name="ServicesBinding" maxReceivedMessageSize="2000000" maxBufferSize="2000000">
<readerQuotas maxArrayLength="2000000" maxStringContentLength="2000000"/>
</binding>
</basicHttpBinding>
</bindings>

Tell your Binding to use this new configuration with the property, bindingConfiguration:

<endpoint address="" bindingConfiguration="ServicesBinding" binding="basicHttpBinding" contract="WCFServices.IUpload">

Call the Upload Service on the Silverlight Client

A user must select a file using the OpenFileDialog Control in order to gain read access to a file on the Client. Once Silverlight has the ability to read a file, then the file’s Stream is converted into a byte[] array. Finally, the byte[] array and file name are sent to the WCF Service.

1. Add a Service Reference to your Silverlight project. I called mine, UploadServiceReference.

2. Create the WCF Client that calls your Upload Service

UploadServiceReference.UploadClient UploadServiceClient = null;

System.ServiceModel.BasicHttpBinding Binding = new BasicHttpBinding(BasicHttpSecurityMode.None);

Binding.MaxBufferSize = 2000000;
Binding.MaxReceivedMessageSize = 2000000;

EndpointAddress Address = new EndpointAddress("http://localhost/MyWCFServices/Upload.svc");

UploadServiceClient = new UploadServiceReference.UploadClient(Binding, Address);

Note: The BasicHttpBinding’s MaxBufferSize must be changed if you want to upload a file bigger than 8124 bytes. The default is low to help defend against DOS attacks. In this example I have set the maximum upload size of the file to 2 MB. This setting MUST be set in the code because Silverlight 2 Beta 1 does not read the settings from the ServiceReferences.ClientConfig file.

When I didn’t have the MaxBufferSize set I would receive a 404 error. This error of course made no sense. I had to download the WCF Service Configuration Utility that is included in the Windows SDK. After enabling the log of my WCF Service sent/received messages I found that the real error was: “The maximum string content length quota (8192) has been exceeded while reading XML data. This quota may be increased by changing the MaxStringContentLength property on the XmlDictionaryReaderQuotas object used when creating the XML reader.”

3. Create a function to call the WCF Service and upload a file after a file has been selected by a user with the OpenFileDialog Control. Below is the Event that is attached to a Button control. When the Button is clicked it uploads the file.

private void AddFile_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
Stream Stream = (System.IO.Stream)UploadOpenFileDialog.SelectedFile.OpenRead();

byte[] Buffer = new byte[Stream.Length];
Stream.Read(Buffer, 0, (int)Stream.Length);

Stream.Dispose();
Stream.Close();

UploadServiceReference.FileUpload FileUpload = new UploadServiceReference. FileUpload();
FileUpload.FileName = UploadOpenFileDialog.SelectedFile.Name;
FileUpload.File = Buffer;

UploadServiceClient.StoreFileAsync(FileUpload);
UploadServiceClient.StoreFileCompleted += new EventHandler<Upload. UploadServiceReference.StoreFileCompletedEventArgs>(StoreFile_Completed);
}

Additional Items that will help

I had a need to use Server.MapPath when dealing with storing files. To enable HttpContext.Current.Server.MapPath:

Add the line:


[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]

Above your Service class:


public class Upload : IUpload

Then in your Web.config add the line:


<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />

To:


<system.serviceModel></system.serviceModel>

Note: The sourcecode will be uploaded very soon. The sourcecode is uploaded. Thanks for reading.

Silverlight 2 (beta1): User Control Inheritance

We have been discussing about how to inherit a Silverlight page or Silverlight control from the base class lately in Silverlight Forum. (You can read our discussions here, here, here and here.) As the most of .NET developers have the ASP.NET background, we all want to have the base class/master page that can be inherited from other controls. Unlike ASP.NET Master Page, it’s a lit bit tricky to do inheritance in Silverlight. In this post, I’m gonna give you the step-by-step guide for that.

User Control Inheritance in Silverlight

Note: As you know, you can change the name as you like but I will use the following names in my sample.

1. Create new silverlight project called “SL2Controls”

2. Add a class called BaseControl

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace SL2Controls {
public class BaseControl : UserControl {

}
}

3. Add Silverlight User control called “InheritedControl”

XAML


<BaseControl x:Class="SL2Controls.InheritedControl"
xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300">
<Grid x:Name="LayoutRoot" Background="Red">

</Grid>
</BaseControl>

C#


using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace SL2Controls {
public partial class InheritedControl : BaseControl {
public InheritedControl() {
InitializeComponent();
}
}
}

4. Add mapping in AssemblyInfo.cs under Properties of SL2Controls


using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Windows.Markup;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("SL2Controls")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("SL2Controls")]
[assembly: AssemblyCopyright("Copyright ©  2008")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: XmlnsDefinition("http://schemas.microsoft.com/client/2007", "SL2Controls")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components.  If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]

// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("27885afb-0308-473e-9773-73350bc1555f")]

// Version information for an assembly consists of the following four values:
//
//      Major Version
//      Minor Version
//      Build Number
//      Revision
//
// You can specify all the values or you can default the Revision and Build Numbers
// by using the '*' as shown below:
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

5. Add this Inherited control to Page.xaml.


<UserControl x:Class="SL2Controls.Page"
xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:myctl="clr-namespace:SL2Controls"
Width="400" Height="300">
<Grid x:Name="LayoutRoot" Background="White">
<myctl:InheritedControl/>
</Grid>
</UserControl>

then, run the application. (You don’t need to update *.g.cs file.)

Download Source: http://michaelsync.net/demo/SL2Controls.zip

There is one weakness in this trick. You will lost the designer in InheritedControl.xaml but you won’t get any error. If you want to know how to do for Silverlight page, you can read the second post in this link.

Yes. As we all are new to Silverlight 2 beta1, we probably need to explore more thing about it. Feel free to discuss with me if you have any comment or suggestion.

Update: If you don’t add namespace mapping in assembly, I think it will be working fine. but this is a known issue that will fix in next release. Yi-Lun from Microsoft said as below ~

Hello, there’re some issues related to UserControl inheriting that we’re investigating… I’m surprised to see this works:

<MyUserControlBase x:Class=”SL2Test.Page”
xmlns=”http://schemas.microsoft.com/client/2007″
xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”
Width=”400″ Height=”300″>
<Canvas Width=”400″ Height=”300″ Background=”Red”>
</Canvas>
</MyUserControlBase>

Actually it shouldn’t work. MyUserControlBase is not in the namespace http://schemas.microsoft.com/client/2007. This xml namespaces maps to a series of clr namespaces such as System.Windows.Controls. But there’s no way it can map to your own namespace. Also this behavior is inconsistent with WPF.

This is likely to be a bug. I’ll redirect this to our product team. Thanks for letting us know.

You’re right. This can be a work round.

In the class library project’s AssemblyInfo.cs file, add this:

[assembly: XmlnsDefinition("http://schemas.microsoft.com/client/2007", "YourNamespace")]

Now after you add reference to this assembly in your main project, you can use any classes in this namespace in your XAML files.

But without the namespace mapping, your original code should not work. So this still seems to be an issue…

Tips/Tricks: How to center Silverlight control on a webpage?

[Post written as of Silverlight 2 beta 1]

Question:

How can I center my Silverlight UserControl on the center of the web page (horizontally and vertically). To reproduce, create a new default Silverlight application in VS2008. I want that default xaml to appear in the center of the page, instead of the top left.

Source: http://silverlight.net/forums/p/11233/35791.aspx

My answer :

Centering something horizontally is so easy but vertically (especially for cross-browser). However, I found the CSS trick that works in any browser from this link. (Thanks to the original developer for this CSS trick.)

Silverlight

Let’s say your project name is “SL2Center” .

The following code is the default code from SL2CenterTestPage.aspx


<%@ Page Language="VB" AutoEventWireup="true" %>

<%@ Register Assembly="System.Web.Silverlight" Namespace="System.Web.UI.SilverlightControls"
TagPrefix="asp" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" style="height:100%;">
<head runat="server">
<title>Test Page For SL2Center</title>
</head>
<body style="height:100%;margin:0;">
<form id="form1" runat="server" style="height:100%;">
<asp:ScriptManager ID="ScriptManager1" runat="server"></asp:ScriptManager>
<div  style="height:100%;">
<asp:Silverlight ID="Xaml1" runat="server" Source="~/ClientBin/SL2Center.xap" Version="2.0" Width="100%" Height="100%" />
</div>
</form>
</body>
</html>

You change the width and height properties of Usercontrol to 300. And also, you add one TextBlock in that control.


<UserControl x:Class="SL2Center.Page"
xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="300" Height="300">
<Grid x:Name="LayoutRoot" Background="Red">
<TextBlock Text="Silverlight Content" Foreground="Yellow" FontSize="30" FontWeight="Bold" VerticalAlignment="Center"  HorizontalAlignment="Center"/>
</Grid>
</UserControl>

The first thing that you need to do is that you have put the following CSS in <head> of SL2CenterTestPage.aspx.

<style type="text/css">
<!--

DIV.sl
{

position: absolute;
left: 50%;
top: 50%;
width: 300px;
height: 300px;
margin-left: -150px; /* half of width */
margin-top: -150px;  /* half of height */
background-color: #6699CC;
}

-->
</style>

I assume that the height and width properties of your xaml is 300. So, I set 300 to width and height in CSS.

Secondly, you have to set the class of DIV to the CSS class that we have created.


<div class="sl">
<asp:Silverlight ID="Xaml1" runat="server"
Source="~/ClientBin/SL2Center.xap" Version="2.0" Width="100%"
Height="100%" />
</div>

That’s all. You can run the application. You will see that the SL content is showing at the middle of web page. Cool, isn’t it? but one thing you should know is that if you want to change either width or height of XAML, you have to change the CSS again. I didn’t spend that much time for that but I hope you will get some ideas how you can customize it. Let me know if you have any problem or better solution.

You can download the sourcecode here.

Tips/Tricks: Where is DataGrid in Microsoft Expression Blend 2.5?

This post is just a tip for those who are not able to find DataGrid in Expression Blend 2.5 (March 2008 Preview). Laurent Duveau asked this question in Silverlight forum. I tried to find this solution and replied him in this post.

No datagrid in Blend 2.5? Yes, Silverlight Datagrid doesn’t show by default in the toolbox of Blend. The controls that you see on that toolbox are from System.Windows.Controls namespace. Silverlight Datagrid is NOT under that namespace. So, Datagrd is under which namespace? That control is under System.Windows.Controls.Data namespace. Okay. How to add Datagrid control to toolbox? Yes. This is the reason why I wrote this post. Please keep on reading further. I will tell you the step-by-step as below.

1. Expand the “Reference” node in Expression Blend to check whether System.Windows.Controls.Data.dll is already referenced in the project or not.

Blend Reference

2. If that dll is not there then right-click on the “References” node and select “Add Reference”

Add References

3. Go to the Silverlight SDK folder (e.g. C:\Program Files\Microsoft SDKs\Silverlight\v2.0\Libraries\Client) . Select “System.Windows.Controls.Data.dll” to add as a reference in your Blend project.

data-dll-added.jpg

4. Click on “Asset Library” as shown in picture below

Click Asset Library

5. Click “Show All” and Select “Datagrid” in Asset Library

datagrid-in-asset-library.jpg

6. Finally, you got the Datagrid control on toolbox as you want.

datagrid-on-toolbox.jpg

Yes.. Good Job! you have successfully added the Datagrid control to Blend. :)

ADO.NET Data Service (Astoria) in Silverlight 2 (beta1)

Download : SL2Astoria.zip (1.21 MB)

vs-design-view.jpg

Content

  • Introduction
  • Background
  • Creating database in SQL 2005
  • Creating Silverlight project and ADO.NET Data Service in Visual Studio 2008
  • Creating a XMLHttpRequestWrapper class
  • Inserting new record in Silverlight
  • Updating the existing record in Silverlight
  • Retrieving the record from Database in Silverlight
  • Deleting the record in Silverlight
  • FAQs

Introduction

This post is written for those who like to use Astoria in Silverlight 2 before Astoria Team release the new version of Astoria Silverlight add-on. This post will guide you how to insert new record to database, how to update, retrieve or delete the existing records from the database using ADo.NET Data Service (Astoria) in Silverlight 2. You all know that Astoria Client addon for SL 2 (beta1) is not compatible with SL2beta1 and the next verion of Astoria Client addon won’t be available until end of April so that I can’t use that addon in this post either. but I will use XmlHttpRequest wrapper instead of Astoria client add-on for consuming Astoria from Silverlight. (Thanks to Jackbone from Silverlight forum for contributing very light-weight XmlHttpRequest wrapper code.).

As this post is focusing on how to do CRUD operations with Astoria in SL, I’m not gonna include other markups or animation in this post. I hope it would be easier for you to read the code that you really need.

Background

As I wrote a few articles about how to use Astoria in Silverlight 1.1 Alpha here and here, desopedr (one of my reader of my blog) and a few friends asked me how to use Astoria in Silverlight 2 (beta1).

  • The first attempt was simple. I tried to use Astoria add-on in Silverlight project but it didn’t work. When I read the Astoria forum, I found that the current version of Astoria addon doesn’t work with SL2b1. (You can read about that here and here.)
  • Secondly, I tried to use Web Client to do CRUD operations with Astoria in SL. I could successfully retrieve the data from Astoria service by using WebClient but we can’t make httpPost request or etc with WebClient so that the operations (e.g. insert) that requires other http verbs (e.g. POST, PUT, DELET) can’t be done with WebClient. So, the second attempt was failed too.
  • Then, I tried using HttpWebRequest to invoke Astoria service from Silverlight. but whenever I tried to invoke, I always get “null” for response. I’m not sure whether this is Silverlight issue or not. I posted this issue in forum and you can read this issue here.
  • After the third attempt was failed, I got the idea to invoke the service using XmlHttpRequest object from Javascript. then, Jackbond posted the Silverlight XmlHttpRequest Wrapper in our forum. (You can read the original post here.) So, I decided to use his wrapper instead of pure Javascript. After spending some times, I can successfully CUD operations with that wrapper. (I have a few problems in updating so that I’m not able to include about this for now. but I will update once I got the solution.) In this article, I will share you how to do CUD operations with Astoria in Silvrlight 2 beta1.

Creating database in SQL 2005

You have to create one table called Products with the following structure below. I have written so many time how to create a database and table in SQL 2008 so I ain’t gonna repeat here again. Please read “Creating the database in SQL 2005″ section of this post if you don’t know how to create the table.

table.jpg

Creating Silverlight project and Astoria Service in Visual Studio 2008

1. Create new project with the name “SL2Astoria” in VS 2008.

new-project-thumb.jpg

2. Attach ASP.NET project with Silverlight.

add-silverlight.jpg

ADO.NET Entity Data Model

1. Right-click on ASP.NET project and Select “Add New Item”.

2. Choose “ADO.NET Entity Data Model” and Click “OK” button

edm.jpg

3. The following dialog will be shown (It’s asking where you want to put EDM.) Click “Yes” button

app_code.jpg

4. Choose “General” and Click “Next” button

emd-wizard.jpg

5. Select the connectionstring if you already have. If there is nothing shown in connection, please click “New Connection” to create new connection. After that, click “Next” button

choose-your-data-connect.jpg

6. Unchecked all objecs first and select the table that you want. (In my case, I checked the table named “Products” only and unchecked all other tables, views and stored procedures.)

choose-your-database-object.jpg

7. Click “Finish” button.

ADO.NET Data Service

1. Right-click on ASP.NET project and Add “ADO.NET Data Service”

adonet-data-service.jpg
2. Change the sourcecode as below in WebDataService.cs. First thing we need to do is that we have to set our data model class in WebDataService. In my case, MyStoreModel.MyStoreEntities is the data model class. Then, enable the operations from our data service . Note that it’s just for testing purpose. You should not enable all operations in production.

public class WebDataService : WebDataService<MyStoreModel.MyStoreEntities>
{
// This method is called once during service initialization to allow
// service-specific policies to be set
public static void InitializeService(IWebDataServiceConfiguration config)
{
// TODO: set rules to indicate which entity sets and service operations are
// visible, updatable, etc.
// (for testing purposes use "*" to indicate all entity sets/service
// operations, but that option should NOT be used in production systems)

// Example for entity sets (this example uses "AllRead" which allows reads but not writes)
config.SetResourceContainerAccessRule("*", ResourceContainerRights.All);

// Example for service operations
config.SetServiceOperationAccessRule("*", ServiceOperationRights.All);

}

// Query interceptors, change interceptors and service operations go here
}

That’s all we need to do in ASP.NET project.

Creating a XMLHttpRequestWrapper class

XMLHttpRequestWrapper class is just a wrapper class of Javascript XmlHttpRequest object. If you are familiar with Ajax, I’m sure that you have good understanding about this object. In my example, this wrapper class is just like the way that we wrote in Javascript except I used C# instead of Javascript.


using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Browser;
using System.Text;
using System.Xml;
namespace SL2Astoria {
/// <summary>
/// Ref: http://silverlight.net/forums/t/11508.aspx
/// </summary>
public static class XMLHttpRequestWrapper {
static ScriptObject _xmlHttpRequest;

public static void DoPost(Uri url, string httpVerb) {
DoPost(url, httpVerb, string.Empty);
}
public static void DoPost(Uri url, string httpVerb, string param) {
_xmlHttpRequest = HtmlPage.Window.CreateInstance("XMLHttpRequest");

_xmlHttpRequest.Invoke("open", httpVerb, url, false);
_xmlHttpRequest.Invoke("setRequestHeader", "Content-Type", "application/json");

if (param == string.Empty) {
_xmlHttpRequest.Invoke("send");
}
else {
_xmlHttpRequest.Invoke("send", param);
}
}
}
}

CRUD operations with Astoria in Silverlight

After creating this wrapper class, we can start writing the code for CRUD operations with Astoria. but before that, you should understand which http verbs we will use for each operation. Please take a look at the table below.

Operations HTTP verbs
Insert POST
Retrieve GET
Delete DELETE
Update PUT

Inserting new record in Silverlight

We will start with inserting new record to database. In order to insert new record, we have to make Http POST request to Astoria Data Service. We will pass the data as a JSON object to that service. Yes. I hard-coded the service URL in my code. It’s just a sample, right? I’m not showing the best practice of using Silverlight. I’m just showing how to use XmlHttpRequestWrapper class to deal with Astoria. ProductName from json object is the property of entity set of Astoria and it’s also the column name of “Products” table.

string productName = "ComponentOne Silverlight Studio";
string serviceURL = "http://localhost:52976/SL2Astoria_Web/WebDataService.svc/Products/";

string jsonString = "{" + Environment.NewLine;
jsonString += "ProductName:\"" + productName + "\"" + Environment.NewLine;
jsonString += "}" + Environment.NewLine;

XMLHttpRequestWrapper.DoPost(new Uri(serviceURL), "POST", jsonString);

Updating the existing record in Silverlight

[As I told you earlier, I'm having some problems in updating. I will update this post once I got the solution. Please keep on watching.]

Retrieving the record from Database in Silverlight

Currently, there are two way to retrieve the data from Astoria in Silverlight. You can use either WebClient or XmlHttpRequestWrapper class.

string serviceURL = "http://localhost:52976/SL2Astoria_Web/WebDataService.svc/Products?$orderby=ProductID";

string result = XMLHttpRequestWrapper.DoPost(new Uri(serviceURL), "GET");

The following code is the same as the code above. But It uses WebClient instead of XmlHttpRequestWrapper.

void retrieveButton_Click(object sender, RoutedEventArgs e) {
try {

string serviceURL = "http://localhost:52976/SL2Astoria_Web/WebDataService.svc/Products?$orderby=ProductID";

////retriving data
WebClient astoriaService = new WebClient();
astoriaService.DownloadStringCompleted += new DownloadStringCompletedEventHandler(AstoriaService_DownloadStoriesCompleted);
astoriaService.DownloadStringAsync(new Uri(serviceURL));
}
catch (Exception ex) {
Console.WriteLine(ex.Message);
}
}

void AstoriaService_DownloadStoriesCompleted(object sender, DownloadStringCompletedEventArgs e) {
if (e.Error == null) {
DisplayProducts(e.Result);
}
}

Deleting the record in Silverlight

The following code is for deleting the existing data from database. All we need to do is that we specify the id of project in service URL and send the HTTP DELETE request to Astoria to delete that record.


string serviceURL = "http://localhost:52976/SL2Astoria_Web/WebDataService.svc/Products(18)/";
XMLHttpRequestWrapper.DoPost(new Uri(serviceURL), "DELETE");

FAQs

1. I have downloaded the sample. How can I run this sample?

There is MyStore.mdf in SQL Database folder. You should attach this database to MS SQL in your machine. Then, you need to change the connection string in ASP.NET project.

2. Why did you hard-code the service URL?

Yes. I hard-coded the service URL in my code. It’s just a sample, right? I’m not showing the best practice of using Silverlight. I’m just showing how to use XmlHttpRequestWrapper class to deal with Astoria.

3. Why don’t you make nice-looking UIs in your sample? Are you just lazy?

No. I have been trying to do this since last week. As I told you in “Background” section of this article, I have tried a lot of ways and I faced a lot of problems during these days. Until now, I still have some problems in updating. but I know that there are some people (e.g. desopedr ) is waiting to know how to do CRUD operations with Astoria in Silverlight. So, I just make this sample and I wrote this article in very short and limited time. I hope I will be able to create another sample with nice-looking UIs in future.

Another thing is that I just want to focus on the functionality. If I put a lot of controls, animation and etc, there will be a lot of codes for reader to look at. So, I made this sample with the code that are required only.

4. Does it support cross-domain?

No. This wrapper has exactly the same limitations as what XmlHttpRequest object has. Another thing is that invoking the Astoria data service is not in async-mode. However, you can change it easily if you want.

That’s all. I hope you might find it useful. Feel free to let me know if you have any problem or comment. Thanks.

Silverlight 2 (beta1) – Database Operations with ASP.NET Web Service in Silverlight 2

Update You can download the latest version of sample that works with Silverlight 2 beta2 from this link.

Introduction

This is the step-by-step tutorial for how to do database operations (Create, Retrieve, Update, Delete) with ASP.NET web service (asmx) in Silverlight 2 beta 1.

Background

A few people asked me how to do database operations (CRUD) in Silverlight 2 (beta1). As I have some experiences in using Astoria in Silverlight 1.1 Alpha, I was thinking to use Astoria service in Silverlight 2. Unfortunately, Astoria Client add-on doesn’t work with Silverlight 2 (beta1) and Astoria team said that the next version will be available around the end of April. So, for now, I made this sample with normal ASP.NET web service for those who like to do CRUD operations in Silverlight 2.

Software Needed

  • Silverlight 2 (beta1) (Please read this post if you don’t know where you can get those installers.)
  • Visual Studio 2008
  • SQL 2005 Express with Management Studio

Download : SL2WebSrv.zip (1.45 MB)

Screenshots
Silverlight 2

Fig: Retrieving data from ASP.NET web service and displaying those data in Silverlight Datagrid.

sl2-entry.jpg

Fig: Entry Form for adding new record to database from Silverlight 2 application

Creating the database in SQL 2005

Note: If you already know about how to create the database in SQL 2005, please skip and jump to next section.

Step 1: Open SQL Server Management Studio Express

SQL Server Management Studio Express - FREE edition

Step 2: Connect to SQL Server that you have installed on your local machine

Connect to Server

Step 3: Right-click on Database node from Object Explorer and Select “New Database”

New Database - SQL 2005

Step 4: Type your database name ( I named it “MyStore” in this sample) and Click “OK” button

create-new-database-small.jpg

Step 5: Right-click on Table node of the database that you have created and select “New Table”

New Table

Step 5: Create two columns called “ProductID(INT Identity PK)” and “ProductName”. Name the table “Products”

Structure of Products Table

Okay. That is all about creating new table in SQL 2005.

Creating the Silverlight 2 (beta1) project in Visual Studio 2008

  • Open VS 2008 and Create new Silverlight 2 project.

new-project-thumb.jpg

  • It will ask you whether you want to create ASP.NET project or HTML page to host Silverlight content. Just click “OK” button

add-silverlight-application.jpg

  • You will get two projects (ASP.NET and Silverlight) under one solution.

solution-explorer.jpg

Creating Web Service in ASP.NET project

  • Right-click on ASP.NET project node and Choose “Add New Item” as shown in picture below.

add-new-item.jpg

  • “Add New Item” dialog will be shown. Please choose “Web Service” item in that dialog.

add-new-item-detail-thumb.jpg

  • Give the name “ProductManager.asmx” to this web service and click “OK” button.
  • Go to web.config and Add the connection string as below under <configuration> in web.config. (Note: You have to add your connection string for SQL so that it might not be the same as mine.)
    <connectionStrings>
    <add name="sqlConnectionString" connectionString="Data Source=MICHAELSYNC-PC\SQLEXPRESS;Initial Catalog=MyStore;Integrated Security=True"/>
    </connectionStrings>
    
  • Go to the ProductManager.asmx again. Uncomment [System.Web.Script.Services.ScriptService] at the top of Class
  • Write the four methods for CRUD operations. (I will show the code for retrieving data from SQL in this post. If you want to know about CUD operations, please download the sample and take a look at that asmx file.)
    [WebMethod]
    public string RetrieveProduct(int productId) {
    try {
    SqlConnection _sqlConnection = new SqlConnection();
    _sqlConnection.ConnectionString = ConfigurationManager.ConnectionStrings["sqlConnectionString"].ToString();
    _sqlConnection.Open();SqlDataAdapter da = new SqlDataAdapter();
    da.SelectCommand = new SqlCommand("SELECT * FROM Products WHERE ProductID = " + productId.ToString().Replace("'", "''"), _sqlConnection);
    
    DataSet ds = new DataSet();
    da.Fill(ds);
    
    StringBuilder sb = new StringBuilder();
    sb.Append("<?xml version=\"1.0\" encoding=\"utf-8\" ?>");
    sb.Append("<Products>");
    foreach (DataRow dr in ds.Tables[0].Rows) {
    sb.Append("<Product>");
    sb.Append("<ID>");
    sb.Append(dr[0].ToString());
    sb.Append("</ID>");
    sb.Append("<Name>");
    sb.Append(dr[1].ToString());
    sb.Append("</Name>");
    sb.Append("</Product>");
    }
    sb.Append("</Products>");
    _sqlConnection.Close();
    
    return sb.ToString();
    }
    catch (Exception ex) {
    return string.Empty;
    }
    }
    
  • Go to the propertypad of ASP.NET project and set False to “Use dynamic ports” property.static-port.jpg
  • then, Build ASP.NET project.

Consuming ASP.NET web service in Silverlight 2 (beta1)

  • Right-click on the Reference node of Silverlight project. And choose “Add Service Reference” as shown in picture below.add-service-reference.jpg
  • The following dialog will be shown. Click “Discover” buttondiscover-thumb.jpg
  • (One web service will be shown in “Service:” panel after clicking “Discover” button.) Double-click on that one.discovering-webservice.jpg
  • It will show “ProductManager” service that we created in ASP.NET project
  • Change the namespace to “WebServiceProxy” and hit “OK” button
  • Now, you can start using web service from Silverlight project. I will show you how to retrieve the data from web service.
  • Please take a look at “ListingControl.xaml.cs. You will see the following code that retrieve the data from Web Service
    void ListingControl_Loaded(object sender, RoutedEventArgs e) {WebServiceProxy.ProductManagerSoapClient productMgrSoapClient =
    new SL2WebSrv.WebServiceProxy.ProductManagerSoapClient();
    
    productMgrSoapClient.RetrieveProductsAsync();
    productMgrSoapClient.RetrieveProductsCompleted +=
    new EventHandler<SL2WebSrv.WebServiceProxy.RetrieveProductsCompletedEventArgs>(productMgrSoapClient_RetrieveProductsCompleted);
    }
    void productMgrSoapClient_RetrieveProductsCompleted(object sender, SL2WebSrv.WebServiceProxy.RetrieveProductsCompletedEventArgs e) {
    if (e.Error == null)
    displayData(e.Result);
    }
    

    Note: ListingControl_Loaded is attached in ListingControl constructor. displayData(string) is another function for showing data.

  • I created Product class in Silverlight project too. Because Silverlight doesn’t support binding Datagrid with anonymous type. (You can read about this issue more details in this post.)
  • The following code is for displayData() function.
    void displayData(string xmlContent) {
    try {if (xmlContent != string.Empty) {
    XDocument xmlProducts = XDocument.Parse(xmlContent);
    
    var products = from product in xmlProducts.Descendants("Product")
    select new
    {
    ProductID = Convert.ToInt32(product.Element("ProductId").Value),
    ProductName = (string)product.Element("ProductName").Value
    };
    
    //Bug: http://silverlight.net/forums/t/11147.aspx
    List<Product> productsList = new List<Product>();
    
    foreach (var p in products) {
    Product pdt = new Product { ProductID = p.ProductID, ProductName = p.ProductName };
    productsList.Add(pdt);
    }
    productsDataGrid.ItemsSource = productsList;
    }
    else {
    productsDataGrid.ItemsSource = null;
    }
    
    }
    catch (Exception ex) {
    Console.Write(ex.Message);
    }
    }
    
  • Yes. That’s all about retrieving data from Web Service. If you run that sample, the data from database will be displayed in DataGrid.
  • You can also read the code from EntryControl.xaml.cs file if you want to know how to insert the data.

How to run this sample

First thing that you need to do is that you should attach the database to your SQL express. After that, you have to change the connection string. then, try to run the sample. If you are not seeing anything then please try to uncomment the code for calling web service. (because I’m not sure whether you have the connection problem or not.) then, run it again. You should be able to see the silverlight content as shown in my screenshot except datagrid. If it’s running fine then try to check the connection string again.

Feel free to let me know if you have any problem or suggestion. I hope you will find it useful.

Related ~