Uploading Files in ASP.NET 2.0

 

Bill Evjen
Reuters

December 2005

Applies to:

   Microsoft ASP.NET 2.0
   Microsoft Visual Web Developer 2005 Express Edition

Summary: Learn how to use the new FileUpload server control in Microsoft ASP.NET 2.0. (18 printed pages)

Contents

Introduction
An Example of the FileUpload Server Control
Conclusion

Introduction

Ever since Microsoft ASP.NET was introduced with version 1.0, there has been the built-in means of building Web applications that had the ability to upload files to the hosting server. This was done through the use of the File Field HTML server control. I previously wrote an MSDN article on how to effectively use this control in your ASP.NET applications. This article is a reintroduction to the file upload process, but instead of using the File Field control, I will show you how to effectively use the new FileUpload server control that is offered through ASP.NET 2.0.

It is important to note that while this article introduces you to the new FileUpload server control, it is still quite possible to use the File Field control in your applications today.

An Example of the FileUpload Server Control

When using the File Field control in ASP.NET 1.x you had to take a few extra steps to get everything in line and working. For example, you were required to add enctype="multipart/form-data" to the page's <form> element on your own. The new FileUpload server control provided in ASP.NET 2.0 makes the process of uploading files to the hosting server as simple as possible.

In the end, you are trying to allow access to program the HTML <input type="file"> tag. This tag is used to work with file data within an HTML form. In the past when using classic ASP (ASP 3.0 or earlier), many programmers worked with third-party components to upload files from the client to the server. Now, with .NET and this new control, uploading is taken care of for you. Listing 1 shows you how to use the FileUpload control to upload files to the server.

Note   The sample code is provided in both Microsoft Visual Basic and C#.

Listing 1. Uploading files to the server using the FileUpload control

Visual Basic

<%@ Page Language="VB" %>

<script runat="server">
    Protected Sub Button1_Click(ByVal sender As Object, _
      ByVal e As System.EventArgs)
        If FileUpload1.HasFile Then
            Try
                FileUpload1.SaveAs("C:\Uploads\" & _
                   FileUpload1.FileName)
                Label1.Text = "File name: " & _
                   FileUpload1.PostedFile.FileName & "<br>" & _
                   "File Size: " & _
                   FileUpload1.PostedFile.ContentLength & " kb<br>" & _
                   "Content type: " & _
                   FileUpload1.PostedFile.ContentType
            Catch ex As Exception
                Label1.Text = "ERROR: " & ex.Message.ToString()
            End Try
        Else
            Label1.Text = "You have not specified a file."
        End If
    End Sub
</script>

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Upload Files</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:FileUpload ID="FileUpload1" runat="server" /><br />
        <br />
        <asp:Button ID="Button1" runat="server" OnClick="Button1_Click" 
         Text="Upload File" />&nbsp;<br />
        <br />
        <asp:Label ID="Label1" runat="server"></asp:Label></div>
    </form>
</body>
</html>

C#

<%@ Page Language="C#" %>

<script runat="server">
    protected void Button1_Click(object sender, EventArgs e)
    {
        if (FileUpload1.HasFile)
            try
            {
                FileUpload1.SaveAs("C:\\Uploads\\" + 
                     FileUpload1.FileName);
                Label1.Text = "File name: " +
                     FileUpload1.PostedFile.FileName + "<br>" +
                     FileUpload1.PostedFile.ContentLength + " kb<br>" +
                     "Content type: " +
                     FileUpload1.PostedFile.ContentType;
            }
            catch (Exception ex)
            {
                Label1.Text = "ERROR: " + ex.Message.ToString();
            }
        else
        {
            Label1.Text = "You have not specified a file.";
        }
    }
</script>

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Upload Files</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:FileUpload ID="FileUpload1" runat="server" /><br />
        <br />
        <asp:Button ID="Button1" runat="server" OnClick="Button1_Click" 
         Text="Upload File" />&nbsp;<br />
        <br />
        <asp:Label ID="Label1" runat="server"></asp:Label></div>
    </form>
</body>
</html>

Running this page, you will notice a few things if you look at the source code generated for the page. This source code is presented in Listing 2.

Listing 2. The source code generated from the FileUpload control

<html xmlns="http://www.w3.org/1999/xhtml" >
<head><title>
   Upload Files
</title></head>
<body>
    <form name="form1" method="post" action="MyFileUpload.aspx" 
     id="form1" enctype="multipart/form-data">
<div>
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDwUJNDcxNTg5NDg3D2QWAgIEDxYCHgdlbmN0eXBlBRNtdWx0aXBhcnQvZm9yb
       S1kYXRhZGQUQEUFMY1+/fp1mnrkbqmVNQIzFA==" />
</div>

    <div>
        <input type="file" name="FileUpload1" id="FileUpload1" /><br />
        <br />
        <input type="submit" name="Button1" value="Upload File" 
         id="Button1" />&nbsp;<br />
        <br />
        <span id="Label1"></span>
    </div>
    
<div>

   <input type="hidden" name="__EVENTVALIDATION" id="__EVENTVALIDATION" 
    value="/wEWAgLB+7jIAwKM54rGBv2Iz6LxVY7jWec0gZMxnuaK2ufq" />
</div></form>
</body>
</html>

The first thing to notice is that because the FileUpload control is on the page, ASP.NET 2.0 modified the page's <form> element on your behalf by adding the appropriate enctype attribute. You will also notice that the FileUpload control was converted to an HTML <input type="file"> element.

When the page from Listing 1 is run, you can select a file and upload it to the server by clicking the Upload File button on the page. There are some important items we should go over for this example so you understand all the needed pieces to make this work. For the example in Listing 1 to work, you have to make the destination folder on the server writeable for the account used by ASP.NET so the file can be saved to the specified folder.

If you think your ASP.NET account is not enabled to write to the folder you want, simply open up Microsoft Windows Explorer and navigate to the folder to which you want to add this permission. Right-click on the folder (in this case, the Uploads folder), and then select Properties. In the Properties dialog box, click on the Security tab and make sure the ASP.NET Machine Account is included in the list and has the proper permissions to write to disk (see Figure 1).

Aa479405.uploadasp201(en-us,MSDN.10).gif

Figure 1. Looking at the Security tab of the Uploads folder

If you don't see the ASP.NET Machine Account under the Security tab, you can add it by clicking the Add button and entering ASPNET (without the period) in the text area, as illustrated in Figure 2.

Aa479405.uploadasp202(en-us,MSDN.10).gif

Figure 2. Adding the ASP.NET Machine Account to the folder security definition

Click OK to add the ASP.NET Machine Account to the list. From here, make sure you give this account the proper permissions and then click OK, and you are ready to go.

The Submit button on the page causes the Button1_Click event to occur. This event uploads the file and then displays a message telling you if the upload was successful by posting information about the file uploaded. If it was unsuccessful, the page displays an error message describing why the upload failed.

By using the FileUpload control that converts itself to an <input type="file"> tag, the browser automatically places a Browse button next to the text field on the ASP.NET page. You don't have to program anything else for this to occur. When the end user clicks the Browse button, he can navigate through the local file system to find the file to be uploaded to the server. This is shown in Figure 3. Clicking Open will place that filename and the file's path within the text field.

Aa479405.uploadasp203(en-us,MSDN.10).gif

Figure 3. Choosing a file

Working Around File Size Limitations

You may not realize it, but there is a limit to the size of a file that can be uploaded using this technique. By default, the maximum size of a file to be uploaded to the server using the FileUpload control is around 4MB. You cannot upload anything that is larger than this limit.

One of the great things about .NET, however, is that it usually provides a way around limitations. You can usually change the default settings that are in place. To change this size limit, you make some changes in either the web.config.comments (found in the ASP.NET 2.0 configuration folder at C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\CONFIG) or your application's web.config file.

In the web.config.comments file, find a node called <httpRuntime> that looks like the following:

<httpRuntime 
 executionTimeout="110" 
 maxRequestLength="4096" 
 requestLengthDiskThreshold="80" 
 useFullyQualifiedRedirectUrl="false" 
 minFreeThreads="8" 
 minLocalRequestFreeThreads="4" 
 appRequestQueueLimit="5000" 
 enableKernelOutputCache="true" 
 enableVersionHeader="true" 
 requireRootedSaveAsPath="true" 
 enable="true" 
 shutdownTimeout="90" 
 delayNotificationTimeout="5" 
 waitChangeNotification="0" 
 maxWaitChangeNotification="0" 
 enableHeaderChecking="true" 
 sendCacheControlHeader="true" 
 apartmentThreading="false" />

A lot is going on in this single node, but the setting that takes care of the size of the files to be uploaded is the maxRequestLength attribute. By default, this is set to 4096 kilobytes (KB). Simply change this value to increase the size of the files that you can upload to the server. If you want to allow 10 megabyte (MB) files to be uploaded to the server, set the maxRequestLength value to 11264, meaning that the application allows files that are up to 11000 KB to be uploaded to the server.

Making this change in the web.config.comments file applies this setting to all the applications that are on the server. If you want to apply this to only the application you are working with, apply this node to the web.config file of your application, overriding any setting that is in the web.config.comments file. Make sure this node resides between the <system.web> nodes in the configuration file.

Another setting involved in the size limitation of files to be uploaded is the value given to the executionTimeout attribute in the <httpRuntime> node.

The value given the executionTimeout attribute is the number of seconds the upload is allowed to occur before being shut down by ASP.NET. If you are going to allow large files to be uploaded to the server, you are also going to want to increase this value along with the maxRequestLength value.

One negative with increasing the size of a file that can be uploaded is that there are hackers out there who attack servers by throwing a large number of requests at them. To guard against this, you can actually decrease the size of the files that are allowed to be uploaded; otherwise, you may find hundreds or even thousands of 10 MB requests hitting your server.

Client-Side Validation of File Types Permissible to Upload

There are several methods you can use to control the types of files that are uploaded to the server. Unfortunately, there is no bullet-proof method to protect you from someone uploading files that would be considered malicious. You can take a few steps, however, to make this process of allowing end users to upload files a little more manageable.

One nice method you can employ is to use the ASP.NET validation controls that are provided for free with ASP.NET. These controls enable you to do a regular-expression check upon the file that is being uploaded to see if the extension of the file is one you permit to be uploaded.

This is ideal for browsers that allow client-side use of the validation controls because it forces the checking to be done on the client; the file is not uploaded to the server if the signature isn't one you allow. Listing 3 shows you an example of using validation controls to accomplish this task.

Note   The use of validation controls is not explained here. Take a look at Validating ASP.NET Server Controls for a complete explanation of validation controls and how to use them in your ASP.NET pages.

Listing 3. Using validation controls to restrict the types of files uploaded to the server

<asp:FileUpload ID="FileUpload1" runat="server" /><br />
<br />
<asp:Button ID="Button1" runat="server" OnClick="Button1_Click" 
 Text="Upload File" />&nbsp;<br />
<br />
<asp:Label ID="Label1" runat="server"></asp:Label>
<asp:RegularExpressionValidator 
 id="RegularExpressionValidator1" runat="server" 
 ErrorMessage="Only mp3, m3u or mpeg files are allowed!" 
 ValidationExpression="^(([a-zA-Z]:)|(\\{2}\w+)\$?)(\\(\w[\w].*))
    +(.mp3|.MP3|.mpeg|.MPEG|.m3u|.M3U)$" 
 ControlToValidate="FileUpload1"></asp:RegularExpressionValidator>
<br />
<asp:RequiredFieldValidator 
 id="RequiredFieldValidator1" runat="server" 
 ErrorMessage="This is a required field!" 
 ControlToValidate="FileUpload1"></asp:RequiredFieldValidator>

This simple ASP.NET page uses validation controls so that the end user can only upload .mp3, .mpeg, or .m3u files to the server. If the file type is not one these three choices, a Validation control throws an exception onto the screen. This is shown in Figure 4.

Aa479405.uploadasp204(en-us,MSDN.10).gif

Figure 4. Validating the file type using validation controls

Using Validation controls is not a foolproof way of controlling the files that are uploaded to the server. It wouldn't be too hard for someone to change the file extension of a file so it would be accepted and uploaded to the server, thereby bypassing this simple security model.

Adding Server-Side File Type Validation

You just saw an easy way to add some ASP.NET validation server controls to your ASP.NET page to perform a client side validation of the file extension (in just a textual manner). Now let's take a look at how to perform a similar operation on the server-side. This is presented in Listing 4.

Listing 4. Checking the file type on the server

Visual Basic

    Protected Sub Button1_Click(ByVal sender As Object, _
      ByVal e As System.EventArgs)
        If FileUpload1.HasFile Then
            Dim fileExt As String
            fileExt = System.IO.Path.GetExtension(FileUpload1.FileName)
            
            If (fileExt = ".mp3") Then
                Try
                    FileUpload1.SaveAs("C:\Uploads\" & _
                       FileUpload1.FileName)
                    Label1.Text = "File name: " & _
                      FileUpload1.PostedFile.FileName & "<br>" & _
                      "File Size: " & _
                      FileUpload1.PostedFile.ContentLength & " kb<br>" & _
                      "Content type: " & _
                      FileUpload1.PostedFile.ContentType
                Catch ex As Exception
                    Label1.Text = "ERROR: " & ex.Message.ToString()
                End Try
            Else
                Label1.Text = "Only .mp3 files allowed!"
            End If
        Else
            Label1.Text = "You have not specified a file."
        End If
    End Sub

C#

    protected void Button1_Click(object sender, EventArgs e)
    {

        if (FileUpload1.HasFile)
        {
            string fileExt = 
               System.IO.Path.GetExtension(FileUpload1.FileName);

            if (fileExt == ".mp3")
            {
                try
                {
                    FileUpload1.SaveAs("C:\\Uploads\\" + 
                       FileUpload1.FileName);
                    Label1.Text = "File name: " +
                        FileUpload1.PostedFile.FileName + "<br>" +
                        FileUpload1.PostedFile.ContentLength + " kb<br>" +
                        "Content type: " +
                        FileUpload1.PostedFile.ContentType;
                }
                catch (Exception ex)
                {
                    Label1.Text = "ERROR: " + ex.Message.ToString();
                }
            }
            else
            {
                Label1.Text = "Only .mp3 files allowed!";
            }
        }
        else
        {
            Label1.Text = "You have not specified a file.";
        }
    }

Now, by using the GetExtension method from the System.IO.Path namespace, you can perform basically the same operation. It is important to note that this doesn't get around an end user's ability to simply change the file extension to something that works and upload that altered file to the hosting server.

Uploading Multiple Files at the Same Time

So far, you have seen some good examples of how to upload a file to the server without much hassle. Now let's take a look at how to upload multiple files to the server from a single page.

No built-in capabilities in the Microsoft .NET Framework enable you to upload multiple files from a single ASP.NET page. With a little work, however, you can easily accomplish this task just as you would have in the past using .NET 1.x.

The trick is to import the System.IO class into your ASP.NET page, and to then use the HttpFileCollection class to capture all the files that are sent in with the Request object. This approach enables you to upload as many files as you want from a single page.

If you wanted to, you could simply handle each and every FileUpload control on the page individually, as presented in Listing 5.

Listing 5. Handling each FileUpload control individually

Visual Basic

If FileUpload1.HasFile Then
   ' Handle file
End If

If FileUpload2.HasFile Then
   ' Handle file
End If

C#

if (FileUpload1.HasFile) {
   // Handle file
}

if (FileUpload2.HasFile) {
   // Handle file
}

This approach works, but there may be instances where you are going to want to handle the files using the HttpFileCollection class instead—especially if you are working with a dynamically generated list of server controls.

For an example of this, you can build an ASP.NET page that has three FileUpload controls and one Submit button (using the Button control). After the user clicks the Submit button and the files are posted to the server, the code behind takes the files and saves them to a specific location on the server. After the files are saved, the file information that was posted is displayed in the ASP.NET page (see Listing 6).

Listing 6. Uploading multiple files to the server

Visual Basic

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

   Dim filepath As String = "C:\Uploads"
   Dim uploadedFiles As HttpFileCollection = Request.Files
   Dim i As Integer = 0

   Do Until i = uploadedFiles.Count
     Dim userPostedFile As HttpPostedFile = uploadedFiles(i)

     Try
        If (userPostedFile.ContentLength > 0) Then
           Label1.Text += "<u>File #" & (i + 1) & "</u><br>"
           Label1.Text += "File Content Type: " & _
              userPostedFile.ContentType & "<br>"
           Label1.Text += "File Size: " & _
              userPostedFile.ContentLength & "kb<br>"
           Label1.Text += "File Name: " & _
              userPostedFile.FileName & "<br>"

           userPostedFile.SaveAs(filepath & "\" & _
              System.IO.Path.GetFileName(userPostedFile.FileName))

           Label1.Text += "Location where saved: " & _
              filepath & "\" & _
              System.IO.Path.GetFileName(userPostedFile.FileName) & _
              "<p>"
        End If
     Catch ex As Exception
        Label1.Text += "Error:<br>" & ex.Message
     End Try
     i += 1
   Loop
End Sub

C#

protected void Button1_Click(object sender, EventArgs e)
{
   string filepath = "C:\\Uploads";
   HttpFileCollection uploadedFiles = Request.Files;
    
   for (int i = 0; i < uploadedFiles.Count; i++)
   {    
      HttpPostedFile userPostedFile = uploadedFiles[i];
    
      try
      {    
         if (userPostedFile.ContentLength > 0 )
         {
            Label1.Text += "<u>File #" + (i+1) + 
               "</u><br>";
            Label1.Text += "File Content Type: " + 
               userPostedFile.ContentType + "<br>";
            Label1.Text += "File Size: " + 
               userPostedFile.ContentLength + "kb<br>";
            Label1.Text += "File Name: " + 
               userPostedFile.FileName + "<br>";
    
            userPostedFile.SaveAs(filepath + "\\" + 
               System.IO.Path.GetFileName(userPostedFile.FileName));
    
            Label1.Text += "Location where saved: " + 
               filepath + "\\" + 
               System.IO.Path.GetFileName(userPostedFile.FileName) + 
               "<p>";
         }    
      } 
      catch (Exception Ex)
      {    
         Label1.Text += "Error: <br>" + Ex.Message;    
      }    
   }    
}

The end user can select up to four files and click the Upload Files button, which initializes the Button1_Click event. Using the HttpFileCollection class with the Request.Files property lets you gain control over all the files that are uploaded from the page. When the files are in this state, you can do whatever you want with them. In this case, the files' properties are examined and written to the screen. In the end, the files are saved to the Uploads folder in the root directory of the server. The result of this action is illustrated in Figure 5.

Aa479405.uploadasp205(en-us,MSDN.10).gif

Figure 5. Uploading four files at once to the server from a single ASP.NET page

As you may have noticed, one interesting point about this example is that the states of the file input text boxes are not saved with the postback. You can see this in Figure 5. In ASP.NET, the state of the file-input text boxes cannot be saved because doing so might pose a security risk.

Conclusion

The FileUpload server control provided by ASP.NET is a powerful control that was quite difficult to achieve in the days of Active Server Pages 3.0. This new capability allows your end-users to upload one or more files to your server. Remember, you can control the size of the files that are uploaded by working with settings in either the web.config.comments or web.config file.

 

About the author

Bill Evjen is an active proponent of .NET technologies and community-based learning initiatives for .NET. He is a technical director for Reuters, the international news and financial services company based in St. Louis, Missouri. Bill is the founder and executive director of the International .NET Association (INETA), which represents more than 100,000 members worldwide. Bill is also an author and speaker and has written such books as ASP.NET Professional Secrets, XML Web Services for ASP.NET, Web Services Enhancements, and the Visual Basic .NET Bible (all from Wiley).

© Microsoft Corporation. All rights reserved.