.NET和.NET Core Web APi FormData多文件上傳

【導讀】最近因維護.NET和.NET Core項目用到文件上傳功能,雖然說也作過,可是沒作過什麼對比,藉此將兩者利用Ajax經過FormData上傳文件作一個總結,經過視圖提交表單太簡單,這裏不作闡述,但願對有須要的童鞋能有力所能及的幫助。


.NET Web APi FormData文件上傳前端


咱們將參數和文件都經過FormData來上傳,給出以下HTML代碼web

 <div class="form-horizontalstyle="margin-top:80px;">
    <div class="form-group">
        <label class="control-label col-md-2for="caption">標題</label>
        <div class="col-md-10">
            <input name="titleid="titletype="text" />
        </div>
    </div>

    <div class="form-group">
        <label class="control-label col-md-2for="caption">文件</label>
        <div class="col-md-10">
            <input name="fileid="filemultiple type="file" />
        </div>
    </div>
    <div class="form-group">
        <div class="col-md-offset-2 col-md-10">
            <input type="submitid="btnvalue="提交" class="btn btn-success" />
        </div>
    </div>
</div>


恕我有點強迫症,界面好看點,看着也舒服,接下來則是腳本天然不用多說,利用FormData上傳文件網上一搜遍地都是ajax

 $(function () {
    $('#btn').click(function () {

        var data = new FormData();

        var title = $('#title').val();
        data.append("title", title);

        var files = $('#file')[0].files;;
        for (var i = 0; i < files.length; i++) {
            data.append("file", files[i]);
        }
        $.ajax({
            url: '/api/upload/upload',
            type"post",
            cache: false,
            contentType: false,
            processData: false,
            data: data,
        });
    });
});

不過須要注意的是,對現代大多瀏覽器都都已支持將上述contentType設置爲false後,就是在請求頭中添加multipart/form-data,如果老版本瀏覽器則須要在請求頭中手動添加表單多文件上傳標識,以下
api

beforeSend: function (request) {
    request.setRequestHeader("Content-Type""multipart/form-data; boundary=" + data.boundary);
}

前端咱們已經搞完,接下來咱們回到後臺,.NET Web APi已提供專門讀取FormData數據的APi,以下:
瀏覽器

//檢查請求是否包含multipart/form-data.
if (!Request.Content.IsMimeMultipartContent())
{
    throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}

//將文件存儲到App_Data文件夾下
var root = HttpContext.Current.Server.MapPath("~/App_Data");

//實例化MultipartFormDat流
var provider = new MultipartFormDataStreamProvider(root);

// 讀取表單數據
await Request.Content.ReadAsMultipartAsync(provider);

若上傳2個文件,此時上傳App_Data目錄下的文件,以下這般
微信

 若要讀取提交的表單參數,咱們以下獲取app

//獲取表單參數數據
var formData = provider.FormData;

那麼咱們怎麼將上述相似臨時文件數據轉換爲咱們上傳的文件數據呢?咱們只需將上述文件名轉換咱們上傳的文件名或者其餘自定義文件名稱便可,以下:編輯器

// 獲取文件數據
foreach (MultipartFileData file in provider.FileData)
{
    string fileName = file.Headers.ContentDisposition.FileName;

    if (fileName.StartsWith("\"") && fileName.EndsWith("\""))
    {
        fileName = fileName.Trim('"');
    }
    if (fileName.Contains(@"/") || fileName.Contains(@"\"))
    {
        fileName = Path.GetFileName(fileName);
    }

    //將本地文件轉換爲實際所需文件
    File.Move(file.LocalFileName, Path.Combine(root, fileName));
}


固然除了經過上述流讀取表單相關數據外,.NET Web APi還提供了內存表單流,只是利用此流時,表單參數和文件放置在一塊兒,咱們須要經過文件相關參數來作區分,而後分別獲取文件和表單參數,以下:ide

var provider = new MultipartMemoryStreamProvider();

await Request.Content.ReadAsMultipartAsync(provider);

var formData = new NameValueCollection();

foreach (var httpContent in provider.Contents)
{
    var formFileName = httpContent.Headers.ContentDisposition?.FileName?.Trim('\"');
    var formContentType = httpContent.Headers?.ContentType?.ToString();

    if (!string.IsNullOrEmpty(formFileName) && !string.IsNullOrEmpty(formContentType))
    {
        //文件數據
        using (var fileStream = new FileStream(root, FileMode.Create))
        {
            await httpContent.CopyToAsync(fileStream);
        }
    }
    else
    {
        //表單參數
        var formFieldName = httpContent.Headers.ContentDisposition.Name;

        var formFieldValue = await httpContent.ReadAsStringAsync();

        formData.Add(formFieldName, formFieldValue);
    }
}


.NET Core Web APi FormData文件上傳post


HTML和腳本在上述已經提供,這裏咱們只需關注APi獲取便可。在.NET Core中沒有專門提供獲取FormData數據的APi,那麼咱們是如何獲取的呢?找了找網上資料,發現大部分是來自廣告網站CSDN,不過這些文章都是轉載的博客園,都是以下這樣獲取

[Route("api/[controller]/[action]")]
[ApiController]
public class UploadController : ControllerBase
{
    public IActionResult Upload()
    {
        var files = Request.Form.Files;

        return Ok();
    }
}


如上也沒問題,我能說你這思路還停留在.NET Web APi嗎,啥年代了,還經過請求上下文去獲取,.NET Core靈活綁定機制使用起來它不香嗎,經過以下直接綁定豈不完事

此時有的童鞋又有疑問了,上傳不單單包括文件還包括參數,好比上述還有標題,那該如何是好,.NET Core的強類型綁定機制它不香嗎,以下定義強類型:

public class ExampleUpload
{
    public string Title { getset; }
    public List<IFormFile> Files { getset; }
}


注意:綁定參數時必定要使用[FromForm],不然將出現請求415,同時也要將前端Ajax FormData文件的參數名和強類型參數名一致。

[Route("api/[controller]/[action]")]
[ApiController]
public class UploadController : ControllerBase
{
    public IActionResult Upload([FromForm]ExampleUpload example)
    {
        return Ok();
    }
}



主要發現網上一部分資料對於利用FormData上傳文件在利用.NET Core接收參數時姿式不是很正確,故而纔有此文,在.NET Core中參數的綁定已徹底不須要藉助請求上下文來獲取,其綁定機制靈活且強大

本文分享自微信公衆號 - JeffckyShare(JeffckyShare)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索