Boot Camp - C# - Syringe.Net.Nz

Download Report

Transcript Boot Camp - C# - Syringe.Net.Nz

ASP.net Form State
Jeremy Boyd,
Senior Technical Lead - Intergen
MSDN Regional Director – New Zealand
Todays Objectives
Discuss ViewState
– Used for supplemental state transmission
Event Identification
– Hidden fields used to distinguish events
– ViewState used to trigger change notification events
Per-client state
– ViewState
– Session
– Cookies
Todays Objectives
Alternative inter-page state propagation
– Query string
– Items collection
ViewState
To complete the control-based model,
additional state must be transferred with each
post back
– Many HTML elements do not have their values sent
in a POST
• table, span, div, p, li, etc.
– If the value of one of these elements is changed in
a server-side control, it should retain that value
across multiple requests
– Additional hidden input element is generated with
each Page rendering called __VIEWSTATE
Sample Page relying on ViewState
<%@ Page Language="C#" %>
<html>
<script runat="server">
protected void Page_Load(object src, EventArgs e)
{
if (IsPostBack)
{
int op1 = int.Parse(_op.Value);
int op2 = int.Parse(_sum.InnerText);
_sum.InnerText = (op1+op2).ToString();
}
}
</script>
<body>
<form runat="server">
<h2>ASP.NET accumulator page</h2>
<input size="2" type="text" id="_op" runat="server"/>
Sum:<span id="_sum" runat="server">0</span>
<p><input type="submit" value="Add" /></p>
</form>
</body></html>
Sample Page – HTML output
<html>
<body>
<form name="_ctl0" method="post"
action="accumulator.aspx" id="_ctl0">
<input type="hidden" name="__VIEWSTATE"
value="dDwtMTE3NzEwNDc2Njs7PvcRil1nMNe70yha9afq+YEvj46N" />
<h2>ASP.NET accumulator page</h2>
<input name="_op" id="_op" type="text" size="2" />
Sum:<span id="_sum"></span>
<p>
<input type=submit value="Add" />
</p>
</form>
</body>
</html>
Decoding ViewState
ViewState is persisted as a tuple-based data
structure and encoded as a base64 string
dDwxMTgxOTcyOTQwO3Q8O2w8aTwxPjs+O2w8dDw7bDxpPDU+Oz47bDx0PHA8cDxsPFR
leHQ7PjtsPDE7Pj47Pjs7Pjs+Pjs+Pjs+coPvKE0gKu8gNg298/1rC07unJE=
t<1181972940;t<;l<i<1>;>;l<t<;l<i<5>;>;l<t<p<p<l<Text;>;l<1;>>;>;;>;>>;>>;>r(M * 6kN
ViewStateDecoder
Available at
– http://www.develop.com/devresources/
Disabling ViewState
ViewState can be disabled for individual
controls, an entire page, or even an entire
application
<%@
Page
Language="C#"
EnableViewState="False"
%> %>
<%@
Page
Language="C#"
EnableViewState="False"
<html>
<!-- ... -->
<%@
<%@Page
PageLanguage="C#"
Language="C#"%>
%>
<html>
<body>
<form runat="server" ID="Form1">
<input type="text" id="_op" runat="server" EnableViewState="false" />
<span id="_span1" runat="server" EnableViewState="false" />
<p><input type="button" value="Enter" runat="server" /></p>
</form>
</body></html>
Protecting ViewState
ASP.NET provides two mechanisms for
protecting ViewState
– Tamper-proofing using a hashcode (SHA1 or MD5)
– Encryption using Triple DES symmetric algorithm
(3DES)
Tamper-proofing can be enabled at the Page
level
(on by default)
– <%@ Page enableViewStateMac='true' %>
Or at the application or machine level
ViewState Encryption
Must be enabled at the machine level:
– <machineKey validation='3DES' />
Significantly increases the size of ViewState use with caution!
No need to encrypt if already using SSL
For deployment on a WebFarm, you must
specify the same validation key on all
machines:
– <machineKey validation='3DES'
validationKey='7DFB068D0FC3D9E2E3C2BCA32DF9509DEFF71B8F44
DF95578CCFCD2B6EA50475BEE615AF0E64072EC07A1D4720F11A51259
47C592512BA72290812F911963CC8' />
Generating a Validation Key
using
using
using
using
System;
System.Text;
System.Security;
System.Security.Cryptography;
class App {
static void Main(string[] argv)
int len = 48;
if (argv.Length > 0)
len = int.Parse(argv[0]);
{
byte[] buff = new byte[len/2];
RNGCryptoServiceProvider rng = new
RNGCryptoServiceProvider();
rng.GetBytes(buff);
StringBuilder sb = new StringBuilder(len);
for (int i=0; i<buff.Length; i++)
sb.Append(string.Format("{0:X2}", buff[i]));
Console.WriteLine(sb);
}
}
Identifying server-side events
Server-side events are issued during a POST
request
– Not obvious which controls fired events with a
generic POST
• Was a select box changed?
• Was button 1 pressed?
• Was button 2 pressed?
– ASP.NET propagates additional event information
• Hidden field __EVENTTARGET stores the control id that
issued the event
• Hidden field __EVENTARGUMENT stores any parameters to
the event
Page with Multiple Events
<%@ Page Language="C#" %>
<html><script runat="server">
protected void OnLinkButton(object src, EventArgs e)
{ _message.Text = "You clicked the link button!"; }
protected void OnIndexChanged(object src, EventArgs e) {
_message.Text = string.Format("You changed the index to {0}!",
_ddl.SelectedItem.Value);
}
</script><body><form runat="server">
<h2>ASP.NET event page</h2>
<asp:LinkButton runat="server" Text="Click Me!"
OnClick="OnLinkButton" /> <br/>
<asp:DropDownList runat="server" ID="_ddl" AutoPostBack="true"
OnSelectedIndexChanged="OnIndexChanged">
<asp:ListItem Selected="True" Value="1"> item 1 </asp:ListItem>
<asp:ListItem Value="2"> item 2 </asp:ListItem>
<asp:ListItem Value="3"> item 3 </asp:ListItem>
<asp:ListItem Value="4"> item 4 </asp:ListItem>
</asp:DropDownList> <br/>
<asp:Label id="_message" runat="server" EnableViewState="false" />
</form></body></html>
Event Page Rendering
<html><body>
<form name="_ctl0" method="post" action="event.aspx" id="_ctl0">
<input type="hidden" name="__EVENTTARGET" value="" />
<input type="hidden" name="__EVENTARGUMENT" value="" />
<input type="hidden" name="__VIEWSTATE" value="..." />
<script language="javascript">
function __doPostBack(eventTarget, eventArgument) {
var theform;
if (window.navigator.appName.toLowerCase().indexOf("netscape") > -1){
theform = document.forms["_ctl0"];
}
else {
theform = document._ctl0;
}
theform.__EVENTTARGET.value = eventTarget.split("$").join(":");
theform.__EVENTARGUMENT.value = eventArgument;
theform.submit();
}
</script>
<h2>ASP.NET event page</h2>
<a href="javascript:__doPostBack('_ctl1','')">Click Me!</a>
<br/>
<select name="_ddl" onchange="__doPostBack('_ddl','')"
language="javascript" id="_ddl"> ...
Change notification events
Server-side controls that issue change
notification events rely on ViewState
– Prior value stored in ViewState
– During subsequent POST current value is
compared with value cached in ViewState and
change notification issued if different
Corollary: do not disable ViewState on controls
whose server-side change events you are
handling
Explicit use of ViewState
ViewState can also be used as a means to store
client-specific state
public class PurchasePage : Page
{
private void Page_Load(object sender, EventArgs e)
{
ArrayList cart = (ArrayList)ViewState["Cart"];
if (cart == null)
{
cart = new ArrayList();
ViewState["Cart"] = cart;
}
// Use items stored in ArrayList
}
Session State
Session state is used to store individual data
for a user during page interaction
– Session state is scoped by a single client session,
and is tagged with a unique (and hard to guess)
session ID
– The session ID is transmitted between the client
and server using cookies (or munged URLs if
cookieless mode is enabled)
– Accessed through the Session property of a page,
which references the current HttpSession object
provided by the HTTP runtime
Session State – Sample usage
// Inside a page of the application
protected void Submit_Click(Object sender, EventArgs e)
{
Session["Age"] = AgeField.Value; // save age user entered
// ...
}
// Inside another page of the application
// only let user vote if he/she is over 18
if (((int)Session["Age"]) >= 18)
VoteButton.Enabled = true;
else
VoteButton.Enabled = false;
Cookies
Client-side cookies can be used to store user
preferences/information
–
–
–
–
Server requests client to set cookie in response
Client sends cookie values in subsequent requests
Cookies may be persisted if the Expires property
Browsers limit cookie data -- only 4096 bytes
guaranteed
– Clients may disable cookies
Cookie interaction controlled with two
collections:
– Request.Cookies - cookies sent by client
Using Cookies in ASP.net
protected void Page_Load(object sender, EventArgs e) {
if (Request.Cookies["Age"] == null)
Response.Cookies.Add(new HttpCookie("Age", "21"));
else
{
// use existing cookie value...
int age = int.Parse(Request.Cookies["Age"].Value);
}
}
QueryString State
State can be passed between pages by
appending a query string to the URL
– Must be passed as name/value pairs
– Restricted to URL compatible strings
• Must use % to represent restricted characters as encoded
(including /.#?;:$,+@&={}|\^[]')
– Indicate query string with '?' character
– Delimit name/value pairs with '&' character
– Access query string values through the indexer in
HttpRequest
?name=joe&age=21
http://turtle.net.nz/test.aspx?name=joe&age=21
QueryString Example
Signup.aspx.cs
private void _signupButton_Click(object sender, System.EventArgs e)
{
StringBuilder url = new StringBuilder(); // prepare query string
url.Append("ThankYou.aspx?firstname=");
url.Append(_firstname.Text);
url.Append("&lastname=");
url.Append(_lastname.Text);
url.Append("&zipcode=");
url.Append(_zipcode.Text);
Response.Redirect(url.ToString());
}
ThankYou.aspx.cs
private void Page_Load(object sender, System.EventArgs e)
{
StringBuilder msg = new StringBuilder();
msg.Append("<b>Registered user:</b> ");
Request["firstname"]
msg.Append(Request["firstname"]);
msg.Append(" ");
msg.Append(Request["lastname"]);
Request["lastname"]
msg.Append("<br/> <b>location=</b>");
msg.Append(Request["zipcode"]);
Request["zipcode"]
_summary.InnerHtml = msg.ToString();
}
Context.Items State
The Items collection of HttpContext can be
used to store per-request state
– Useful when passing data between elements in the
pipeline (like modules)
– Can be used to pass data between pages when
using Server.Transfer
Context.Items State Example
Signup.aspx.cs
private void _signupButton_Click(object sender, System.EventArgs e)
{
Context.Items["firstname"]= _firstname.Text;
Context.Items["firstname"]
Context.Items["lastname"]
Context.Items["lastname"] = _lastname.Text;
Context.Items["zipcode"]
Context.Items["zipcode"] = _zipcode.Text;
Server.Transfer("ThankYou.aspx");
}
ThankYou.aspx.cs
private void Page_Load(object sender, System.EventArgs e)
{
StringBuilder msg = new StringBuilder();
msg.Append("<b>Registered user:</b> ");
Context.Items["firstname"]
msg.Append(Context.Items["firstname"]);
msg.Append(" ");
msg.Append(Context.Items["lastname"]);
Context.Items["lastname"]
msg.Append("<br/> <b>location=</b>");
msg.Append(Context.Items["zipcode"]);
Context.Items["zipcode"]
_summary.InnerHtml = msg.ToString();
}
Summary
ASP.NET developers must be aware of the
various types of state forms use
– ViewState is used for controls whose contents does
not propagate with traditional POST bodies
– Change notifications managed via ViewState
– Server-side events use supplemental hidden fields
Several types are available for use
– ViewState - client-specific for POST requests to
same page
– Session state - client-specific tied to browser
session