1. Trang chủ
  2. » Công Nghệ Thông Tin

Professional ASP.NET 3.5 in C# and Visual Basic Part 111 doc

10 233 0
Tài liệu đã được kiểm tra trùng lặp

Đang tải... (xem toàn văn)

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 10
Dung lượng 216,33 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

When you store information in cookies, remember that it’s quite different from storing data in the Sessionobject: ❑ Cookies are passed back and forth on every request.. Listing 22-9: Hid

Trang 1

Figure 22-8

Additionally, all URLS must be relative Remember that the Session ID appears as if it were a directory.

The Session is lost if an absolute URL such as/myapp/retrieve.aspxis invoked If you are

generat-ing URLs on the server side, useHttpResponse.ApplyAppPathModifier() It changes a URL when the

Session ID is embedded, as shown here:

Response.Write(Response.ApplyAppPathModifier("foo/bar.aspx"));

The previous line generates a URL similar to the following:

/myapp/ (S(avkbnbml4n1n5mi5dmfqnu45))/foo/bar.aspx

Notice that not only was session information added to the URL, but it was also converted from a relative

URL to an absolute URL, including the application’s virtual directory This method can be useful when

you need to useResponse.Redirector build a URL manually to redirect from an HTTP page to an

HTTPS page while still maintaining cookieless session state

Choosing the Correct Way to Maintain State

Now that you’re familiar with the variety of options available for maintaining state in ASP.NET 2.0,

here’s some real-world advice from production systems The In-Process (InProc) Session provider is the

fastest method, of course, because everything held in memory is a live object reference This provider

is held in theHttpApplication’scache and, as such, it is susceptible to application recycles If you use

Windows 2000 Server or Windows XP, theaspnet_wp.exeprocess manages the ASP.NET HTTP pipeline

If you’re running Windows 2003 Server or Vista,w3wp.exeis the default process that hosts the runtime

You must find a balance between the robustness of the out-of-process state service and the speed of the

in-process provider In our experience, the out-of-process state service is usually about 15 percent slower

than the in-process provider because of the serialization overhead and marshaling SQL Session State is

about 25 percent slower than InProc Of course your mileage will likely vary Don’t let these numbers

concern you too much Be sure to do scalability testing on your applications before you panic and make

inappropriate decisions

Trang 2

It’s worth saying again: We recommend that all developers use Out-Of-Process

Session State during development, even if this is not the way your application will

be deployed Forcing yourself to use the Out-Of-Process provider enables you to

catch any potential problems with custom objects that do not carry the

Serializable attribute If you design your entire site using the In-Process provider

and then discover, late in the project, that requirements force you to switch to the

SQL or Out-Of-Process providers, you have no guarantee that your site will work as

you wrote it Developing with the Out-Of-Process provider gives you the best of

both worlds and does not affect your final deployment method Think of it as an

insurance policy that costs you nothing upfront.

The Application Object

TheApplicationobject is the equivalent of a bag of global variables for your ASP.NET application

Global variables have been considered harmful for many years in other programming environments, and ASP.NET is no different You should give some thought to what you want to put in theApplication

object and why Often, the more flexibleCacheobject that helps you control an object’s lifetime is the

more useful Caching is discussed in depth in Chapter 23

TheApplicationobject is not global to the machine; it’s global to theHttpApplication If you are

running in the context of a Web farm, each ASP.NET application on each Web server has its own Appli-cationobject Because ASP.NET applications are multithreaded and are receiving requests that are being handled by your code on multiple threads, access to theApplicationobject should be managed using the

Application.LockandApplication.Unlockmethods If your code doesn’t call Unlock directly (which

it should, shame on you) the lock is removed implicitly at the end of theHttpRequestthat called Lock

originally

This small example shows you how to lock theApplicationobject just before inserting an object Other threads that might be attempting to write to theApplicationwill wait until it is unlocked This example assumes there is an integer already stored inApplicationunder the keyGlobalCount

VB

Application.Lock()

Application("GlobalCount") = CType(Application("GlobalCount"), Integer) + 1

Application.UnLock()

C#

Application.Lock();

Application["GlobalCount"] = (int)Application["GlobalCount"] + 1;

Application.UnLock();

Object references can be stored in theApplication, as in theSession, but they must be cast back to their known types when retrieved (as shown in the preceding sample code)

Trang 3

Quer yStrings

The URL, or QueryString, is the ideal place for navigation-specific — not user-specific — data The

QueryString is the most hackable element on a Web site, and that fact can work for you or against you

For example, if your navigation scheme uses your own page IDs at the end of a query string (such as

/localhost/mypage.aspx?id = 54) be prepared for a user to play with that URL in his browser, and try

every value foridunder the sun Don’t blindly castidto an int, and if you do, have a plan if it fails

A good idea is to returnResponse.StatusCode=404when someone changes a URL to an unreasonable

value Another fine idea that Amazon.com implemented was the Smart 404 Perhaps you’ve seen these:

They say ‘‘Sorry you didn’t find what you’re looking for Did you mean _?’’

Remember, your URLs are the first thing your users may see, even before they see your HTML Hackable

URLs — hackable even by my mom — make your site more accessible Which of these URLs is friendlier

and more hackable (for the right reason)?

http://reviews.cnet.com/Philips_42PF9996/4505-6482_7-31081946.html?tag=cnetfd.sd

or

http://www.hanselman.com/blog/CategoryView.aspx?category=Movies

Cookies

Do you remember the great cookie scare of 1997? Most users weren’t quite sure just what a cookie was,

but they were all convinced that cookies were evil and were storing their personal information Back then,

it was likely personal information was stored in the cookie! Never, ever store sensitive information, such

as a user ID or password, in a cookie Cookies should be used to store only non-sensitive information, or

information that can be retrieved from an authoritative source Cookies shouldn’t be trusted, and their

contents should be able to be validated For example, if a Forms Authentication cookie has been tampered

with, the user is logged out and an exception is thrown If an invalid Session ID cookie is passed in for

an expired Session, a new cookie can be assigned

When you store information in cookies, remember that it’s quite different from storing data in the

Sessionobject:

Cookies are passed back and forth on every request That means you are paying for the size of

your cookie during every HTTP GET and HTTP POST.

❑ If you have ten 1-pixel spacer GIFs on your page used for table layouts, the user’s browser is

sending the same cookie eleven times: once for the page itself, and once for each spacer GIF, even

if the GIF is already cached

❑ Cookies can be stolen, sniffed, and faked If your code counts on a cookie’s value, have a plan in

your code for the inevitability that cookie will get corrupted or be tampered with

❑ What is the expected behavior of your application if a cookie doesn’t show? What if it’s 4096

bytes? Be prepared You should design your application around the ’’principle of least surprise.’’

Your application should attempt to heal itself if cookies are found missing or if they are larger

than expected

❑ Think twice before Base64 encoding anything large and placing it in a cookie If your design

depends on this kind of technique, rethink using either the Session or another backing-store

Trang 4

PostBacks and Cross- Page PostBacks

In classic ASP, in order to detect logical events such as a button being clicked, developers had to inspect theFormcollection of theRequestobject Yes, a button was clicked in the user’s browser, but no object

model was built on top of stateless HTTP and HTML ASP.NET 1.x introduced the concept of the

post-back, wherein a server-side event was raised to alert the developer of a client-side action If a button is

clicked on the browser, the Form collection is POSTed back to the server, but now ASP.NET allowed the developer to write code in events such asButton1_ClickandTextBox1_Changed

However, this technique of posting back to the same page is counter-intuitive, especially when you are

designing user interfaces that aim to create wizards to give the user the sense of forward motion

This chapter is about all aspects of state management Postbacks and cross-page postbacks, however, are covered extensively in Chapter 3 so this chapter touches on them only in the context of state management

Postbacks were introduced in ASP.NET 1.x to provide an eventing subsystem for Web development It

was inconvenient to have only single-page postbacks in 1.x, however, and that caused many developers

to store small objects in theSessionon a postback and then redirect to the next page to pick up the stored data With cross-page postbacks, data can be posted ’’forward’’ to a different page, often obviating the

need for storing small bits of data that could be otherwise passed directly

ASP.NET 2.0 and above includes the notion of aPostBackUrlto all the Button controls including LinkBut-ton and ImageButLinkBut-ton ThePostBackUrlproperty is both part of the markup when a control is presented

as part of the ASPX page, as seen in the following, and is a property on the server-side component that’s available in the code-behind:

<asp:Button PostBackUrl="url" >

When a button control with thePostBackUrlproperty set is clicked, the page does not post back to itself; instead, the page is posted to the URL assigned to the button control’sPostBackUrlproperty When

a cross-page request occurs, thePreviousPageproperty of the currentPageclass holds a reference to

the page that caused the postback To get a control reference from thePreviousPage, use theControls

property or use theFindControlmethod

Create a fresh site with aDefault.aspx(as shown in Listing 22-8) Put aTextBoxand aButtonon it, and set theButton PostBackUrlproperty toStep2.aspx Then create aStep2.aspxpage with a singleLabel

and add aPage_Loadhandler by double-clicking the HTML Designer

Listing 22-8: Cross-page postbacks

Default.aspx

<!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>Cross-page PostBacks</title>

</head>

<body>

<form id="form1" runat="server">

<div>

<asp:TextBox ID="TextBox1" Runat="server"></asp:TextBox>

<asp:Button ID="Button1" Runat="server" Text="Button"

Trang 5

PostBackUrl="~/Step2.aspx" />

</div>

</form>

</body>

</html>

Step2.aspx

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"

"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >

<head runat="server">

<title>Step 2</title>

</head>

<body>

<form id="form1" runat="server">

<div>

<asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>

</div>

</form>

</body>

</html>

VB — Step2.aspx.vb

Partial Class Step2

Inherits System.Web.UI.Page

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) _

Handles Me.Load

If PreviousPage IsNot Nothing AndAlso PreviousPage.IsCrossPagePostBack Then Dim text As TextBox = _

CType(PreviousPage.FindControl("TextBox1"), TextBox)

If text IsNot Nothing Then Label1.Text = text.Text End If

End If End Sub

End Class

CS — Step2.aspx.cs

using System;

using System.Web.UI.WebControls;

public partial class Step2 : System.Web.UI.Page

{

protected void Page_Load(object sender, EventArgs e)

{

if (PreviousPage != null && PreviousPage.IsCrossPagePostBack) {

TextBox text = PreviousPage.FindControl("TextBox1") as TextBox;

if (text != null) {

Trang 6

Label1.Text = text.Text;

} }

}

}

In Listing 22-8,Default.aspxposts forward toStep2.aspx, which can then access thePage.PreviousPage

property and retrieve a populated instance of thePagethat caused the postback A call toFindControl

and a cast retrieves theTextBoxfrom the previous page and copies its value into the Label ofStep2.aspx

Hidden F ields, V iewState, and ControlState

Hidden input fields such as<input type=""hidden" name="foo">are sent back as name/value pairs

in a Form POST exactly like any other control, except they are not rendered Think of them as hidden

text boxes Figure 22-9 shows a HiddenField control on the Visual Studio Designer with its available

properties Hidden fields are available in all versions of ASP.NET

Figure 22-9

ViewState, on the other hand, exposes itself as a collection of key/value pairs like theSessionobject, but renders itself as a hidden field with the name" VIEWSTATE"like this:

<input type="hidden" name=" VIEWSTATE" value="/AAASSDAS Y/lOI=" />

Trang 7

Any objects put into the ViewState must be markedSerializable ViewState serializes the objects with

a special binary formatter called the LosFormatter LOS stands for limited object serialization It serializes

any kind of object, but it is optimized to contain strings, arrays, and hashtables

To see this at work, create a new page and drag aTextBox,Button, andHiddenFieldonto it Double-click

in the Designer to create aPage_Loadand include the code from Listing 22-9 This example adds a string

toHiddenField.Value, but adds an instance of aPersonto theViewStatecollection This listing

illus-trates that while ViewState is persisted in a single HTMLTextBoxon the client, it can contain both simple

types such as strings, and complex types such asPerson This technique has been around since ASP.NET

1.x and continues to be a powerful and simple way to persist small pieces of data without utilizing server

resources

Listing 22-9: Hidden fields and ViewState

ASPX

<!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>Hidden Fields and ViewState</title>

</head>

<body>

<form id="form1" runat="server">

<div>

<asp:TextBox ID="TextBox1" Runat="server"></asp:TextBox>

<asp:Button ID="Button1" Runat="server" Text="Button" />

<asp:HiddenField ID="HiddenField1" Runat="server" />

</div>

</form>

</body>

</html>

VB

<Serializable> _

Public Class Person

Public firstName As String

Public lastName As String

End Class

Partial Class _Default

Inherits System.Web.UI.Page

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) _

Handles Me.Load

If Not Page.IsPostBack Then HiddenField1.Value = "foo"

ViewState("AnotherHiddenValue") = "bar"

Dim p As New Person

Trang 8

p.firstName = "Scott"

p.lastName = "Hanselman"

ViewState("HiddenPerson") = p End If

End Sub

End Class

C#

using System;

using System.Web.UI.WebControls;

using System.Web.UI.HtmlControls;

[Serializable]

public class Person

{

public string firstName;

public string lastName;

}

public partial class _Default : System.Web.UI.Page

{

protected void Page_Load(object sender, EventArgs e)

{

if (!Page.IsPostBack)

{

HiddenField1.Value = "foo";

ViewState["AnotherHiddenValue"] = "bar";

Person p = new Person();

p.firstName = "Scott";

p.lastName = "Hanselman";

ViewState["HiddenPerson"] = p;

}

}

}

In Listing 22-9, a string is added to aHiddenFieldand to theViewStatecollection Then aPerson

instance is added to theViewStatecollection with another key A fragment of the rendered HTML is

shown in the following code:

<form method="post" action="Default.aspx" id="form1">

<div>

<input type="hidden" name=" VIEWSTATE"

value="/wEPDwULLTIxMjQ3OTEzODcPFgQeEkFub3RoZXJIaWRkZW5WYWx1ZQUDYmFyHgxIaWRkZW5QZXJz

b24ypwEAAQAAAP////8BAAAAAAAAAAwCAAAAP3ZkcTVqYzdxLCBWZXJzaW9uPTAuMC4wLjAsIEN1bHR1cmU

9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49bnVsbAUBAAAAE0RlZmF1bHRfYXNweCtQZXJzb24CAAAACWZpcn

N0TmFtZQhsYXN0TmFtZQEBAgAAAAYDAAAABVNjb3R0BgQAAAAJSGFuc2VsbWFuC2RkI/CLauUviFo58BF8v

pSNsjY/lOI=" />

</div>

Trang 9

<input name="TextBox1" type="text" id="TextBox1" />

<input type="submit" name="Button1" value="Button" id="Button1" />

<input type="hidden" name="HiddenField1" id="HiddenField1" value="foo" />

</div>

</form>

Notice that theViewStatevalue uses only valid ASCII characters to represent all its contents Don’t let

the sheer mass of it fool you It is big and it appears to be opaque However, it’s just a hidden text box

and is automatically POSTed back to the server The entireViewStatecollection is available to you in the

Page_Load The value of theHiddenFieldis stored as plain text

Neither ViewState nor Hidden Fields are acceptable for any kind of sensitive data

People often complain about the size of ViewState and turn if off completely

without realizing its benefits ASP.NET 2.0 cut the size of serialized ViewState

nearly in half You can find a number of tips on using ViewState on my blog by

Googling for ’’Hanselman ViewState’’ Fritz Onion’s free ViewStateDecoder tool

from www.pluralsight.com is a great way to gain insight into what’s stored in your

pages’ ViewState Note also Nikhil Kotari’s detailed blog post on ViewState

improvements at www.nikhilk.net/ViewStateImprovements.aspx

By default, the ViewState field is sent to the client with a salted hash to prevent tampering Salting means

that the ViewState’s data has a unique value appended to it before it’s encoded As Keith Brown says

’’Salt is just one ingredient to a good stew.’’ The technique used is called HMAC, or hashed message

authentication code As shown in the following code, you can use the<machineKey>element of the

web.config fileto specify thevalidationKey, as well as the algorithm used to protect ViewState This

section of the file and thedecryptionKeyattribute also affect how Forms Authentication cookies are

encrypted (see Chapter 21 for more on forms authentication)

<machineKey validationKey="AutoGenerate,IsolateApps"

decryptionKey="AutoGenerate,IsolateApps" validation="SHA1" />

If you are running your application in a Web farm,<validationKey>and<decryptionKey>have to

be manually set to the same value Otherwise, ViewState generated from one machine could be POSTed

back to a machine in the farm with a different key! The keys should be 128 characters long (the maximum)

and generated totally by random means If you addIsolateAppsto these values, ASP.NET generates a

unique encrypted key for each application using each application’s application ID

I like to use security guru Keith Brown’s GenerateMachineKey tool, which you can find atwww

pluralsight.com/tools.aspx, to generate these keys randomly.

Thevalidationattribute can be set to SHA1 or MD5 to provide tamper-proofing, but you can include

added protection by encrypting ViewState as well In ASP.NET 1.1 you can encrypt ViewState only by

using the value 3DES in thevalidationattribute, and ASP.NET 1.1 will use the key in the

decryp-tionKeyattribute for encryption However, ASP.NET 2.0 adds a new decryption attribute that is used

exclusively for specifying the encryption and decryption mechanisms for forms authentication tickets,

Trang 10

and thevalidationattribute is used exclusively for ViewState, which can now be encrypted using 3DES

or AES and the key stored in thevalidationKeyattribute

ASP.NET 2.0 also adds theViewStateEncryptionModeattribute to the<pages>configuration element

with two possible values,AutoorAlways Setting the attribute toAlwayswill force encryption of View-State, whereas setting it toAutowill encrypt ViewState only if a control requested encryption using the newPage.RegisterRequiresViewStateEncryptionmethod

Added protection can be applied to ViewState by settingPage.ViewStateUserKeyin thePage_Initto a unique value such as the user’s ID This must be set inPage_Initbecause the key should be provided to ASP.NET before ViewState is loaded or generated For example:

protected void Page_Init (Object sender, EventArgs e)

{

if (User.Identity.IsAuthenticated)

ViewStateUserKey = User.Identity.Name;

}

When optimizing their pages, ASP.NET programmers often disable ViewState for many controls when

that extra bit of state isn’t absolutely necessary However, in ASP.NET 1.x, disabling ViewState was a

good way to break many third-party controls, as well as the included DataGrid’s sorting functionality

ASP.NET now includes a second, parallel ViewState-like collection calledControlState This dictionary can be used for round-tripping crucial information of limited size that should not be disabled even when ViewState is You should only store data in theControlStatecollection that is absolutely critical to the functioning of the control

Recognize that ViewState, and also ControlState, although not secure, is a good place to store small bits of

a data and state that don’t quite belong in a cookie or theSessionobject If the data that must be stored is relatively small and local to that specific instance of your page, ViewState is a much better solution than littering theSessionobject with lots of transient data

Using HttpContext.Current.Items for Ver y

Shor t- Term Storage

TheItemscollection ofHttpContextis one of ASP.NET’s best-kept secrets It is anIDictionary

key/value collection of objects that’s shared across the life of a singleHttpRequest That’s a single

HttpRequest Why would you want to store state for such a short period of time? Consider these reasons:

When you share content between IHttpModules and IHttpHandlers:If you write a custom

IHttpModule, you can store context about the user for use later in a page

When you communicate between two instances of the same UserControl on the same page:

Imagine you are writing a UserControl that serves banner ads Two instances of the same control could select their ads fromHttpContext.Itemsto prevent showing duplicates on the same page

When you store the results of expensive calls that might otherwise happen twice or more on a page:If you have multiple UserControls that each show a piece of data from a large, more

Ngày đăng: 05/07/2014, 19:20

TỪ KHÓA LIÊN QUAN