Practical .NET

Get Data to the Client and Save Server-Side Storage

You've got data on your server that you need in your page. Here are all the solutions you require, including one that will make your application more scalable.

The normal processing cycle for an ASP.NET MVC is to retrieve some data in the Controller, move it into a Model object, and then pass that data to a View to be embedded into some HTML. It's not unusual, however, for there to be some data in that mix that shouldn't be displayed to the user but that you still need on the client (often in to pass in calls to a Web Service). It's also not unusual for some of that data not to be needed on the client at all, but is required back on the server when the user's input is posted back from the browser after the user is done.

Simple Solution
There are a couple of ways to handle that "non-displayed" data. For the data required on the client (but not shown to the user) a common solution is to shove it into HTML hidden tags in the View, like this:

<input type="hidden" name=CustomerId id=CustomerId value="@Model.CustomerId"/>
<input type="hidden" name=CreditLimit id=CreditLimit value="@Model.CreditLimit"/>

Unfortunately, to use that data from JavaScript code in your client, you'll need to issue a jQuery call to retrieve it from the hidden element:

var CustomerId;
CustomerId = $("CustomerId").val();

There is, at least, one benefit to this technique: The data will post back to the server with the rest of the data on the page so it will be available on the server after the client is done.

Alternatively, you can place the data in a set of JavaScript variables:
<script>
var CustomerId;
var CreditLimit;
CustomerId = "@Model.CustomerId";
CreditLimit = @Model.CreditLimit;
</script>

This data is now immediately available to your JavaScript code. There are some costs, however. First, as the number of variables increases, the code to convert the data into JavaScript variables increases (as does the number of variables with which your code is working). Second, this data won't post back to the server and won't be available for processing there after the user is done.

For the data that isn't required in the client, but is needed when the page posts back, it's not unusual to store the data in Session object. Because the Model object passed to the View is often assembled from several other data objects, typically the simplest solution is to put those objects into the Session object where they'll be available when the client posts back to the server:

Dim cust As Customer
Dim credit As CustomerCreditInfo
cust = New Customer("A123")
credit = New CustomerCreditInfo("A123")

Session("Customer") = cust
Session("CreditInfo") = credit

Using the Session object isn't as scalable as other solutions precisely because the objects are stored on the server and the server is a shared resource: As the number of users increases, the amount of data on the server increases.

A Client-Side JSON Alternative
An alternative to using the Session object is to store the data on the client. This follows Vogel's First Law of Client/Server programming: "The user's computer should be regarded as a free, unlimited resource that should be exploited mercilessly." The benefit of storing data on the client is that, as the number of users increases, so does the amount of storage available for your use.

There is a cost associated with storing the data on the client because you have to send the data to the client as part of the page. By bulking up the size of the page being sent to the browser you can increase transmission time and lengthen response time for the user.

However, unless you're storing a Model object with dozens and dozens of properties or embedding BLOBs, you probably won't be able to measure the "extra" time required to move the data to the browser. Having said that, you'd still like to avoid increasing the number of JavaScript variables on your page.

Rather than shove the data into multiple JavaScript variables, you can, instead, generate a single JSON object to store in your page. This code stores whatever object is in your View's Model property in the page as a JavaScript object:

var cust;
cust = @Html.Raw(Json.Encode(Model));

The Json object's Encode method does the heavy lifting required to convert a .NET Framework object into JSON format. The Html object's Raw method is required to prevent Razor replacing all of the quotation marks in the JavaScript object with &quot; entities.

The resulting code would look like this in your page (and is visible if you right-click on the page in the browser and select View Source):

cust = {"CustomerId":"A123","FirstName":"Peter","LastName":"Vogel","CreditLimit":2000};

This can make debugging easier because this data is easier to view than data stored in the Session object. On the other hand, it also exposes the most significant issue with this approach: The data is very easily viewed. You won't want to store secure data using this technique unless you encrypt it before storing the data in the object's properties.

Like using JavaScript variables, the data in your JSON object is now immediately available to your JavaScript code. This example displays the FirstName and CreditLimit properties in an element on the page:

$("#custName").val(cust.FirstName + ": " + cust.CreditLimit);

It's just as easy to send the object back to an Action method on the server in an AJAX call. This code posts the object to a method called Customer in a Controller called HomeController (assuming the default routing rules for an ASP.NET MVC site):

$.post("/home/customer", cust);

The method to catch and process that data would look like this:

<HttpPost()>
Public Function Customer(cust As Customer) As ActionResult
  ...process data and update it before returning it to the client...
  return Json(cust, JsonRequestBehavior.AllowGet);
End Function

As with any JavaScript object, you can add additional information to the object just by providing a name for the property. This code adds an Age property to the object:

cust.Age = 62;

Of course, to catch this data on the server, the class you use in your Action method's parameter must have an Age property.

Returning Data to the Server
As with all data stored in JavaScript variables, the data stored in your JSON object will not automatically be returned to the server when the user clicks the Submit button. If you do need the data back on the server, you'll need to move it to a hidden element. The first step in that process, therefore, is to add that element to your page's form element:

<form action="/home/PostedData" method="post">
  <input type="hidden" name="custString" id="custString" />

The second step is to catch the form's Submit event and tie a JavaScript function to it. I'd do that as soon as the page is ready for processing, using this jQuery code:

$(function()
{
  $("form").submit(SendData);
});

In that function, you need to use the JavaScript stringify function to convert the JSON object to a string format. Once you've done that, it's just a matter of stuffing it into your hidden element:

function SendData()
{
  $("#custString").val(JSON.stringify(cust));
}

To finish this process of roundtripping your data from the server to the client and back to the server, you need to catch that string in the server-side Action method that processes the request. That method's declaration might look like this:

<HttpPost()>
Public Function PostedData(custString As String) As ActionResult

Within that method you need to convert the String back into a .NET Framework object. As fond as I am of JSON.NET, I find the original JavaScriptSerializer is easier to use for this kind of transformation. Here's all the code you need to convert a JSON string into a .NET Framework Customer object:

Dim cust As Customer
Dim json As JavaScriptSerializer
json = New JavaScriptSerializer
cust = json.Deserialize(Of Customer)(custString)

I wouldn't begin to suggest that using a JSON object is a complete replacement for using the Session object (there's that whole issue around exposing data on the client, after all). Using a JSON object is, however, a great way to get data to the client in a way that client-side JavaScript code can use. And if, on top of that, you want to take advantage of your users as a place to store data, the more power to you!

About the Author

Peter Vogel is a system architect and principal in PH&V Information Services. PH&V provides full-stack consulting from UX design through object modeling to database design. Peter tweets about his VSM columns with the hashtag #vogelarticles. His blog posts on user experience design can be found at http://blog.learningtree.com/tag/ui/.

comments powered by Disqus

Featured

Subscribe on YouTube