Introduction
HTML5 Web Storage provides a streamlined data storage mechanism that allows developers to store data on the client as key-value pairs. This article explores what Web Storage is, its flavors and illustrates how Web Storage data can be transferred between client and server in ASP.NET websites.
Introduction
Most of the websites developed today deal with data in one or the other form. It follows that application data needs some storage mechanism. As far as server is concerned we have sophisticated storage mechanisms such as an RDBMS. However, storing data on the client side can be tricky. Traditionally developers used Cookies to persist data on the client side but with many limitations. To help developers get rid of these limitations and provide a streamlined data storage mechanism HTML5 has introduced what is called as Web Storage. This article explores what Web Storage is, its flavors and using Web Storage in ASP.NET websites.
What is Web Storage?
Web Storage allows you to persist data on the client side as key-value pairs. The W3C recommended storage limit for Web Storage is 5 MB per origin. Comparing this storage size with that of Cookies (4 KB), it can be clearly seen that Web Storage offers a reasonable space for client side storage.
There are differences, however, between Cookies and Web Storage in terms of how they work. Cookies are passed between client and server with each and every request of a given website. On the other hand, Web Storage is never passed to the server automatically. If you ever need to transmit data from Web Storage to the server side code, you must resort to some programmatic approach such as jQuery calling a Web Method or a WCF service. Additionally, unlike cookies you cannot set expiration time for Web Storage. You either need to clear it programmatically or through some user interface dialog offered by the browser.
The term Web Storage is used to indicate client side data storage mechanism of HTML5. Web Storage comes in two flavors viz. Session Storage and Local Storage. These two types are exposed as sessionStorage and localStorage attributes of the window object.
As you might have guessed, Session Storage is persisted as long as the current browser (or its tab) instance is running. The moment you close the browser instance (or tab) the persisted data is removed. If you load the page again, it won’t be able to see any of the previously stored data. Session Storage is suitable for a single transaction. Local Storage, unlike Session Storage, persists data across multiple instances of the browser and that too beyond current session. Thus closing a browser window won’t remove the data. The data will be stored locally for future runs of the website.
Session Storage and Local Storage objects
As mentioned earlier sessionStorage and localStorage objects store data as key-value pairs. They have similar set of properties and methods. The following table lists them for your quick reference:
Table 1: Session Storage and Local Storage methods and properties
Property / Method |
Description |
setItem() |
setItem() method stores a key-value pair in the respective Web Storage object. |
getItem() |
getItem() method retrieves value of a specified key from the respective Web Storage object. |
removeItem() |
removeItem() method removes a specified key-value pair from the Web Storage object under consideration. |
clear() |
clear() method removes all the key-value pairs from the Web Storage object. |
key() |
key() method takes a 0 based index and returns key name at that index. |
length |
length property returns the total number of key-value pairs present in the Web Storage object. |
remainingSpace |
remainingSpace property returns the amount of storage space in bytes still available for storing data. This property is specific to IE. Other browsers may implement similar property. |
Now that you have some idea about session storage and local storage, let’s try out the above properties and methods in a sample web form. Though you can use plain HTML page to test these properties and methods, we will use an ASP.NET web form so that you can modify the same form when we develop a more realistic example in the later sections.
Begin by creating a new ASP.NET website and design the default web form as shown in Figure 1. The complete markup of the web form can be found in the code download associated with this article. You will be using jQuery to handle button click events and to store data in Web Store. So you need to refer jQuery library in your website. The examples discussed in this article use IE9 as the browser but you can use any other browser that supports Web Store feature of HTML5 (including the latest versions of FireFox, Safari, Opera and Chrome).
Figure 1: Storing and retrieving data in Web Storage
As you can see, the form consists of two textboxes to enter key name and value respectively. Clicking the Store Data button saves the key-value pair to the localStorage and clicking on the Clear Data button clears all the key-value pairs. The table below the buttons reflect the latest key-value pair and total number of items in the localStorage.
The following jQuery code shows how the above form works:
01.
var
storage = window.localStorage;
02.
$(document).ready(
function
() {
03.
$(
"#store"
).click(OnStoreClick);
04.
$(
"#clear"
).click(OnClearClick);
05.
});
06.
function
OnStoreClick(event) {
07.
var
key = $(
"#keyName"
).val();
08.
var
value = $(
"#keyValue"
).val();
09.
storage.setItem(key, value);
10.
$(
"#divKey"
).text(storage.key(storage.length - 1));
11.
$(
"#divValue"
).text(storage.getItem(key));
12.
$(
"#divLength"
).text(storage.length);
13.
}
14.
function
OnClearClick(event) {
15.
storage.clear();
16.
$(
"#divKey"
).text(
"-- No key --"
);
17.
$(
"#divValue"
).text(
"-- No value --"
);
18.
$(
"#divLength"
).text(storage.length);
19.
}
First, the code stores a reference to localStorage object in a variable – storage. This way you can easily test the code for sessionStorage also by changing just one line. The ready event handler of the document wires click event of the two buttons – Store Data and Clear Data – with event handler functions namely OnStoreClick()
and OnClearClick().
The OnStoreClick()
event handler function stores a key-value pair in the storage object using setItem() method. It then uses key()
and getItem()
methods are then used to retrieved the key just stored. The key-value pair along with the length of the storage is then displayed in respective DIV elements.
The OnClearClick()
method removes all the items from the store using clear()
method. This can be verified by outputting length of the storage again.
Session Storage and Local Storage Events
The sessionStorage and localStorage objects support storage event that is raised whenever the underlying storage area changes. You should be aware of two things while dealing with this event. Firstly, storage event is raised on the window object. Secondly, for most of the browsers except IE9, storage event is fired on every browser instance (or tab) except for the one that changed the storage object. In case of IE9 storage event is raised for all the instances of the browser. So, if Example1.aspx is loaded in three browser windows Window1, Window2 and Window3 and Window1 changes the web storage, Window2 and Window3 will receive the storage event. In IE9 all the windows receive the storage event.
The storage event handler receives event information as a StorageEvent object whose properties are shown in the following table:
Table 2: StorageEvent
Event data |
Description |
key |
Represents the key of the item that is being changed. |
oldValue |
The old value of the key (if any) being changed |
newValue |
The new value being assigned to the key |
url |
The url of the page that is changing the storage area |
storageArea |
Reference to the storage area |
Just to check how the storage event works, modify the previous code as shown below:
1.
$(document).ready(
function
() {
2.
window.addEventListener(
'storage'
, OnStorage,
false
);
3.
...
4.
});
5.
function
OnStorage (event) {
6.
alert(
"Storage event fired for key : "
+ event.key +
" in page "
+ event.url);
7.
alert(
"Old Value - New Value : "
+ event.oldValue +
" - "
+ event.newValue);
8.
}
Notice how storage event handler has been attached using addEventListener() method of the window object. The OnStorage() function uses various pieces of event parameter and displays them in a message box. The Figure 2 shows a sample run of the form when a new key is added:
Figure 2: Handling storage event
Clearing Web Storage Manually
If you add some key-value pairs to the localStorage and then close the browser without clearing the storage area, the data is preserved on the disk. As mentioned earlier, unlike Cookies you cannot set any specific expiration date and time for local storage. One way to clear the localStorage data is programmatically calling the removeItem() method for each item or by calling the clear() method. Alternatively, you can manually delete the data using the browser dialogs. For example, have a look at Figure 3 that shows “Delete Browsing History” dialog of IE9.
Figure 3: Clearing localStorage manually
There are two checkboxes you should be aware of – Cookies and Preserve Favorites website data. Un-checking the Cookies checkbox will clear all the storage areas for all domains that are not in your favorites folder. If you want to clear everything make sure to un-check Preserve Favorites website data checkbox.
Passing data from Web Storage to server
Unlike Cookies, Web Storage data is not passed between the client and server with each and every request. If you wish to send the Web Storage data to the server you must device a programmatic way to do so such as a hidden field or an AJAX call. As far as ASP.NET web forms are concerned one neat way is to call a Web Service or a WCF Service from the client script and pass the data to the server. The server can then examine and process the data and may store it into a database.
In the example discussed in the next section, you will use jQuery to call Web Methods. The Web Methods perform two functions – they fetch data from the server so that client can render it as required and they persist the Web Storage data in SQL Server database. While dissecting the example, our focus will be on Web Storage related functionality and we won’t go into the details of making AJAX calls using jQuery.
A more realistic example – Survey
Now that you know everything needed to make use of Web Store features of HTML5, let’s develop a more realistic example than the previous one that will put to use all the information we discussed so far. In this section you will develop a simple survey form that captures user feedback. As you might be aware, filling up a survey may not be a priority for the end user while he is using your website. Chances are that he may start filling it and navigate to some other part of the website that interests him more. He may even close the browser and come back to your website sometime later. In any such scenarios it would be nice to persist the survey data locally as the user is entering it. Later when user comes back, you can reload the persisted data and save him some time. Your survey form will look as shown in Figure 4:
Figure 4: Survey form developed using Local Storage
To begin developing the survey form, create a new ASP.NET website and add a SQL Server database to its App_Data folder. You will need to design four tables viz. Questions, Choices, Users and Results. The schema of these tables is shown in Figure 5:
Figure 5: Tables required in Survey form
The Questions table stores survey questions and QuestionID
is the primary key. The Choices table stores choices for questions and its primary key is ChoiceID
. One question can have multiple choices. The Users table stores user information such as FirstName
, LastName
and Email
and its primary key is UserID
column. Finally, Results table stores user response to the survey questions.
To get the data in and out of these tables, you will use Entity Framework. So, add a new ADO.NET Entity Data Model to the website. Drag and drop all the four tables onto the surface of the designer so as to create data model classes as shown in Figure 6:
Figure 6: Entity Data Model for required tables
The communication between client and server will happen via jQuery and Web Methods. You will need to write three web methods in all viz. GetQuestions
(), GetChoices()
and SaveResults
(). These methods are discussed next.
1.
[WebMethod]
2.
public
static
IQueryable<Question> GetQuestions()
3.
{
4.
DatabaseEntities db=
new
DatabaseEntities();
5.
var data = from item
in
db.Questions
6.
select item;
7.
return
data;
8.
}
The GetQuestions()
Web Method is intended to return all the survey questions from the Questions table. As you can see, it simply returns all the Question instances to the caller.
1.
[WebMethod]
2.
public
static
IQueryable<Choice> GetChoices()
3.
{
4.
DatabaseEntities db =
new
DatabaseEntities();
5.
var data = from item
in
db.Choices
6.
select item;
7.
return
data;
8.
}
The GetChoices()
Web Method is similar to GetQuestions()
method but returns all the choices from Choices table.
01.
[WebMethod]
02.
public
static
void
SaveResults(Dictionary<
string
,
string
> data)
03.
{
04.
DatabaseEntities db =
new
DatabaseEntities();
05.
User usr =
new
User();
06.
usr.FirstName = data[
"FirstName"
];
07.
usr.LastName = data[
"LastName"
];
08.
usr.Email = data[
"Email"
];
09.
db.Users.AddObject(usr);
10.
db.SaveChanges();
11.
string
userEmail = data[
"Email"
];
12.
int
usrId = (from item
in
db.Users
13.
where item.Email == userEmail
14.
select item.UserID).SingleOrDefault();
15.
data.Remove(
"FirstName"
);
16.
data.Remove(
"LastName"
);
17.
data.Remove(
"Email"
);
18.
foreach
(
string
str
in
data.Keys)
19.
{
20.
int
choiceId =
int
.Parse(str);
21.
int
questionId =
int
.Parse(data[str]);
22.
Result result =
new
Result();
23.
result.QuestionID = questionId;
24.
result.ChoiceID = choiceId;
25.
result.UserID = usrId;
26.
db.Results.AddObject(result);
27.
}
28.
db.SaveChanges();
29.
}
The SaveResults()
Web Method saves user response to the survey in the database. In order to understand the SaveResults()
method you need to understand how you will be storing data in the localStorage. The following table lists the keys used to store data in the localStorage.
Table 3: Local Storage keys to store data
Key |
Value |
FirstName |
A string value indicating first name of the user. |
LastName |
A string value indicating last name of the user. |
Email |
A string indicating Email address of the user. |
<choice_id> |
<question_id> – An integer indicating QuestionID of the choice. E.g localStorage[“3”] = 1 where 3 is a ChoiceID and 1 is a QuestionID |
Notice that localStorage is a key-value collection and each key needs to be unique. That is why we make ChoiceID
as key and QuestionID
as value. If you do other way round, you will not be able to store multiple choices for a question because latest ChoiceID
will overwrite the previously stored ChoiceID
since QuestionID
for both will be the same.
The SaveResults()
method accepts a Dictionary that will contain all the key-value pairs from the localStorage. Inside it inserts a record in the Users table and fetches back its UserID
. It then removes FirstName
, LastName
and Email
keys from the dictionary so that you can iterate through the remaining keys and with each iteration inserts a record in the Results table.
The web methods just discussed are called from the client side jQuery code. Let’s see how.
01.
$(document).ready(
function
() {
02.
// wire event handlers
03.
$(
"#submit"
).click(SubmitData);
04.
$(
"#firstName"
).change(
function
() { window.localStorage[
"FirstName"
] = $(event.target).val(); });
05.
$(
"#lastName"
).change(
function
() { window.localStorage[
"LastName"
] = $(event.target).val(); });
06.
$(
"#email"
).change(
function
() { window.localStorage[
"Email"
] = $(event.target).val(); });
07.
// load data stored previously
08.
$(
"#firstName"
).val(window.localStorage[
"FirstName"
]);
09.
$(
"#lastName"
).val(window.localStorage[
"LastName"
]);
10.
$(
"#email"
).val(window.localStorage[
"Email"
]);
11.
GetQuestions();
12.
})
The ready event handler wires click event of the “Submit Answers” button to SubmitData
function (discussed later). It also wires change event of three textboxes – firstName
, lastName
and email
– to a function. The change event handler function essentially stores value of the respective textbox in the localStorage. This way even if user navigates away by filling the survey form half way, you still have the data with you. Just in case data is already there in the localStorage you load it in the textboxes. Survey questions are dynamically fetched from the database and displayed to the user. This is done inside the GetQuestions()
function.
01.
function
GetQuestions() {
02.
var
url =
"Example2.aspx/GetQuestions"
;
03.
successHandler =
function
(results) {
04.
for
(
var
i = 0; i < results.d.length; i++) {
05.
$(
"#container"
).append(
"<div data-questions-questionid='"
+ results.d[i].QuestionID +
"'>"
+ results.d[i].QuestionText +
"</div>"
);
06.
$(
"div[data-questions-questionid]"
).addClass(
"paddedDiv"
);
07.
}
08.
GetChoices();
09.
}
10.
$.ajax({
11.
type:
"POST"
,
12.
url: url,
13.
contentType:
"application/json; charset=utf-8"
,
14.
dataType:
"json"
,
15.
success: successHandler,
16.
error:
function
(err) {
17.
alert(err.status +
" - "
+ err.statusText);
18.
}
19.
})
20.
}
The GetQuestions()
function calls GetQuestions()
Web Method you wrote previously. To call the GetQuestions()
Web Method you use jQuery .ajax()
function. Notice how the URL is specified in the .ajax() call. Make sure to change it as per the web form URL at your end.
The successHandler
function is called upon successful completion of the Web Method and receives all the Question instances as an array. You then iterate through the questions and with each iteration append a <DIV>
element to the container. Notice how the code uses data-* attributes of HTML5 to store QuestionID
. This way you can easily find out the QuestionID
for a particular question in later code. Markup of a sample <DIV>
element added by the above code is shown below:
1.
<div data-questions-questionid=
'1'
> Which programming languages
do
you use? </div>
Once all the questions are loaded, you need to load all the choices. This is done by calling another function – GetChoices
(). The GetChoices()
function is shown below:
01.
function
GetChoices() {
02.
var
url =
"Example2.aspx/GetChoices"
;
03.
successHandler =
function
(results) {
04.
for
(
var
i = 0; i < results.d.length; i++) {
05.
$(
"div[data-questions-questionid='"
+ results.d[i].QuestionID +
"']"
).append(
"<br /><input type='checkbox' data-choices-questionid='"
+ results.d[i].QuestionID +
"' data-choices-choiceid='"
+ results.d[i].ChoiceID +
"'/><span>"
+ results.d[i].ChoiceText +
"</span>"
);
06.
if
(window.localStorage[results.d[i].ChoiceID] !=
null
) {
07.
var
choiceId = results.d[i].ChoiceID;
08.
$(
"input[data-choices-choiceid='"
+ choiceId +
"']"
).attr(
'checked'
,
'checked'
);
09.
}
10.
}
11.
$(
"input[data-choices-questionid]"
).change(
function
(event) {
12.
var
key = $(event.target).attr(
"data-choices-choiceid"
);
13.
if
($(event.target).is(
':checked'
) ==
true
) {
14.
window.localStorage[key] = $(event.target).attr(
"data-choices-questionid"
);
15.
}
16.
else
{
17.
window.localStorage.removeItem(key);
18.
}
19.
});
20.
}
21.
$.ajax({
22.
type:
"POST"
,
23.
url: url,
24.
contentType:
"application/json; charset=utf-8"
,
25.
dataType:
"json"
,
26.
success: successHandler,
27.
error:
function
(err) {
28.
alert(err.status +
" - "
+ err.statusText);
29.
}
30.
})
31.
}
The GetChoices()
function is similar to GetQuestions()
function in that it calls a Web Method using jQuery .ajax()
call. This time, however, it calls GetChoices()
Web Method. You need to append all the choices belonging to a question inside that question’s <DIV>
element. This is done by finding a <DIV>
element whose data-questions-questionid
attribute matches with the QuestionID
of the current choice. An <INPUT>
checkbox element and a <SPAN>
element is then added to that <DIV
>. Notice how the code sets data-choices-questionid and data-choices-choiceid attributes of the <INPUT>
element for later use. These two attributes represent QuestionID
and ChoiceID
of a choice respectively.
Whenever user toggles a checkbox, you need to either store the user choice in the localStorage (checked) or remove it from the localStorage (unchecked). This is done by handling change event of the checkboxes. The change event handler essentially checks whether a checkbox is being checked or unchecked. Accordingly it adds or removes an entry to the localStorage.
When a user fills out the survey form and clicks on the “Submit Answers” button, SubmitData()
function is called. This function in turn calls SaveResults()
Web Method. The following code shows how this is done.
01.
function
SubmitData(event) {
02.
var
url =
"Example2.aspx/SaveResults"
;
03.
successHandler =
function
(results) {
04.
alert(
'Results saved!'
);
05.
window.localStorage.clear();
06.
}
07.
var
data=
''
;
08.
for
(
var
i = 0; i < window.localStorage.length; i++) {
09.
var
key = window.localStorage.key(i);
10.
var
value = window.localStorage[key];
11.
var
pair =
'"'
+ key +
'":"'
+ value +
'"'
;
12.
data = data + pair +
","
;
13.
}
14.
if
(data.charAt(data.length - 1) ==
','
) {
15.
data = data.substring(0, data.length - 1)
16.
}
17.
data =
'{"data":{'
+ data +
'}}'
;
18.
$.ajax({
19.
type:
"POST"
,
20.
url: url,
21.
contentType:
"application/json; charset=utf-8"
,
22.
data: data,
23.
dataType:
"json"
,
24.
success: successHandler,
25.
error:
function
(err) {
26.
alert(err.status +
" - "
+ err.statusText);
27.
}
28.
})
29.
}
The SubmitData()
function forms a JSON representation of all the key-value pairs from the localStorage by iterating through all the keys. The following JSON string represents a sample set of key-value pairs from the localStorage.
01.
{
"data"
:
02.
{
03.
"FirstName"
:
"Tom"
,
04.
"LastName"
:
"Jerry"
,
05.
"Email"
:
"tom@somedomain.com"
,
06.
"5"
:
"2"
,
07.
"7"
:
"3"
,
08.
"1"
:
"1"
,
09.
"9"
:
"3"
10.
}
11.
}
Notice how each key and value is enclosed in double quotes. Also note that “data” is the parameter name of the SaveResults()
Web Method. This way ASP.NET maps the incoming JSON data with a particular parameter of a Web Method.
Once the SaveResults()
Web Method returns successfully, all the data from the localStorage is removed using clear()
method.
You can now run the web form and test the functionality by entering some data. Also verify that the data gets stored in the localStorage even if the browser is closed and is loaded back when the survey form is visited again.
Summary
Web Storage features offered by HTML5 allow you to store data on the client machine. The two objects – sessionStorage and localStorage – store key-value pairs of data. The sessionStorage can persist data only for the current session whereas localStorage can persist data across sessions. Web Storage is not transmitted to the server automatically. You need to device some programmatic approach such as AJAX calls to a web service or WCF service, to send the Web Storage data to the server.
Source : http://dotnetslackers.com/articles/aspnet/Using-HTML5-Web-Storage-in-ASP-NET.aspx
Download Sample Code
You must be logged in to post a comment.