ASP.NET Web api接收multipart/form-data文件,解析MultipartFormDataStreamProvider文件保存过程

在ASP.NET Web api 中,接收multipart/form-data文件,我们可以使用MultipartFormDataStreamProvider来保存图片

   [HttpPost,Route("api/Job/newJob")]
    public async Task<IHttpActionResult> PostNewJob()
    {
           string root = HttpContext.Current.Server.MapPath("~/img/workImg");//指定要将文件存入的服务器物理位置
           //继承MultipartFormDataStreamProvider类
           var provider =new MultipartFormDataStreamProvider(root);
           try
           {       //执行完这条之后,文件便保存了
                await Request.Content.ReadAsMultipartAsync(provider);
           }
            catch (IOException innException)
            {     //下面可以不用看,主要是上面的代码
                //检测是否是MyMultipartFormDataStream的 GetLocalFileName方法发生异常
                if (innException.InnerException.InnerException.InnerException == null)
                {
                     return Json(new { code = "500", Message = "文件写入错误" });
                }
                return Json(new { code = "500", Message = innException.InnerException.InnerException.InnerException.Message          
            }
    }

在这里插入图片描述

这里我们可以看到,使用MultipartFormDataStreamProvider默认保存的文件名的格式是BodyPart加上一串数字字母组合而成,如果我们想要自定义文件名的话,我们可以继承MultipartFormDataStreamProvider类并重写GetLocalFileName方法

 public class MyMultipartFormDataStreamProvider:MultipartFormDataStreamProvider
 {
       public MyMultipartFormDataStreamProvider(string path) : base(path) { }
       
       public override string GetLocalFileName(HttpContentHeaders headers)
       {
            //这里获取上传的文件名
            string Name = headers.ContentDisposition.FileName.Replace("\"", string.Empty);
            
            //这里做了一个判断,只有jpg,png,gif为后缀的,才给保存,否则抛出一个错误(写这个判断的原因是因为需求原因)
             if (Name.EndsWith(".jpg", StringComparison.CurrentCultureIgnoreCase) || 
                 Name.EndsWith(".png", StringComparison.CurrentCultureIgnoreCase) ||
                 Name.EndsWith(".gif", StringComparison.CurrentCultureIgnoreCase))
             {
                   //以ContentDisposition的哈希值加上传的名字作为文件名
                   return $"{headers.ContentDisposition.GetHashCode()}_{Name}";
             }
             throw new InvalidOperationException("上传格式错误");
       }
 }

在这里插入图片描述
这里我们可以看到文件的文件名被改写成我们想要的名字了,到这里,出现两个疑问。
1.为什么重写GetLocalFileName方法就可以重写文件名呢?

2.文件是怎么保存的呢?
我们先来讲解第二个问题,因为第二个问题讲解完了 第一个问题就知道答案了


文件是怎么保存的呢?
await Request.Content.ReadAsMultipartAsync(provider);

文件能够自动保存的秘密就在这个ReadAsMultipartAsync这个方法里面,下面我们来看看它的源代码是怎么样的。

在这里插入图片描述
在这里插入图片描述
1.首先ReadAsMultipartAsync中获取了请求中的流,然后存储在MultipartAsyncContext里面,然后把MultipartAsyncContext作为参数调用了MultipartReadAsync方法。

在这里插入图片描述
2.在MultipartReadAsync方法中,这里我也不知道这个方法做了什么,但是我们看到了WriteSegment方法,看起来比较可疑,看看这个方法是什么来的。

在这里插入图片描述
3.在WriteSegment方法中,我们发现调用了GetOutputStream()方法 ,细心的小伙伴可能会发现,GetOutputStream调用了MultipartFormDataStreamProvider的GetStream方法

在这里插入图片描述
4.GetStream方法中,我们可以通过源代码发现,这个方法的目的是为了获取被File.Create创造的文件的流,而想要流,就要有文件的路径,这里它调用了GetLocalFileName方法,这里就解答了为什么重写GetLocalFileName方法会改写文件名。
WriteSegment方法获取了文件的流之后,使用WriteAsync方法向流里面写东西进去,写入的东西我猜是上传文件的数据。

下面我们来简单回答下我们提出的两个问题:
2.文件是怎么保存的呢?
调用ReadAsMultipartAsync的过程中,它首先根据文件路径 (MultipartFormDataStreamProvider提供) 创造一个文件并获取这个文件的流,然后在把数据写进流里面保存,这样,一个文件就保存完成了。

1.为什么重写GetLocalFileName方法就可以重写文件名呢?
因为在保存文件的过程中需要获取文件的流,而获取文件的流需要文件的路径,文件的路径是由MultipartFormDataStreamProviderGetStreamGetLocalFileName

到这里,文件的保存过程就讲完了,以上是我的观点,如果有什么说错的地方,别喷O(∩_∩)O,欢迎留言。

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值