ASP.NET: Using Server.TransferRequest

If you haven't heard about this new method, don't be surprised - it is not well documented. You will only be able to use the method if you're hosting your pages on IIS 7 or higher --it doesn't work with previous versions of IIS.

For the page programmer, it is  similar to the old Transfer method, but better. When you issue a Server.Transfer, you're basically creating a new instance of the default page destination and executing it. It's fast, but there are some problems with it. If you are writing a  module, there is no way to get a reference to that new page since it would be instantiated "in-place" in the current request.

The new TransferRequest method  performs a complete request by using an IIS 7 worker thread. This means that the page request will go through the complete ASP.NET pipeline, giving every module a chance of interacting with the request. This means that authorization will be applied to the new url you're asking for.  Another advantage is that you can redirect to any handler. You can even define the headers that will be passed to the new handler you're asking for since one of the overloads of the method expects NameValueCollection parameter.

So HttpServerUtility.TransferRequest performs a full IIS child request under the covers, which allows it to re-run the entire request pipeline for the new request as if it was a separate request, getting the correct configuration for it, and running all of the normal IIS modules including authentication, authorization, etc.  For example, IIS will apply the authorization rules for the new url, as opposed to the previous url.

It does have one issue: if the parent request (the one from which you call TransferRequest) has acquired session state, then you need to release it before calling the method.  If you don't, then the new request will block for several seconds. This will affect mostly pages since the problem won't appear if you call the method before the AcquireRequestState or after the ReleaseRequestState HttpApplication events.

This happens because if the parent request has acquired session state and calls TransferRequest, it will wait until  the child request finishes in order to execute the end request notifications. The end request notifications is the place where the request releases the session state (if it has acquired it). When the child request starts executing, it tries to  get the session state which hasn't been released by the parent request. so, we're in a dead lock scenario with a built-in timeout.

There's a workaround for this if you need it. The idea is to make sure that the parent request will release the session before starting the child request. To achieve this, you can call the CompleteRequest method and then, from within a method that handles the EndRequest event raised by the HttpApplication, you should perform the TransferRequest method call. Here's a global.asax file that shows how to achieve this:

<%@ classname="MySample" %>

<script language="C#" runat="server">

string _transferRequestPath;

public void TransferRequest(string path) {
    // remember the path for later
    _transferRequestPath = path;

     // short circuit the pipeline by jumping to the
    // end request notifications where we can release
    // session state
    this.CompleteRequest();
}

// In Session_Start, we acquire session state.  This will
// cause TransferRequest to hang unless we release session state first.
void Session_Start() {

}

// By the time Application_EndRequest is called, session state has been released
void Application_EndRequest() {

    // we may need to call TransferRequest
    if (_transferRequestPath != null) {

        // make copy of path and set instance field to null
        // since application instances are pooled and reused.

        string path = _transferRequestPath;
        _transferRequestPath = null;

        Context.Server.TransferRequest(path);
    }
}

</script>


Mike Volodarsky has more information on this:.

By Peter Bromberg   Popularity  (3756 Views)