New to Telerik UI for ASP.NET AJAXStart a free 30-day trial

How to Create a Custom Handler for RadAsyncUpload

This article explains how to create your own file upload handler to be used through RadAsyncUpload. Such a handler allows you to implement features specific to your use case; direct storage of files to a desired location like a database; advanced security measures specific to the application like tying uploads to user session, scanning files before saving them to the disk, throttling uploads and so on.

This article contains the following sections:

You can find an example implementation in the following Live Demo: Custom HTTP Handler.

Create a Custom Handler

To create a custom handler, you must inherit the built-in AsyncUploadHandler class and then implement the desired functionality (for example, saving images directly to a database, without using temporary folder).

  1. Create the Custom Handler

    1. Create a generic handler in your Web Application (for example, myHandler.ashx)

    2. Make sure the class extends the Telerik.Web.UI.AsyncUploadHandler class

    3. Override the Process method

C#
public class CustomUploadHandler : AsyncUploadHandler
{
    protected override IAsyncUploadResult Process(UploadedFile file, HttpContext context, IAsyncUploadConfiguration configuration, string tempFileName)
    {
	// do something here

	return base.Process(file, context, configuration, tempFileName);
    }
}
  1. Set the path to the custom handler in the RadAsyncUpload through its HttpHandlerUrl property:

    ASPX
     <telerik:RadAsyncUpload runat="server" ID="RadAsyncUpload1" HttpHandlerUrl="~/myHandler.ashx"></telerik:RadAsyncUpload>

Process Method Arguments and Usage

In the Process method, the arguments provide the following:

  • UploadedFile is the file that is currently processed. You can use it to obtain the input stream, file name, extension and so on.

  • HttpContext is the current HttpContext. Since the handler implements the IRequiresSessionState interface, the Session object is available as well.

  • Configuration is a class that implements the IAsyncUploadConfiguration interface and, by default, has the following properties:

    • TargetFolder—the folder where RadAsyncUpload would have saved the file if the built-in handler is used, as provided by the developer.

    • TempTargetFolder—the temporary folder where RadAsyncUpload would have stored the file before saving it to the target folder, if the built-in handler is used, as provided by the developer.

    • MaxFileSize—the maximum file size set by the developer for the RadAsyncUpload.

    • TimeToLive—the time until the file is deleted from the temporary folder if the built-in handler were used.

  • TempFileName is the uploaded file's temporary name. It is used by the built-in handler for the temporary folder only.

Temporary Folder Usage

When a custom handler is used, the temporary folder is used as follows:

  • File chunks are stored in it until the entire file is collected and passed to the Process method of the handler. The entire file is not saved to the temporary folder after that.

  • Entire files (when chunk upload is disabled or when the file fits in a single chunk) go directly to the Process method of the handler and are not saved to the temporary folder. In such cases, the files are not stored to the hard disk of the server at all and remain in memory only.

  • When a RadAsyncUpload instance initializes, it will write a test file (an empty file with the RadUploadTestFile name) to the temporary folder in its PreRender event. You can disable that by setting the control's EnablePermissionsCheck property to false.

Thus, to save files, you would usually use the Process method. If you are using the FileUploaded event to save files, you may get an error: UploadedFiles.SaveAs Throws FileNotFound Error with Custom Handler.

Advanced Features of the Handler

The custom handler inherits the built-in handler and you can use it to customize the behavior and information. Once you have the custom handler in place, you can amend it with the following features:

Send Custom Information To and From the Handler

The Process method returns an interface—IAsyncUploadResult. You can use it to transmit custom information between the client and the server. For example, a User ID or other piece of application logic.

If you use this, see Security - Custom Metadata.

Send Information From the Handler to the Client

To return custom information to the client:

  1. Create a class that implements IAsyncUploadResult. For example, SampleAsyncUploadResult.

  2. Populate it with the CreateDefaultUploadConfiguration<T> method exposed by the RadAsyncUpload instance.

  3. Set the desired custom values.

  4. Return the created object.

How to send information from the custom handler to the client

C#
protected override IAsyncUploadResult Process(UploadedFile file, HttpContext context, IAsyncUploadConfiguration configuration, string tempFileName)
{
	// Populate the default (base) result into an object of type SampleAsyncUploadResult
	SampleAsyncUploadResult result = CreateDefaultUploadResult<SampleAsyncUploadResult>(file);
	
	//generate the custom information in the custom field
	result.CustomField = "some value";
	
	//return the data to the client
	return result;
}

You can also use this approach to send meaningful error information from the custom handler to the browser. See the How to Capture File Upload Errors with Custom Handler KB article.

Then, you can use this information on the page that was used to upload the file:

  1. Subscribe to the FileUploaded event of the RadAsyncUpload.

  2. Cast the UploadResult property of the event arguments object to your custom class.

Consuming the custom information from the control event on the page

C#
protected void RadAsyncUpload1_FileUploaded(object sender, FileUploadedEventArgs e)
{   
	//SampleAsyncUploadResult is the custom class
	SampleAsyncUploadResult result = e.UploadResult as SampleAsyncUploadResult;
} 			

Send Information to the Custom Handler

With the IAsyncUploadConfiguration interface you can also send information to the handler. To do that:

  1. create an object that implements IAsyncUploadConfiguration.

  2. Set it to the UploadConfiguration property of the RadAsyncUpload. You can obtain the configuration object from the CreateDefaultUploadConfiguration<T> method provided by RadAsyncUpload.

Such an object is serialized and sent to the handler with each request.

How to send custom information to the handler

C#
protected void Page_Load(object sender, EventArgs e) 
{
    // Populate the default (base) upload configuration into an object of type SampleAsyncUploadConfiguration 
	// The custom configuration class name may vary in your application     
    SampleAsyncUploadConfiguration config = RadAsyncUpload1.CreateDefaultUploadConfiguration<SampleAsyncUploadConfiguration>(); 
    // Populate any additional fields      
    config.UserID = 1;
    // The upload configuration will be available in the handler      
    RadAsyncUpload1.UploadConfiguration = config;
}			

Then, in the handler, the sent information can be obtained in the following way

  1. Cast the IAsyncUploadConfiguration argument to your custom class

Consuming the custom information from the handler

C#
protected override IAsyncUploadResult Process(UploadedFile file, HttpContext context, IAsyncUploadConfiguration configuration, string tempFileName) 
{         
    int userID = -1;
    // You can obtain any custom information passed from the page via casting the configuration parameter to your custom class    
    var sampleConfiguration = configuration as SampleAsyncUploadConfiguration;    
    
    if (sampleConfiguration != null)    
    {       
        userID = sampleConfiguration.UserID;    
    }          
    // More code here.. 
}  		

Change Cache Dependency

By default, RadAsyncUpload deletes the temporary files after some time, in case they are not saved to the target folder. You can set this time interval through the TemporaryFileExpiration property. The default is 4 hours.

Overriding the AddCacheDependency method allows you to modify or even remove the default temporary files removal callback. In order to leave temporary files instead of deleting them, you can store the file path in cache and leave out the CacheItemRemovedCalback in the override of the AddCacheDependency method.

For this to have effect, you must not override the Process method. This is equivalent to you using the built-in handler code, but only overriding the way the cache dependency is managed. Alternatively, in the Process override, call the base method to save the uploaded file to the temporary folder base.Process(file, context, configuration, tempFileName);.

How to remove the default temporary files expiration

C#
protected override void AddCacheDependency(HttpContext context, string tempFileName, TimeSpan timeToLive, string fullPath)
{
    if (context.Cache.Get(tempFileName) == null)
    {
        context.Cache.Insert(tempFileName, fullPath);
		// Instead of the predefined
		// context.Cache.Insert(tempFileName, fullPath, null, DateTime.Now.Add(timeToLive), TimeSpan.Zero, CacheItemPriority.NotRemovable, RemovedCallback);
    }
}

Custom File Name Validation

By default, the CheckOriginalFileNameForInvalidChars verifies the File Name against the Microsoft's Naming Convention.

Overriding the CheckOriginalFileNameForInvalidChars method allows you to extend this validity check.

Implement custom file name validation

C#
protected override bool CheckOriginalFileNameForInvalidChars(string originalFileName)
{
	// Check if the fileName is a null value or an empty string
	bool fileNameIsNullOrEmpty = string.IsNullOrEmpty(originalFileName);
	// Check if the fileName contains invalid path characters
	bool fileNameHasInvalidPathCharacters = originalFileName.IndexOfAny(Path.GetInvalidFileNameChars()) > -1;
	// Check if the fileName contains "A" (or any other custom validation)
	bool fileNameContainsA = originalFileName.IndexOf("A") > -1;
	
	return (fileNameIsNullOrEmpty || fileNameHasInvalidPathCharacters || fileNameContainsA);
}

Accommodate Linux and MacOS File Names

On some operating systems like MAC OS and Linux, it is possible to have file names which are invalid for the Windows File System. File names may contain special characters or might not be in accordance with the Microsoft's Naming Convention.. This makes file uploading impossible for such files.

To upload a file with an invalid name, you must rename it before the uploading takes place. You can do that by overriding ChangeOriginalFileName.

Change the file name to accommodate Linux and MacOS file names

C#
protected override string ChangeOriginalFileName(string fileName)
{
    //Return the current name if there is no invalid character
    if (fileName.IndexOfAny(System.IO.Path.GetInvalidFileNameChars()) == -1)
    {
        return fileName;
    }
    else
    {
        //Escape invalid characters
        fileName = Regex.Replace(fileName, @"[^\w\.@-]", "", RegexOptions.None, TimeSpan.FromSeconds(1.5));
        //If all characters are invalid return underscore as a file name
        if (Path.GetFileNameWithoutExtension(fileName).Length == 0)
        {
            return fileName.Insert(0, "_");
        }
        //Else return the escaped name
        return fileName;
    }
}

See Also