【问题标题】:How to make a fileupload interface in ASP.NET如何在 ASP.NET 中制作文件上传接口
【发布时间】:2011-07-21 14:16:22
【问题描述】:

我正在尝试在 ASP.NET 网络表单中创建文件上传接口,并正在寻找有关如何继续的建议。

文件上传界面是我正在制作的网站的一部分,用户可以在该网站上发布广告。该界面是“创建新广告”的一部分,用户最多可以上传 6 张图片。我只使用 asp.net FileUpload 服务器控件,因为我正在尝试制作一个在用户禁用 javascript 时可以工作的控件。这就是背景。

所有 6 个文件的上传发生在单击按钮时。这会将文件存储在临时文件夹 (/UserUploads/temp) 中,直到用户提交表单,在这种情况下,文件将移动到 /UserUploads 文件夹和数据库中的引用,或者直到用户点击取消按钮或导航离开在这种情况下文件被删除。

第一个问题是:将文件存储在临时目录中是否正确?或者有没有更好的方法在提交父表单之前将临时文件保存在服务器上?我能想到的唯一选择是将文件保存到会话中,但这似乎是杀死服务器的秘诀......

第二个问题:我不清楚当用户刚刚关闭浏览器窗口时该怎么做。我想避免在临时目录中出现一堆孤立的文件。如果用户没有完成表单提交,是否有某种方法可以确保清除所有文件?还是我只需要经常清理临时目录?

第三个问题:我这样做是不是完全错误,实际上有更好的方法来上传多个文件?

【问题讨论】:

  • 文件允许有多大?有多少用户?
  • 如果您使用 SQL Server,我个人更喜欢将上传的文件存储在 varbinary(max) 字段中,并通过它们的唯一 ID 使用它们。然后,您不必担心数据库与文件系统的名称冲突或不同步。这也允许您的上传过程独立于父表单的插入。如果您对此感兴趣,我可以在答案中发布一些示例代码。
  • @BonyT,我不确定这是否与我的问题相关,但潜在的用户数量是无限的。最大文件大小为 2MB,但我以后可能会设置为 4MB。
  • @pseudocoder 一些示例代码确实非常有用。
  • @user643192 好的,我在下面发布了完整的答案。

标签: asp.net file-upload


【解决方案1】:

1) 如果您使用的是 SQL Server,我个人更喜欢将上传的文件存储在 varbinary(max) 字段中,并通过它们的唯一 ID 来处理它们。然后,您不必担心数据库与文件系统的名称冲突或不同步。这也允许您的上传过程独立于父表单的插入。

以下示例展示了如何从FormView 中的FileUpload 控件中获取文件流(和元数据)并将其作为参数提供给SQL 存储过程。然后,使用实现IHTTPHandler 的类从数据库中检索文件。

2) 至于清除临时文件,我会将每个上传的文件与临时主记录相关联,以便将它们捆绑在一起。确认真正的主控后,删除临时主控(以及来自真正主控的参考文件)。然后定期运行 SQL 代理作业,以删除超过 X 时间的临时主文件和关联文件。

保存:

Protected Sub DetailsView1_ItemInserting(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.DetailsViewInsertEventArgs) Handles DetailsView1.ItemInserting
    Dim objUploader As FileUpload = DetailsView1.FindControl("fuFile")
    If objUploader.HasFile Then
        Dim strFileName As String = objUploader.PostedFile.FileName
        strFileName = strFileName.Substring(strFileName.LastIndexOf("\") + 1)
        Dim objFileStream As System.IO.Stream = objUploader.PostedFile.InputStream
        Dim arrFileImageByteArray(objFileStream.Length) As Byte
        objFileStream.Read(arrFileImageByteArray, 0, objFileStream.Length)
        e.Values.Insert(0, "FileImage", arrFileImageByteArray)
        e.Values.Insert(1, "FileName", strFileName)
        e.Values.Insert(3, "PostingDate", Now)
        e.Values.Insert(5, "Application", "CorpForms")
    Else
        e.Cancel = True
        objMessages.Add(New StatusMessage(MessageType.Warning, "File Upload canceled.  No file was selected."))
    End If
End Sub

检索:

Public Class FileServiceHandler : Implements IHttpHandler

    Public Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest

        Dim idFileID As Guid
        If context.Request.QueryString("FileID") IsNot Nothing Then
            Dim strFileID As String = context.Request.QueryString("FileID")
            Try
                idFileID = Guid.Parse(strFileID)
            Catch ex As Exception
                Throw New Exception("Unable to parse File ID")
            End Try
        End If

        Dim objConnection As New SqlConnection(ConfigurationManager.ConnectionStrings("PublicWebConnectionString").ConnectionString)
        Dim objCommand As SqlCommand = objConnection.CreateCommand
        Dim objReader As SqlDataReader

        objCommand.CommandType = Data.CommandType.StoredProcedure
        objCommand.CommandText = "spGetUploadedFile"
        objCommand.Parameters.AddWithValue("FileID", idFileID.ToString)

        Dim arrFileImage() As Byte = Nothing
        Dim strFileName As String = String.Empty
        Try
            objConnection.Open()
            objReader = objCommand.ExecuteReader
            While objReader.Read
                If Not IsDBNull(objReader("FileImage")) Then
                    arrFileImage = objReader("FileImage")
                End If
                If Not IsDBNull(objReader("FileName")) Then
                    strFileName = objReader("FileName")
                End If
            End While
        Catch ex As Exception
            Throw New Exception("There was a problem retreiving the file: " & ex.Message)
        End Try
        If objConnection.State <> Data.ConnectionState.Closed Then
            objConnection.Close()
        End If
        If arrFileImage IsNot Nothing Then
            context.Response.Clear()
            context.Response.AddHeader("content-disposition", "attachment;filename=" & strFileName)
            context.Response.BinaryWrite(arrFileImage)
            context.Response.End()
        Else
            context.Response.ContentType = "text/plain"
            context.Response.Write("Unable to retrieve file ID# " & idFileID.ToString)
        End If
    End Sub

    Public ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
        Get
            Return True
        End Get
    End Property

End Class

文件检索路径中的Web.Config:

<configuration>
  <system.web>
    <httpHandlers>
      <add verb="GET" path="*" type="MyNamespace.FileServiceHandler" />
    </httpHandlers>
  </system.web>
    <system.webServer>
        <handlers>
            <add name="MyNamespace.FileServiceHandler" path="*" verb="*" type="MyNamespace.FileServiceHandler" resourceType="Unspecified" preCondition="integratedMode" />
        </handlers>
    </system.webServer>
</configuration>

【讨论】:

  • 感谢您的代码。我会尝试这样做。一个问题:那么除了定期清理临时存储之外,没有其他方法可以删除孤立文件吗?
  • 好吧,无论您做什么,都必须涉及某种有关超时值的决定。由于您不能依赖检测网络用户是否只是关闭窗口,因此必须有一些机制来决定何时记录太旧并因此被视为放弃。对我来说,最简单的实现方法是在 SQL 代理计划作业中,但 YMMV。
  • @user643192 如果您觉得有一个关于临时记录清理的更具体的子问题想要提出,我会敦促您在单独的问题中进行。我对运行清理作业的不同方法了解不多,因此您可能会通过一个新问题获得更多关注。
  • 我想我会那样做的。非常感谢到目前为止的帮助!
【解决方案2】:

文件上传总是很烦人。我最近发现了一个很棒的组件,它可以做我认为所有上传组件都应该做的事情。

参见: http://aquantum-demo.appspot.com/file-upload

还有一个 C# 示例,位于: https://github.com/BoSchatzberg/jfu-CSharp-Example

而且,您应该在创建数据库行之前将文件存储在临时文件夹中。为避免一堆无用的文件,您可以在删除或不删除这些文件时使用 windows 临时文件夹来代理到 windows。

System.IO.Path.GetTempPath()

【讨论】:

    【解决方案3】:

    我建议将文件存储在数据库中,而不是临时文件夹中。

    不要将它们存储在 Session Db 中 - 信息太多,但在 Files Database 记录中包含 SessionId。

    所以你会有一个文件数据库,其中包含一个表格

     Id (int identity field)
     Data (varbinary(max))
     MimeType (varchar(50))
     SessionId (varchar(50))
    
     UserId ??
    

    然后您只需要编写一个计划的 SQL 任务来清除会话已过期的图像。

    【讨论】:

    • 谢谢。听起来与伪编码器相同。如果我可以选择两个,我也会将此标记为答案。伪编码器更详细。
    • 如果您要上传大文件,将它们存储在数据库中可能不是最好的主意。有一个概念称为“Blob 存储”(blob = binary large object),其中实际数据对象存储在外部数据库中,但对它的引用存储在内部 数据库。在数据库中存储“blob”会降低服务器和 Web 应用程序的速度。
    猜你喜欢
    • 2018-01-19
    • 2016-04-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-28
    • 2021-12-19
    • 2016-04-11
    相关资源
    最近更新 更多