使用WebApi,ajax上传文件

时间:2015-01-09 15:03:17

标签: c# ajax asp.net-web-api

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

6 个答案:

答案 0 :(得分:14)

答案有几个部分。

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

@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. maxRequestLength="max size in bytes"中添加<configuration><system.web><httpRuntime>。 (或者如果它不存在则创建这个元素):

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

  3. 这些条目如下所示:

    <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文件夹中的根。{/ p>

    第四,关于在数据库中保存数据,如果你使用EF,你只需要一个这样的实体:

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

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

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

答案 1 :(得分:3)

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

创建一个web 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”属性中更改文件类型(要接受的扩展名)。 希望它会有所帮助!享受!

答案 2 :(得分:1)

如果要将文件保存到数据库中的BLOB字段,则可以使用以下帖子中提供的代码: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;
}

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

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

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

答案 3 :(得分:0)

您无法直接将文件保存到数据库中。

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

答案 4 :(得分:0)

我认为你想要实现的目标在这个previous question

中得到了部分回答

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

答案 5 :(得分:0)

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

            }
        }


    }