.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源创计划”,欢迎正在阅读的你也加入,一块儿分享。

相关文章
相关标签/搜索