September 2008 - Posts

Redirect to Error Page When Maximum Request Length is Exceeded [FileUpload]

 How many times you tried to catch the maximum request length error thrown by the FileUplad control if the web.config HttpRuntime entry is not modified?
In this blog post, Haissam Abdul Malak will create an HttpModule which check if the file is larger than 4 MB to redirect the user to a webform "Error.aspx".
The module will register to the BeginRequest event to execute the needed code


Below is the implementation

using System;
using System.Collections.Generic;
using System.Text;
using System.Web;


namespace HAMModule
{
    public class MyModule : IHttpModule
    {
        public void Init(HttpApplication app)
        {
            app.BeginRequest += new EventHandler(app_BeginRequest);
           
        }
        void app_BeginRequest(object sender, EventArgs e)
        {
            HttpContext context = ((HttpApplication)sender).Context;

            if (context.Request.ContentLength > 4096000)
            {
                IServiceProvider provider = (IServiceProvider)context;
                HttpWorkerRequest wr = (HttpWorkerRequest)provider.GetService(typeof(HttpWorkerRequest));

                // Check if body contains data
                if (wr.HasEntityBody())
                {
                    // get the total body length
                    int requestLength = wr.GetTotalEntityBodyLength();
                    // Get the initial bytes loaded
                    int initialBytes = wr.GetPreloadedEntityBody().Length;
         
                    if (!wr.IsEntireEntityBodyIsPreloaded())
                    {
                        byte[] buffer = new byte[512000];
                        // Set the received bytes to initial bytes before start reading
                        int receivedBytes = initialBytes;
                        while (requestLength - receivedBytes >= initialBytes)
                        {
                            // Read another set of bytes
                            initialBytes = wr.ReadEntityBody(buffer, buffer.Length);
                            // Update the received bytes
                            receivedBytes += initialBytes;
                        }
                        initialBytes = wr.ReadEntityBody(buffer, requestLength - receivedBytes);
                       
                    }
                }
  // Redirect the user to an error page.
                context.Response.Redirect("Error.aspx");
            }

        }
        public void Dispose()
        {
        }
    }
}

Now all you need to do is to add the module in the web.config file by adding the below entry under system.Web

 <httpModules>
        <add type="HAMModule.MyModule" name="MyModule"/>
 </httpModules>

Hope this helps,

Chunking Viewstate

One interresting feature a developer should know is the ability to chunk the viewstate field into multiple fields. Why you

need such feature? Some proxy servers and firewalls won't allow a request to be processed if a hidden fields' length is

large. To overcome this, You can set up in the web.config file for all the pages to have a maximum viewstate field.

<system.web>
<pages maxPageStateFieldLength = "1024" />
</system.web>

The value of maxPageStateFieldLength is in Bytes.

In this way, if the hidden viewstate field is larger than 1 kb, ASP.NET will create multiple hidden viewstate field to hold

the data entered by the user before the postback. For example if the size of the data entered by the user is 2KB, the below

fields in the page once being rendered to HTML will be created

<input type="hidden" name="__VIEWSTATEFIELDCOUNT" value="2" />
<input type="hidden" name="__VIEWSTATE" value="..." />
<input type="hidden" name="__VIEWSTATE1" value="..." />

Keep in mind that this won't improve the application performance. It will add more steps to serialize the data back before

being sent to the client.

Hope this helps,
 

Upload Large Files in ASP.NET Using HttpModule

 AS you may know, ASP.NET by default only allows the maximum request length to be 4MB. The developer needs to modify the web.config file to allow the upload process to handle large files.
If you use Reflactor and you dissamble the HttpRequest under System.Web, you will find a method called GetEntireRawContent which will check if the request is larger than the value in the web.config and throws an error

                if (length > maxRequestLengthBytes)
                {
                    throw new HttpException(SR.GetString("Max_request_length_exceeded"), null, 0xbbc);
                }


In this article, Haissam Abdul Malak will demonstrate how to upload large files in ASP.NET without the need to modify the value of maxRequestLength attribute of the httpRuntime tag in the web.config.

We will create an HttpModule which will read the file in chunks (500KB per chunk).
We will handle the BeginRequest event and use the HttpWorkerRequest which provides more low level control for the request.
Below is the full implementation of the HttpModule. I included comments to enable you to fully understand each line of code.

I recommend connecting to msdn and read about HttpWorkerRequest class. Personally i didnt know about the existence of such class except lately.

using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.IO;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace HAMModule
{
    public class MyModule : IHttpModule
    {
        public void Init(HttpApplication app)
        {
            app.BeginRequest += new EventHandler(app_BeginRequest);
           
        }
        void app_BeginRequest(object sender, EventArgs e)
        {
            HttpContext context = ((HttpApplication)sender).Context;

            if (context.Request.ContentLength > 4096000)
            {
                IServiceProvider provider = (IServiceProvider)context;
                HttpWorkerRequest wr = (HttpWorkerRequest)provider.GetService(typeof(HttpWorkerRequest));
                FileStream fs = null;
                // Check if body contains data
                if (wr.HasEntityBody())
                {
                    // get the total body length
                    int requestLength = wr.GetTotalEntityBodyLength();
                    // Get the initial bytes loaded
                    int initialBytes = wr.GetPreloadedEntityBody().Length;
         
                    if (!wr.IsEntireEntityBodyIsPreloaded())
                    {
                        byte[] buffer = new byte[512000];
                        string[] fileName = context.Request.QueryString["fileName"].Split(new char[] { '\\' });
                        fs = new FileStream(context.Server.MapPath("~/Uploads/" + fileName[fileName.Length-1]), FileMode.CreateNew);
                        // Set the received bytes to initial bytes before start reading
                        int receivedBytes = initialBytes;
                        while (requestLength - receivedBytes >= initialBytes)
                        {
                            // Read another set of bytes
                            initialBytes = wr.ReadEntityBody(buffer, buffer.Length);
                            // Write the chunks to the physical file
                            fs.Write(buffer, 0, buffer.Length);
                            // Update the received bytes
                            receivedBytes += initialBytes;
                        }
                        initialBytes = wr.ReadEntityBody(buffer, requestLength - receivedBytes);
                       
                    }
                }
                 fs.Flush();
                 fs.Close();
                 context.Response.Redirect("UploadFinished.aspx");
            }

        }
        public void Dispose()
        {
        }
    }
}


To know the file name selected by the user, I had to use javascript function on the page containing the fileupload control to change the action property of the form tag to post to the same page with a query

string parameter containing the selected file name. Users will be redirected to a page called "UploadFinished.aspx" to display a successful upload process message.

Below is the javascript function

 <script language="javascript">
        function SetAction()
        {
                   document.form1.action = 'default.aspx?fileName=' + document.getElementById('FileUpload1').value;
        }
    </script>
And call it using
<asp:FileUpload ID="FileUpload1" runat="server" onpropertychange="SetAction()" />
You need to register the module in the application web.config file by placing the below inside the <system.web> tag.

<httpModules>
        <add type="HAMModule.MyModule" name="MyModule"/>
</httpModules>

Hope this helps,

 

Convert ASPX Pages to Word Document

 Convert ASPX Webforms To Word

We will discuss how to convert an ASPX page to word document and send it to the client. We will create an HttpModule which use the Application_BeginRequest event to check if a specific query string parameter exists to render the page into a word file.
First of all, Create a new class library project "WordConverter", Rename the class into "Converter" and let it implement IhttpModule interface which exists in System.Web namespace (you need to add it to your references before being able to add it to your namespace collection)

         public class Converter : IHttpModule

After this stage, use the Init() to register for the Application_BeginRequest event.

        public void Init(HttpApplication app)
        {
            app.BeginRequest += new EventHandler(app_BeginRequest);
        }
        void app_BeginRequest(object sender, EventArgs e)
        {
 }
 // Dispose should be added
        public void Dispose()
 {
 }

In the app_BeginRequest event you will need to write the below code

            HttpContext.Current.Response.Clear();
            // Check if ToWord exists in the query string parameters
            if(HttpContext.Current.Request.QueryString["ToWord"]!=null)
            {
            // Set the buffer to true
            HttpContext.Current.Response.Buffer = true;
            // Create a new HttpWebRequest to the same url
            HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(HttpContext.Current.Request.Url.ToString().Split('?')[0]);
            // Set the credentials to default credentials: used if you are under proxy server
            webRequest.Credentials = CredentialCache.DefaultCredentials;
            // Get the response as stream
            Stream stream = webRequest.GetResponse().GetResponseStream();
            // Set the content type of the response on msword
            HttpContext.Current.Response.ContentType = "application/msword";
            // Read the response as string
            string pageHTML = new StreamReader(stream).ReadToEnd();
            // Write it to the response
            HttpContext.Current.Response.Write(pageHTML.ToString());
            // Complete the Request
            ((HttpApplication)sender).CompleteRequest();
            // End the response.
            HttpContext.Current.Response.End();
            }
P.S: Make sure you added the below namespaces
using System.Net;
using System.Web;
using System.IO;

After finishing implementing the code, compile your project. Now you need to add this module to your web application by adding it to your references and add the below code into the web.config to register the module.

    <httpModules>
        <add type="WordConverter.Converter" name="Converter"/>
      </httpModules>

You can find the Module solution attached to this blog post.

Hope this helps,

Execute same code on every WebForm

Have you ever encountered the need to execute lines of code on each page_load event for each page you have in your project! I have seen a lot of developers from the official ASP.NET forums writting the same code on each page which works fine but in case you need to change something you have to reflect it on all the pages.

Below i will describe a way you can implement to overcome this issue.

  1- Create a class "MyPage" which inherits from Page class.

      public partial class MyPage: Page
 
  2- Override the onLoad event of the Page class by adding the below code
   
        protected override void OnLoad(EventArgs e)
        {
            Response.Write("hello World");
            base.OnLoad(e);
        }


  3- In your webform replace System.Web.UI.Page by MyPage

 

Hope this helps,

This site

Search

Go

This Blog

Syndication

Sponsors

  • MaximumASP