Sfoglia il codice sorgente

Release 2.3.1 (#221)

* Update README.zh-cn.md

* Delete README.2.2.md

* Fix  flush unclaer data bugs.

* Update README.md

* Update README.md

* Update README.zh-cn.md

* update readme.md to add the subscriber group descriptions.

* update readme

* update version to 2.3.1

* add SnowflakeId unit tests

* update build.cake for unit test adjustment

* remove unused config file

* update readme

* update readme

* Fixed dashboard messages requeue error. ( #205 )

* Refactoring

* Fixed SnowflakeId workerId to random id.

* Update README.md

* upgrade dependent nuget packages.

* Add SourceLink Support
master
Savorboard 6 anni fa
committed by GitHub
parent
commit
b62a49ffbd
Non sono state trovate chiavi note per questa firma nel database ID Chiave GPG: 4AEE18F83AFDEB23
25 ha cambiato i file con 268 aggiunte e 644 eliminazioni
  1. +0
    -51
      .gitattributes
  2. +1
    -1
      .github/ISSUE_TEMPLATE
  3. +1
    -5
      CAP.sln
  4. +0
    -230
      CAP.vssettings
  5. +25
    -14
      Directory.Build.props
  6. +0
    -241
      README.2.2.md
  7. +49
    -10
      README.md
  8. +90
    -55
      README.zh-cn.md
  9. +7
    -1
      build.cake
  10. +1
    -1
      build/version.props
  11. +1
    -1
      src/DotNetCore.CAP.Kafka/DotNetCore.CAP.Kafka.csproj
  12. +1
    -1
      src/DotNetCore.CAP.MySql/DotNetCore.CAP.MySql.csproj
  13. +1
    -1
      src/DotNetCore.CAP.PostgreSql/DotNetCore.CAP.PostgreSql.csproj
  14. +3
    -3
      src/DotNetCore.CAP/Dashboard/BatchCommandDispatcher.cs
  15. +1
    -1
      src/DotNetCore.CAP/Dashboard/RouteCollectionExtensions.cs
  16. +4
    -2
      src/DotNetCore.CAP/ICapTransaction.Base.cs
  17. +1
    -1
      src/DotNetCore.CAP/ISubscribeExecutor.Default.cs
  18. +0
    -1
      src/DotNetCore.CAP/Infrastructure/Helper.cs
  19. +13
    -5
      src/DotNetCore.CAP/Infrastructure/SnowflakeId.cs
  20. +6
    -3
      test/DotNetCore.CAP.MongoDB.Test/DotNetCore.CAP.MongoDB.Test.csproj
  21. +7
    -4
      test/DotNetCore.CAP.MySql.Test/DotNetCore.CAP.MySql.Test.csproj
  22. +7
    -4
      test/DotNetCore.CAP.PostgreSql.Test/DotNetCore.CAP.PostgreSql.Test.csproj
  23. +7
    -4
      test/DotNetCore.CAP.SqlServer.Test/DotNetCore.CAP.SqlServer.Test.csproj
  24. +7
    -4
      test/DotNetCore.CAP.Test/DotNetCore.CAP.Test.csproj
  25. +35
    -0
      test/DotNetCore.CAP.Test/SnowflakeIdTest.cs

+ 0
- 51
.gitattributes Vedi File

@@ -1,51 +0,0 @@
*.doc diff=astextplain
*.DOC diff=astextplain
*.docx diff=astextplain
*.DOCX diff=astextplain
*.dot diff=astextplain
*.DOT diff=astextplain
*.pdf diff=astextplain
*.PDF diff=astextplain
*.rtf diff=astextplain
*.RTF diff=astextplain

*.jpg binary
*.png binary
*.gif binary

*.cs text=auto diff=csharp
*.vb text=auto
*.resx text=auto
*.c text=auto
*.cpp text=auto
*.cxx text=auto
*.h text=auto
*.hxx text=auto
*.py text=auto
*.rb text=auto
*.java text=auto
*.html text=auto
*.htm text=auto
*.css text=auto
*.scss text=auto
*.sass text=auto
*.less text=auto
*.js text=auto
*.lisp text=auto
*.clj text=auto
*.sql text=auto
*.php text=auto
*.lua text=auto
*.m text=auto
*.asm text=auto
*.erl text=auto
*.fs text=auto
*.fsx text=auto
*.hs text=auto

*.csproj text=auto
*.vbproj text=auto
*.fsproj text=auto
*.dbproj text=auto
*.sln text=auto eol=crlf
*.sh eol=lf

+ 1
- 1
.github/ISSUE_TEMPLATE Vedi File

@@ -11,7 +11,7 @@ Thank you for reporting an issue.
2. 我们推荐如果是小问题(错别字修改,小的 bug fix)直接提交 PR。
3. 如果是一个新需求,请提供:详细需求描述,最好是有伪代码实现。
4. 如果是一个 BUG,请提供:复现步骤,错误日志以及相关配置,并尽量填写下面的模板中的条目。
6. 扩展阅读:[如何向开源项目提交无法解答的问题](https://zhuanlan.zhihu.com/p/25795393)
6. 如果可能,请使用【英文】来提交你的问题。
-->

Please answer these questions before submitting your issue.


+ 1
- 5
CAP.sln Vedi File

@@ -9,14 +9,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{C09CDAB0-6
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{57A8A8E5-5715-41BF-A0A6-46B819933FBC}"
ProjectSection(SolutionItems) = preProject
.gitattributes = .gitattributes
.gitignore = .gitignore
.travis.yml = .travis.yml
appveyor.yml = appveyor.yml
CAP.vssettings = CAP.vssettings
CHANGELOG.md = CHANGELOG.md
CODE_OF_CONDUCT.md = CODE_OF_CONDUCT.md
ConfigureMSDTC.ps1 = ConfigureMSDTC.ps1
.github\ISSUE_TEMPLATE = .github\ISSUE_TEMPLATE
LICENSE.txt = LICENSE.txt
README.md = README.md
@@ -36,6 +31,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{10C0818D
build.cake = build.cake
build.ps1 = build.ps1
build.sh = build.sh
Directory.Build.props = Directory.Build.props
build\index.cake = build\index.cake
build\util.cake = build\util.cake
build\version.cake = build\version.cake


+ 0
- 230
CAP.vssettings
File diff soppresso perché troppo grande
Vedi File


+ 25
- 14
Directory.Build.props Vedi File

@@ -1,18 +1,29 @@
<Project>

<Import Project="build\version.props" />
<PropertyGroup Label="Package">
<Product>CAP</Product>
<Authors>.NET Core Community;Savorboard</Authors>
<RepositoryUrl>https://github.com/dotnetcore/CAP</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<RepositoryRoot>$(MSBuildThisFileDirectory)</RepositoryRoot>
<PackageIconUrl>https://avatars2.githubusercontent.com/u/19404084</PackageIconUrl>
<PackageProjectUrl>https://github.com/dotnetcore/CAP</PackageProjectUrl>
<PackageLicenseUrl>https://github.com/dotnetcore/CAP/blob/master/LICENSE.txt</PackageLicenseUrl>
<PackageTags>CAP;EventBus;Distributed Transaction</PackageTags>
<Description>EventBus and eventually consistency in distributed architectures.</Description>
</PropertyGroup>
<Import Project="build\version.props" />

<PropertyGroup Label="Package">
<Product>CAP</Product>
<Authors>.NET Core Community;Savorboard</Authors>
<RepositoryUrl>https://github.com/dotnetcore/CAP</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<RepositoryRoot>$(MSBuildThisFileDirectory)</RepositoryRoot>
<PackageIconUrl>https://avatars2.githubusercontent.com/u/19404084</PackageIconUrl>
<PackageProjectUrl>https://github.com/dotnetcore/CAP</PackageProjectUrl>
<PackageLicenseUrl>https://github.com/dotnetcore/CAP/blob/master/LICENSE.txt</PackageLicenseUrl>
<PackageTags>CAP;EventBus;Distributed Transaction</PackageTags>
<Description>EventBus outbox integration and eventually consistency in microservice architectures.</Description>
</PropertyGroup>

<!-- Using SourceLink -->
<PropertyGroup>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0-beta-63127-02" PrivateAssets="All"/>
</ItemGroup>

</Project>

+ 0
- 241
README.2.2.md Vedi File

@@ -1,241 +0,0 @@
# CAP                       [中文](https://github.com/dotnetcore/CAP/blob/develop/README.zh-cn.md)
[![Travis branch](https://img.shields.io/travis/dotnetcore/CAP/develop.svg?label=travis-ci)](https://travis-ci.org/dotnetcore/CAP)
[![AppVeyor](https://ci.appveyor.com/api/projects/status/4mpe0tbu7n126vyw?svg=true)](https://ci.appveyor.com/project/yuleyule66/cap)
[![NuGet](https://img.shields.io/nuget/v/DotNetCore.CAP.svg)](https://www.nuget.org/packages/DotNetCore.CAP/)
[![NuGet Preview](https://img.shields.io/nuget/vpre/DotNetCore.CAP.svg?label=nuget-pre)](https://www.nuget.org/packages/DotNetCore.CAP/)
[![Member project of .NET Core Community](https://img.shields.io/badge/member%20project%20of-NCC-9e20c9.svg)](https://github.com/dotnetcore)
[![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/dotnetcore/CAP/master/LICENSE.txt)

CAP is a library based on .Net standard, which is a solution to deal with distributed transactions, also has the function of EventBus, it is lightweight, easy to use, and efficiently.

## OverView

In the process of building an SOA or MicroService system, we usually need to use the event to integrate each services. In the process, the simple use of message queue does not guarantee the reliability. CAP is adopted the local message table program integrated with the current database to solve the exception may occur in the process of the distributed system calling each other. It can ensure that the event messages are not lost in any case.

You can also use the CAP as an EventBus. The CAP provides a simpler way to implement event publishing and subscriptions. You do not need to inherit or implement any interface during the process of subscription and sending.

This is a diagram of the CAP working in the ASP.NET Core MicroService architecture:

![](http://images2015.cnblogs.com/blog/250417/201707/250417-20170705175827128-1203291469.png)

> The solid line in the figure represents the user code, and the dotted line represents the internal implementation of the CAP.

## Getting Started

### NuGet

You can run the following command to install the CAP in your project.

```
PM> Install-Package DotNetCore.CAP
```

If you want use Kafka to send integrating event, installing by:

```
PM> Install-Package DotNetCore.CAP.Kafka
```

If you want use RabbitMQ to send integrating event, installing by:

```
PM> Install-Package DotNetCore.CAP.RabbitMQ
```

CAP supports SqlServer, MySql, PostgreSql as event log storage.

```

// select a database provider you are using, event log table will integrate into.

PM> Install-Package DotNetCore.CAP.SqlServer
PM> Install-Package DotNetCore.CAP.MySql
PM> Install-Package DotNetCore.CAP.PostgreSql
```

### Configuration

First,You need to config CAP in your Startup.cs:

```cs
public void ConfigureServices(IServiceCollection services)
{
//......

services.AddDbContext<AppDbContext>();

services.AddCap(x =>
{
// If you are using EF, you need to add the following configuration:
// Notice: You don't need to config x.UseSqlServer(""") again! CAP can autodiscovery.
x.UseEntityFramework<AppDbContext>();

// If you are using ado.net,you need to add the configuration:
x.UseSqlServer("Your ConnectionStrings");
x.UseMySql("Your ConnectionStrings");
x.UsePostgreSql("Your ConnectionStrings");
// If you are using RabbitMQ, you need to add the configuration:
x.UseRabbitMQ("localhost");

// If you are using Kafka, you need to add the configuration:
x.UseKafka("localhost");
});
}

public void Configure(IApplicationBuilder app)
{
//.....

app.UseCap();
}

```

### Publish

Inject `ICapPublisher` in your Controller, then use the `ICapPublisher` to send message

```c#
public class PublishController : Controller
{
[Route("~/publishWithTransactionUsingEF")]
public async Task<IActionResult> PublishMessageWithTransactionUsingEF([FromServices]AppDbContext dbContext, [FromServices]ICapPublisher publisher)
{
using (var trans = dbContext.Database.BeginTransaction())
{
// your business code

//If you are using EF, CAP will automatic discovery current environment transaction, so you do not need to explicit pass parameters.
//Achieving atomicity between original database operation and the publish event log thanks to a local transaction.
await publisher.PublishAsync("xxx.services.account.check", new Person { Name = "Foo", Age = 11 });

trans.Commit();
}
return Ok();
}

[Route("~/publishWithTransactionUsingAdonet")]
public async Task<IActionResult> PublishMessageWithTransactionUsingAdonet([FromServices]ICapPublisher publisher)
{
var connectionString = "";
using (var sqlConnection = new SqlConnection(connectionString))
{
sqlConnection.Open();
using (var sqlTransaction = sqlConnection.BeginTransaction())
{
// your business code

publisher.Publish("xxx.services.account.check", new Person { Name = "Foo", Age = 11 }, sqlTransaction);

sqlTransaction.Commit();
}
}
return Ok();
}
}

```

### Subscribe

**Action Method**

Add the Attribute `[CapSubscribe()]` on Action to subscribe message:

```c#
public class PublishController : Controller
{
[CapSubscribe("xxx.services.account.check")]
public async Task CheckReceivedMessage(Person person)
{
Console.WriteLine(person.Name);
Console.WriteLine(person.Age);
return Task.CompletedTask;
}
}

```

**Service Method**

If your subscribe method is not in the Controller,then your subscribe class need to Inheritance `ICapSubscribe`:

```c#

namespace xxx.Service
{
public interface ISubscriberService
{
public void CheckReceivedMessage(Person person);
}


public class SubscriberService: ISubscriberService, ICapSubscribe
{
[CapSubscribe("xxx.services.account.check")]
public void CheckReceivedMessage(Person person)
{
}
}
}

```

Then inject your `ISubscriberService` class in Startup.cs

```c#
public void ConfigureServices(IServiceCollection services)
{
//Note: The injection of services needs before of `services.AddCap()`
services.AddTransient<ISubscriberService,SubscriberService>();
services.AddCap(x=>{});
}
```

### Dashboard

CAP 2.1 and above provides the dashboard pages, you can easily view the sent and received messages. In addition, you can also view the message status in real time on the dashboard.

In the distributed environment, the dashboard built-in integrated [Consul](http://consul.io) as a node discovery, while the realization of the gateway agent function, you can also easily view the node or other node data, It's like you are visiting local resources.

```c#
services.AddCap(x =>
{
//...
// Register Dashboard
x.UseDashboard();
// Register to Consul
x.UseDiscovery(d =>
{
d.DiscoveryServerHostName = "localhost";
d.DiscoveryServerPort = 8500;
d.CurrentNodeHostName = "localhost";
d.CurrentNodePort = 5800;
d.NodeId = 1;
d.NodeName = "CAP No.1 Node";
});
});
```

The default dashboard address is :[http://localhost:xxx/cap](http://localhost:xxx/cap) , you can also change the `cap` suffix to others with `d.MatchPath` configuration options.

![dashboard](http://images2017.cnblogs.com/blog/250417/201710/250417-20171004220827302-189215107.png)

![received](http://images2017.cnblogs.com/blog/250417/201710/250417-20171004220934115-1107747665.png)

![subscibers](http://images2017.cnblogs.com/blog/250417/201710/250417-20171004220949193-884674167.png)

![nodes](http://images2017.cnblogs.com/blog/250417/201710/250417-20171004221001880-1162918362.png)


## Contribute

One of the easiest ways to contribute is to participate in discussions and discuss issues. You can also contribute by submitting pull requests with code changes.

### License

[MIT](https://github.com/dotnetcore/CAP/blob/master/LICENSE.txt)

+ 49
- 10
README.md Vedi File

@@ -1,6 +1,6 @@
# CAP                       [中文](https://github.com/dotnetcore/CAP/blob/develop/README.zh-cn.md)
[![Travis branch](https://img.shields.io/travis/dotnetcore/CAP/develop.svg?label=travis-ci)](https://travis-ci.org/dotnetcore/CAP)
[![AppVeyor](https://ci.appveyor.com/api/projects/status/4mpe0tbu7n126vyw?svg=true)](https://ci.appveyor.com/project/yuleyule66/cap)
[![AppVeyor](https://ci.appveyor.com/api/projects/status/v8gfh6pe2u2laqoa?svg=true)](https://ci.appveyor.com/project/yuleyule66/cap)
[![NuGet](https://img.shields.io/nuget/v/DotNetCore.CAP.svg)](https://www.nuget.org/packages/DotNetCore.CAP/)
[![NuGet Preview](https://img.shields.io/nuget/vpre/DotNetCore.CAP.svg?label=nuget-pre)](https://www.nuget.org/packages/DotNetCore.CAP/)
[![Member project of .NET Core Community](https://img.shields.io/badge/member%20project%20of-NCC-9e20c9.svg)](https://github.com/dotnetcore)
@@ -8,7 +8,7 @@

CAP is a library based on .Net standard, which is a solution to deal with distributed transactions, also has the function of EventBus, it is lightweight, easy to use, and efficiently.

## OverView
## Overview

In the process of building an SOA or MicroService system, we usually need to use the event to integrate each services. In the process, the simple use of message queue does not guarantee the reliability. CAP is adopted the local message table program integrated with the current database to solve the exception may occur in the process of the distributed system calling each other. It can ensure that the event messages are not lost in any case.

@@ -18,6 +18,8 @@ This is a diagram of the CAP working in the ASP.NET Core MicroService architectu

![cap.png](http://oowr92l0m.bkt.clouddn.com/cap.png)

> CAP implements the Outbox Pattern described in the [eShop ebook](https://docs.microsoft.com/en-us/dotnet/standard/microservices-architecture/multi-container-microservice-net-applications/subscribe-events#designing-atomicity-and-resiliency-when-publishing-to-the-event-bus).

## Getting Started

### NuGet
@@ -63,7 +65,7 @@ public void ConfigureServices(IServiceCollection services)
// If you are using EF, you need to add the configuration:
x.UseEntityFramework<AppDbContext>(); //Options, Notice: You don't need to config x.UseSqlServer(""") again! CAP can autodiscovery.

// If you are using Ado.Net, you need to add the configuration:
// If you are using Dapper, you need to add the configuration:
x.UseSqlServer("Your ConnectionStrings");
x.UseMySql("Your ConnectionStrings");
x.UsePostgreSql("Your ConnectionStrings");
@@ -102,7 +104,7 @@ public class PublishController : Controller
{
using (var transaction = connection.BeginTransaction(_capBus, autoCommit: true))
{
//your business code
//your business logic code

_capBus.Publish("xxx.services.show.time", DateTime.Now);
}
@@ -116,7 +118,7 @@ public class PublishController : Controller
{
using (var trans = dbContext.Database.BeginTransaction(_capBus, autoCommit: true))
{
//your business code
//your business logic code

_capBus.Publish("xxx.services.show.time", DateTime.Now);
}
@@ -129,7 +131,7 @@ public class PublishController : Controller

### Subscribe

**Action Method**
**In Controller Action**

Add the Attribute `[CapSubscribe()]` on Action to subscribe message:

@@ -145,17 +147,17 @@ public class PublishController : Controller

```

**Service Method**
**In Business Logic Service**

If your subscribe method is not in the Controller,then your subscribe class need to Inheritance `ICapSubscribe`:

```c#

namespace xxx.Service
namespace BusinessCode.Service
{
public interface ISubscriberService
{
public void CheckReceivedMessage(Person person);
public void CheckReceivedMessage(DateTime datetime);
}

public class SubscriberService: ISubscriberService, ICapSubscribe
@@ -177,8 +179,45 @@ public void ConfigureServices(IServiceCollection services)
//Note: The injection of services needs before of `services.AddCap()`
services.AddTransient<ISubscriberService,SubscriberService>();

services.AddCap(x=>{});
services.AddCap(x=>
{
//...
});
}
```

#### Subscribe Group

The concept of a subscription group is similar to that of a consumer group in Kafka. it is the same as the broadcast mode in the message queue, which is used to process the same message between multiple different microservice instances.

When CAP startup, it will use the current assembly name as the default group name, if multiple same group subscribers subscribe the same topic name, there is only one subscriber can receive the message.
Conversely, if subscribers are in different groups, they will all receive messages.

In the same application, you can specify the `Group` property to keep they are in different subscribe groups:

```C#

[CapSubscribe("xxx.services.show.time", Group = "group1" )]
public void ShowTime1(DateTime datetime)
{
}

[CapSubscribe("xxx.services.show.time", Group = "group2")]
public void ShowTime2(DateTime datetime)
{
}

```
`ShowTime1` and `ShowTime2` will be called at the same time.

BTW, You can specify the default group name in the configuration :

```C#
services.AddCap(x =>
{
x.DefaultGroup = "default-group-name";
});

```

### Dashboard


+ 90
- 55
README.zh-cn.md Vedi File

@@ -1,6 +1,6 @@
# CAP                       [English](https://github.com/dotnetcore/CAP/blob/develop/README.md)
[![Travis branch](https://img.shields.io/travis/dotnetcore/CAP/develop.svg?label=travis-ci)](https://travis-ci.org/dotnetcore/CAP)
[![AppVeyor](https://ci.appveyor.com/api/projects/status/4mpe0tbu7n126vyw?svg=true)](https://ci.appveyor.com/project/yuleyule66/cap)
[![AppVeyor](https://ci.appveyor.com/api/projects/status/v8gfh6pe2u2laqoa?svg=true)](https://ci.appveyor.com/project/yuleyule66/cap)
[![NuGet](https://img.shields.io/nuget/v/DotNetCore.CAP.svg)](https://www.nuget.org/packages/DotNetCore.CAP/)
[![NuGet Preview](https://img.shields.io/nuget/vpre/DotNetCore.CAP.svg?label=nuget-pre)](https://www.nuget.org/packages/DotNetCore.CAP/)
[![Member project of .NET Core Community](https://img.shields.io/badge/member%20project%20of-NCC-9e20c9.svg)](https://github.com/dotnetcore)
@@ -10,6 +10,8 @@ CAP 是一个基于 .NET Standard 的 C# 库,它是一种处理分布式事务

你可以在这里[CAP Wiki](https://github.com/dotnetcore/CAP/wiki)看到更多详细资料。

你可以在这里看到[CAP 视频教程](https://www.cnblogs.com/savorboard/p/cap-video-1.html),学习如何在项目中集成CAP。

## 预览(OverView)

在我们构建 SOA 或者 微服务系统的过程中,我们通常需要使用事件来对各个服务进行集成,在这过程中简单的使用消息队列并不能保证数据的最终一致性,
@@ -19,9 +21,9 @@ CAP 采用的是和当前数据库集成的本地消息表的方案来解决在

这是CAP集在ASP.NET Core 微服务架构中的一个示意图:

![](http://images2015.cnblogs.com/blog/250417/201707/250417-20170705175827128-1203291469.png)
![cap.png](http://oowr92l0m.bkt.clouddn.com/cap.png)

> 图中实线部分代表用户代码,虚线部分代表CAP内部实现。
> CAP 实现了 [eShop 电子书](https://docs.microsoft.com/en-us/dotnet/standard/microservices-architecture/multi-container-microservice-net-applications/subscribe-events#designing-atomicity-and-resiliency-when-publishing-to-the-event-bus) 中描述的发件箱模式

## Getting Started

@@ -33,25 +35,21 @@ CAP 采用的是和当前数据库集成的本地消息表的方案来解决在
PM> Install-Package DotNetCore.CAP
```

如果你的消息队列使用的是 Kafka 的话,你可以
CAP 支持 Kafka 或者 RabbitMQ 消息队列,你可以选择下面的包进行安装

```
PM> Install-Package DotNetCore.CAP.Kafka
```

如果你的消息队列使用的是 RabbitMQ 的话,你可以:

```
PM> Install-Package DotNetCore.CAP.RabbitMQ
```

CAP 提供了 Sql Server, MySql, PostgreSQL 的扩展作为数据库存储:
CAP 提供了 Sql Server, MySql, PostgreSQL,MongoDB 的扩展作为数据库存储:

```
// 按需选择安装你正在使用的数据库
PM> Install-Package DotNetCore.CAP.SqlServer
PM> Install-Package DotNetCore.CAP.MySql
PM> Install-Package DotNetCore.CAP.PostgreSql
PM> Install-Package DotNetCore.CAP.MongoDB
```

### Configuration
@@ -67,28 +65,23 @@ public void ConfigureServices(IServiceCollection services)

services.AddCap(x =>
{
// 如果你的 SqlServer 使用的 EF 进行数据操作,你需要添加如下配置:
// 注意: 你不需要再次配置 x.UseSqlServer(""")
x.UseEntityFramework<AppDbContext>();
//如果你使用的 EF 进行数据操作,你需要添加如下配置:
x.UseEntityFramework<AppDbContext>(); //可选项,你不需要再次配置 x.UseSqlServer 了
// 如果你使用的Dapper,你需要添加如下配置:
//如果你使用的Ado.Net,根据数据库选择进行配置:
x.UseSqlServer("数据库连接字符串");
x.UseMySql("Your ConnectionStrings");
x.UsePostgreSql("Your ConnectionStrings");

// 如果你使用的 RabbitMQ 作为MQ,你需要添加如下配置:
//如果你使用的 MongoDB,你可以添加如下配置:
x.UseMongoDB("Your ConnectionStrings"); //注意,仅支持MongoDB 4.0+集群
//如果你使用的 RabbitMQ 或者 Kafka 作为MQ,根据使用选择配置:
x.UseRabbitMQ("localhost");

//如果你使用的 Kafka 作为MQ,你需要添加如下配置:
x.UseKafka("localhost");
});
}

public void Configure(IApplicationBuilder app)
{
.....

app.UseCap();
}

```

### 发布
@@ -96,39 +89,50 @@ public void Configure(IApplicationBuilder app)
在 Controller 中注入 `ICapPublisher` 然后使用 `ICapPublisher` 进行消息发送

```c#

public class PublishController : Controller
{
[Route("~/checkAccountWithTrans")]
public async Task<IActionResult> PublishMessageWithTransaction([FromServices]AppDbContext dbContext, [FromServices]ICapPublisher publisher)
private readonly ICapPublisher _capBus;

public PublishController(ICapPublisher capPublisher)
{
using (var trans = dbContext.Database.BeginTransaction())
{
// 此处填写你的业务代码
_capBus = capPublisher;
}
//不使用事务
[Route("~/without/transaction")]
public IActionResult WithoutTransaction()
{
_capBus.Publish("xxx.services.show.time", DateTime.Now);
return Ok();
}

//如果你使用的是EF,CAP会自动发现当前环境中的事务,所以你不必显式传递事务参数。
//由于本地事务, 当前数据库的业务操作和发布事件日志之间将实现原子性。
await publisher.PublishAsync("xxx.services.account.check", new Person { Name = "Foo", Age = 11 });
//Ado.Net 中使用事务,自动提交
[Route("~/adonet/transaction")]
public IActionResult AdonetWithTransaction()
{
using (var connection = new MySqlConnection(ConnectionString))
{
using (var transaction = connection.BeginTransaction(_capBus, autoCommit: true))
{
//业务代码

trans.Commit();
_capBus.Publish("xxx.services.show.time", DateTime.Now);
}
}
return Ok();
}

[Route("~/publishWithTransactionUsingAdonet")]
public async Task<IActionResult> PublishMessageWithTransactionUsingAdonet([FromServices]ICapPublisher publisher)
//EntityFramework 中使用事务,自动提交
[Route("~/ef/transaction")]
public IActionResult EntityFrameworkWithTransaction([FromServices]AppDbContext dbContext)
{
var connectionString = "";
using (var sqlConnection = new SqlConnection(connectionString))
using (var trans = dbContext.Database.BeginTransaction(_capBus, autoCommit: true))
{
sqlConnection.Open();
using (var sqlTransaction = sqlConnection.BeginTransaction())
{
// 此处填写你的业务代码,通常情况下,你可以将业务代码使用一个委托传递进来进行封装该区域代码。
//业务代码

publisher.Publish("xxx.services.account.check", new Person { Name = "Foo", Age = 11 }, sqlTransaction);

sqlTransaction.Commit();
}
_capBus.Publish("xxx.services.show.time", DateTime.Now);
}
return Ok();
}
@@ -145,12 +149,10 @@ public class PublishController : Controller
```c#
public class PublishController : Controller
{
[CapSubscribe("xxx.services.account.check")]
public async Task CheckReceivedMessage(Person person)
[CapSubscribe("xxx.services.show.time")]
public void CheckReceivedMessage(DateTime datetime)
{
Console.WriteLine(person.Name);
Console.WriteLine(person.Age);
return Task.CompletedTask;
Console.WriteLine(datetime);
}
}

@@ -166,16 +168,14 @@ namespace xxx.Service
{
public interface ISubscriberService
{
public void CheckReceivedMessage(Person person);
public void CheckReceivedMessage(DateTime datetime);
}


public class SubscriberService: ISubscriberService, ICapSubscribe
{
[CapSubscribe("xxx.services.account.check")]
public void CheckReceivedMessage(Person person)
[CapSubscribe("xxx.services.show.time")]
public void CheckReceivedMessage(DateTime datetime)
{
}
}
}
@@ -194,6 +194,41 @@ public void ConfigureServices(IServiceCollection services)
}
```


#### 订阅者组

订阅者组的概念类似于 Kafka 中的消费者组,它和消息队列中的广播模式相同,用来处理不同微服务实例之间同时消费相同的消息。

当CAP启动的时候,她将创建一个默认的消费者组,如果多个相同消费者组的消费者消费同一个Topic消息的时候,只会有一个消费者被执行。
相反,如果消费者都位于不同的消费者组,则所有的消费者都会被执行。

相同的实例中,你可以通过下面的方式来指定他们位于不同的消费者组。

```C#

[CapSubscribe("xxx.services.show.time", Group = "group1" )]
public void ShowTime1(DateTime datetime)
{
}

[CapSubscribe("xxx.services.show.time", Group = "group2")]
public void ShowTime2(DateTime datetime)
{
}

```
`ShowTime1` 和 `ShowTime2` 处于不同的组,他们将会被同时调用。

PS,你可以通过下面的方式来指定默认的消费者组名称:

```C#
services.AddCap(x =>
{
x.DefaultGroup = "default-group-name";
});

```

### Dashboard

CAP 2.1+ 以上版本中提供了仪表盘(Dashboard)功能,你可以很方便的查看发出和接收到的消息。除此之外,你还可以在仪表盘中实时查看发送或者接收到的消息。


+ 7
- 1
build.cake Vedi File

@@ -55,9 +55,15 @@ Task("Test")
.IsDependentOn("Build")
.Does(() =>
{
var settings = new DotNetCoreTestSettings
{
Configuration = build.Configuration,
NoBuild = false
};

foreach (var testProject in build.TestProjectFiles)
{
DotNetCoreTest(testProject.FullPath);
DotNetCoreTest(testProject.FullPath, settings);
}
});



+ 1
- 1
build/version.props Vedi File

@@ -2,7 +2,7 @@
<PropertyGroup>
<VersionMajor>2</VersionMajor>
<VersionMinor>3</VersionMinor>
<VersionPatch>0</VersionPatch>
<VersionPatch>1</VersionPatch>
<VersionQuality></VersionQuality>
<VersionPrefix>$(VersionMajor).$(VersionMinor).$(VersionPatch)</VersionPrefix>
</PropertyGroup>


+ 1
- 1
src/DotNetCore.CAP.Kafka/DotNetCore.CAP.Kafka.csproj Vedi File

@@ -13,7 +13,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Confluent.Kafka" Version="0.11.5" />
<PackageReference Include="Confluent.Kafka" Version="0.11.6" />
</ItemGroup>

<ItemGroup>


+ 1
- 1
src/DotNetCore.CAP.MySql/DotNetCore.CAP.MySql.csproj Vedi File

@@ -15,7 +15,7 @@
<PackageReference Include="Dapper" Version="1.50.5" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.1.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="2.1.0" />
<PackageReference Include="MySqlConnector" Version="0.43.0" />
<PackageReference Include="MySqlConnector" Version="0.46.1" />
</ItemGroup>

<ItemGroup>


+ 1
- 1
src/DotNetCore.CAP.PostgreSql/DotNetCore.CAP.PostgreSql.csproj Vedi File

@@ -15,7 +15,7 @@
<PackageReference Include="Dapper" Version="1.50.5" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.1.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="2.1.0" />
<PackageReference Include="Npgsql" Version="4.0.2" />
<PackageReference Include="Npgsql" Version="4.0.3" />
</ItemGroup>

<ItemGroup>


+ 3
- 3
src/DotNetCore.CAP/Dashboard/BatchCommandDispatcher.cs Vedi File

@@ -9,9 +9,9 @@ namespace DotNetCore.CAP.Dashboard
{
internal class BatchCommandDispatcher : IDashboardDispatcher
{
private readonly Action<DashboardContext, int> _command;
private readonly Action<DashboardContext, long> _command;

public BatchCommandDispatcher(Action<DashboardContext, int> command)
public BatchCommandDispatcher(Action<DashboardContext, long> command)
{
_command = command;
}
@@ -27,7 +27,7 @@ namespace DotNetCore.CAP.Dashboard

foreach (var messageId in messageIds)
{
var id = int.Parse(messageId);
var id = long.Parse(messageId);
_command(context, id);
}



+ 1
- 1
src/DotNetCore.CAP/Dashboard/RouteCollectionExtensions.cs Vedi File

@@ -103,7 +103,7 @@ namespace DotNetCore.CAP.Dashboard
public static void AddPublishBatchCommand(
this RouteCollection routes,
string pathTemplate,
Action<DashboardContext, int> command)
Action<DashboardContext, long> command)
{
if (routes == null)
{


+ 4
- 2
src/DotNetCore.CAP/ICapTransaction.Base.cs Vedi File

@@ -23,13 +23,15 @@ namespace DotNetCore.CAP
{
_bufferList.Add(msg);
}
protected void Flush()
protected virtual void Flush()
{
foreach (var message in _bufferList)
{
_dispatcher.EnqueueToPublish(message);
}

_bufferList.Clear();
}

public abstract void Commit();


+ 1
- 1
src/DotNetCore.CAP/ISubscribeExecutor.Default.cs Vedi File

@@ -164,7 +164,7 @@ namespace DotNetCore.CAP
if (!_selector.TryGetTopicExector(receivedMessage.Name, receivedMessage.Group,
out var executor))
{
var error = $"message can not be found subscriber, Message:{receivedMessage},\r\n see: https://github.com/dotnetcore/CAP/issues/63";
var error = $"Message can not be found subscriber. {receivedMessage} \r\n see: https://github.com/dotnetcore/CAP/issues/63";
throw new SubscriberNotFoundException(error);
}



+ 0
- 1
src/DotNetCore.CAP/Infrastructure/Helper.cs Vedi File

@@ -4,7 +4,6 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using DotNetCore.CAP.Diagnostics;
using Newtonsoft.Json;


+ 13
- 5
src/DotNetCore.CAP/Infrastructure/SnowflakeId.cs Vedi File

@@ -23,10 +23,10 @@ namespace DotNetCore.CAP.Infrastructure
private static SnowflakeId _snowflakeId;

private readonly object _lock = new object();
private static readonly object s_lock = new object();
private static readonly object SLock = new object();
private long _lastTimestamp = -1L;

private SnowflakeId(long workerId, long datacenterId, long sequence = 0L)
public SnowflakeId(long workerId, long datacenterId, long sequence = 0L)
{
WorkerId = workerId;
DatacenterId = datacenterId;
@@ -45,11 +45,19 @@ namespace DotNetCore.CAP.Infrastructure

public long Sequence { get; internal set; }

public static SnowflakeId Default(long datacenterId = 0)
public static SnowflakeId Default()
{
lock (s_lock)
lock (SLock)
{
return _snowflakeId ?? (_snowflakeId = new SnowflakeId(AppDomain.CurrentDomain.Id, datacenterId));
if (_snowflakeId != null)
{
return _snowflakeId;
}

var random = new Random();
var workerId = random.Next((int)MaxWorkerId);
var datacenterId = random.Next((int)MaxDatacenterId);
return _snowflakeId = new SnowflakeId(workerId, datacenterId);
}
}



+ 6
- 3
test/DotNetCore.CAP.MongoDB.Test/DotNetCore.CAP.MongoDB.Test.csproj Vedi File

@@ -10,9 +10,12 @@
<PackageReference Include="Microsoft.Extensions.Logging" Version="2.1.0" />
<PackageReference Include="FluentAssertions" Version="5.4.1" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="2.1.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.7.2" />
<PackageReference Include="xunit" Version="2.3.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
<PackageReference Include="xunit" Version="2.4.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>


+ 7
- 4
test/DotNetCore.CAP.MySql.Test/DotNetCore.CAP.MySql.Test.csproj Vedi File

@@ -12,12 +12,15 @@
<ItemGroup>
<PackageReference Include="Dapper" Version="1.50.5" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.7.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
<PackageReference Include="xunit" Version="2.3.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
<PackageReference Include="xunit" Version="2.4.0" />
<PackageReference Include="Microsoft.AspNetCore.Http" Version="2.1.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="2.1.0" />
<PackageReference Include="Moq" Version="4.9.0" />
<PackageReference Include="Moq" Version="4.10.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="2.1.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="2.1.0" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="2.1.0" />


+ 7
- 4
test/DotNetCore.CAP.PostgreSql.Test/DotNetCore.CAP.PostgreSql.Test.csproj Vedi File

@@ -7,10 +7,13 @@

<ItemGroup>
<PackageReference Include="Dapper" Version="1.50.5" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.7.2" />
<PackageReference Include="Npgsql" Version="4.0.2" />
<PackageReference Include="xunit" Version="2.3.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
<PackageReference Include="Npgsql" Version="4.0.3" />
<PackageReference Include="xunit" Version="2.4.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>


+ 7
- 4
test/DotNetCore.CAP.SqlServer.Test/DotNetCore.CAP.SqlServer.Test.csproj Vedi File

@@ -12,13 +12,16 @@

<ItemGroup>
<PackageReference Include="Dapper" Version="1.50.5" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.7.2" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
<PackageReference Include="System.Data.SqlClient" Version="4.5.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
<PackageReference Include="xunit" Version="2.3.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
<PackageReference Include="xunit" Version="2.4.0" />
<PackageReference Include="Microsoft.AspNetCore.Http" Version="2.1.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="2.1.0" />
<PackageReference Include="Moq" Version="4.9.0" />
<PackageReference Include="Moq" Version="4.10.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="2.1.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="2.1.0" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="2.1.0" />


+ 7
- 4
test/DotNetCore.CAP.Test/DotNetCore.CAP.Test.csproj Vedi File

@@ -6,13 +6,16 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.7.2" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
<PackageReference Include="System.Data.Common" Version="4.3.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
<PackageReference Include="xunit" Version="2.3.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
<PackageReference Include="xunit" Version="2.4.0" />
<PackageReference Include="Microsoft.AspNetCore.Http" Version="2.1.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="2.1.0" />
<PackageReference Include="Moq" Version="4.9.0" />
<PackageReference Include="Moq" Version="4.10.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="2.1.0" />
</ItemGroup>



+ 35
- 0
test/DotNetCore.CAP.Test/SnowflakeIdTest.cs Vedi File

@@ -0,0 +1,35 @@
using System.Linq;
using System.Threading.Tasks;
using DotNetCore.CAP.Infrastructure;
using Xunit;

namespace DotNetCore.CAP.Test
{
public class SnowflakeIdTest
{
[Fact]
public void NextIdTest()
{
var result = SnowflakeId.Default().NextId();

Assert.IsType<long>(result);
Assert.True(result > 0);
Assert.True(result.ToString().Length == long.MaxValue.ToString().Length);
}

[Fact]
public void ConcurrentNextIdTest()
{
var array = new long[1000];

Parallel.For(0, 1000, i =>
{
var id = SnowflakeId.Default().NextId();
array[i] = id;
});

Assert.True(array.Distinct().Count() == 1000);
}

}
}

Caricamento…
Annulla
Salva