What is the best way to upload files with ASP.NET MVC 2?
Asked Answered
P

2

6

What is the best method for uploading files of variable size (either very large or very small to an ASP.NET MVC 2 application file system)?

This is what I understand so far:

It seems like there are two ways that people handle this. (Let's assume the files may be very large or very small)

(1) Handle the upload in a controller action via Request.Files or HttpPostedFileBase, which seems to have a drawback of taking a long time because ASP.NET loads the files into active memory.

or

(2) intercept the file upload early on with an HttpModule which somehow circumvents the performance issue. (I'm a little cloudy on how this works, but I've been using this post http://darrenjohnstone.net/2008/07/15/aspnet-file-upload-module-version-2-beta-1/ as a reference). The part I'm fuzzy about is at what point ASP.NET loads the submitted files to active memory, and how intercepting this in a module actually changes this behavior.

Since the second option is faster, it seems like the better option. But it seems like an application submitting an upload form will probably have some data associated with the file that needs to be persisted in a database. I don't want to make persistence calls in my HttpHandler or HttpModule, (because then I will have two very similar functionalities occurring in different places : the controller and the http handler).

I guess one work around would be to store the target file location in HttpContext.Items, but is this the best way?

One last concern about this is that I want to render an HttpResponse before the file is finished uploading. So, if there is a big file, I will send the user a view with the value of the upload status, and make AJAX calls to keep the status updated. How do I render a result, while keeping the upload process going? Do I need to make an AsyncHandler or AsyncController? Do I need to manually grab another thread?

Thanks a lot guys. I know this is a lot of questions, and probably reflects a general lack of understanding about something. The funny thing about general lacks of understanding is that people who have them also tend to lack the understanding of what understanding they are lacking...so, if anyone can point me in the right direction on that note as well, I would appreciate it.

Planoconcave answered 25/1, 2011 at 4:28 Comment(3)
possible duplicate of File upload MVCFretful
@jguaffin - the question you link to is not related to this issue at all.Fagan
Sometimes. However, the client side implementation is not the focus of this question.Planoconcave
M
2

If I remember correctly from ASP.NET 2.0 large files are being flushed to disk, so even using HttpPostedFileBase there should not be any memory/performance problems. I am not sure asynccontrollers is an solutions here, asynccontrollers is for long running server processes. For an example off AsyncControllers see http://www.aaronstannard.com/post/2011/01/06/asynchonrous-controllers-ASPNET-mvc.aspx

Moneyed answered 25/1, 2011 at 12:23 Comment(8)
Do you mean that as a general rule regarding AsyncController and AJAX? Why would that be?Planoconcave
changed my answer the line about ajax and asynccontrollers was falseMoneyed
Is using uploadify.com on client side and a simple HttpPostedFileBase on server side not a solution to your problem?Moneyed
No. Uploadify facilitates the client-side but adds a flash dependency to the application. In addition, my question was not about the client side integration, but about how to best handle the request once it has been received by ASP.NET. As I stated in the question, using an HttpPostedFileBase is one of many ways to accomplish the task of uploading a file. My question is what is the most reliable and performance-optimized way to accomplish the task when there is variable file size.Planoconcave
I see that you said it is flushed to disk and doesn't incur a performance cost - Could you possibly provide documentation of this process so I can understand exactly where, why and under what conditions this happens and how to modify that process?Planoconcave
You can find documentation about the file being flushed to disk here: msdn.microsoft.com/en-us/library/system.web.httppostedfile.aspxMoneyed
some more info can be found here: codeproject.com/KB/aspnet/UpldFileToDiskProgressBar.aspxMoneyed
I'd given up on getting an answer - you're a rockstar. P.S. It would be helpful for future users if you edited your post to include the info you left in the comments.Planoconcave
A
0

I use this javascript tool

This is the controller (I double check cause IE has a strange behavior) :

<HttpPost()> _
Function UploadExcelPriceList(ByVal id As String) As System.String

    Dim bResult As Boolean = False
    Dim IsIE As Boolean = False
    Dim sFileName As String = ""

    If (Request.Files Is Nothing) OrElse (Request.Files.Count = 0) Then
        If String.IsNullOrEmpty(Request.Params("qqfile")) Then
            Return ("{success:false, error:'request file is empty'}")
        Else
            sFileName = Request.Params("qqfile").ToString
        End If
    Else
        sFileName = Request.Files(0).FileName
        IsIE = True
    End If

    If String.IsNullOrEmpty(sFileName) Then
        Return ("{success:false, error:'request file is empty'}")
    End If

    Dim DocumentName As String = Id & Path.GetExtension(sFileName)

    If IsIE Then
        Try
            Request.Files(0).SaveAs(Path.Combine(My.Settings.TempFolder, DocumentName))
        Catch ex As Exception
            Return ("{success:false, error:'" & ex.Message & "'}")
        End Try
    Else
        Try
            If (Request.InputStream IsNot Nothing) AndAlso (Request.InputStream.CanRead) AndAlso (Request.InputStream.Length > 0) Then
                Using fileStream As FileStream = New FileStream(Path.Combine(My.Settings.TempFolder, DocumentName), FileMode.Create)
                    Dim FileBytes(Core.Convert.ToInt32(Request.InputStream.Length)) As Byte
                    Dim bytesRead As Int32 = 0
                    bytesRead = Request.InputStream.Read(FileBytes, 0, FileBytes.Length)
                    fileStream.Write(FileBytes, 0, bytesRead)
                    fileStream.Flush()
                    fileStream.Close()
                    bytesRead = Nothing
                End Using
            End If
        Catch ex As Exception
            Return ("{success:false, error:'" & ex.Message & "'}")
        End Try
    End If

    Return ("{success:true, id: '" & Id & "'}")

End Function

I put this HTML in my View:

<div id="PopupExcelUploader" title="Carica Listino Excel">
    <div id="uploaderFile"></div>
</div>

and this is the javascript:

function CreateFileUploader() {
    var uploader = new qq.FileUploader({
        element: $('#uploaderFile')[0],
        template: '<div class="qq-uploader">' +
                              '<div class="qq-upload-drop-area"><span>Drop files here to upload</span></div>' +
                              '<div class="qq-upload-button ui-button ui-widget ui-corner-all ui-button-text-only ui-state-default">Seleziona il Listino Excel</div>' +
                              '<ul class="qq-upload-list"></ul>' +
                              '</div>',
        hoverClass: 'ui-state-hover',
        focusClass: 'ui-state-focus',
        action: UploaderAction,
        allowedExtensions: ['xls', 'xlsx'],
        params: { id: ModelId },
        onSubmit: function(file, ext) {
        },
        onComplete: function(id, fileName, responseJSON) {
            if ((responseJSON.success == null) || (responseJSON.success == 'false')) {
                $.jGrowl("Error!", { theme: 'MessageError', life: 3000 });
            }
            else {
                documentUploaded = true;
                $.jGrowl("Document uploaded successfully!", { theme: 'MessageOk', life: 1800 });
                window.setTimeout(function() {
                    $("#PopupExcelUploader").dialog('close');
                    $("#PriceListDynamicGrid").trigger("reloadGrid");
                }, 3000);
            }
        }
    });
}
Alanalana answered 25/1, 2011 at 10:46 Comment(1)
Thank you for the code sample, but this does not address the question.Planoconcave

© 2022 - 2024 — McMap. All rights reserved.