Scheduler Components and Controls > Data-centric Architecture with Silverlight > The Sample Application > Implement the Server Side > Implement the Web Service |
The server side of the application consists of Web services that load the data from the database and returns it to the server, or receive a list of changes from the client and applies it to the database.
We could implement the server side as a generic handler class (ashx), as a Web Service (asmx), or as a Silverlight-enabled WCF service (SVC). For this sample, any of the choices would do. We will choose a classic Web Service.
Follow these steps to create the service:
After you click the Add button, Visual Studio will open the newly created DataService.asmx.cs (or DataService.asmx.vb) file. The file contains a single HelloWorld method.
Edit the file as follows:
C# |
Copy Code
|
---|---|
using System.IO; using System.Data; |
[System.Web.Script.Services.ScriptService]
C# |
Copy Code
|
---|---|
[WebMethod] public byte[] GetData(string tables) { // Create DataSet with connection string var ds = GetDataSet(); // Load data into DataSet ds.Fill(tables.Split(',')); // Persist to stream var ms = new System.IO.MemoryStream(); ds.WriteXml(ms, XmlWriteMode.WriteSchema); // Return stream data return ms.ToArray(); } |
The method starts by creating a SmartDataSet, then fills it with the tables specified by the tables parameter. Finally, it uses the WriteXml method to persist the DataSet into a stream, converts the stream into a byte array, and returns the result.
Remember that this code will run on the server. You could use a data compression library such as C1.Zip to compress the stream and reduce its size significantly before returning it to the client. We did not bother to do this here to keep the example as simple as possible.
C# |
Copy Code
|
---|---|
[WebMethod] public string UpdateData(byte[] dtAdded, byte[] dtModified, byte[] dtDeleted) { try { UpdateData(dtAdded, DataRowState.Added); UpdateData(dtModified, DataRowState.Modified); UpdateData(dtDeleted, DataRowState.Deleted); return null; } catch (Exception x) { return x.Message; } } |
The method takes three parameters, each corresponding to a different type of change to be applied to the database: records that were added, modified, and deleted. It calls the UpdateData helper method to apply each set of changes, and returns null if all changes were applied successfully. If there are any errors, the method returns the a message that describes the exception.
C# |
Copy Code
|
---|---|
void UpdateData(byte[] data, DataRowState state) { // No changes, no work if (data == null) return; // Load data into dataset var ds = GetDataSet(); var ms = new MemoryStream(data); ds.ReadXml(ms); ds.AcceptChanges(); // Update row states with changes foreach (DataTable dt in ds.Tables) { foreach (DataRow dr in dt.Rows) { switch (state) { case DataRowState.Added: dr.SetAdded(); break; case DataRowState.Modified: dr.SetModified(); break; case DataRowState.Deleted: dr.Delete(); break; } } } // Update the database ds.Update(); } |
The method starts by creating a SmartDataSet and loading all the changes into it. It then changes the RowState property on each row to identify the type of change that has been applied to the row (added, modified, or deleted). Finally, it calls the SmartDataSet.Update method to write the changes to the database.
C# |
Copy Code
|
---|---|
Type yoSmartDataSet GetDataSet() { // Get physical location of the mdb file string mdb = Path.Combine( Context.Request.PhysicalApplicationPath, @"App_Data\Schedule.mdb"); // Check that the file exists if (!File.Exists(mdb)) { string msg = string.Format("Cannot find database file {0}.", mdb); throw new FileNotFoundException(msg); } // Make sure file is not read-only (source control often does this...) FileAttributes att = File.GetAttributes(mdb); if ((att & FileAttributes.ReadOnly) != 0) { att &= ~FileAttributes.ReadOnly; File.SetAttributes(mdb, att); } // Create and initialize the SmartDataSet var dataSet = new SmartDataSet(); dataSet.ConnectionString = "provider=microsoft.jet.oledb.4.0;data source=" + mdb; return dataSet; } |
The method starts by locating the database file, making sure it exists, and checking that it is not read-only (or the updates would fail). Once that is done, it creates a new SmartDataSet, initializes its ConnectionString property, and returns the newly created SmartDataSet to the caller.