旧 WCF 项目迁移到 asp.net core + gRPC 的尝试

一个月前,公司的运行WCF的windows服务器down掉了,由于 AWS 没有通知,没有能第一时间发现问题。
所以,客户提出将WCF服务由C#改为JAVA,在Linux上面运行;一方面,AWS对Linux有较多的监控措施,另一方面,假如出现问题,可以设置自动重启等服务。

老旧的WCF服务

目前WCF服务,主要提供windows桌面软件的数据接口,应该有五六年的历史了。我进入公司后,WCF服务的代码,一直由我一个人来维护。存在很多历史遗留问题,也有不同版本的共存。

如果java重写的话,其中的业务逻辑代码,难免会出现各种各样的bug,增加开发和测试的工作量。听说,要移植到linux服务上后,第一时间想到的就是跨平台.net core
.net core 经过了四年的发展,到目前的 3.1 LST版本,已经是非常成熟的跨平台解决方案了。

之后,我就在网上查找,有没有WCF的.net core 版本,查询到的信息总结如下:

  1. Core WCF不打算做WCF到.NET Core的100%兼容的移植;

  2. 对于新应用程序,WCF这种SOAP技术不建议使用;

  3. 对于老的应用程序,建议将这些保留在.NET Framework上;

  4. 如果您真的想将一个旧的应用程序迁移到.NET Core并且想继续使用WCF和WF, 社区的开源项目也是可以的,但是上生产的时间表就要到了2020年.NET 5;

  5. 开源社区,也强烈建议目前不要用于生产环境。

很遗憾,想不改动代码就迁移到 Linux 上面,基本是不可能的了。
我的最理想情况,尽量少的手写代码,最好可以像WCF一样,自动生成代理类,像访问本地代码一样,来调用接口。之后,就发现了asp.net core + gRPC这种形式。

了解gRPC

gRPC 的好处非常多:高性能传输数据小,支持多语言生成工具使用HTTP2协议,这些好处网上都有大量详细的介绍,本文不做赘述。
其实我最看重的部分还是:客户端和服务端代码,都可以通过一个 proto 协议文件来自动生成

而微软官方,也建议用 ASP.NET Core gRPC。《适用于 WCF 开发人员的 ASP.NET Core gRPC》

gRPC 的 proto 文件

为了了解 proto 文件的写法,硬着头皮看谷歌英文文档, proto3 勉强了解大概。《Language Guide (proto3)》,下面列出一些,我在使用过程中的经验总结:

  1. 一个RPC服务必须有且仅有一个入参一个出参;假如不需要的话,可以设置为空的对象google.protobuf.Empty

  2. 基本类型( string, int32 等)不能作为PRC服务的参数,可使用谷歌提供的封装对象,如:google.protobuf.StringValuegoogle.protobuf.Int32Value 详见 google/protobuf/wrappers.proto文件;

  3. proto3 不允许null值,这是由于 Protobuf 二进制序列化,空和null不能区分,利用google.protobuf.StringValue 则可以实现null值;同第2点;

  4. string name=1;这个数字必须写,用作 Protobuf 二进制序列化,并且常用的属性最好放在前12;PS: 太不习惯了,总以为是在赋值操作;

  5. 枚举类型必须从0开始,即:enum Weekday {Sunday=0;Monday=2;}

  6. 时间类型google.protobuf.Timestamp,必须是 UTC 时间;

  7. 消息体 message 不能继承,可多层嵌套,可以导入 import;

// 我的例子
syntax = "proto3";option csharp_namespace = "GrpcServiceTest.Protos";import "Protos/ClientInfoModel.proto";
import "google/protobuf/timestamp.proto";
import "google/protobuf/wrappers.proto";package UserManagement;
service UserManagement {rpc UserReset(google.protobuf.Empty) returns (google.protobuf.Empty);rpc UserLogin(LoginRequestV2) returns(LoginResponseV2);
}message LoginRequestV2 {string UserName = 1;string Password = 2;
}message LoginResponseV2 {int32 TAG = 1;string Message = 2;UserModelV2 UserInfo = 3;message UserModelV2 {int64 UserID = 1;string UserName = 2;google.protobuf.StringValue Address = 3;google.protobuf.Timestamp LastLoginTime = 4;repeated PrivGroupPluginModelV2 PrivGroupPlugins = 5;bool IsDeleted = 6;message PrivGroupPluginModelV2{int64 Id=1;google.protobuf.Timestamp CreateDateTime=2;google.protobuf.Timestamp ModifyDateTime=3;int64 PluginId=4;int64 PrivGroupPluginID=5;}}
}

根据 proto 生成代码

用vs2019,选择gRPC Service项目模板,创建项目。它会自动加上nuget包Grpc.AspNetCore。如果没有的话,则需要自己安装nuget包:Grpc.coreGoogle.ProtobufGrpc.Tools
由 proto 文件生成代码有两种方式:

  1. 通过vs右键 proto文件,选择 属性Property,选择Build Action中的Protobuf complier,会看到 gRPC Stub Classes,有三个选项 Server Only , Clent Only 和 Both 按需选择;

  2. 编辑项目文件 csproj,编辑 Protobuf 属性,这种方法还可以使用路径宏通配符等,相当方便,强烈推荐

<ItemGroup><Protobuf Include="Protos/*.proto" OutputDir="%(ProjectDir)ServerGrpc" GrpcServices="Server" />
</ItemGroup>

asp.net core 3.1

现在,恰好赶上了net core 3.1的这个 LST版本 ( long-term-support )的发布,而 NET Core 3.0 生命周期终结于 2020年3月3日,下个大一统版本 NET 5 ,正式版本还要等到明年。至于为什么没有 NET 4.0版本,官方解释,为了避免于 .NET Framework 4.X 产生歧义。

一步步的按照官方文档的指引,跟着做就可以了。《使用 ASP.NET Core 的 gRPC 服务》,《教程:在 ASP.NET Core 中创建 gRPC 客户端和服务器》

仔细回想了一下,这部分确实没有什么值得说的,官方文档已经非常的详细了。唯一不同的感受就是,net core 需要什么功能的话,需要通过nuget来安装;这点与 net framework 大有不同,framework 更像是,一次帮你全部装好。

Entity Framework Core

旧的WCF项目,数据库访问使用的是 Entity Framework + Linq + MySql。需要安装的 Nuget 包:

  • MySql.Data.EntityFrameworkCore Mysql的EF核心库;

  • Microsoft.EntityFrameworkCore.Proxies 《Lazy loading》 懒加载的插件;

  • Microsoft.EntityFrameworkCore.DesignMicrosoft.EntityFrameworkCore.Tools 这两个插件,用于生成代码;

另外,还需要下载安装 mysql-connector-net-8.0.21.msi 来访问数据库。其中有一个 Scaffold-DbContext 的bug 99419 TINYINT(1) 转化为 byte,而不是预期的 bool。这个问题将会在 8.0.22 版本中修复,目前只能手动修改。
EF当然是 Database First 了,生成EF代码需要在Package Manager Console用到 Scaffold-DbContext 命令,有三点需要注意:

  • Start up 启始项目一定要是引用它的项目,并且编译成功的;

  • Default project 生成后,代码存放的项目;

  • 如果生成失败,提示:“Your startup project 'XXXX' doesn't reference Microsoft.EntityFrameworkCore.Design. This package is required for the Entity Framework Core Tools to work. Ensure your startup project is correct, install the package, and try again.”。编辑项目文件 csproj 移除 <PrivateAssets>All</PrivateAssets> 从 "Microsoft.EntityFrameworkCore.Design"和"Microsoft.EntityFrameworkCore.Tools"中;

我的命令:Scaffold-DbContext -Connection "server=10.50.40.50;port=3306;user=myuser;password=123456;database=dbname" -Provider MySql.Data.EntityFrameworkCore -OutputDir "EFModel" -ContextDir "Context" -Project "DataAccess" -Context "BaseEntities" -UseDatabaseNames -Force

其他建议:

  • Library类库最好是 netstandard 方便移植;

  • 新建一个类来继承BaseEntities,覆盖 OnConfiguring 方法,可配置的数据库连接字符串;

public class Entities : BaseEntities
{private static string _lstDBString;public static void SetDefaultDBString(string _dbString){if (string.IsNullOrEmpty(_lstDBString)){_lstDBString = _dbString;}}protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder){if (!optionsBuilder.IsConfigured){optionsBuilder.UseLazyLoadingProxies().UseMySQL(_lstDBString);}}
}
  • 最好采用 asp.net core 的框架注入;鉴于项目的原因,假如强行采用的话,改动比较大,只好放弃;

public void ConfigureServices(IServiceCollection services)
{string _dbString = Configuration.GetConnectionString("LstDatabase");services.AddDbContext<DataAccess.Context.Entities>(options => options.UseLazyLoadingProxies().UseMySQL(_dbString));services.AddGrpc();
}
  • 数据库链接字符串有多种存放的方式,有更加安全的方式;而我采用简单方式存放在 appsettings.json

{"ConnectionStrings": {"LstDatabase": "server=127.0.0.1;port=3306;user=myuser;password=123456;database=dbname"},"log4net": "log4net.config","Logging": {"LogLevel": {"Default": "Information","Microsoft": "Warning","Microsoft.Hosting.Lifetime": "Information"}},"AllowedHosts": "*"
}

部署到 Ubuntu

生产环境运行的服务器是 Ubuntu 14.04.6 LTS,在《ubuntu Releases wiki》上描述,14版本在去年已经停止了标准支持,而 .net core 的 runtime 最低支持也是 Ubuntu 16.04.6 LTS,只好选择最新的版本Ubuntu 20.04.1 LTS

安装Ubuntu Server系统小插曲:IT支持部门的同事,帮忙重装了两遍系统,一次14.04桌面版,一次20.04服务器版;安装20版本后,发现网卡没有启用,主机后面网线的灯都没有亮起来。
由于我和他都不熟悉Ubuntu系统,网上查找办法,然后用手机拍照,再来服务器上尝试,搞了好一会儿,才连上网络,SSH也居然没有启用????。可能 Ubuntu 还是比较适合做桌面系统吧。

然后参考 《在 Ubuntu 上安装 .NET Core SDK 或 .NET Core 运行时》,安装 net core的环境,最初用的是 aspnetcore-runtime ,在测试的时候发现,gRPC需要 HTTPS。折腾了半天的 HTTPS,一会儿需要签名,一会儿还要生成密钥,一会儿还要放到指定的位置,可信任的证书还要去还要折腾????????。折腾了半天,脑壳一团浆糊。只好又安装了 dotnet-sdk,这个是自带开发的证书,反正是将就用把。

剩下的就比较简单了,编译发布asp.net core,打包上传到服务器,然后运行dotnet GrpcServiceLST.dll --urls "http://*:5000;http://*:5001"。打开浏览器测试访问,没毛病。

客户端的编写

在编写windows客户端的时候,遇到个问题:《.NET Core 中的 gRPC 客户端工厂集成》推荐的插件 Grpc.Net.ClientFactory 只能适用于 net core,而大部分客户的 windows7 系统不会安装 net core;如果想在 net framework 上使用 gRPC的话,只能用原生的方法来自己实现

使用 proto 文件生成代码的方法,与上面的一致,只需要把 Server Only 改为 Client Only ;代码部分要注意,部署的 HTTPS 是不受信任的,需要额外处理一下。

/// net core 3.1
private void button2_Click(object sender, EventArgs e)
{// 取消不受信任var httpHandler = new HttpClientHandler();httpHandler.ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;var channel = GrpcChannel.ForAddress("https://10.50.40.237:5001", new GrpcChannelOptions { HttpHandler = httpHandler });var client = new UserManagement.UserManagementClient(channel);var _param = new GrpcServiceLST.Protos.LoginRequestV2(){UserName = "user",Password = "123456"};var reply = client.UserLoginOSDShadowEx(_param);MessageBox.Show("net core login: " + reply.Message);
}/// framework 4.0
private void button1_Click(object sender, EventArgs e)
{var channel = new Channel("10.50.40.237:5000", ChannelCredentials.Insecure);var client = new UserManagement.UserManagementClient(channel);var _param = new GrpcServiceLST.Protos.LoginRequestV2(){UserName = "user",Password = "123456"};var _reply = client.UserLoginOSDShadowEx(_param);MessageBox.Show("framework login:" + _reply.Message);
}

经过测试发现,net core 的gRPC桌面程序 不支持 http 的访问;net framework 的桌面程序使用gRPC原生版本,只能访问 http 端口 5000 ,不能访问 https 端口 5001 ,不能用 http 或者 https 这样的前缀(如: http://10.50.40.237:5000),localhost这种域名也无法解析


HTTPHTTPS域名IP
net core gRPC客户端x
framework gRPC客户端xx

最最要命的是,在 win7 系统上,安装了 net core ,使用 Grpc.Net.ClientFactory 居然也不可以访问。在github上面找到了答案, win7 不会支持 http2 ,并且 win7 微软已经在2020 年1 月14 日停止提供支持。

issues : ASP.NET Core uses the operating system for HTTP/2 TLS support. macOS may support hosting servers with HTTP/2 TLS in the future, Windows 7 will not.

总结

这次WCF升级到 asp.net core + gRPC,迁移到 Linux 的部分,方案虽然可以运行。但是要放弃 win7 用户是不太可能的,只好放弃 gRPC这种方案。

幸运的是,放弃 gPRC 的那一刻,我突然意识到,为什么不用 web api ,REST Full 的方式也满足,逻辑部分的代码尽量不变。下一篇介绍,WCF 迁移到 asp.net core web api ,到目前为止,这个方案是我最为满意的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/308266.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

黑鲨会升级鸿蒙吗,买华为别乱选!这3款才是“最佳选择”,未来能升级鸿蒙系统...

原标题&#xff1a;买华为别乱选&#xff01;这3款才是“最佳选择”&#xff0c;未来能升级鸿蒙系统众所周知&#xff0c;当下国产手机品牌的进步很快&#xff0c;越来越多品牌的崛起让消费者们十分的纠结。而在国产品牌当中&#xff0c;华为一直都处于“领头羊”大家都知道现在…

.NET Core 部署IIS无法启动Hangfire方案

【导读】不知道是否有童鞋遇到过将.NET Core部署到IIS上时&#xff0c;但Hangfire无法启动&#xff0c;自然而然也就导致作业无法良好运行的问题&#xff0c;本文给出两个方案&#xff0c;不知是否有完美解决方案&#xff0c;若有&#xff0c;请于留言中给出&#xff0c;谢谢。…

初识ABP vNext(3):vue对接ABP基本思路

点击上方蓝字"小黑在哪里"关注我吧登录权限本地化创建项目ABPvue-element-admin前言上一篇介绍了ABP的启动模板以及AbpHelper工具的基本使用&#xff0c;这一篇将进入项目实战部分。因为目前ABP的官方模板只支持MVC和Angular&#xff0c;MVC的话咱.NET开发人员来写还…

leedcode04:转换字符串的最少操作次数

一&#xff1a;题目 给你一个字符串 s &#xff0c;由 n 个字符组成&#xff0c;每个字符不是 ‘X’ 就是 ‘O’ 。 一次 操作 定义为从 s 中选出 三个连续字符 并将选中的每个字符都转换为 ‘O’ 。注意&#xff0c;如果字符已经是 ‘O’ &#xff0c;只需要保持 不变 。 返…

android 手机无线投屏,安卓手机无线投屏问与答

一、Android手机使用Miracast为什么经常投不上&#xff1f;A、Android手机机型较多&#xff0c;各个厂家实现Miracast有差异&#xff0c;导致有时候连接不稳定或者无法连接B、Miracast底层使用的WiFi-P2P功能&#xff0c;各家WiFi模组厂家支持情况有好坏&#xff0c;导致有时候…

.NET Core + Ocelot:API 网关

关于 API 网关的作用&#xff0c;核心是 API 请求的收口及控制&#xff0c;如&#xff1a;鉴权、限流、熔断、数据缓存 等都是开发中常见的需求&#xff0c;将此类需求交给网关层处理&#xff0c;可以使每个微服务更聚焦于业务功能开发&#xff0c;同时也可为下游服务的安全及稳…

leedcode05 找出缺失的观测数据(思路加详解)

一&#xff1a;题目 现有一份 n m 次投掷单个 六面 骰子的观测数据&#xff0c;骰子的每个面从 1 到 6 编号。观测数据中缺失了 n 份&#xff0c;你手上只拿到剩余 m 次投掷的数据。幸好你有之前计算过的这 n m 次投掷数据的 平均值 。 给你一个长度为 m 的整数数组 rolls …

关于导入c3p0-0.9.5.5.jar包引发NoClassDefFoundError、ClassNotFoundException

一&#xff1a;问题描述 明明已经导入包了&#xff0c;而且还可以进入导入jar包的类中&#xff0c;可就是一运行就报错 NoClassDefFoundErrorClassNotFoundException 二&#xff1a;问题解决 再多导入一个jar包即可 这两个包必须全部导入才可&#xff0c;查了半天。

IT技术人,“三十而已”

最近电视剧《三十而已》热播&#xff0c;我家的电视机自然也是被霸屏&#xff0c;我还是跟着妹纸看了看&#xff0c;开头和结局完整看完&#xff0c;中间看了一点&#xff0c;大部分都是在微信公众号上通过别人的文章看完的。我个人也已经30了&#xff0c;今天也和你聊聊30这个…

html5访问本地资源,HTML5实现一个访问本地文件的实例今

怎么通过 html5 读取本地文件看你要读取什么 在高深一点的要phphtml5 打开本地文件夹我想在chrome浏览器下实现点击 打开文件夹html5本地存储怎么做&#xff0c;html5本地存储实例详解html5本地存储实例详解之创建 1 首先我们新建一个html5的空白文档&#xff0c;小编这里演示用…

[PBI催化剂]国际水准,中国首款重量级PowerBIDeskTop外部工具问世

今天看到PowerBI社区里有人推荐了SQLBI开发的Excel连接PowerBIDeskTop的外部工具功能。经了解后&#xff0c;发现其功能还是存在较大的缺陷&#xff0c;更增加了对【PBI催化剂】的优秀程度的信心。在Excel的应用领域&#xff0c;催化剂有绝对的信心是领先国际水准的。Excel连接…

查询在具有最小内存容量的所有PC中具有最快处理器的PC制造商 (20 分)(两种思路+详解)

一&#xff1a;题目&#xff1a; 本题目要求编写SQL语句&#xff0c; 查询在具有最小内存容量的所有PC中具有最快处理器的PC制造商。 提示&#xff1a;请使用SELECT语句作答。 表结构: CREATE TABLE product ( maker CHAR(20) , --制造商model CHAR(20) NOT NULL, …

用过 mongodb 吧, 这三个大坑踩过吗?

一&#xff1a;背景1. 讲故事前段时间有位朋友在微信群问&#xff0c;在向 mongodb 中插入的时间为啥取出来的时候少了 8 个小时&#xff0c;8 在时间处理上是一个非常敏感的数字&#xff0c;又吉利又是一个普适的话题&#xff0c;后来我想想初次使用 mongodb 的朋友一定还会遇…

vector容器中清空元素(但原来的元素还在)

一&#xff1a;上码演示 1&#xff1a;清空元素但其原来的元素还在 #include<bits/stdc.h> using namespace std; int main(){vector <int> vecInt;for (int i0;i<500;i){vecInt.push_back(i);}int j vecInt.capacity(); //j512int i vecInt.size(); …

html刮刮卡开始刮奖页面,html5刮刮卡抽奖 示例源码

【实例简介】【实例截图】【核心代码】Lottery Demobody{height:1000px;}#lotteryContainer {position:relative;width: 300px;height:100px;}#drawPercent {color:#F60;}刷新彩票已刮开 0% 区域。window.onload function () {var lottery new Lottery(lotteryContainer, #CC…

7-1 作业调度算法--先来先服务 (30 分)(思路+详解+vector+map+map做法)Come Baby!!!!!!!!!!!

一&#xff1a;题目&#xff1a; 输入N(N>0)个作业&#xff0c;输入每个作业的名字&#xff0c;到达时间&#xff0c;服务时间&#xff0c;按照先来先服务算法&#xff0c;计算每个作业的完成时间&#xff0c;周转时间&#xff0c;带权周转时间&#xff08;保留2位小数&…

html位置下移像素点,吃透移动端 1px的具体用法

最近在写移动端 H5 应用&#xff0c;遇到一个值得记录下来的点。现在从它的由来到实现&#xff0c;我们来聊一下移动端 1px&#xff0c;说 1px 不够准确&#xff0c;应该说成 1 物理像素 。通过阅读下面文章&#xff0c;你将会理解以下问题&#xff1a;问题为什么有 1px 这个问…

腾讯招.NET,居然要求精通MySQL,而不是SQLServer!

Docker、K8S、DevOps、微服务、云原生是这几年最火的技术名词&#xff0c;也是互联网的技术发展方向&#xff0c;.NET CoreMySQL的开源跨平台解决方案是.NET领域的不二之选&#xff01;然而大多数开发者甚至架构师&#xff0c;都聚焦在.NET Core上&#xff0c;以至于在MySQL性能…

7-2 作业调度算法--短作业优先 (30 分)(思路+详解+vector容器做法)Come Baby!!!!!!!!!!!

一&#xff1a;题目 输入N&#xff08;N>0&#xff09;个作业&#xff0c;输入每个作业的名字&#xff0c;到达时间&#xff0c;服务时间&#xff0c;按照短作业优先算法&#xff0c;计算每个作业的完成时间&#xff0c;周转时间&#xff0c;带权周转时间&#xff08;保留2…

程序员过关斩将--Http请求中如何保持状态?

微信搜一搜架构师修行之路这是一个被无数程序员撸过的问题&#xff0c;却只有少数人了解了真相。大体上搜了一下&#xff0c;网上关于http协议保持状态误导大家的文章还是有的&#xff0c;比如&#xff1a;有人说利用ViewState&#xff0c;那是asp.net下独有的东西&#xff0c;…