Giter VIP home page Giter VIP logo

abp.grpc's Introduction

0.简介

Abp.Grpc 包是基于 Abp 框架并集成 MagicOnion 实现的一个模块,能够使你的 Abp 项目支持 Grpc,并且还集成了 Consul 进行服务注册与发现。

流程图

ABP vNext 版本正在开发当中,新的仓库地址届时会在本说明当中贴出。

1.目前存在的问题

参考 Issues 里面里程碑提列出来的问题。

2.包状态

Package Status Downloads
Abp.Grpc.Server NuGet version downloads
Abp.Grpc.Client NuGet version downloads

3.使用方法

在定义接口的时候可能会很复杂,但是使用还是挺简单的。

3.1 Grpc 服务提供者

3.1.1 安装 NuGet 包

需要提供 Grpc 服务的项目,只需引用 NuGet 包 Abp.Grpc.Client ,之后进行相应的配置即可。

NuGet 包地址:https://www.nuget.org/packages/Abp.Grpc.Server/

包管理器安装命令:

Install-Package Abp.Grpc.Server

3.1.2 项目模块配置

在需要使用该模块的项目的启动模块中当中添加如下引用:

using Abp.Grpc.Server;
using Abp.Grpc.Server.Extensions;

之后再启动模块的类名上面注明依赖模块:

[DependsOn(typeof(AbpGrpcServerModule)]
public class StartupModule : AbpModule
{
	// 其他代码
}

重载项目 Module 的 PreInitialize 方法,在当中进行如下配置:

public override void PreInitialize()
{
    Configuration.Modules.UseGrpcService(option =>
    {
        // GRPC 服务绑定的 IP 地址
        option.GrpcBindAddress = "0.0.0.0";
        // GRPC 服务绑定的 端口号
        option.GrpcBindPort = 5001;
    })
    .AddRpcServiceAssembly(typeof(AbpGrpcServerDemoModule).Assembly); // 扫描当前程序集的所有 GRPC 服务
}

3.1.2.1 【可选】启用 Consul 注册

如果需要启用 Consul 注册的话,则在 Module 的 PreInitialize 方法当中使用 UseConsul() 方法配置 Consul 服务器,代码如下。

public override void PreInitialize()
{
    Configuration.Modules.UseGrpcService(option =>
    {
        // GRPC 服务绑定的 IP 地址
        option.GrpcBindAddress = "0.0.0.0";
        // GRPC 服务绑定的 端口号
        option.GrpcBindPort = 5001;
        // 启用 Consul 服务注册【可选】
        option.UseConsul(consulOption =>
        {
            // Consul 服务注册地址
            consulOption.ConsulAddress = "10.0.75.1";
            // Consul 服务注册端口号
            consulOption.ConsulPort = 8500;
            // 注册到 Consul 的服务名称
            consulOption.RegistrationServiceName = "TestGrpcService";
            // 健康检查接口的地址,不填为默认当前机器的随机 IP 地址
            consulOption.ConsulHealthCheckAddress = "172.31.61.41";
            // 健康检查接口的端口号
            consulOption.ConsulHealthCheckPort = 5000;
        });
    })
    .AddRpcServiceAssembly(typeof(AbpGrpcServerDemoModule).Assembly); // 扫描当前程序集的所有 GRPC 服务
}        

如果你启用了 Consul 注册,需要新建一个控制器,其名称取名为 HealthController ,并且新建一个 Check 接口,用于 Consul 进行健康检查。

public class HealthController : HKERPControllerBase
{
	public HealthController()
	{
	}

	public IActionResult Check() => Ok("Ok");
}

3.1.4 定义提供的服务接口

如果你使用了 Abp.Grpc.Server 则需要在某个程序集当中定义你的 RPC 服务,下面代码就定义了两个简单的服务,是计算两数之和的服务。

为了统一服务定义与调用者接口的定义,在此建议你的接口定义请单独新建一个项目,并且在该项目当中引用 Abp.Grpc.Common 库,用于定义服务提供者所提供的 Grpc 接口。

public interface IMyService : IService<IMyService>
{
    UnaryResult<int> CalculateNumber(int x,int y);
}

3.1.5 实现提供的服务接口

public class MyService : ServiceBase<IMyService>,IMyService
{
    public UnaryResult<int> CalculateNumber(int x,int y)
    {
        return UnaryResult(x + y);
    }
}

实现了服务接口之后就只需要在客户端引入 Abp.Grpc.Client 配置好服务即可进行使用。

3.1.6 MagicOnion 的依赖注入支持

MagicOnion 库的 v 2.1.0 版本当中支持依赖注入,这也意味着在实现服务的时候,可以通过构造注入/属性注入来使用 IoC 容器里面的服务。(在老版本只能使用 ABP 提供的静态 IIocManager 实例)

如果用户需要启用依赖注入支持,无需进行其他的配置。

3.1.7 注意事项

在定义 Rpc 方法的时候,如果需要序列化自定义对象的话,需要在该对象类型定义上方打上 [MessagePackObject(true)] 标签,例如:

[MessagePackObject(true)]
public class UserIdentifierDto
{

   public int? TenantId { get; set; }

	public long UserId { get; set; }
}

然后我们的接口定义如下:

public interface IUserAuthenticationService : IService<IUserAuthenticationService>, ITransientDependency
{
	/// <summary>
	/// 检测用户是否存在,存在的话则返回对应的用户数据
	/// </summary>
	/// <returns>验证结果,验证成功的话返回用户相应的数据</returns>
	UnaryResult<UserVerificationResultModel> UserIsExist(UserVerificationModel user);
}

3.2 Grpc 服务调用者

3.2.1 安装 NuGet 包

NuGet 包地址:https://www.nuget.org/packages/Abp.Grpc.Client/

包管理器安装命令:

Install-Package Abp.Grpc.Client

3.2.2 项目模块配置

首先在 Web.Core 项目或者 Web.Host 的模块的 PreInitiailze() 方法当中进行配置,首先引入以下命名空间:

using Abp.GRpc.Client;
using Abp.Grpc.Client.Extensions;
using Abp.Grpc.Common.Configuration;

然后在启动模块的顶部加上依赖特性:

[DependsOn(typeof(AbpGrpcClientModule)]
public class StartupModule : AbpModule
{
	// 其他代码
}

3.2.2.1 Consul 发现模式

重载其 PreInitialize 方法,进行模块配置:

public override void PreInitialize()
{
    // 如果你需要客户端进行负载均衡操作,请传入 Consul 的 IP 地址与端口号
    Configuration.Modules.UseGrpcClient(new ConsulRegistryConfiguration("10.0.75.1", 8500, null));
}

3.2.2.2 直连模式

重载其 PreInitialize 方法,进行模块配置:

public override void PreInitialize()
{
	// 使用直连模式
	Configuration.Modules.UseGrpcClientForDirectConnection(new[]
	{
		new GrpcServerNode
		{
			GrpcServiceIp = "127.0.0.1",
			GrpcServiceName = "TestServiceName",
			GrpcServicePort = 40001
		}
	});   
}

3.2.3 引用服务提供者的接口

在这里添加服务提供者所发布 Grpc 接口的 NuGet 包,或者直接引用该项目,以便调用接口。在 DEMO 项目中即是引用的项目,当然为了版本管理,你可以将该项目发布为 NuGet 包,客户端在使用的时候需要引用该 NuGet 包。

3.2.4 调用接口

要调用远程服务,需要在你是用的地方注入连接管理器 IGrpcConnectionUtility,然后通过 IGrpcConnectionUtility.GetRemoteService() 方法即可获得服务并进行调用。

当然 Consul 模式与直连模式获取服务的方法都是不一样的,下面代码展示了两者之间的区别。

public class TestAppService : ApplicationService
{
	private readonly IGrpcConnectionUtility _connectionUtility;
	
	public TestAppService(IGrpcConnectionUtility connectionUtility)
    {
    	_connectionUtility = connectionUtility;
    }
    
    public async Task TestMethod()
    {
    	// 从 Consul 当中获取 BasicDataServer 服务提供者集群,然后获取到 IMyService 的接口
    	var service = await _connectionUtility.GetRemoteService<IMyService>("BasicDataServer");
    	// 调用服务 IMyService 服务提供的 CalculateNumber 接口
    	var result = await service.CalculateNumber(1,1);
    	Console.WriteLine("计算结果:" + result);
    	return Task.FromResult(0);
    }
}

3.3 使用直连模式还是 Consul 模式?

使用直连模式,那么如果要实现负载均衡的话,十分方便,直接在 GrpcNode 节点定义填写时,填上负载均衡器的地址即可。

使用 Consul 模式,则需要用户自己重写 IGrpcChannelManager 实现,自己实现负载均衡算法。

在这里我建议直接使用直连模式。

4. Session 状态传递

因为本模块是基于 Abp 框架的,所以在我们开发一个 Grpc 接口的时候,A 平台调用 B 平台提供的服务时,需要传递用户状态。而我们可以通过在接口定义时附加一个 GrpcSession 参数,通过该参数我们可以传递 A 平台调用时他的 AbpSession 的值。

我们可以定义一个接口,该接口主要打印当前登录用户的 UserId 信息:

/// <summary>
/// 打印调用者传递的用户 ID 数据,并返回其转换为字符串的结果
/// </summary>
/// <param name="session">AbpSession 的值</param>
/// <returns>用户 ID</returns>
UnaryResult<string> PrintCurrentUserId(GrpcSession session);

在该接口内部,可以通过 IAbpSession 提供的 Use() 方法临时将当前服务端平台登录用户的 UserId 进行临时变更。

public UnaryResult<string> PrintCurrentUserId(GrpcSession session)
{
    Console.WriteLine($"接收客户端传递 Session 值之前,服务端的用户 Id 值: {_tmpAbpSession.UserId}");
    string resultUserIdStr;

    using (_tmpAbpSession.Use(session.TenantId, session.UserId))
    {
        resultUserIdStr = (_tmpAbpSession.UserId ?? 0).ToString();
        Console.WriteLine($"临时变更的 AbpSession 值: {_tmpAbpSession.UserId}");
    }

    Console.WriteLine($"退出 using 语句块时,当前用户的 Id 值: {_tmpAbpSession.UserId}");

    return new UnaryResult<string>(resultUserIdStr);
}

那么在客户端调用的时候,只需要传递客户端当前的 IAbpSession 值即可。

public void TestMethod()
{
	// ... 其他代码
	// 取得 IAbpSession 对象
	var abpSession = bootstarp.IocManager.Resolve<IAbpSession>();
	// 临时更改
	using (abpSession.Use(1000,2000))
	{
		var userId = services.PrintCurrentUserId(abpSession as AbpSessionBase).GetAwaiter().GetResult();
		Console.WriteLine($"服务端收到的 UserId 值: {userId}");
	}
	// ... 其他代码
}

5. DEMO 项目

如果你仍然针对上述说明存有疑问,那么可以跳转到 DEMO 目录下,运行 DEMO 项目进行了解。

abp.grpc's People

Contributors

myzony avatar qu28 avatar real-zony avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

abp.grpc's Issues

虫洞区块链技术社区合作邀约(技术签约作者入驻)

Zony大神

您好,我是虫洞区块链技术社区的内容运营:小小舒。之前有幸在您的博客里看到一篇推文《[C#] 使用 C# 编写自己区块链的挖矿算法》,觉得您对区块链技术的理解特别深,想邀请您作为签约作者入驻我们新筹备的区块链技术社区:虫洞。目前邀约作者是为产品上线做内容储备,如果您这边同意签约的话,待虫洞上线之后过来注册发文就行。

咱们这边给到签约作者的奖励主要有:

代币奖励:作者每发布一篇精华原创文章,平台这边会奖励您2万token。2万token一篇,按篇打币(单个token的锚定价格在0.05-0.1元之间)

流量扶持:站内加精、社区公众号、自媒体官方号头条全网推送

个人IP打造:有机会成为虫洞区块链直播课程主讲人,虫洞社群分享大咖(PS:咱们之前是做区块链课程培训起家,目前课程与社区两项目并行)

因为虫洞目前正处于冷启动阶段,一些相关文档还未对外公布,但我们之前做智能合约开发和共识算法课程已经积累了近千人的开发者和发烧友,现在做社区也是想借助作者及平台的力量帮助更多开发者从行业外走向行业内,看了您的文章,觉得里面的内容能够真正的帮助到开发者,我们也希望能够用全站的力量帮您推广文章。

方便的话,可以留个微信交流,或者加我微信:1176311242
期待回复,谢谢!

以上

如何在abpvnext中使用?

我已经在正式环境中使用abp vnext了,拿了一个小产品尝试,还比较稳定,开发效率相对低一点。
考虑使用Abp.Grpc实现服务注册发现,方便开始支持abp vnext了不?有个简单的demo也要的。

请问服务接口实现应该如何使用依赖注入?

3.1.5 实现提供的服务接口

public class MyService : ServiceBase<IMyService>,IMyService
{
    public UnaryResult<int> CalculateNumber(int x,int y)
    {
        return UnaryResult(x + y);
    }
}

关于实现服务接口,请问这里怎样才能使用ABP的依赖注入系统?
调用时的服务实例创建并没有被依赖注入容器管理,
IocManager.Instance.Resolve可用,但是对单元测试不友好,不知大佬是否有更好的办法?

会考虑支持Abp vnext不?

abp vnext里没找到使用consul的开源方案。
同时rest api的自动生成和rest api client的自动生成。如果能整合在自动生成内,就比较方便了嗯。

实现可用服务发现

目前客户端在向 Consul 获取可用服务端的时候,使用的是 GetRemoteService 方法来进行发现,但是在其内部实现仍然是获取的缓存的 Channel。如果目标服务器故障的话,再次调用 GetRemoteService 会导致使用缓存的 Channel。

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.