Scheduler for WPF and Silverlight | ComponentOne
Scheduler Components and Controls / Data-centric Architecture with Silverlight / The Sample Application / Implement the Server Side / Implement the Web Service
In This Topic
    Implement the Web Service
    In This Topic

    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:

    1. Right-click the Scheduler.Web 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".
    6. Click the Add button to create the new Web 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:

    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:
      [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.

      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.

    4. Next, 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 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.

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

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