Data for Silverlight
Implement the Web Service
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 chose a classic Web Service.

Follow these steps to create the service:

  1. Right-click the MasterDetailWeb project.
  2. Select Add | New Item.
  3. In the Add New Item dialog box, select Web from the list of categories in the left pane.
  4. In the right pane, select the Web Service template from the list of templates.
  5. Name the new service "DataService.asmx."
    The dialog box looks like the image below.


  6. Click the Add button to create the new Web Service.

After you click the Add button, Visual Studio opens the newly created DataService.asmx.cs (or DataService.asmx.vb) file. The file contains a single HelloWorld method.

Edit the file as follows:

  1. Add the following import statements to the statements block at the start of the file:
    C#
    Copy Code
    using System.IO;
    using System.Data;
    
  2. Uncomment the line below so the service can be called from Silverlight:
    C#
    Copy Code
    [System.Web.Script.Services.ScriptService]
    
  3. Delete the HelloWorld method that Visual Studio created and replace it with the following code:
    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.
    Note: Remember that this code runs 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 do this here in the interest of keeping the example as simple as possible.
  4. Add the method that saves the changes back into the database with the following code:
    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 apply to the database: records added, modified, and deleted. It calls the UpdateData helper method to apply each set of changes, and returns null if all changes apply successfully. If there are any errors, the method returns a message that describes the exception.
  5. Add the following code for the UpdateData helper method:
    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 to the row (addition, modification, or deletion). Finally, it calls the SmartDataSet.Update method to write the changes to the database.
  6. The server-side code is almost ready. The only part still missing is the method that creates and configures the SmartDataSet. Add the following code for the implementation:
    C#
    Copy Code
    SmartDataSet GetDataSet()
    {
      // Get physical location of the mdb file
      string mdb = Path.Combine(
        Context.Request.PhysicalApplicationPath, @"App_Data\nwind.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.
See Also