.NET和.NET Core Web APi FormData多文件上传对比

前言

最近因维护.NET和.NET Core项目用到文件上传功能,虽说也做过,但是没做过什么对比,借此将二者利用Ajax通过FormData上传文件做一个总结,通过视图提交表单太简单,这里不做阐述,希望对有需要的童鞋能有力所能及的帮助。

.NET Web APi FormData文件上传

我们将参数和文件都通过FormData来上传,给出如下HTML代码

复制代码
<div class="form-horizontal" style="margin-top:80px;">
    <div class="form-group">
        <label class="control-label col-md-2" for="caption">标题</label>
        <div class="col-md-10">
            <input name="title" id="title" type="text" />
        </div>
    </div>

    <div class="form-group">
        <label class="control-label col-md-2" for="caption">文件</label>
        <div class="col-md-10">
            <input name="file" id="file" multiple type="file" />
        </div>
    </div>
    <div class="form-group">
        <div class="col-md-offset-2 col-md-10">
            <input type="submit" id="btn" value="提交" class="btn btn-success" />
        </div>
    </div>
</div>
复制代码

恕我有点强迫症,界面好看点,看着也舒服,接下来则是脚本自然不用多说,利用FormData上传文件网上一搜遍地都是

复制代码
$(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,若是老版本浏览器则需要在请求头中手动添加表单多文件上传标识,如下

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目录下的文件,如下这般

 若要读取提交的表单参数,我们如下获取

//获取表单参数数据
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还提供了内存表单流,只是利用此流时,表单参数和文件放置在一起,我们需要通过文件相关参数来做区分,然后分别获取文件和表单参数,如下:

复制代码
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文件上传

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 { get; set; }
    public List<IFormFile> Files { get; set; }
}

注意:绑定参数时一定要使用[FromForm],否则将出现请求415,同时也要将前端Ajax FormData文件的参数名和强类型参数名一致。

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

 

总结

.NET Core用起来就是这么流畅和舒适,它也是真的香啊,好了,关于此二者多文件上传暂且总结于此,我们下节再会。


为了方便大家在移动端也能看到我分享的博文,现已注册个人公众号,扫描上方左边二维码即可,欢迎大家关注,有时间会及时分享相关技术博文。

感谢花时间阅读此篇文章,如果您觉得这篇文章你学到了东西也是为了犒劳下博主的码字不易不妨打赏一下吧,让楼主能喝上一杯咖啡,在此谢过了!
如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!
本文版权归作者和博客园共有,来源网址:http://www.cnblogs.com/CreateMyself)/欢迎各位转载,但是未经作者本人同意,转载文章之后必须在文章页面明显位置给出作者和原文连接,否则保留追究法律责任的权利。
posted @   Jeffcky  阅读(3263)  评论(5编辑  收藏  举报
编辑推荐:
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
历史上的今天:
2015-08-05 VS 2015 Enterprise第二大坑
点击右上角即可分享
微信分享提示