Implementing Auto Save Feature Using ASP.NET Ajax and WCF Service

by Bipin Joshi

Use the power of ASP.NET Ajax and Windows Communication Foundation (WCF) to automatically and periodically save webform data and provide an enhanced user experience.


ASP.NET Ajax opens a lot of possibilities to provide users a rich user experience. At the code level developers can create components, client behaviors or controls that harness the power of ASP.NET and Ajax to provide features that are otherwise difficult to offer. Ajax components are basically client side classes that usually do not have any user interface. They inherit from Sys.Component base class. Once inherited you can add your own properties, methods and events to them in order to provide the necessary functionality. In this article you are going to see how an Ajax component can be developed, that talks with the server side data via a Windows Communication Foundation (WCF) service.

Example Scenario

Many web based email systems now a days offer a rich user interface. They provide features such as automatically checking for new emails periodically and automatically saving the messages you are still composing. The later feature can be implemented in lengthy data entry forms. Imagine a scenario where a user is presented with a lengthy data entry form. He starts filling the form and mid way goes away for some other work. By the time he returns something causes the browser to close or machine to restart (say a crash or power failure). Obviously his data is lost since he didn't submit the form. Wouldn't it be nice if the web form automatically saves the entered data on the server periodically so that the web form state can be retrieved even after a crash? This is precisely what you are going to develop in the remainder of the article.

At first glance you may think of using the UpdatePanel control along with Timer. Though you can achieve similar results using UpdatePabel and Timer control there are a few limitations. Consider, for example, that your form is too lengthy and you have placed everything inside an UpdatePanel. Now when UpdatePanel refreshes the whole data entry form will be refreshed and the user will have to wait till it reappears. Also, saving selected fields for auto save operation will be tedious and may call for a rearrangement of the data entry fields. So it is best to rollout your own auto saving mechanism.

Software Needed

In order to work through the example that follows you need to have ASP.NET Framework 4.0 installed on your machine. Though the example is developed using Microsoft Visual Studio 2010 even Visual Web Developer Express Edition can be used. Additionally, you need SQL Server 2005 / 2008 database as our data will be stored there.

Creating a Web Site

To begin with, create a new ASP.NET Web Site using Microsoft Visual Studio. Figure 1 shows the "New Web Site" dialog. Give Web Site folder name as AutoSave.

Figure 1

Adding SQL Server Database

Once the web site is ready you need to add a new SQL Server database. If you have a stand-alone installation of SQL Server along with SQL Sever Management Studio you can also create a database externally. To add a new database to your web site locate the App_Data folder in Solution Explorer, right click on it and choose "Add New Item...". The Add New Item dialog as shown in Figure 2 will be displayed.

Figure 2

Select "SQL Server database" from the list, give the database the name of your choice and click the Add button. Once the database is added double click on it in the Solution Explorer so as to open the Server Explorer. Expand the database node, right click on the Tables node and choose Add New Table. This will open the table definition dialog as shown in Figure 3.

open the table definition dialog
Figure 3

Figure 3 shows a sample table named Article with five columns viz. Id, ArticleTitle, ArticleContent, SubmittedBy and SubmittedOn. Notice the data types of individual columns. Once the Articles table is created proceed to add a WCF service that works with the data from this table.

Creating a WCF Service

To add a new WCF service right click on the web site, choose "Add New Item" and then select WCF Service (Figure 4). Give service name as Service and click the Add button.

Figure 4

Adding a new WCF service will create a .svc file with the @ServiceHost directive as shown below:

<%@ ServiceHost Language="C#" Service="Service" CodeBehind="~/App_Code/Service.cs" %>

The CodeBehind attribute is pointing to Service.cs file automatically created in the App_Code folder. If you open the Service.cs file it will look like this:

[ServiceContract(Namespace = "AutoSaveService")]
(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class Service

The Service class is marked with [ServiceContract] attribute which indicates that the underlying class is a WCF service. Its Namespace property is set to AutoSaveService indicating that the caller of the service (client side Ajax code in our case) will see the service class (Service) to be part of AutoSaveService namespace. You can, of course, give it the name of your choice instead of AutoSaveService.

You need to transfer data from the web form controls to the WCF service you just created. One way to do this is to add the required number of parameters to the service method. A more elegant way is, however, to create a separate class to carry the data from client to the service. To do this, manually add a new class in the Service.cs file as shown below:

public class AutoSaveData
public string ArticleTitle {get;set;}
public string ArticleContent{ get; set; }
public string SubmittedBy { get; set; }

The above code consists of a class named AutoSaveData that is marked with [DataContract] attribute. The [DataContract] attribute marks a class as a data contract and makes it serializable for the sake of data transfer. The AutoSaveData class consists of three public properties namely ArticleTitle, ArticleContent and SubmittedBy. All of them are marked with the [DataMember] attribute. The [DataMember] attribute marks the members for serialization. Now that the AutoSaveData class is ready let's complete the Service class by adding a method to get the data in and out of the database.

You will use LINQ to SQL to communicate with the database. Right click on the App_Code folder, select "Add New Item" and choose LINQ to SQL classes (Figure 5). Doing so will add a .dbml file to your web site.

Figure 5

Once added drag and drop the Articles table from Server Explorer onto the design surface of the dbml file. This will automatically create a LINQ to SQL class named Article as shown in Figure 6.

Figure 6

As you can see, the article class has all the properties corresponding to the columns of the articles table.

Next, add a new method to the Service class as shown below:

public void SaveWork(AutoSaveData data)
  DataClassesDataContext dc = new DataClassesDataContext();
  IQueryable<Article> list = from art in dc.Articles
                             where art.SubmittedBy == data.SubmittedBy
                             select art;
  int i;
  if (list.Count() == 0)
    Article art = new Article();
    art.Id = new Guid();
    art.ArticleTitle = data.ArticleTitle;
    art.ArticleContent = data.ArticleContent;
    art.SubmittedBy = data.SubmittedBy;
    art.SubmittedOn = DateTime.Now;


The SaveWork method takes a parameter of type AutoSaveData (the class you created earlier) and is decorated with the [OperationContract] attribute. The [OperationContract] attribute marks a method as remotely callable. Inside the SaveWork method you first need to determine if there is any data saved for the same user. If not the supplied data is inserted into the articles table otherwise the existing record is updated. Notice that here you are following a simplistic approach by checking merely the SubmittedBy value. In more realistic case you will have Forms Authentication enabled for your site and user name along with some extra parameters will be used while querying the data.

The SaveWork method first creates an instance of the DataClassesDataContext class (the LINQ to SQL class that gets created when you add a .dbml file). As the name suggests the DataClassesDataContext class represents a LINQ data context and provides access to the data. The code then finds out if there is any record matching the SubmittedBy value. This is done using a LINQ query. If the query does not return any record that means there is no data for that user and you insert a new record otherwise you update the existing record. The SubmitChanges() method of the LINQ data context saves the changes to the database. Notice that the values to be inserted or updated are supplied by the AutoSaveData object.

At the end of the SaveWork method a delay is introduced using the Thread.Sleep() method. This is done purely for testing purposes so that you can see the client messages even during local run. Once you are done you should remove this delay.

Now that you have finished the SaveWork method let's move ahead and create the Ajax client side component that consumes the WCF service you just created.

Creating the Ajax Component

The Ajax client side code can be added as a part of <script> tag within the web form. However, since you are creating a component it is better to keep the code in a separate file. To do so, add a new JScript file to your web site (Figure 7).

Figure 7

In the JScript file you will create an Ajax class named AutoSave. Begin by placing the namespace declaration as shown below:


The code above declares the AjaxDemos namespace. The AutoSave class you create further will be part of this namespace. The following code fragment shows the constructor of the AutoSave class.

AjaxDemos.AutoSave = function (serviceCallback, dataCallback) 
  this._interval = 5000;
  this._enabled = false;
  this._handle = null;
  this._serviceCallback = serviceCallback;
  this._dataCallback = dataCallback;

The code calls the initializeBase() method that invokes the base class constructor. Recollect from our earlier discussion that the Ajax components inherits from Sys.Component base class. You also need to declare certain private variables (all that begin with an _ character are private variables for Ajax) to store interval of auto save operation and to indicate whether the auto save operation is enabled. The default interval for auto save operation is set to 5000 milliseconds. The serviceCallback and dataCallback parameters are function references. These functions will be invoked later to construct an instance of Service class and AutoSaveData class respectively.

Next comes the prototype of the AutoSave class that contains the properties and methods. The public properties viz. Interval and Enabled are shown below:

AjaxDemos.AutoSave.prototype =
get_Interval: function () {
return this._interval;
set_Interval: function (value) {
if (this._interval != value) {
this._interval = value;
get_Enabled: function () {
return this._enabled;
set_Enabled: function (value) {
if (this._enabled != value) {
this._enabled = value;
if (value)

The get_Interval and get_Enabled properties are straightforward and need no explanation. The set_Interval property sets the _interval variable to a new value and calls the raisePropertyChanged() method supplying the name of the property being changed. If the client code has wired an event handler to propertyChanged event of the Sys.Component class you can process this change if needed. The _StopAutoSave() and the _StartAutoSave() methods (you will code them in a minute) simply stop and start the auto save operation so that the new interval comes into effect. The set_Enabled property simply calls the _StartAutoSave() or _StopAutoSave() methods depending on the boolean value supplied.

AddDataSavingEvantHandler: function (handler) {
this.get_events().addHandler("DataSaving", handler);
RemoveDataSavingEvantHandler: function (handler) {
this.get_events().removeHandler("DataSaving", handler);
AddDataSavedEvantHandler: function (handler) {
this.get_events().addHandler("DataSaved", handler);
RemoveDataSavedEvantHandler: function (handler) {
this.get_events().removeHandler("DataSaved", handler);

Next the AutoSave class defines a few methods to add event handlers for two events viz. DataSaving and DataSaved. The DataSaving event will be raised just before the auto save operation and DataSaved event is raised after the auto save operation is over. All the AddXXXX and RemoveXXXX methods shown above make use of events collection provided by the base class Sys.Component and add or remove event handler using the addHandler() and the removeHandler() method respectively.

_RaiseDataSavingEvent: function () {
var handler = this.get_events().getHandler("DataSaving");
if (handler)
handler(this, Sys.EventArgs.Empty);
_RaiseDataSavedEvent: function () {
var handler = this.get_events().getHandler("DataSaved");
if (handler)
handler(this, Sys.EventArgs.Empty);

The actual task of raising DataSaving and DataSaved events happens inside _RaiseDataSavingEvent() and _RaiseDataSavedEvent() methods. These methods simply get a reference to the handler method and invoke it with two parameters viz. object instance and EventArgs. As you can see the event handler looks similar to standard server side event handlers. 

_SaveWork: function () {

var successCode = Function.createDelegate(this, this._OnSuccess);
var errorCode = Function.createDelegate(this, this._OnError);

var objService = this._serviceCallback();
var objData = this._dataCallback();

objService.SaveWork(objData, successCode, errorCode, null);
_OnSuccess: function (result) {

_OnError: function (err) {

The _SaveWork() method is important one as it calls the WCF service created earlier. Inside this method you first turn off the Enabled property so that next call to _SaveWork() will not fire unless the previous is finished. DataSaving event is also raised so that client web form can give some visual notification to the user. The createDelegate() method essentially creates a pointer to the code you wish to execute. Doing so preserves the context for the code being called. Notice the use of _serviceCallback and _dataCallback function references. The first call returns an instance of the WCF service proxy class whereas the second call returns an instance of AutoSaveData class filled with textbox values. You then call SaveWork() method on the WCF service proxy passing it four parameters. The first parameter is the actual parameter required by the SaveWork() method on the server. The second parameter is a JavaScript function that gets called when the operation is successful. The third parameter represents a JavaScript function that gets called in case of an error. The last parameter is user context and you pass it as a null since you don't need it in this example. Notice that since the Ajax calls remote methods asynchronously the return value of the SaveWork() method is not available immediately.

The _OnSuccess() method is called when the remote service call returns successfully and receives a parameter that represents the actual return value of the remote method that was called. Inside this function you just raise the DataSaved event and enable the auto save operation again. The _OnError() method is called in case of an error while executing the remote method. You simply display the error message using the get_message() method of the error object received as a parameter.

 _StartAutoSave: function () {
var code = Function.createDelegate(this, this._SaveWork);
this._handle = window.setInterval(code, this._interval);
_StopAutoSave: function () {
if (this._handle) {
this._handle = null;

The _StartAutoSave() method first creates a delegate that points to the _SaveWork() method. This is done with the help of the createDelegate() method. The setInterval() method of JavaScript window object is then called passing this delegate and interval. The setInterval() method is responsible for invoking the saving operation after a predefined period of time. Notice the use of the _handle variable to store the returned integer value of the setInterval() method. This value is needed further in the _StopAutoSave() method.

The _StopAutoSave() method calls the clearInterval() method of the window object and clears the previously set interval.

dispose: function () {
AjaxDemos.AutoSave.callBaseMethod(this, "dispose");

The dispose() method performs some cleanup task such as disabling the auto save operation and calls the base class dispose() method.

Finally, the AutoSave class you just created is registered with the Ajax framework.

AjaxDemos.AutoSave.registerClass("AjaxDemos.AutoSave", Sys.Component);

The registerClass() method takes two parameters viz. fully qualified name of the class being registered and base class (Sys.Component in our case). 

Creating a Data Entry WebForm

Now that your AutoSave Ajax class is ready let's build a web form that actually uses this class. Begin by opening the default web form (when you create a new website in Microsoft Visual Studio 2010 a default web form with a master page gets added for you. In our example the master page has been removed for the sake of simplicity) and design it as shown in Figure 8.

Figure 8

The web form has a ScriptManager control placed on it. In order to use any Ajax functionality a web form must have a ScriptManager control. The Label control placed at the top displays messages before and after auto saving operation so that the user is aware that the data is automatically getting saved on the server. The Title, Content and Submitted By textboxes collect the respective pieces of information. The Submit button performs the saving operation explicitly.

Once the web form is designed select the ScriptManager control and open its Properties window. Locate Scripts collection and add a reference to JScript.js file that contains AutoSave class. This way the ScriptManager knows about your Ajax class and you can use the class properties and methods on the web form. Figure 9 shows the ScriptReference collection editor dialog.

Figure 9

Similarly locate Services collection and add a reference to Service.svc. This is necessary because in order to call methods of the WCF service (which is on the server side) Ajax code needs a proxy for it. ScriptManager does this job for you based on the service references. Figure 10 shows the ServiceReference collection editor with a reference pointing to Service.svc.

Figure 10

Setting the properties as shown above adds the following markup to your web form:

<asp:ScriptReference Path="~/JScript.js" />
<asp:ServiceReference Path="~/service.svc" />

Next, add a <script> block somewhere below the markup of ScriptManager control and add the code shown below:

var app = Sys.Application;
var autosave = null;

The Application class from Sys namespace provides access to client components that are registered with the application. The load event of Application object is raised when all the registered components are fully constructed and initialized. The load event handler is shown below:

function appLoadHandler(sender, args)
  autosave = new AjaxDemos.AutoSave(GetServiceInstance,GetDataInstance);

Inside the load event handler you create an instance of the AutoSave class and pass two function references. The GetServiceInstance() and GetDataInstance() functions will be coded in a minute. Two event handlers to handle DataSaving and DataSaved events of AutoSave class are added using the AddDataSavingEvantHandler() and AddDataSavedEvantHandler() methods. Its Enabled property is set to true and Interval property is set to 5000 milliseconds.

function GetServiceInstance() {
var service = new AutoSaveService.Service();
return service;
function GetDataInstance() {
var data = new AutoSaveData();
data.ArticleTitle = $get("Textbox1").value;
data.ArticleContent = $get("Textbox2").value;
data.SubmittedBy = $get("Textbox3").value;
return data;

The GetServiceInstance() function simply creates an instance of the Service class from AutoSaveService namespace. The GetDataInstance() then creates an instance of AutoSaveData class and fills its properties. Notice the use of $get to retrieve textbox values instead of traditional the getElementById() method of document object.

function OnDataSaving(sender, args) {
$get("Label6").innerHTML="Auto saving data..."
function OnDataSaved(sender, args) {
$get("Label6").innerHTML = "Autosaved data successfully!";

The OnDataSaving() and OnDataSaved() methods act as event handlers for DataSaving and DataSaved events of the AutoSave class. They simply display a message to the end user so that the user is informed about the status of the auto save operation.

protected void Button1_Click(object sender, EventArgs e)
  Service s = new Service();
  AutoSaveData data = new AutoSaveData();
  data.ArticleTitle = TextBox1.Text;
  data.ArticleContent = TextBox2.Text;
  data.SubmittedBy = TextBox3.Text;
  Label5.Text = "Data saved successfully!";

The server side Click event handler of Submit button simply creates an instance of Service class and calls its SaveWork() method.

Testing the Web Form

Now that your coding is complete let's run the web form and see the auto save operation in action. Run the default web form and fill the textboxes with some data. Figure 11 and 12 show how the label placed at the top displays the auto saving related messages.

Figure 11

Figure 12

Figure 13 shows the data that got saved in the database because of the auto save operation. Try the functionality by changing the "Submitted By" value.

Figure 13


ASP.NET Ajax component is a non-visual class that inherits from Sys.Component base class. In this article you learned how Ajax and WCF can be used to implement the auto save feature in web forms. You first developed a WCF service that talks with the database to store information. You then consumed this service from client web form using an Ajax component. Auto saving feature thus implemented can be very useful for lengthy data entry forms.


Related Articles

This article was originally published on Tuesday Dec 28th 2010
Mobile Site | Full Site