使用 WebApi, ajax 上传文件

本文关键字:文件 ajax WebApi 使用 | 更新日期: 2023-09-27 18:36:51

我想通过进行ajax调用使用WebApi上传文件,该文件将保存到数据库中。我尝试了此链接。在这里,它将接收到的数据作为未指定扩展名的文件保存到硬盘驱动器,但我想做一些事情,例如当我将文件保存到数据库时,我还想保存文件名和扩展名,因为稍后如果我需要下载文件,我可以提供文件名和扩展名。在链接中,文件将作为文件保存到硬盘驱动器,但是有什么方法可以直接将文件保存到DB。

使用 WebApi, ajax 上传文件

答案有几个部分。

首先,要上传文件,您可以使用包含如下代码的视图:

@using (Html.BeginForm())
{
    <input type="file" value="Choose a file"/>
    <br/>
    <input type="button" value="Upload" id="upload"/>
}
@section scripts
{
<script type="text/javascript">
    $(document).ready(function() {
        $('#upload').click(function () {
            var data = new FormData();
            var file = $('form input[type=file]')[0].files[0];
            data.append('file',file);
            $.ajax({
                url: '/Api/File/Upload',
                processData: false,
                contentType: false,
                data: data,
                type: 'POST'
            }).done(function(result) {
                alert(result);
            }).fail(function(a, b, c) {
                console.log(a, b, c);
            });
        });
    });
</script>    
}

其次,要接收此数据,请使用如下方法创建一个控制器:

public class FileController : ApiController
{
    [HttpPost]
    public async Task<string> Upload()
    {
       var provider = new MultipartMemoryStreamProvider();
       await Request.Content.ReadAsMultipartAsync(provider);
       // extract file name and file contents
       var fileNameParam = provider.Contents[0].Headers.ContentDisposition.Parameters
           .FirstOrDefault(p => p.Name.ToLower() == "filename");
       string fileName = (fileNameParam == null) ? "" : fileNameParam.Value.Trim('"');
       byte[] file = await provider.Contents[0].ReadAsByteArrayAsync();
       // Here you can use EF with an entity with a byte[] property, or
       // an stored procedure with a varbinary parameter to insert the
       // data into the DB
       var result 
           = string.Format("Received '{0}' with length: {1}", fileName, file.Length);
       return result;
    }
}

第三,默认情况下最大上传大小是有限的。您可以克服此限制,修改web.config

  1. <configuration><system.web><httpRuntime>中添加maxRequestLength="max size in bytes"。(或者如果它不存在,请创建此 lement):

  2. maxAllowedContentLength添加到<configuration><system.web><security><requestFiltering><requestLimits>元素(如果此元素不存在,则创建此元素)

这些条目如下所示:

<configuration>
  <system.web>
    <!-- kilobytes -->
    <httpRuntime targetFramework="4.5" maxRequestLength="2000000" />
<configuration>
  <system.webServer>
   <security>
    <requestFiltering>
      <!-- bytes -->
      <requestLimits maxAllowedContentLength="2000000000"/>

注意:您应该将其包含在 <location> 元素中,以便此限制仅适用于上传文件的特定路由,如下所示:

<location path="Api/File/Upload">
  <system.web>
     ...
  <system.webServer>
     ...

注意修改根web.config,而不是Views文件夹中

的根。

第四,对于将数据保存在数据库中,如果使用 EF,则只需要如下所示的实体:

public class File
{
  public int FileId { get; set; }
  public string FileName { get; set; }
  public byte[] FileContent { get; set; }
}

创建此类的新对象,添加到上下文并保存更改。

如果使用存储过程

,请创建一个具有 varbinary 参数的存储过程,并将byte[] file作为值传递。

使用 webAPI 控制器执行此操作的更简洁方法如下:

创建 Web API 控制器文件:上传文件控制器.cs

public class UploadFileController : ApiController
{
    // POST api/<controller>
    public HttpResponseMessage Post()
    {
        HttpResponseMessage result = null;
        var httpRequest = HttpContext.Current.Request;
        if (httpRequest.Files.Count > 0)
        {
            var docfiles = new List<string>();
            foreach (string file in httpRequest.Files)
            {
                var postedFile = httpRequest.Files[file];
                int hasheddate = DateTime.Now.GetHashCode();
                //Good to use an updated name always, since many can use the same file name to upload.
                string changed_name = hasheddate.ToString() + "_" + postedFile.FileName;
                var filePath = HttpContext.Current.Server.MapPath("~/Images/" + changed_name);
                postedFile.SaveAs(filePath); // save the file to a folder "Images" in the root of your app
                changed_name = @"~'Images'" + changed_name; //store this complete path to database
                docfiles.Add(changed_name);
            }
            result = Request.CreateResponse(HttpStatusCode.Created, docfiles);
        }
        else
        {
            result = Request.CreateResponse(HttpStatusCode.BadRequest);
        }
        return result;
    }
}

在标记中使用此 WebAPI。使用以下方法:

<input type="hidden" id="insertPicture" />
<input id="insertFileupload" type="file" name="files[]" accept="image/*" data-url="/api/uploadfile" multiple>
<script>
 $(function () {
 $('#insertFileupload').fileupload({
   add: function (e, data) {
     var jqXHR = data.submit()
       .success(function (result, textStatus, jqXHR) {/* ... */
          $('#insertPicture').val(result);
          alert("File Uploaded");
       })
       .error(function (jqXHR, textStatus, errorThrown) {/* ... */
          alert(errorThrown);
       })
    }
  });
});

您可以在输入标签的"accept"属性中更改文件类型(要接受的扩展名)。希望它能有所帮助!享受!

不能直接将文件保存到数据库。

除了在本地保存文件之外,其中一个选项是将其保存到内存流中,然后将其传递到数据库。这个问题可以为您提供如何获取文件名和扩展名并将文件保存到内存中的代码示例:Web API:如何在使用MultipartMemoryStreamProvider时访问多部分表单值?

我认为你想在这里实现的目标在上一个问题中得到了部分回答

现在,关于直接保存到数据库,您应该能够在不先将文件保存到硬盘驱动器的情况下实现这一点,通常是通过获取流字节数组并将其作为 byte[](字节数组)放入数据库实体或行属性中

如果要

将文件保存到数据库中的BLOB字段中,则可以使用以下帖子中提供的代码:将任何文件保存到数据库中,只需将其转换为字节数组即可?

相关代码如下:

public static int databaseFilePut(MemoryStream fileToPut)
{
    int varID = 0;
    byte[] file = fileToPut.ToArray();
    const string preparedCommand = @"
                    INSERT INTO [dbo].[Raporty]
                               ([RaportPlik])
                         VALUES
                               (@File)
                        SELECT [RaportID] FROM [dbo].[Raporty]
            WHERE [RaportID] = SCOPE_IDENTITY()
                    ";
    using (var varConnection = Locale.sqlConnectOneTime(Locale.sqlDataConnectionDetails))
    using (var sqlWrite = new SqlCommand(preparedCommand, varConnection))
    {
        sqlWrite.Parameters.Add("@File", SqlDbType.VarBinary, file.Length).Value = file;
        using (var sqlWriteQuery = sqlWrite.ExecuteReader())
            while (sqlWriteQuery != null && sqlWriteQuery.Read())
                varID = sqlWriteQuery["RaportID"] is int ? (int) sqlWriteQuery["RaportID"] : 0;
    }
    return varID;
}

您可以将发送的链接中的方法与用于将MemoryStream提交到我链接到的答案中提供的数据库的代码相结合。

您将需要表中的特定列来保存实际文件名。基本上,您需要一个BLOB列用于文件内容,另一个TEXTVARCHAR列用于文件名。您提供的链接显示了获取文件名的方法。

但是,正如其他人指出的那样,您不应将文件保存到数据库中。处理文件上载的最常见方法是将它们保存到服务器上的某个位置,并将保存文件的路径提交到数据库中的TEXTVARCHAR字段。

js 代码如下。

var Sendmodel = new FormData();Sendmodel.append("TemplatePath",$('#fileTemplatePath')[0].files[0]);Sendmodel.append("Name","pradip");
        $.ajax({
            url: "api/project/SaveCertificateSettings",
            type: 'POST',               
            contentType: false,                
            processData: false,
            data: Sendmodel,
            success: function (data, textStatus, xhr) {
            },
            error: function (xhr, textStatus, errorThrown) {
                alert('error');
            }
        });

WEb 接口代码如下。

public object SaveCertificateSettings()
    {
        string Name = Convert.ToString(HttpContext.Current.Request.Form["Name"]);
        if (HttpContext.Current.Request.Files.AllKeys.Any())
        {
            // Get the uploaded image from the Files collection
            var httpPostedFile = HttpContext.Current.Request.Files["TemplatePath"];
            if (httpPostedFile != null)
            {
                // httpPostedFile.FileName;
                // Get the complete file path
            }
        }

    }