c#通过grpc服务传输文件的完整步骤

c#通过grpc服务传输文件的完整步骤,第1张

此说明文档基于class="superseo">.netcore的实现方案编写,
阅读本文档之前请先熟悉netcore如何使用grpc。

grpc服务端 定义proto文件
syntax = "proto3";

option csharp_namespace = "FileService";

package file.grpc;

import "google/protobuf/wrappers.proto";
//文件传输体
message FilePart{
	//文件名,不含路径,包含扩展名
	string  file_name = 1;
	//文件内容,查询文件列表时内容为空
	google.protobuf.BytesValue file_data = 2;
	//文件存放命名空间
	google.protobuf.StringValue name_space = 3;
}
//文件 *** 作结果
message FileOpResult{
	//结果
	bool ok = 1;
	//传输成功会生成唯一标识
	int64 file_id = 2;
	google.protobuf.StringValue msg = 3;
}
//文件查询请求
message FileRequest {
	//文件id
	int64 file_id = 1;
}
//文件列表查询请求
message FileListRequest{
	//文件名关键字
	google.protobuf.StringValue keyword = 1;
	//命名空间
	google.protobuf.StringValue name_space = 2;
	int32 page_index = 3;
	int32 page_size = 4;
}
//文件列表
message FileListResponse{
	repeated FilePart items = 1;
	int32 page_index = 2;
	int32 page_size = 3;
	int32 total = 4;
}
//文件传输服务
service FileOP{
	//向服务端发送文件
	rpc SendFile(stream FilePart) returns (FileOpResult);
	//从服务端获取文件
	rpc GetFile(FileRequest) returns (stream FilePart);
	//删除文件
	rpc RemoveFile(FileRequest) returns (FileOpResult);
	//查询文件列表
	rpc GetFilePaged(FileListRequest) returns (FileListResponse);
}
grpc服务实现
public class FileService : FileOP.FileOPBase
    {
    	//数据库交互,自行按需实现
        ICommonService<FileIndex> _commonService;
        public FileService(ICommonService<FileIndex> _commonService)
        {
            this._commonService = _commonService;
        }
        public override async Task<FileOpResult> SendFile(IAsyncStreamReader<FilePart> requestStream, ServerCallContext context)
        {
        	//生成主键的算法自行实现
            var file_id = Snowflake.Instance().GetId();
            var idx = 0;
            var filepath = string.Empty;
            var nameSpace = string.Empty;
            var filename = string.Empty;
            FileStream fs = null;
            try
            {
            	//从请求流分片获取文件内容
                while (await requestStream.MoveNext())
                {
                    if (idx == 0)
                    {
                        filename = requestStream.Current.FileName;
                        var fileext = Path.GetExtension(filename);

                        if (!string.IsNullOrWhiteSpace(requestStream.Current.NameSpace))
                        {
                            nameSpace = requestStream.Current.NameSpace;
                        }
                        var savedir = $"savefile/{nameSpace}/{DateTime.Now:yyyy-MM-dd}";
                        filepath = Path.Combine(savedir, $"{file_id}{fileext}");
                        var savedir_full = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, savedir);
                        if (!Directory.Exists(savedir_full))
                        {
                            Directory.CreateDirectory(savedir_full);
                        }
                        fs = File.OpenWrite(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, filepath));
                    }
                    //关键步骤,把文件内容写入文件流
                    requestStream.Current.FileData.WriteTo(fs);
                    idx++;
                }

            }
            finally
            {
                fs?.Close();
                fs?.Dispose();
            }
            var fileindex = new FileIndex
            {
                Id = file_id,
                Name = filename,
                NameSpace = nameSpace,
                FilePath = filepath,
                CreateTime = DateTime.Now,
                LastUpdateTime = DateTime.Now
            };
            return new FileOpResult
            {
            	//文件索引存到数据库,此处自行实现
                Ok = await _commonService.Add(fileindex),
                FileId = file_id
            };
        }
        public override async Task GetFile(FileRequest request, IServerStreamWriter<FilePart> responseStream, ServerCallContext context)
        {
        	//从数据库获取文件信息
            var fileindex = await _commonService.Get(d => d.Id == request.FileId);
            if (fileindex == null)
            {
                throw new Exception("文件不存在");
            }
            //最后访问时间
            fileindex.LastUpdateTime = DateTime.Now;
            _commonService.Update(fileindex, "LastUpdateTime");

            var filepath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, fileindex.FilePath);
            using (var fs = File.OpenRead(filepath))
            {
            
                var buffer = new byte[1024 * 1024];
                var totallength = fs.Length;
                //从文件流取分片发送到响应流
                while (totallength > 0)
                {
                    var len = await fs.ReadAsync(buffer);
                    totallength -= len;
                    await responseStream.WriteAsync(new FilePart
                    {
                        FileData = ByteString.CopyFrom(buffer, 0, len),
                        FileName = fileindex.Name,
                        NameSpace = fileindex.NameSpace
                    });
                }
            }
        }
        public override async Task<FileOpResult> RemoveFile(FileRequest request, ServerCallContext context)
        {
            var result = new FileOpResult
            {
                Ok = false,
                FileId = 0
            };
            var fileindex = await _commonService.Get(d => d.Id == request.FileId);
            if (fileindex == null)
            {
                result.Msg = "文件不存在";
                return result;
            }
            result.Ok = await _commonService.Delete(fileindex);
            if (result.Ok)
            {
                var filepath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, fileindex.FilePath);
                File.Delete(filepath);
            }
            return result;
        }

        public override async Task<FileListResponse> GetFilePaged(FileListRequest request, ServerCallContext context)
        {
            string keyword = null;
            if (!string.IsNullOrWhiteSpace(request.Keyword))
            {
                keyword = request.Keyword.ToLower();
            }
            string name_space = null;
            if (!string.IsNullOrWhiteSpace(request.NameSpace))
            {
                name_space = request.NameSpace;
            }
            var query = await _commonService.GetPaged(d => (keyword == null || keyword == d.Name || d.Name.ToLower().Contains(keyword)) && (name_space == null || d.NameSpace == name_space), request.PageIndex, request.PageSize, d => d.CreateTime, Enums.OrderMode.Desc);
            var result = new FileListResponse
            {
                PageIndex = query.PageIndex,
                PageSize = query.PageSize,
                Total = query.Total
            };
            result.Items.AddRange(query.Items.Select(d => new FilePart
            {
                FileName = d.Name,
                NameSpace = d.NameSpace
            }));
            return result;
        }
    }

数据库的表结构参考,这里用的postgresql

-- Table: public."FileIndex"

-- DROP TABLE public."FileIndex";

CREATE TABLE public."FileIndex"
(
    "Id" bigint NOT NULL,
    "CreateTime" timestamp without time zone NOT NULL DEFAULT now(),
    "LastUpdateTime" timestamp without time zone NOT NULL DEFAULT now(),
    "LastUpdateUserId" character varying(50) COLLATE pg_catalog."default",
    "CreateUserId" character varying(50) COLLATE pg_catalog."default",
    "Description" character varying(50) COLLATE pg_catalog."default",
    "IsDelete" boolean NOT NULL DEFAULT false,
    "Name" character varying(100) COLLATE pg_catalog."default",
    "FilePath" character varying(200) COLLATE pg_catalog."default",
    "NameSpace" character varying(50) COLLATE pg_catalog."default"
)
WITH (
    OIDS = FALSE
)
TABLESPACE pg_default;
grpc调用端

这里的案例是webapi调用grpc

[Route("[controller]")]
    [ApiController]
    public class FileController : ControllerBase
    {
        FileService.FileOP.FileOPClient _fileOPClient;
        string appcode;
        public FileController(FileService.FileOP.FileOPClient _fileOPClient)
        {
            this._fileOPClient = _fileOPClient;
            appcode = "webapidemo";
        }
        /// 
        /// 上传文件
        /// 
        /// 
        [HttpPost, Route("upload")]
        public async Task<string> Upload([FromForm] IFormCollection formData)
        {
            var filelist = formData.Files;
            if (filelist.Count == 0)
            {
                var msg = new HttpResponseMessage(HttpStatusCode.UnsupportedMediaType);
                msg.Content = new StringContent("no file");
                throw new Exception(msg.Content.ToString());
            }
            var postfile = filelist[0];
            var stream = postfile.OpenReadStream();
            var totallength = postfile.Length;
             var clientCall = _fileOPClient.SendFile();
            var RequestStream = clientCall.RequestStream;
            var buffer = new byte[1024 * 1024];
            FileOpResult fileOpResult;
            try
            {
            	//将待上传的文件流分片发给grpc服务端
                while (totallength > 0)
                {
                    var len = await stream.ReadAsync(buffer);
                    totallength -= len;
                    await RequestStream.WriteAsync(new FileService.FilePart
                    {
                        FileName = postfile.FileName,
                        NameSpace = appcode,
                        FileData = ByteString.CopyFrom(buffer, 0, len)
                    });
                }
                await RequestStream.CompleteAsync();
                fileOpResult = await clientCall.ResponseAsync;
            }
            finally
            {
                stream.Close();
                stream.Dispose();
                clientCall.Dispose();
            }

            return fileOpResult.Ok ? fileOpResult.FileId.ToString() : string.Empty;
        }
        /// 
        /// 下载文件
        /// 
        /// 
        /// 
        [HttpGet, Route("download/{fileid}")]
        public async Task<FileResult> Download(long fileid)
        {
            var clientCall = _fileOPClient.GetFile(new FileRequest
            {
                FileId = fileid
            });
            var responseStream = clientCall.ResponseStream;
            var cts = new CancellationToken();
            var ms = new MemoryStream();
            ms.Position = 0;
            var filename = string.Empty;
            var idx = 0;
            try
            {
            	//从grpc服务端分片获取文件内容
                while (await responseStream.MoveNext(cts))
                {
                    if (idx == 0)
                    {
                        filename = responseStream.Current.FileName;
                    }
                    responseStream.Current.FileData.WriteTo(ms);
                    idx++;
                }
            }
            finally
            {
                clientCall.Dispose();
            }
            var data = ms.ToArray();
            ms.Close();
            ms.Dispose();
            return File(data, "application/octet-stream", filename);
        }
    }

以上。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/995787.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-21
下一篇 2022-05-21

发表评论

登录后才能评论

评论列表(0条)

保存