Often we need to store some client-side data from request to request. Because the browser supports two simultaneous connections to the server it's easy to do two concurrent requests to the server - and when response is received we want to somehow differentiate between that requests. For example when I click on Button1 - I want to pass let's say exact time when request was invoked, or some javascript object on which I need to perform some actions in endRequestHandler.
So what I want to do - attach some javascript object to the request somehow, to later use it when that request is served by the server and response is sent back. At the same time I don't want to sent that attached object to the server with request and then receive it from the server, because it's not efficient - we can store that object on client side.
To do this I will use userContext Property of WebRequest Class in ASP.NET AJAX library.
I created the sample page. The code looks like:
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Untitled Page</title>
<style type="text/css">
.loggerDiv
{
width: 200px;
height: 400px;
overflow: auto;
float: left;
border: solid 1px black;
padding: 3px;
}
</style>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server" />
<div>
<script type="text/javascript">
var loggerObj = new Logger();
function beginRequestHandler(sender, args) {
// get WebRequest object
var request = args.get_request();
// get button that invoked postBack
var clickedButton = args.get_postBackElement();
var customData =
{
requestStart:new Date(),
button:args._postBackElement
};
// modify WebRequest, assigning custom data to _userContext property
request.set_userContext(customData);
};
function endRequestHandler(sender, args) {
var response = args.get_response();
if(response.get_responseAvailable()) {
// get associated WebRequestObject
var webRequest = response.get_webRequest();
// get custom data we assigned to WebRequest earlier
var customData = webRequest.get_userContext();
if(customData.button && loggerObj) {
var loggerDiv;
if(customData.button.attributes.getNamedItem("logger")) {
loggerDiv = customData.button.attributes.getNamedItem("logger").value;
var sb = new Sys.StringBuilder();
sb.append("----------------" + "<br />");
sb.append("request start: "+customData.requestStart.toTimeString() + "<br />");
sb.append("request end: "+new Date().toTimeString() + "<br />");
sb.append("request invoked by: "+customData.button.id + "<br />");
// display registered dataItems
sb.append("Data items:" + "<br />");
var dataItemKey = "";
for(dataItemKey in sender._dataItems) {
sb.append(dataItemKey + ": " + sender._dataItems[dataItemKey]+"<br />");
}
sb.append("----------------" + "<br />");
loggerObj.log(loggerDiv, sb.toString());
}
}
}
};
function Logger(divId) {
// logs a message into div
this.log = function(logger, message) {
if($get(logger)) {
$get(logger).innerHTML += message + "<br />";
$get(logger).scrollTop = $get(logger).scrollHeight - 400;
}
};
this.clearLog = function(logger) {
if($get(logger)) {
$get(logger).innerHTML = "";
}
};
};
</script>
<asp:UpdatePanel runat="server" ID="UP">
<ContentTemplate>
<asp:Button ID="Button1" logger="logger1" runat="server" Text="Button1"
onclick="Button1_Click" />
<asp:Button ID="Button2" logger="logger2" runat="server" Text="Button2"
onclick="Button2_Click" />
<asp:Button ID="Button3" logger="logger3" runat="server" Text="Button3"
onclick="Button3_Click" />
<asp:Button ID="Button4" logger="logger4" runat="server" Text="Button4"
onclick="Button4_Click" />
</ContentTemplate>
</asp:UpdatePanel>
<div>
<div id="logger1" class="loggerDiv">
</div>
<div id="logger2" class="loggerDiv">
</div>
<div id="logger3" class="loggerDiv">
</div>
<div id="logger4" class="loggerDiv">
</div>
</div>
</div>
</form>
<script type="text/javascript">
Sys.WebForms.PageRequestManager.getInstance().add_endRequest(endRequestHandler);
Sys.WebForms.PageRequestManager.getInstance().add_beginRequest(beginRequestHandler);
</script>
</body>
</html>
Code behind:
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Threading;
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
Thread.Sleep(100);
}
protected void Button1_Click(object sender, EventArgs e)
{
ScriptManager1.RegisterDataItem(this, "Button1 - confirmed from the server");
}
protected void Button2_Click(object sender, EventArgs e)
{
ScriptManager1.RegisterDataItem(this, "Button2 - confirmed from the server");
}
protected void Button3_Click(object sender, EventArgs e)
{
ScriptManager1.RegisterDataItem(this, "Button3 - confirmed from the server");
}
protected void Button4_Click(object sender, EventArgs e)
{
ScriptManager1.RegisterDataItem(this, "Button4 - confirmed from the server");
}
}
The most important in this code is how we attach custom object in beginRequestHandler:
var request = args.get_request();
request.set_userContext(customData);
And how we retrieve it later:
var response = args.get_response();
var webRequest = response.get_webRequest();
var customData = webRequest.get_userContext();
As you can see I am attaching DataItems to asynchronous responses - this is just demonstration of how can we pass some additional data from server, that can be tracked trough
sender._dataItems
property in endRequestHandler.