New to Telerik UI for ASP.NET AJAX? Download free 30-day trial

Create custom Temp File Appender for AsyncUpload

Environment

Product RadAsyncUpload for ASP.NET AJAX

Description

Create custom Temp File Appender for AsyncUpload by using Reflection that will access the internal properties and invoke the instance constructors.

This approach can be used to change the chunk sizes that are appended at once when uploading large files, thus, improving the Input/output Operations per Second (IOPS).

Solution

This scenario requires the following:

Custom Temp File Appender

At first, create a class that will implement the ITempFileAppender interface. Here you can change the buffer size (chunk size) to append at once when uploading the files.

using System.IO;
using Telerik.Web.UI.AsyncUpload;

public class CustomTempFileAppender : ITempFileAppender
{
    private readonly Stream _content;
    private const int MaxRetries = 10;
    public static long ContentLength { get; set; }
    public long AppendedContentLength
    {
        get
        {
            return ContentLength;
        }
    }

    public CustomTempFileAppender() { }
    public CustomTempFileAppender(Stream stream)
    {
        _content = stream;
    }

    public void AppendTo(string fullPath)
    {
        AppendToFile(fullPath, _content);
    }

    private void AppendToFile(string fullPath, Stream content, int retries = 1)
    {
        try
        {
            using (FileStream stream = new FileStream(fullPath, FileMode.Append, FileAccess.Write, FileShare.ReadWrite))
            {
                using (content)
                {
                    ContentLength = (stream.Length + content.Length);

                    int kiloByte = 1024; // 1KB
                    int megaByte = 1000 * kiloByte; // 1MB


                    int bufferSize = 4 * kiloByte; // 4KB chunks (Recommended for most cases)

                    bufferSize = megaByte; // 1MB chunks (increase the buffer size if necessary)

                    content.CopyTo(stream, bufferSize);
                }
            }
        }
        catch (IOException ex)
        {
            if (retries < MaxRetries)
            {
                AppendToFile(fullPath, content, retries + 1);
                return;
            }
            throw ex;
        }
    }
}
Imports Microsoft.VisualBasic
Imports System.IO
Imports Telerik.Web.UI.AsyncUpload

Public Class CustomTempFileAppender
    Inherits ITempFileAppender

    Private ReadOnly _content As Stream
    Private Const MaxRetries As Integer = 10
    Public Shared Property ContentLength As Long

    Public ReadOnly Property AppendedContentLength As Long
        Get
            Return ContentLength
        End Get
    End Property

    Public Sub New()
    End Sub

    Public Sub New(ByVal stream As Stream)
        _content = stream
    End Sub

    Public Sub AppendTo(ByVal fullPath As String)
        AppendToFile(fullPath, _content)
    End Sub

    Private Sub AppendToFile(ByVal fullPath As String, ByVal content As Stream, ByVal Optional retries As Integer = 1)
        Try

            Using stream As FileStream = New FileStream(fullPath, FileMode.Append, FileAccess.Write, FileShare.ReadWrite)

                Using content

                    ContentLength = (stream.Length + content.Length)

                    Dim kiloByte As Integer = 1024 ' 1KB
                    Dim megaByte As Integer = 1000 * kiloByte ' 1MB

                    Dim bufferSize As Integer = 4 * kiloByte ' 4KB chunks (Recommended for most cases)
                    bufferSize = megaByte ' 1MB chunks (increase the buffer size if necessary)

                    content.CopyTo(stream, bufferSize)

                End Using
            End Using

        Catch ex As IOException

            If retries < MaxRetries Then
                AppendToFile(fullPath, content, retries + 1)
                Return
            End If

            Throw ex
        End Try
    End Sub
End Class

Custom Upload Handler

To activate the Custom Temp File Appender, you will also need to create a Custom Upload Handler and use it for the AsyncUpload.

In the Class constructor of the Custom Upload Handler you can access the AsyncUploadHandler Type instance, the instance properties and change their values to use the new Custom Temp File Appender.

using System;
using System.Web;
using Telerik.Web.UI;
using Telerik.Web.UI.AsyncUpload;

public class CustomAsyncUploadHandler : AsyncUploadHandler
{
    public CustomAsyncUploadHandler() : base()
    {
        System.Reflection.Assembly a = System.Reflection.Assembly.Load("Telerik.Web.UI");
        Type t = a.GetType("Telerik.Web.UI.AsyncUpload.RequestData");

        System.Reflection.ConstructorInfo ctorInfo = t.GetConstructors()[1];

        IRequestData requestData = (IRequestData) ctorInfo.Invoke(new object[] { HttpContext.Current });

        ITempFileAppender tempFileAppender = new CustomTempFileAppender(requestData.UploadedFile.InputStream);

        this.GetType().GetProperty("FileAppender", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).SetValue(this, tempFileAppender);
        this.GetType().GetProperty("RequestData", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).SetValue(this, requestData);
    }

    public CustomAsyncUploadHandler(IRequestData requestData, IResponseWriter responseWriter, ITempFileAppender fileAppender) : base(requestData, responseWriter, new CustomTempFileAppender(requestData.UploadedFile.InputStream))
    {
    }
}
Imports Microsoft.VisualBasic
Imports System
Imports System.Web
Imports Telerik.Web.UI
Imports Telerik.Web.UI.AsyncUpload

Public Class CustomAsyncUploadHandler
    Inherits AsyncUploadHandler

    Public Sub New()
        MyBase.New()

        Dim a As System.Reflection.Assembly = System.Reflection.Assembly.Load("Telerik.Web.UI")

        Dim t As Type = a.[GetType]("Telerik.Web.UI.AsyncUpload.RequestData")

        Dim ctorInfo As System.Reflection.ConstructorInfo = t.GetConstructors()(1)

        Dim requestData As IRequestData = CType(ctorInfo.Invoke(New Object() {HttpContext.Current}), IRequestData)
        Dim tempFileAppender As ITempFileAppender = New CustomTempFileAppender(requestData.UploadedFile.InputStream)

        Me.[GetType]().GetProperty("FileAppender", System.Reflection.BindingFlags.NonPublic Or System.Reflection.BindingFlags.Instance).SetValue(Me, tempFileAppender)
        Me.[GetType]().GetProperty("RequestData", System.Reflection.BindingFlags.NonPublic Or System.Reflection.BindingFlags.Instance).SetValue(Me, requestData)
    End Sub

    Public Sub New(ByVal requestData As IRequestData, ByVal responseWriter As IResponseWriter, ByVal fileAppender As ITempFileAppender)
        MyBase.New(requestData, responseWriter, New CustomTempFileAppender(requestData.UploadedFile.InputStream))
    End Sub
End Class
In this article