GitHub - dotnetcore/CAP
快速开始 - CAP
eShopOnContainers
CAP 是一个基于 .NET Standard 的 C# 库,它是一种处理分布式事务的解决方案,同样具有 EventBus 的功能,它具有轻量级、易使用、高性能等特点。
CAP 具有 Event Bus 的所有功能,并且CAP提供了更加简化的方式来处理EventBus中的发布/订阅。
CAP 具有消息持久化的功能,也就是当你的服务进行重启或者宕机时,她可以保证消息的可靠性。
CAP 实现了分布式事务中的最终一致性,你不用再去处理这些琐碎的细节。
CAP 提供了基于 Microsoft DI 的 API 服务,她可以和你的 ASP.NET Core 系统进行无缝结合,并且能够和你的业务代码集成支持强一致性的事务处理。
CAP 是开源免费的。CAP基于MIT协议开源,你可以免费的在你的私人或者商业项目中使用,不会有人向你收取任何费用。
CAP 支持 Kafka、RabbitMQ、AzureServiceBus、AmazonSQS 等消息队列。
CAP 提供了 Sql Server, MySql, PostgreSQL,MongoDB 的扩展作为数据库存储:
发布事件/消息
订阅事件/消息
数据库表名称
cap.lock
cap.published
cap.received
1、管理 NuGet 程序包
DotNetCore.CAP
DotNetCore.CAP.RabbitMQ
DotNetCore.CAP.Dashboard
DotNetCore.CAP.SqlServer
DotNetCore.CAP.MySql
DotNetCore.CAP.PostgreSql
DotNetCore.CAP.Kafka
DotNetCore.CAP.MongoDB
DotNetCore.CAP.Dashboard.K8s
2、Program.cs中使用
using DotNetCore.CAP.Dashboard.NodeDiscovery;
builder.Services.AddCap(options =>
{
options.UseMySql(builder.Configuration.GetConnectionString("MySqlDefault"));
options.UseDashboard();
options.UseRabbitMQ(rabbitMq =>
{
rabbitMq.HostName = builder.Configuration["CAP:RabbitMq:HostName"];
rabbitMq.Port = Convert.ToInt32(builder.Configuration["CAP:RabbitMq:Port"]);
rabbitMq.UserName = builder.Configuration["CAP:RabbitMq:UserName"];
rabbitMq.Password = builder.Configuration["CAP:RabbitMq:Password"];
});
options.UseDashboard();
#region .NET Core 3.0
DiscoveryOptions discoveryOptions = new DiscoveryOptions();
discoveryOptions.CurrentNodePort = 5173;
builder.Configuration.Bind(discoveryOptions);
options.UseDiscovery(d =>
{
d.DiscoveryServerHostName = "localhost";
d.DiscoveryServerPort = 8500;
d.CurrentNodeHostName = "localhost";
d.CurrentNodePort = 5222;
d.NodeId = "1";
d.NodeName = "fanlin";
d.Scheme = "http";
d.MatchPath = "/api/HealthCheck";
});
#endregion
#region .NET 6.0
ConsulDiscoveryOptions discoveryOptions = new ConsulDiscoveryOptions();
discoveryOptions.CurrentNodePort = 5173;
builder.Configuration.Bind(discoveryOptions);
options.UseConsulDiscovery(d =>
{
d.DiscoveryServerHostName = "localhost";
d.DiscoveryServerPort = 8500;
d.CurrentNodeHostName = "localhost";
d.CurrentNodePort = 5222;
d.NodeId = "1";
d.NodeName = "fanlin";
d.Scheme = "http";
d.MatchPath = "/api/HealthCheck";
});
#endregion
//失败后的重试次数,默认50次
options.FailedRetryCount = 2;
//失败后的重试间隔,默认60秒
options.FailedRetryInterval = 5;
//设置处理成功的数据在数据库中保存的时间(秒),数据会定期删除,默认24*3600秒
options.SucceedMessageExpiredAfter = 24 * 3600;
options.FailedThresholdCallback = info =>
{
Console.WriteLine("Publish Message Error::" + info.Message);
};
}).AddSubscribeFilter<MyCapFilter>();
SetupCap.cs,过滤器
using DotNetCore.CAP.Filter;
namespace Trial.WebAPI.Extensions
{
public static class SetupCap
{
public static void AddCapSetup(this IServiceCollection services)
{
if (services == null) throw new ArgumentNullException(nameof(services));
// services.AddTransient<ISubscriberService, SubscriberService>();
services.AddCap(x =>
{
//如果你使用的ADO.NET,根据数据库选择进行配置:
x.UseMySql(AppSettings.Configuration["Default"]);
//CAP支持 RabbitMQ、Kafka、AzureServiceBus 等作为MQ,根据使用选择配置:
x.UseRabbitMQ(o =>
{
o.HostName = AppSettings.Configuration["CAP:RabbitMQ:HostName"];
o.UserName = AppSettings.Configuration["CAP:RabbitMQ:UserName"];
o.Password = AppSettings.Configuration["CAP:RabbitMQ:Password"];
o.VirtualHost = AppSettings.Configuration["CAP:RabbitMQ:VirtualHost"];
o.Port = Convert.ToInt32(AppSettings.Configuration["CAP:RabbitMQ:Port"]);
});
//设置处理成功的数据在数据库中保存的时间(秒),为保证系统新能,数据会定期清理。
x.SucceedMessageExpiredAfter = 24 * 3600;
//设置失败重试次数
x.FailedRetryCount = 100;
//设置失败重试间隔
x.FailedRetryInterval = 20 * 60;
// 注册 Dashboard
x.UseDashboard();
}).AddSubscribeFilter<MyCapFilter>();
}
public static void UseCapSetup(this IApplicationBuilder app)
{
}
}
public class MyCapFilter : SubscribeFilter
{
public override Task OnSubscribeExecutingAsync(ExecutingContext context)
{
// 订阅方法执行前
return Task.CompletedTask;
}
public override Task OnSubscribeExecutedAsync(ExecutedContext context)
{
// 订阅方法执行后
return Task.CompletedTask;
}
public override Task OnSubscribeExceptionAsync(ExceptionContext context)
{
// 订阅方法执行异常
return Task.CompletedTask;
}
}
}
3、CapPublishController.cs【发送消息,发送延迟消息,发送包含头信息的消息】
using DotNetCore.CAP;
using Microsoft.AspNetCore.Mvc;
using Trial.Repository.CarCorrectModify;
namespace Trial.WebAPI.Controllers
{
[Route("api/CapPublish/[action]")]
[ApiController]
public class CapPublishController : ControllerBase
{
private static string publishName = "CAPTest.Test";
private readonly ICapPublisher _capPublisher;
private readonly ICarCorrectModifyRepository _repository;
private readonly IConfiguration _configuration;
/// <summary>
///
/// </summary>
public CapPublishController(ICapPublisher capPublisher, ICarCorrectModifyRepository repository, IConfiguration configuration)
{
_capPublisher = capPublisher;
_repository = repository;
_configuration = configuration;
}
/// <summary>
/// 发送消息,发送包含头信息的消息
/// </summary>
/// <returns></returns>
[HttpGet]
public async Task<IActionResult> Publish()
{
IDictionary<string, string?> dictHeader = new Dictionary<string, string?>();
dictHeader.Add("name", "zhangsan");
dictHeader.Add("sex", "男");
dictHeader.Add("age", "18");
await _capPublisher.PublishAsync(publishName, DateTime.Now, dictHeader);
return Ok();
}
/// <summary>
/// 发送延迟消息,发送包含头信息的消息
/// </summary>
/// <returns></returns>
[HttpGet]
public async Task<IActionResult> SendDelayMessage()
{
IDictionary<string, string?> dictHeader = new Dictionary<string, string?>()
{
["my.header.first"] = "first",
["my.header.second"] = "second"
};
dictHeader.Add("name", "zhangsan");
dictHeader.Add("sex", "男");
dictHeader.Add("age", "18");
await _capPublisher.PublishDelayAsync(TimeSpan.FromSeconds(100), "test.show.time", DateTime.Now, dictHeader);
return Ok();
}
}
}
4、CapConsumerController.cs【处理消息,处理包含头信息的消息】
using DotNetCore.CAP;
using Microsoft.AspNetCore.Mvc;
using Trial.Repository.CarCorrectModify;
namespace Trial.WebAPI.Controllers
{
[Route("api/CapConsumer/[action]")]
[ApiController]
public class CapConsumerController : ControllerBase
{
/// <summary>
///
/// </summary>
public CapConsumerController()
{ }
/// <summary>
/// 订阅
/// </summary>
/// <param name="data"></param>
[NonAction]
[CapSubscribe("CAPTest.Test")]
public void Distributed(string data, [FromCap] CapHeader header)
{
string name = header["name"];
string message = $"接收到订阅:{data}";
//to do something ...
}
/// <summary>
/// 订阅
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
[NonAction]
[CapSubscribe("CAPDemo.Test1", Group = "CAPDemo.Test1.Main")]
public void Receive(string data, [FromCap] CapHeader header)
{
string name = header["name"];
string message = $"接收到订阅:{data}";
//to do something ...
}
}
}
5、appsettings.json【注意:修改本地 RabbitMq 密码】
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"ConnectionStrings": {
"MySqlDefault": "Data Source=localhost;Port=3306;Database=dbCap;uid=root;pwd=1q2w3E*;charset=utf8mb4;Allow User Variables=true;AllowLoadLocalInfile=true;MinimumPoolSize=50;MaximumPoolSize=1000",
"SqlServerDefault": "data source=.;initial catalog=dbCap;user id=sa;password=000000;"
},
"Cap": {
"Enabled": "true",
"RabbitMq": {
"HostName": "localhost",
"Port": 5672,
"UserName": "admin",
"Password": "admin",
"VirtualHost": "vhost.adnc.dev"
}
}
}
6、打开CAP页面,可以看到各种事件和状态
http://localhost:5090/cap/index.html#/
*
*
*