使用ASP.NET MVC 2上传文件的最佳方法是什么?

时间:2022-08-26 20:49:11

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)?

上传可变大小文件(非常大或非常小的ASP.NET MVC 2应用程序文件系统)的最佳方法是什么?

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.

(1)通过Request.Files或HttpPostedFileBase处理控制器动作中的上传,由于ASP.NET将文件加载到活动内存中,这似乎有很长一段时间的缺点。

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.

(2)尽早用HttpModule拦截文件上传,HttpModule以某种方式规避了性能问题。 (关于它是如何工作的我有点浑浊,但我一直在使用这篇文章http://darrenjohnstone.net/2008/07/15/aspnet-file-upload-module-version-2-beta-1/作为参考)。我模糊的部分是在什么时候ASP.NET将提交的文件加载到活动内存,以及如何在模块中拦截它实际上改变了这种行为。

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).

由于第二个选项更快,它似乎是更好的选择。但似乎提交上传表单的应用程序可能会有一些与需要保存在数据库中的文件相关联的数据。我不想在我的HttpHandler或HttpModule中进行持久性调用,(因为那时我将在不同的地方发生两个非常相似的功能:控制器和http处理程序)。

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

我想一个解决方法是将目标文件位置存储在HttpContext.Items中,但这是最好的方法吗?

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?

关于这一点的最后一个问题是我想在文件上传完成之前呈现HttpResponse。因此,如果有一个大文件,我将向用户发送一个包含上传状态值的视图,并进行AJAX调用以保持状态更新。如何在保持上传过程的同时呈现结果?我需要制作AsyncHandler或AsyncController吗?我需要手动抓取另一个线程吗?

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.

非常感谢你们。我知道这是很多问题,可能反映了对某些事情的普遍缺乏理解。普遍缺乏理解的有趣之处在于,拥有它们的人也往往缺乏对缺乏理解的理解......所以,如果有人能指出我在正确的方向上,我会很感激。

2 个解决方案

#1


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

如果我从ASP.NET 2.0中正确记得大文件被刷新到磁盘,那么即使使用HttpPostedFileBase也不应该有任何内存/性能问题。我不确定asynccontrollers是否是一个解决方案,asynccontrollers用于长时间运行的服务器进程。有关AsyncControllers的示例,请参阅http://www.aaronstannard.com/post/2011/01/06/asynchonrous-controllers-ASPNET-mvc.aspx

#2


0  

I use this javascript tool

我用这个javascript工具

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

这是控制器(我仔细检查导致IE有一个奇怪的行为):

<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:

我把这个HTML放在我的视图中:

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

and this is the javascript:

这是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);
            }
        }
    });
}

#1


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

如果我从ASP.NET 2.0中正确记得大文件被刷新到磁盘,那么即使使用HttpPostedFileBase也不应该有任何内存/性能问题。我不确定asynccontrollers是否是一个解决方案,asynccontrollers用于长时间运行的服务器进程。有关AsyncControllers的示例,请参阅http://www.aaronstannard.com/post/2011/01/06/asynchonrous-controllers-ASPNET-mvc.aspx

#2


0  

I use this javascript tool

我用这个javascript工具

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

这是控制器(我仔细检查导致IE有一个奇怪的行为):

<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:

我把这个HTML放在我的视图中:

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

and this is the javascript:

这是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);
            }
        }
    });
}