使用 WebApi 上传文件,ajax

Upload file using WebApi, ajax

我想通过调用 ajax 使用 WebApi 上传文件,文件将保存到数据库中。我尝试了中给出的代码 this link。在这里,它将接收到的数据作为一个没有指定扩展名的文件保存到硬盘驱动器,但是我想做一些事情,比如当我将文件保存到数据库时我还想保存文件名和扩展名,因为如果我需要的话要下载文件,我可以提供文件名和扩展名。在 link 中,文件作为文件保存到硬盘驱动器,但是有什么方法可以直接将文件保存到数据库中。

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

除了将文件保存在本地之外,其中一个选项是将其保存到内存流中,然后将其传递到数据库。这个问题可以为您提供如何获取文件名和扩展名并将文件保存到内存中的代码示例:Web API: how to access multipart form values when using MultipartMemoryStreamProvider?

我认为你想在这里实现的部分在这个 previous question

中得到了部分回答

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

答案分为几个部分。

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

@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"。 (或创建此元素,如果它不存在):

  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; }
}

为此 class 创建一个新对象,添加到上下文并保存更改。

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

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

创建网络 api 控制器文件: UploadFileController.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" 属性中更改文件类型(接受的扩展名)。 希望它会有所帮助!享受吧!

如果您想将文件保存到数据库中的BLOB字段,那么您可以使用下面post中提供的代码:Saving any file to in the database, just convert it to a byte array?.

相关代码如下:

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;
}

您可以将您发送的 link 中的方法与将 MemoryStream 提交到我 link 编辑到的答案中提供的数据库的代码结合起来。

您需要在 table 中的特定列中保存实际文件名。基本上,您需要一个 BLOB 列作为文件内容,另一个 TEXTVARCHAR 列作为文件名。您提供的 link 显示了获取文件名的方法。

但是,正如其他人所指出的,您不应该将文件保存到数据库中。处理文件上传的最常见方法是将它们保存到服务器上的某个位置,并将保存文件的路径提交到数据库中的 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 api 代码如下。

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

            }
        }


    }