应无所住,而生其心
排名
1
文章
873
粉丝
112
评论
163
net core webapi post传递参数
庸人 : 确实坑哈,我也是下班好了好几次,发现后台传递对象是可以的,但...
百度编辑器自定义模板
庸人 : 我建议换个编辑器,因为现在百度富文本已经停止维护了,用tinymec...
ICP备案 :渝ICP备18016597号-1
网站信息:2018-2025TNBLOG.NET
技术交流:群号656732739
联系我们:contact@tnblog.net
公网安备:50010702506256
欢迎加群交流技术

.net core gRPC 客户端流式上传图片,文件。gRPC文件分段传输

12704人阅读 2020/2/9 14:02 总访问:5419121 评论:0 收藏:0 手机
分类: .NET Core

html前台,完全一样:

  1. <form method="post" action="/home/UpLoadImgStream" enctype="multipart/form-data">
  2.     <input type="file" name="upfile" />
  3.     <input type="submit" name="上传" />
  4. </form>


gRPC服务端

proto

  1. syntax = "proto3";
  2. option csharp_namespace = "GrpcService1";
  3. package UpImgStream;
  4. // The greeting service definition.
  5. service UpImgStream {
  6.   // Sends a greeting
  7.   rpc DoUpLoad (stream StreamRequestreturns (UpImgStreamReply);
  8. }
  9. // The request message containing the user's name.
  10. message StreamRequest  {
  11.   bytes content = 1;
  12.   //文件后缀名(弃用,通过另外的方式在文件之前传递)
  13.   string fileExt=2;
  14. }
  15. // The response message containing the greetings.
  16. message UpImgStreamReply {
  17.   string message = 1;
  18. }

实现:

  1. public override async Task<UpImgStreamReply> DoUpLoad(IAsyncStreamReader<StreamRequest> requestStream, ServerCallContext context)
  2. {
  3.     try
  4.     {
  5.         //获取调用方的id
  6.         string host = context.Host;
  7.         //if (context.UserState.ContainsKey("fileExt"))
  8.         //{
  9.         //    object fileExt = context.UserState["fileExt"];
  10.         //}
  11.         //注意获取的时候用小写
  12.         var fileExtMetadata = context.RequestHeaders.FirstOrDefault(a => a.Key == "fileext");
  13.         if (fileExtMetadata == null)
  14.         {
  15.             return new UpImgStreamReply
  16.             {
  17.                 Message = "上传失败!"
  18.             };
  19.         }
  20.         string fileExt = fileExtMetadata.Value;
  21.         // 新建一个文件流用于存放我们获取到数据
  22.         using (var fs = new FileStream("c://" + Guid.NewGuid().ToString().Replace("-""") + "." + fileExt, FileMode.Create))
  23.         {
  24.             while (await requestStream.MoveNext()) // 循环从流中读取数据(监听gRPC客户端的流写入)
  25.             {
  26.                 requestStream.Current.Content.WriteTo(fs); // 将数据写入到文件流中
  27.             }
  28.             //数据是先被读到了内存中,再把数据写到文件中,当你数据读完的时候不代表你的数据已经写完了,因为还有一部分有可能会留在内存这个缓冲区中。这时候如果你调用了close()方法关闭了读写流,那么这部分数据就会丢失,所以应该在关闭读写流之前先flush()。
  29.             fs.Flush();
  30.         }
  31.         return new UpImgStreamReply
  32.         {
  33.             Message = "上传成功!"
  34.         };
  35.     }
  36.     catch (Exception ex)
  37.     {
  38.         return new UpImgStreamReply
  39.         {
  40.             Message = "上传失败!"
  41.         };
  42.     }
  43. }

gRPC客户端

方法一:文件分段传输

适用于文件有点点大的情况

  1. /// <summary>
  2. /// 调用gRPC 客户端流式图片上传(文件分段传输)
  3. /// </summary>
  4. public async void UpLoadImgStream(List<IFormFile> upfile)
  5. {
  6.     //获取页面传递的文件流
  7.     foreach (var formFile in upfile)
  8.     {
  9.         if (formFile.Length > 0)
  10.         {
  11.             #region 获取gRPC接口
  12.             AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport"true);
  13.             var channel = GrpcChannel.ForAddress("http://localhost:8099/");
  14.             var client = new UpImgStream.UpImgStreamClient(channel);
  15.             #endregion
  16.             //获取文件的后缀名
  17.             string fileExt = formFile.FileName.Substring(formFile.FileName.LastIndexOf('.') + 1); //文件扩展名
  18.             Metadata entries = new Metadata();
  19.             entries.Add("fileExt", fileExt);
  20.             AsyncClientStreamingCall<StreamRequest, UpImgStreamReply> call = client.DoUpLoad(entries);//先调用服务后面在提供数据
  21.             //得到文件流
  22.             Stream stream = formFile.OpenReadStream();
  23.             try
  24.             {
  25.                 var remainingLength = stream.Length; //文件总长度
  26.                 int sendlength = 100 * 1024;//1048576;
  27.                 //先把分段读取的数据存储在集合里边,因为直接调用gRPC传输,第二次读取流的时候会关闭,暂时还没有解决就使用这种方法
  28.                 List<byte[]> byteList = new List<byte[]>();
  29.                 byte[] buff = new byte[sendlength]; // 缓冲区,这里我们设置为 nkb
  30.                 while (remainingLength > 0// 若未读完则继续读取(把文件分为单位nkb的传递,如果小于nkb则一次传递完)
  31.                 {
  32.                     if (remainingLength < sendlength)//剩下的可以一次传递完
  33.                     {
  34.                         buff = new byte[remainingLength];
  35.                     }
  36.                     //注意读一次后调用WriteAsync,Stream流就关闭了,但是如果不执行WriteAsync是可以读完所有的
  37.                     int len = stream.Read(buff, 0, buff.Length); // 异步从文件中读取数据到缓冲区中
  38.                     remainingLength -= len; // 剩余长度=当前总长度-这次实际读取的长度
  39.                     byteList.Add(buff);
  40.                 }
  41.                 //分段调用gRPC流进行文件传输
  42.                 foreach (byte[] item in byteList)
  43.                 {
  44.                     //向gRPC流中写入我们刚刚读取的数据
  45.                     await call.RequestStream.WriteAsync(new StreamRequest() { Content = ByteString.CopyFrom(item) });
  46.                 }
  47.                 await call.RequestStream.CompleteAsync();//完成关闭客户端流
  48.             }
  49.             catch (Exception ex)
  50.             {
  51.             }
  52.         }
  53.     }
  54. }

方法二:一次性传输

  1. /// <summary>
  2. /// 调用gRPC 客户端流式图片上传(一次性传输)
  3. /// </summary>
  4. public async void UpLoadImgStream(List<IFormFile> upfile)
  5. {
  6.     //获取页面传递的文件流
  7.     foreach (var formFile in upfile)
  8.     {
  9.         if (formFile.Length > 0)
  10.         {
  11.             #region 获取gRPC接口
  12.             AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport"true);
  13.             var channel = GrpcChannel.ForAddress("http://localhost:8099/");
  14.             var client = new UpImgStream.UpImgStreamClient(channel);
  15.             #endregion
  16.             //获取文件的后缀名
  17.             string fileExt = formFile.FileName.Substring(formFile.FileName.LastIndexOf('.') + 1); //文件扩展名
  18.             Metadata entries = new Metadata();
  19.             entries.Add("fileExt", fileExt);
  20.             AsyncClientStreamingCall<StreamRequest, UpImgStreamReply> call = client.DoUpLoad(entries);//先调用服务后面在提供数据
  21.             //得到文件流
  22.             Stream stream = formFile.OpenReadStream();
  23.             try
  24.             {
  25.                 //方法1:一次传递完
  26.                 StreamRequest streamRequest = new StreamRequest() { Content = ByteString.FromStream(stream) };
  27.                 await call.RequestStream.WriteAsync(streamRequest);
  28.                 await call.RequestStream.CompleteAsync();//完成关闭客户端流
  29.             }
  30.             catch (Exception ex)
  31.             {
  32.             }
  33.         }
  34.     }
  35. }

得到流式调用的返回值:

  1. await call.RequestStream.CompleteAsync();//完成关闭客户端流(注意一定要调用不然整个调用过程完成不了)
  2. //得到返回值
  3. UpImgStreamReply upImgStreamReply = await call.ResponseAsync;

下载地址:http://www.tnblog.net/resource/show/aojiancc2/af3134fbbe174025ad34e7ccf7de465f




欢迎加群讨论技术,1群:677373950(满了,可以加,但通过不了),2群:656732739。有需要软件开发,或者学习软件技术的朋友可以和我联系~(Q:815170684)

评价

.net core gRPC base64上传图片文件

客户端前台&lt;div&gt; &lt;inputtype=&quot;file&quot;onchange=&quot;selectImage(this.files)&quot;accept=&quot;&quot...

css弹性盒子flex布局

css弹性盒子由于版本不同浏览器问题造成了一些不同的写法display:flexbox;在google浏览器中如果使用下面的写法就不行displa...

可输入下拉文本框据输入动态加载数据 jquery-editable-select

用到一个jquery-editable-select的控件github地址:https://github.com/indrimuska/jquery-editable-select这个插件的原理是...

.net mvc分部页.net core分部页

.net分部页的三种方式第一种:@Html.Partial(&quot;_分部页&quot;)第二种:@{ Html.RenderPartial(&quot;分部页&quot;);}...

css中单位pxemrem和vh/vw的理解

&gt;px像素(Pixel)。相对长度单位。像素px是相对于显示器屏幕分辨率而言的。em是相对长度单位。相对于当前对象内文本的字...

让IIS支持webp格式图片让IIS支持vtt格式iis设置mime类型iis配置支持的类型

webp格式图片可以让图片体积变小。也让下载图片变得更加困难一点 在线制作webp工具 https://www.upyun.com/webp?utm_mediu...

网页上传文件断点续传的实现无视文件大小上传以及datatables基本用法

首先明白js是客户带执行代码,c#是服务器上执行代码。本地文件需要用到js处理,服务器端接受c#代码处理1.HTML页面,文件信...

如何使用图标像使用文字一样使用文本图标的方法

1.首先在Iconfont-阿里巴巴矢量图标库上面找到你需要的图标然后加入你的购物车然后选择图标;注意:每个类型的图标会大小不...

使用七牛云的cdn服务提高图片的加载速度

CDN介绍CDN的全称是Content Delivery Network,即内容分发网络。CDN加速主要是加速静态资源,如网站上面上传的图片、媒体,...

通俗易懂什么是.net?什么是.net Framework?什么是.net core?

朋友圈@蓝羽 看到一篇文章写的太详细太通俗了,搬过来细细看完,保证你对.NET有个新的认识理解原文地址:https://www.cnblo...

JS监听input、keydown有输入法时打字完成后触发事件

在给输入框绑定input或keydown事件时预期效果是有输入法时,输入中文后触发事件,不希望输一个字母就触发一次事件可以用到c...

修改了css后让浏览器从缓存中更新

当我们修改了css后,如果不做一些操作,浏览器是不会自动更新我们的样式文件的。除非是过期或者用户手动刷新清理缓存等。所...

C MVC RedirectToAction跳转时候传递参数Action之间传值

MVC Action之间传值,页面跳转传值方法一:路由传值很简单直接使用 RedirectToAction(string actionName, string controller...

当你工作遇到以下几种状态时请果断跳槽走人

已经有想跳槽的念头,但是一直磨磨蹭蹭、犹犹豫豫的混日子,这种念头或者一直持续,或者是不是冒出头来占据你的思维了。于...