06 June 2005

What Great .NET Developers Ought To Know (Part Four ASP.NET (UI) Developers)

Part Four ASP.NET (UI) Developers (II)

Give an example of how using an HttpHandler could simplify an existing design that serves Check Images from an .aspx page.
Scot Hanselman himself got something to say on A Boilerplate HttpHandler.
Just like .aspx page is an HttpHandler that handles Http Request:

// System.Web.UI.Page
public class Page : TemplateControl, IHttpHandler

<add type="System.Web.UI.PageHandlerFactory" path="*.aspx" verb="*">

You can implement your own HttpHandler to return other MEMI type (image, download file, pdf etc) to browser. The register your HttpHandler in the web.config (or you can register it in machine.config or IIS Application Configuration properties page if implements IHttpHandlerFactory)
//my HttpHandler
public class MyHandler : IHttpHandler{…}
<add type="Namespace.MyHandler.New, MyHandlerAssemblyName" path="MyHandler.New" verb=" GET, PUT, POST ">

MyHandler implementation (primarily in ProcessRequest)should cater following steps:
1 Setting context.Response.StatusCode
2 Setting context.Response.ContentType = "somespecific/mimetype"; (e.g. Image/jpg)
3 Setting context.Response

What kinds of events can an HttpModule subscribe to? What influence can they have on an implementation? What can be done without recompiling the ASP.NET Application?
An HttpModule implement IHttpModule:
public interface IHttpModule{
void Dispose();
void Init(HttpApplication context)

HttpModules are hooked into the Http request pipeline via entry like this in web.config:
<add type="classname,assemblyname" name="modulename"><remove name="modulename">

The ASP.NET runtime calls the module's Init and Dispose methods. Init is called when the module attaches itself to the HttpApplication object and Dispose is called when the module is detached from HttpApplication. The Init and Dispose methods represent the module's opportunity to hook into a variety of events exposed by HttpApplication.

As can be seen from the above config settings, without recompile the asp.net app, you can remove one or more HttpModules.

An HttpMoudle can subscribe to following events:
AcquireRequestState When ASP.NET acquires the current state (for example, session state) associated with the current request.
AuthenticateRequest When a security module has established the identity of the user
AuthorizeRequest When a security module has verified user authorization
BeginRequest When the first event in the HTTP pipeline chain of execution responds to a request
Disposed When ASP.NET completes the chain of execution when responding to a request
EndRequest When the last event in the HTTP pipeline chain of execution responds to a request
Error When an unhandled exception is thrown
PostRequestHandlerExecute When the ASP.NET handler (page, XML Web Service) finishes execution
PreRequestHandlerExecute Just before ASP.NET begins executing a handler such as a page or XML Web Service
PreSendRequestContent Just before ASP.NET sends content to the client
PreSendRequestHeaders Just before ASP.NET sends HTTP headers to the client
ReleaseRequestState After ASP.NET finishes executing all request handlers; also causes state modules to save the current state data
ResolveRequestCache When ASP.NET completes an authorization event to let the caching modules serve requests from the cache, bypassing execution of the handler (the page or XML Web Service, for example)
UpdateRequestCache When ASP.NET finishes executing a handler in order to let caching modules store responses that will be used to serve subsequent requests from the cache

A sample HttpModule class:

// This module, named HttpModules.CS will be compiled
// into an assembly named HttpModules.dll
// config entry:
// <add type=" HttpModuleExamples.CustomHttpModule, HttpModules.dll" name=" CustomHttpModule">

using System;
using System.Web;

namespace HttpModuleExamples {
public class CustomHttpModule : IHttpModule {
// IHttpModule members
public void Init(HttpApplication httpApp) {
httpApp.BeginRequest +=
new EventHandler(this.OnBeginRequest);

httpApp.EndRequest +=
new EventHandler(this.OnEndRequest);

public void Dispose() {
// Usually, nothing has to happen here...

// event handlers
public void OnBeginRequest(object o, EventArgs ea) {
HttpApplication httpApp = (HttpApplication) o;
HttpContext ctx = HttpContext.Current;
ctx.Response.Write("Beginning Request

public void OnEndRequest(object o, EventArgs ea) {
HttpApplication httpApp = (HttpApplication) o;
HttpContext ctx = HttpContext.Current;

ctx.Response.Write("Ending Request

Pointer: HTTP Modules

Explain <@OutputCache%> and the usage of VaryByParam, VaryByHeader, VaryByCustom?
<@OutputCache%> Declaratively controls the output caching policies of an ASP.NET page or a user control contained in a page. Cached page/control is placed in memory.
VaryByParam: Different versions of the page are stored based on the query string values.

If there are one thousand different ids are queried in 30 sec, there will be one thousand pages cached. On the other hand queries page.aspx?id=1, page.aspx?id=1&Num=1, and page.aspx?id=1&Num=2 will receive the same cached page.
VaryByHeader: Different versions of the page are stored based on the specified HTTP header values.

Four requests arrive for the page with the following Accept-Language headers: 1) de-lu; 2) en-us; 3) fr; 4) en-us, three cached pages is created and the second en-us request reads from cache.
VaryByCustom: Different versions of the page are stored based on browser type and major version. Additionally, you can extend output caching by defining custom strings.

Then override the HttpApplication.GetVaryByCustomString method in the Global.asax file. This string is built by you and used as a key to store and retrieve a cached version of your page. The key can be anything and build from anything. You can create a composite key from other pieces of information available to you like cookies, user-languages, browser capabilities, whatever.

public override string GetVaryByCustomString(HttpContext context, string arg){
if(arg.ToLower() == "mycustomstring"){
HttpCookie cookie = context.Request.Cookies["ID"];
if(cookie != null)
return cookie.Value;
return base.GetVaryByCustomString (context, custom);

Pointer: Advanced ASP.NET Caching and AddValidationCallBack Improving ASP.NET Performance

How would one implement ASP.NET HTML output caching, caching outgoing versions of pages generated via all values of q= except where q=5 (as in http://localhost/page.aspx?q=5)?
Use AddValidationCallBack It provides a mechanism to programmatically check the validity of a item in the cache before the item is returned from the cache. Before the response is served from the Web server cache, all registered handlers are queried to ensure resource validity. If any handler sets a flag indicating that the resource is invalid, the entry is marked invalid and evicted from the cache. The request is then handled as if it were a cache miss.
Pointer: Advanced ASP.NET Caching and AddValidationCallBack MSDN AddValidationCallBack

When can I safely set the EnableViewState property to False?
Pointers: Understanding ASP.NET View State
View state is only need when you need to remember state across postbacks.
For a Web page that has a read-only DataGrid, you'd definitely want to set the DataGrid's EnableViewState property to False. You can even create sortable and pageable DataGrids with the view state disabled.

The DataGrid stores its contents in the view state so the page developer doesn't need to rebind the database data to the DataGrid on each and every page load, but only on the first one. The benefit is that the database doesn't need to be accessed as often. If, however, you set a DataGrid's EnableViewState property to False, you'll need to rebind the database data to the DataGrid on both the first page load and every subsequent postback.

Using cookieless sessions is that the session state is lost if an absolute URL is invoked(Underpinnings of the Session State Implementation in ASP.NET)
The context:
Suppose that you request a page at the following URL:

What is really displayed in the browser's address bar is slightly different and now includes the session ID, as shown here:

When instantiated, the session-state HTTP module checks the value of the cookieless attribute. If true, the request is redirected (HTTP 302) to a modified virtual URL that includes the session ID just before the page name. When processed again, the request embeds the session ID. If the request starts a new session, the HTTP module generates a new session ID and then redirects the request. If the request is a postback, the session ID is already there because postbacks use relative URLs.

The problem:
The drawback of using cookieless sessions is that the session state is lost if an absolute URL is invoked. When cookies are used, you can clear the address bar, go to another application, and then return to the previous one and retrieve the same session values. If you do this when session cookies are disabled, the session data is lost. For example, the following code breaks the session:
<a href="/code/page.aspx" runat="server">Click</a>

The solution:
If you need to use absolute URLs, resort to a little trick and manually add the session ID to the URL. You use the ApplyAppPathModifier method on the HttpResponse class.
<a runat="server"
href=<% =Response.ApplyAppPathModifier("/code/page.aspx")%> >Click</a>

The ApplyAppPathModifier method takes a string representing a URL and returns an absolute URL, which embeds session information. For example, this trick is especially useful in situations in which you need to redirect from a HTTP page to an HTTPS page.

No comments: