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).
-
Create the Custom Handler
-
Create a generic handler in your Web Application (for example,
myHandler.ashx
) -
Make sure the class extends the
Telerik.Web.UI.AsyncUploadHandler
class -
Override the
Process
method
-
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);
}
}
-
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 currentHttpContext
. Since the handler implements theIRequiresSessionState
interface, theSession
object is available as well. -
Configuration
is a class that implements theIAsyncUploadConfiguration
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 itsPreRender
event. You can disable that by setting the control'sEnablePermissionsCheck
property tofalse
.
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
- Change Cache Dependency
- Custom File Name Validation
- Accommodate Linux and MacOS File Names
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:
-
Create a class that implements
IAsyncUploadResult
. For example,SampleAsyncUploadResult
. -
Populate it with the
CreateDefaultUploadConfiguration<T>
method exposed by the RadAsyncUpload instance. -
Set the desired custom values.
-
Return the created object.
How to send information from the custom handler to the client
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:
-
Subscribe to the
FileUploaded
event of the RadAsyncUpload. -
Cast the
UploadResult
property of the event arguments object to your custom class.
Consuming the custom information from the control event on the page
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:
-
create an object that implements
IAsyncUploadConfiguration
. -
Set it to the
UploadConfiguration
property of the RadAsyncUpload. You can obtain the configuration object from theCreateDefaultUploadConfiguration<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
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
- Cast the
IAsyncUploadConfiguration
argument to your custom class
Consuming the custom information from the handler
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
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
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
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;
}
}