Commit 639c41bb authored by Savorboard's avatar Savorboard

Deployed 6f54e5a8 with MkDocs version: 1.0.4

parent 4066dd1c
File mode changed from 100644 to 100755
...@@ -97,7 +97,7 @@ ...@@ -97,7 +97,7 @@
<li > <li >
<a href="../user-guide/design-principle.md.md">Design Principle</a> <a href="../user-guide/design-principle/">Design Principle</a>
</li> </li>
......
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
...@@ -97,7 +97,7 @@ ...@@ -97,7 +97,7 @@
<li > <li >
<a href="user-guide/design-principle.md.md">Design Principle</a> <a href="user-guide/design-principle/">Design Principle</a>
</li> </li>
...@@ -298,5 +298,5 @@ ...@@ -298,5 +298,5 @@
<!-- <!--
MkDocs version : 1.0.4 MkDocs version : 1.0.4
Build Date UTC : 2019-02-02 11:35:20 Build Date UTC : 2019-02-10 08:10:02
--> -->
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
This source diff could not be displayed because it is too large. You can view the blob instead.
File mode changed from 100644 to 100755
...@@ -2,82 +2,82 @@ ...@@ -2,82 +2,82 @@
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"> <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url> <url>
<loc>None</loc> <loc>None</loc>
<lastmod>2019-02-02</lastmod> <lastmod>2019-02-10</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc>None</loc> <loc>None</loc>
<lastmod>2019-02-02</lastmod> <lastmod>2019-02-10</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc>None</loc> <loc>None</loc>
<lastmod>2019-02-02</lastmod> <lastmod>2019-02-10</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc>None</loc> <loc>None</loc>
<lastmod>2019-02-02</lastmod> <lastmod>2019-02-10</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc></loc> <loc>None</loc>
<lastmod>2019-02-10</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc>None</loc> <loc>None</loc>
<lastmod>2019-02-02</lastmod> <lastmod>2019-02-10</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc>None</loc> <loc>None</loc>
<lastmod>2019-02-02</lastmod> <lastmod>2019-02-10</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc>None</loc> <loc>None</loc>
<lastmod>2019-02-02</lastmod> <lastmod>2019-02-10</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc>None</loc> <loc>None</loc>
<lastmod>2019-02-02</lastmod> <lastmod>2019-02-10</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc>None</loc> <loc>None</loc>
<lastmod>2019-02-02</lastmod> <lastmod>2019-02-10</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc>None</loc> <loc>None</loc>
<lastmod>2019-02-02</lastmod> <lastmod>2019-02-10</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc>None</loc> <loc>None</loc>
<lastmod>2019-02-02</lastmod> <lastmod>2019-02-10</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc>None</loc> <loc>None</loc>
<lastmod>2019-02-02</lastmod> <lastmod>2019-02-10</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc>None</loc> <loc>None</loc>
<lastmod>2019-02-02</lastmod> <lastmod>2019-02-10</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc>None</loc> <loc>None</loc>
<lastmod>2019-02-02</lastmod> <lastmod>2019-02-10</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc>None</loc> <loc>None</loc>
<lastmod>2019-02-02</lastmod> <lastmod>2019-02-10</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
</urlset> </urlset>
\ No newline at end of file
No preview for this file type
...@@ -97,7 +97,7 @@ ...@@ -97,7 +97,7 @@
<li > <li >
<a href="../../user-guide/design-principle.md.md">Design Principle</a> <a href="../../user-guide/design-principle/">Design Principle</a>
</li> </li>
......
...@@ -97,7 +97,7 @@ ...@@ -97,7 +97,7 @@
<li > <li >
<a href="../../user-guide/design-principle.md.md">Design Principle</a> <a href="../../user-guide/design-principle/">Design Principle</a>
</li> </li>
...@@ -211,17 +211,26 @@ ...@@ -211,17 +211,26 @@
<div class="col-md-3"><div class="bs-sidebar hidden-print affix well" role="complementary"> <div class="col-md-3"><div class="bs-sidebar hidden-print affix well" role="complementary">
<ul class="nav bs-sidenav"> <ul class="nav bs-sidenav">
<li class="first-level active"><a href="#cap-options">Cap Options</a></li> <li class="first-level active"><a href="#_1">配置</a></li>
<li class="first-level "><a href="#rabbitmq-options">RabbitMQ Options</a></li> <li class="second-level"><a href="#cap-options">Cap Options</a></li>
<li class="first-level "><a href="#kafka-options">Kafka Options</a></li>
<li class="first-level "><a href="#entityframework-options">EntityFramework Options</a></li> <li class="second-level"><a href="#rabbitmq-options">RabbitMQ Options</a></li>
<li class="first-level "><a href="#sqlserver-options">SqlServer Options</a></li>
<li class="first-level "><a href="#mysql-options">MySql Options</a></li> <li class="second-level"><a href="#kafka-options">Kafka Options</a></li>
<li class="first-level "><a href="#postgresql-options">PostgreSql Options</a></li>
<li class="second-level"><a href="#entityframework-options">EntityFramework Options</a></li>
<li class="second-level"><a href="#sqlserver-options">SqlServer Options</a></li>
<li class="second-level"><a href="#mysql-options">MySql Options</a></li>
<li class="second-level"><a href="#postgresql-options">PostgreSql Options</a></li>
</ul> </ul>
</div></div> </div></div>
<div class="col-md-9" role="main"> <div class="col-md-9" role="main">
<h2 id="_1">配置</h2>
<p>CAP 使用 Microsoft.Extensions.DependencyInjection 进行配置的注入,你也可以依赖于 DI 从json文件中读取配置。</p> <p>CAP 使用 Microsoft.Extensions.DependencyInjection 进行配置的注入,你也可以依赖于 DI 从json文件中读取配置。</p>
<h3 id="cap-options">Cap Options</h3> <h3 id="cap-options">Cap Options</h3>
<p>你可以使用如下方式来配置 CAP 中的一些配置项,例如</p> <p>你可以使用如下方式来配置 CAP 中的一些配置项,例如</p>
......
...@@ -97,7 +97,7 @@ ...@@ -97,7 +97,7 @@
<li > <li >
<a href="../../user-guide/design-principle.md.md">Design Principle</a> <a href="../../user-guide/design-principle/">Design Principle</a>
</li> </li>
...@@ -211,19 +211,25 @@ ...@@ -211,19 +211,25 @@
<div class="col-md-3"><div class="bs-sidebar hidden-print affix well" role="complementary"> <div class="col-md-3"><div class="bs-sidebar hidden-print affix well" role="complementary">
<ul class="nav bs-sidenav"> <ul class="nav bs-sidenav">
<li class="first-level active"><a href="#_1">动机</a></li> <li class="first-level active"><a href="#_1">设计原理</a></li>
<li class="first-level "><a href="#_2">持久化</a></li> <li class="second-level"><a href="#_2">动机</a></li>
<li class="first-level "><a href="#_3">通讯数据流</a></li>
<li class="first-level "><a href="#_4">一致性</a></li> <li class="second-level"><a href="#_3">持久化</a></li>
<li class="second-level"><a href="#_4">通讯数据流</a></li>
<li class="second-level"><a href="#_5">一致性</a></li>
</ul> </ul>
</div></div> </div></div>
<div class="col-md-9" role="main"> <div class="col-md-9" role="main">
<h3 id="_1">动机</h3> <h2 id="_1">设计原理</h2>
<h3 id="_2">动机</h3>
<p>随着微服务架构的流行,越来越多的人在尝试使用微服务来架构他们的系统,而在这其中我们会遇到例如分布式事务的问题,为了解决这些问题,我没有发现简单并且易于使用的解决方案,所以我决定来打造这样一个库来解决这个问题。</p> <p>随着微服务架构的流行,越来越多的人在尝试使用微服务来架构他们的系统,而在这其中我们会遇到例如分布式事务的问题,为了解决这些问题,我没有发现简单并且易于使用的解决方案,所以我决定来打造这样一个库来解决这个问题。</p>
<p>最初 CAP 是为了解决分布式系统中的事务问题,她采用的是 异步确保 这种弱一致性事务机制实现了分布式事务的最终一致性,更多这方面的信息可以查看第6节。</p> <p>最初 CAP 是为了解决分布式系统中的事务问题,她采用的是 异步确保 这种弱一致性事务机制实现了分布式事务的最终一致性,更多这方面的信息可以查看第6节。</p>
<p>现在 CAP 除了解决分布式事务的问题外,她另外一个重要的功能就是作为 EventBus 来使用,她具有 EventBus 的所有功能,并且提供了更加简化的方式来处理EventBus中的发布/订阅。</p> <p>现在 CAP 除了解决分布式事务的问题外,她另外一个重要的功能就是作为 EventBus 来使用,她具有 EventBus 的所有功能,并且提供了更加简化的方式来处理EventBus中的发布/订阅。</p>
<h3 id="_2">持久化</h3> <h3 id="_3">持久化</h3>
<p>CAP 依靠本地数据库实现消息的持久化,CAP 使用这种方式来应对一切环境或者网络异常导致消息丢失的情况,消息的可靠性是分布式事务的基石,所以在任何情况下消息都不能丢失。</p> <p>CAP 依靠本地数据库实现消息的持久化,CAP 使用这种方式来应对一切环境或者网络异常导致消息丢失的情况,消息的可靠性是分布式事务的基石,所以在任何情况下消息都不能丢失。</p>
<p>对于消息的持久化分为两种:</p> <p>对于消息的持久化分为两种:</p>
<p><strong>① 消息进入消息队列之前的持久化</strong></p> <p><strong>① 消息进入消息队列之前的持久化</strong></p>
...@@ -233,7 +239,7 @@ ...@@ -233,7 +239,7 @@
<p>消息进入到消息队列之后,CAP会启动消息队列的持久化功能,我们需要说明一下在 RabbitMQ 和 Kafka 中CAP的消息是如何持久化的。</p> <p>消息进入到消息队列之后,CAP会启动消息队列的持久化功能,我们需要说明一下在 RabbitMQ 和 Kafka 中CAP的消息是如何持久化的。</p>
<p>针对于 RabbitMQ 中的消息持久化,CAP 使用的是具有消息持久化功能的消费者队列,但是这里面可能有例外情况,参加 2.2.1 章节。</p> <p>针对于 RabbitMQ 中的消息持久化,CAP 使用的是具有消息持久化功能的消费者队列,但是这里面可能有例外情况,参加 2.2.1 章节。</p>
<p>由于 Kafka 天生设计的就是使用文件进行的消息持久化,在所以在消息进入到Kafka之后,Kafka会保证消息能够正确被持久化而不丢失。</p> <p>由于 Kafka 天生设计的就是使用文件进行的消息持久化,在所以在消息进入到Kafka之后,Kafka会保证消息能够正确被持久化而不丢失。</p>
<h3 id="_3">通讯数据流</h3> <h3 id="_4">通讯数据流</h3>
<p>CAP 中消息的流转过程大致如下:</p> <p>CAP 中消息的流转过程大致如下:</p>
<p><strong>2.2版本以前</strong> </p> <p><strong>2.2版本以前</strong> </p>
<p><img alt="" src="http://images2017.cnblogs.com/blog/250417/201708/250417-20170803174645928-1813351415.png" /></p> <p><img alt="" src="http://images2017.cnblogs.com/blog/250417/201708/250417-20170803174645928-1813351415.png" /></p>
...@@ -242,7 +248,7 @@ ...@@ -242,7 +248,7 @@
</blockquote> </blockquote>
<p><strong>2.2版本以后</strong></p> <p><strong>2.2版本以后</strong></p>
<p>在2.2以后的版本中,我们调整了一些消息的流转流程,我们移除了数据库中的 Queue 表使用内存队列来代替,详情见:<a href="https://github.com/dotnetcore/CAP/issues/96">Improve the implementation mechanism of queue mode</a></p> <p>在2.2以后的版本中,我们调整了一些消息的流转流程,我们移除了数据库中的 Queue 表使用内存队列来代替,详情见:<a href="https://github.com/dotnetcore/CAP/issues/96">Improve the implementation mechanism of queue mode</a></p>
<h3 id="_4">一致性</h3> <h3 id="_5">一致性</h3>
<p>CAP 采用最终一致性作为的一致性方案,此方案是遵循 CAP 理论,以下是CAP理论的描述。</p> <p>CAP 采用最终一致性作为的一致性方案,此方案是遵循 CAP 理论,以下是CAP理论的描述。</p>
<p>C(一致性)一致性是指数据的原子性,在经典的数据库中通过事务来保障,事务完成时,无论成功或回滚,数据都会处于一致的状态,在分布式环境下,一致性是指多个节点数据是否一致;</p> <p>C(一致性)一致性是指数据的原子性,在经典的数据库中通过事务来保障,事务完成时,无论成功或回滚,数据都会处于一致的状态,在分布式环境下,一致性是指多个节点数据是否一致;</p>
<p>A(可用性)服务一直保持可用的状态,当用户发出一个请求,服务能在一定的时间内返回结果;</p> <p>A(可用性)服务一直保持可用的状态,当用户发出一个请求,服务能在一定的时间内返回结果;</p>
......
...@@ -97,7 +97,7 @@ ...@@ -97,7 +97,7 @@
<li > <li >
<a href="../../user-guide/design-principle.md.md">Design Principle</a> <a href="../../user-guide/design-principle/">Design Principle</a>
</li> </li>
......
...@@ -97,7 +97,7 @@ ...@@ -97,7 +97,7 @@
<li > <li >
<a href="../../user-guide/design-principle.md.md">Design Principle</a> <a href="../../user-guide/design-principle/">Design Principle</a>
</li> </li>
......
...@@ -97,7 +97,7 @@ ...@@ -97,7 +97,7 @@
<li > <li >
<a href="../../user-guide/design-principle.md.md">Design Principle</a> <a href="../../user-guide/design-principle/">Design Principle</a>
</li> </li>
......
...@@ -97,7 +97,7 @@ ...@@ -97,7 +97,7 @@
<li > <li >
<a href="../../user-guide/design-principle.md.md">Design Principle</a> <a href="../../user-guide/design-principle/">Design Principle</a>
</li> </li>
...@@ -276,7 +276,7 @@ ...@@ -276,7 +276,7 @@
</tr> </tr>
<tr> <tr>
<td align="left">Added</td> <td align="left">Added</td>
<td align="left"> 创建时间</td> <td align="left">创建时间</td>
<td align="left">DateTime</td> <td align="left">DateTime</td>
</tr> </tr>
<tr> <tr>
......
...@@ -97,7 +97,7 @@ ...@@ -97,7 +97,7 @@
<li > <li >
<a href="../design-principle.md.md">Design Principle</a> <a href="../design-principle/">Design Principle</a>
</li> </li>
...@@ -212,19 +212,19 @@ ...@@ -212,19 +212,19 @@
<div class="col-md-3"><div class="bs-sidebar hidden-print affix well" role="complementary"> <div class="col-md-3"><div class="bs-sidebar hidden-print affix well" role="complementary">
<ul class="nav bs-sidenav"> <ul class="nav bs-sidenav">
<li class="first-level active"><a href="#interfaces">Interfaces</a></li> <li class="first-level active"><a href="#interfaces">Interfaces</a></li>
<li class="second-level"><a href="#publishsend">Publish/Send</a></li> <li class="second-level"><a href="#publish-send">Publish &amp; Send</a></li>
<li class="third-level"><a href="#transactions">Transactions</a></li> <li class="third-level"><a href="#transactions">Transactions</a></li>
<li class="second-level"><a href="#subscribeconsume">Subscribe/Consume</a></li> <li class="second-level"><a href="#subscribe-consume">Subscribe &amp; Consume</a></li>
<li class="third-level"><a href="#exceptional-case">Exceptional case</a></li> <li class="third-level"><a href="#exceptional-case">Exceptional case</a></li>
</ul> </ul>
</div></div> </div></div>
<div class="col-md-9" role="main"> <div class="col-md-9" role="main">
<h2 id="interfaces">Interfaces</h2> <h1 id="interfaces">Interfaces</h1>
<p>CAP only has one interface,It is <code>ICapPublisher</code>,You can get its instance from the DI container and then call it.</p> <p>CAP only has one interface,It is <code>ICapPublisher</code>, You can get its instance from the DI container and then call it.</p>
<h3 id="publishsend">Publish/Send</h3> <h2 id="publish-send">Publish &amp; Send</h2>
<p>You can use the <code>Publish&lt;T&gt;</code> or <code>PublishAsync&lt;T&gt;</code> methods defined in the <code>ICapPublisher</code> interface to send the event messages.</p> <p>You can use the <code>Publish&lt;T&gt;</code> or <code>PublishAsync&lt;T&gt;</code> methods defined in the <code>ICapPublisher</code> interface to send the event messages.</p>
<pre><code class="cs">public class PublishController : Controller <pre><code class="cs">public class PublishController : Controller
{ {
...@@ -264,26 +264,30 @@ ...@@ -264,26 +264,30 @@
return Ok(); return Ok();
} }
} }
</code></pre> </code></pre>
<p>The following is the signature of the of the PublishAsync method</p> <p>The following is the signature of the of the PublishAsync method</p>
<p><strong><code>PublishAsync&lt;T&gt;(string name,T object)</code></strong></p> <pre><code class="cs">PublishAsync&lt;T&gt;(string name, T object)
</code></pre>
<p>By default,when this method(PublishAsync<T>) is called,CAP will create a transaction internally, <p>By default,when this method(PublishAsync<T>) is called,CAP will create a transaction internally,
and then write messages into the <code>Cap.Published</code> message table.</p> and then write messages into the <code>Cap.Published</code> message table.</p>
<p>In some situations,you may need a callback when a message is sent out, you can use the follwing <p>In some situations,you may need a callback when a message is sent out, you can use the follwing
overload of the <code>PublishAsync&lt;T&gt;</code> method:</p> overload of the <code>PublishAsync&lt;T&gt;</code> method:</p>
<p><strong><code>PublishAsync&lt;T&gt;(string name,T object, string callBackName)</code></strong></p> <pre><code class="cs">PublishAsync&lt;T&gt;(string name, T object, string callBackName)
<p>In this overload method,<code>callbackName</code> is the callback name of the subscription method,when the consumption-side finished processing messages,CAP will return the processed result and also call the specified subscription method</p> </code></pre>
<h4 id="transactions">Transactions</h4>
<p>In this overload method, <code>callbackName</code> is the callback name of the subscription method,when the consumption-side finished processing messages,CAP will return the processed result and also call the specified subscription method</p>
<h3 id="transactions">Transactions</h3>
<p>Transaction plays a very import role in CAP, It is a main factor to ensure the reliability of messaging. </p> <p>Transaction plays a very import role in CAP, It is a main factor to ensure the reliability of messaging. </p>
<p>In the process of sending a message to the message queue without transaction we can not ensure that messages are sent to the message queue successfully after we finish dealing the business logic,or messages are send to the message queque successfully but our bussiness logic is failed.</p> <p>In the process of sending a message to the message queue without transaction we can not ensure that messages are sent to the message queue successfully after we finish dealing the business logic,or messages are send to the message queque successfully but our bussiness logic is failed.</p>
<p>There is a variety of reasons that causing failure,eg:connection errors,network errors,etc.</p> <p>There is a variety of reasons that causing failure,eg:connection errors,network errors,etc.</p>
<p><em>Only by putting the business logic and logic in the Publish of CAP in the same transaction so that we can enssure both them to be success or fail</em></p> <div class="admonition note">
<p class="admonition-title">Note</p>
<p>Only by putting the business logic and logic in the Publish of CAP in the same transaction so that we can enssure both them to be success or fail</p>
</div>
<p>The following two blocks of code snippet demonstrate how to use transactions in EntityFramework and dapper when publishing messages.</p> <p>The following two blocks of code snippet demonstrate how to use transactions in EntityFramework and dapper when publishing messages.</p>
<ul> <h4 id="entityframework">EntityFramework</h4>
<li>EntityFramework</li>
</ul>
<pre><code class="cs"> using (var trans = dbContext.Database.BeginTransaction(_capBus, autoCommit: false) <pre><code class="cs"> using (var trans = dbContext.Database.BeginTransaction(_capBus, autoCommit: false)
{ {
// Your business logic。 // Your business logic。
...@@ -298,9 +302,7 @@ overload of the <code>PublishAsync&lt;T&gt;</code> method:</p> ...@@ -298,9 +302,7 @@ overload of the <code>PublishAsync&lt;T&gt;</code> method:</p>
<p>When you set the <code>autoCommit: false</code>, you can put your business logic before or after the Publish logic,the only thing you need to do is to ensure that they are in the same transaction.</p> <p>When you set the <code>autoCommit: false</code>, you can put your business logic before or after the Publish logic,the only thing you need to do is to ensure that they are in the same transaction.</p>
<p>If you set the <code>autoCommit: true</code>, you need publish message <code>_capBus.Publish</code> at the last.</p> <p>If you set the <code>autoCommit: true</code>, you need publish message <code>_capBus.Publish</code> at the last.</p>
<p>During the course,the message content will be serialized as json and stored in the message table.</p> <p>During the course,the message content will be serialized as json and stored in the message table.</p>
<ul> <h4 id="dapper">Dapper</h4>
<li>Dapper</li>
</ul>
<pre><code class="cs">using (var connection = new MySqlConnection(ConnectionString)) <pre><code class="cs">using (var connection = new MySqlConnection(ConnectionString))
{ {
using (var transaction = connection.BeginTransaction(_capBus, autoCommit: false)) using (var transaction = connection.BeginTransaction(_capBus, autoCommit: false))
...@@ -313,47 +315,44 @@ overload of the <code>PublishAsync&lt;T&gt;</code> method:</p> ...@@ -313,47 +315,44 @@ overload of the <code>PublishAsync&lt;T&gt;</code> method:</p>
transaction.Commit(); transaction.Commit();
} }
} }
</code></pre> </code></pre>
<h3 id="subscribeconsume">Subscribe/Consume</h3> <h2 id="subscribe-consume">Subscribe &amp; Consume</h2>
<p><strong>NOTE: The businsess logics in the subscription side should be keep idempotent.</strong></p> <div class="admonition warning">
<p class="admonition-title">Warning</p>
<p>The businsess logics in the subscription side should be keep idempotent.</p>
<p>You can view more details in this <a href="https://github.com/dotnetcore/CAP/issues/29#issuecomment-451841287">ISSUE</a>.</p>
</div>
<p>Use <code>CapSubscribe[""]</code> to decorate a method so that it can subscribe messages published by CAP.</p> <p>Use <code>CapSubscribe[""]</code> to decorate a method so that it can subscribe messages published by CAP.</p>
<pre><code>[CapSubscribe(&quot;xxx.services.bar&quot;)] <pre><code class="cs">[CapSubscribe(&quot;xxx.services.bar&quot;)]
public void BarMessageProcessor() public void BarMessageProcessor()
{ {
} }
</code></pre> </code></pre>
<p>You can also use multiple <code>CapSubscribe[""]</code> to decorate a method so that you can subscribe messages from different sources accordingly.</p> <p>You can also use multiple <code>CapSubscribe[""]</code> to decorate a method so that you can subscribe messages from different sources accordingly.</p>
<pre><code>[CapSubscribe(&quot;xxx.services.bar&quot;)] <pre><code class="cs">[CapSubscribe(&quot;xxx.services.bar&quot;)]
[CapSubscribe(&quot;xxx.services.foo&quot;)] [CapSubscribe(&quot;xxx.services.foo&quot;)]
public void BarAndFooMessageProcessor() public void BarAndFooMessageProcessor()
{ {
} }
</code></pre> </code></pre>
<p><code>xxx.services.bar</code> is the name of the message to be subscribed.And it has different name in different message queque Clients.for example,in kafka the name is called Topic Name and in RAbbitMQ it is called RouteKey.</p> <p><code>xxx.services.bar</code> is the name of the message to be subscribed.And it has different name in different message queque Clients.for example,in kafka the name is called Topic Name and in RAbbitMQ it is called RouteKey.</p>
<p>In RabbitMQ you can use regular expression in RouteKey:
<blockquote> <blockquote>
<p>In RabbitMQ you can use regular expression in RouteKey:</p> <p> <cite title="Source Title">*</cite> (Asterisk) stands for a single word.</p>
<p>*(Asterisk)stands for a single word.</p> <p> <cite title="Source Title">#</cite> (hash sign) standards for zero or more words.</p>
<p># (hash sign) standards for zero or more words.</p> <p class="small">See the following picture(P for Publisher,X for Exchange,C for consumer and Q for Queue)</p>
<p>See the following picture(P for Publisher,X for Exchange,C for consumer and Q for Queue)</p> <p><image src='../../img/rabbitmq-route.png'></image></p>
<p><img alt="" src="http://images2017.cnblogs.com/blog/250417/201708/250417-20170807093230268-283915002.png" /></p> <p class="small">In this example, we're going to send messages which all describe animals. The messages will be sent with a routing key that consists of three words (two dots). The first word in the routing key will describe a celerity, second a colour and third a species: "<celerity>.<colour>.<species>".</p>
<p>In this example, we're going to send messages which all describe animals. The messages will be sent with a routing key that consists of three words (two dots). The first word in the routing key will describe a celerity, second a colour and third a species: "<celerity>.<colour>.<species>".</p> <p class="small">We created three bindings: Q1 is bound with binding key "<em>.orange.</em>" and Q2 with "<em>.</em>.rabbit" and "lazy.#".</p>
<p>We created three bindings: Q1 is bound with binding key "<em>.orange.</em>" and Q2 with "<em>.</em>.rabbit" and "lazy.#".</p> <p class="small">These bindings can be summarised as:</p>
<p>These bindings can be summarised as:</p> <p class="small">Q1 is interested in all the orange animals.Q2 wants to hear everything about rabbits, and everything about lazy animals.A message with a routing key set to "quick.orange.rabbit" will be delivered to both queues. Message "lazy.orange.elephant" also will go to both of them. On the other hand "quick.orange.fox" will only go to the first queue, and "lazy.brown.fox" only to the second. "lazy.pink.rabbit" will be delivered to the second queue only once, even though it matches two bindings. "quick.brown.fox" doesn't match any binding so it will be discarded.</p>
<p>Q1 is interested in all the orange animals. <p class="small">What happens if we break our contract and send a message with one or four words, like "orange" or "quick.orange.male.rabbit"? Well, these messages won't match any bindings and will be lost.</p>
Q2 wants to hear everything about rabbits, and everything about lazy animals. <p class="small">On the other hand "lazy.orange.male.rabbit", even though it has four words, will match the last binding and will be delivered to the second queue.</p>
A message with a routing key set to "quick.orange.rabbit" will be delivered to both queues. Message "lazy.orange.elephant" also will go to both of them. On the other hand "quick.orange.fox" will only go to the first queue, and "lazy.brown.fox" only to the second. "lazy.pink.rabbit" will be delivered to the second queue only once, even though it matches two bindings. "quick.brown.fox" doesn't match any binding so it will be discarded.</p> </blockquote></p>
<p>What happens if we break our contract and send a message with one or four words, like "orange" or "quick.orange.male.rabbit"? Well, these messages won't match any bindings and will be lost.</p> <p>In CAP, we called a method decorated by <code>CapSubscribe[]</code> a <strong>subscriber</strong>, you can group different subscribers.</p>
<p>On the other hand "lazy.orange.male.rabbit", even though it has four words, will match the last binding and will be delivered to the second queue.</p>
</blockquote>
<p>In CAP,we called a method decorated by <code>CapSubscribe[]</code> a <strong>subscriber</strong>,you can group different subscribers.</p>
<p><strong>Group</strong> is a collection of subscribers,each group can have one or multiple consumers,but a subscriber can only belongs to a certain group(you can not put a subscriber into multiple groups).Messages subscribed by members in a certain group can only be consumed once.</p> <p><strong>Group</strong> is a collection of subscribers,each group can have one or multiple consumers,but a subscriber can only belongs to a certain group(you can not put a subscriber into multiple groups).Messages subscribed by members in a certain group can only be consumed once.</p>
<p>If you do not specify any group when subscribing,CAP will put the subscriber into a default group named <code>cap.default.group</code></p> <p>If you do not specify any group when subscribing,CAP will put the subscriber into a default group named <code>cap.default.group</code></p>
<p>the following is a demo shows how to use group when subscribing.</p> <p>the following is a demo shows how to use group when subscribing.</p>
...@@ -365,16 +364,22 @@ public void FooMessageProcessor() ...@@ -365,16 +364,22 @@ public void FooMessageProcessor()
</code></pre> </code></pre>
<h4 id="exceptional-case">Exceptional case</h4> <h3 id="exceptional-case">Exceptional case</h3>
<p>The following situations you shoud be aware of.</p> <p>The following situations you shoud be aware of.</p>
<p><strong>① the subscription side has not started yet when publishing a message</strong></p> <p><strong>① the subscription side has not started yet when publishing a message</strong></p>
<p>Kafka:</p> <h4 id="kafka">Kafka:</h4>
<p>In Kafka,published messages stored in the Persistent log files,so messages will not lost.when the subscription side started,it can still consume the message.</p> <p>In Kafka,published messages stored in the Persistent log files,so messages will not lost.when the subscription side started,it can still consume the message.</p>
<p>RabbitMQ:</p> <h4 id="rabbitmq">RabbitMQ:</h4>
<p>In RabbitMQ,the application will create Persistent Exchange and Queue at the <strong>first start</strong>,CAP will create a new consumer queue for each consumer group,<strong>because the application started but the subscription side hasn's start yet so there has no queue,thus the message can not be persited,and the published messages will lost</strong></p> <p>In RabbitMQ, the application will create Persistent Exchange and Queue at the <strong>first start</strong>, CAP will create a new consumer queue for each consumer group,<strong>because the application started but the subscription side hasn's start yet so there has no queue,thus the message can not be persited,and the published messages will lost</strong></p>
<p>There are two ways to solve this <code>message lost</code> issue in RamitMQ:</p> <p>There are two ways to solve this <code>message lost</code> issue in RamitMQ:</p>
<p>i.Before the deployment of your application,you can create durable Exchange and Queue in RabbitMQ by hand,the default names them are (cap.default.topic, cap.default.group).</p> <ul>
<p>ii.Run all instances in advance to ensure that both Exchange and Queue are initialized.</p> <li>
<p>Before the deployment of your application,you can create durable Exchange and Queue in RabbitMQ by hand,the default names them are (cap.default.topic, cap.default.group).</p>
</li>
<li>
<p>Run all instances in advance to ensure that both Exchange and Queue are initialized.</p>
</li>
</ul>
<p>It is highly recommanded that users adopt the second way,because it is easier to achieve.</p></div> <p>It is highly recommanded that users adopt the second way,because it is easier to achieve.</p></div>
......
...@@ -97,7 +97,7 @@ ...@@ -97,7 +97,7 @@
<li > <li >
<a href="../design-principle.md.md">Design Principle</a> <a href="../design-principle/">Design Principle</a>
</li> </li>
...@@ -194,7 +194,7 @@ ...@@ -194,7 +194,7 @@
</a> </a>
</li> </li>
<li > <li >
<a rel="prev" href="../implementation-mechanisms/"> <a rel="prev" href="../design-principle/">
Next <i class="fas fa-arrow-right"></i> Next <i class="fas fa-arrow-right"></i>
</a> </a>
</li> </li>
...@@ -211,17 +211,26 @@ ...@@ -211,17 +211,26 @@
<div class="col-md-3"><div class="bs-sidebar hidden-print affix well" role="complementary"> <div class="col-md-3"><div class="bs-sidebar hidden-print affix well" role="complementary">
<ul class="nav bs-sidenav"> <ul class="nav bs-sidenav">
<li class="first-level active"><a href="#cap-options">Cap Options</a></li> <li class="first-level active"><a href="#configuration">Configuration</a></li>
<li class="first-level "><a href="#rabbitmq-options">RabbitMQ Options</a></li> <li class="second-level"><a href="#cap-options">Cap Options</a></li>
<li class="first-level "><a href="#kafka-options">Kafka Options</a></li>
<li class="first-level "><a href="#entityframework-options">EntityFramework Options</a></li> <li class="second-level"><a href="#rabbitmq-options">RabbitMQ Options</a></li>
<li class="first-level "><a href="#sqlserver-options">SqlServer Options</a></li>
<li class="first-level "><a href="#mysql-options">MySql Options</a></li> <li class="second-level"><a href="#kafka-options">Kafka Options</a></li>
<li class="first-level "><a href="#postgresql-options">PostgreSql Options</a></li>
<li class="second-level"><a href="#entityframework-options">EntityFramework Options</a></li>
<li class="second-level"><a href="#sqlserver-options">SqlServer Options</a></li>
<li class="second-level"><a href="#mysql-options">MySql Options</a></li>
<li class="second-level"><a href="#postgresql-options">PostgreSql Options</a></li>
</ul> </ul>
</div></div> </div></div>
<div class="col-md-9" role="main"> <div class="col-md-9" role="main">
<h2 id="configuration">Configuration</h2>
<p>CAP uses Microsoft.Extensions.DependencyInjection for configuration injection. </p> <p>CAP uses Microsoft.Extensions.DependencyInjection for configuration injection. </p>
<h3 id="cap-options">Cap Options</h3> <h3 id="cap-options">Cap Options</h3>
<p>You can use the following methods to configure some configuration items in the CAP, for example:</p> <p>You can use the following methods to configure some configuration items in the CAP, for example:</p>
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
<link rel="shortcut icon" href="../../img/favicon.ico"> <link rel="shortcut icon" href="../../img/favicon.ico">
<title>Design principle - CAP</title> <title>Design Principle - CAP</title>
<link rel="stylesheet" href="//use.fontawesome.com/releases/v5.5.0/css/all.css" integrity="sha384-B4dIYHKNBt8Bc12p+WXckhzcICo0wtJAoU8YZTY5qE0Id1GSseTk6S+L3BlXeVIU" crossorigin="anonymous"> <link rel="stylesheet" href="//use.fontawesome.com/releases/v5.5.0/css/all.css" integrity="sha384-B4dIYHKNBt8Bc12p+WXckhzcICo0wtJAoU8YZTY5qE0Id1GSseTk6S+L3BlXeVIU" crossorigin="anonymous">
...@@ -73,7 +73,7 @@ ...@@ -73,7 +73,7 @@
<li class="dropdown"> <li class="dropdown active">
<a href="#" class="dropdown-toggle" data-toggle="dropdown"><img src="https://www.countryflags.io/us/flat/16.png">User Guide <b class="caret"></b></a> <a href="#" class="dropdown-toggle" data-toggle="dropdown"><img src="https://www.countryflags.io/us/flat/16.png">User Guide <b class="caret"></b></a>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
...@@ -96,8 +96,8 @@ ...@@ -96,8 +96,8 @@
<li > <li class="active">
<a href="../design-principle.md.md">Design Principle</a> <a href="./">Design Principle</a>
</li> </li>
...@@ -188,6 +188,16 @@ ...@@ -188,6 +188,16 @@
<i class="fas fa-search"></i> Search <i class="fas fa-search"></i> Search
</a> </a>
</li> </li>
<li >
<a rel="next" href="../configuration/">
<i class="fas fa-arrow-left"></i> Previous
</a>
</li>
<li >
<a rel="prev" href="../implementation-mechanisms/">
Next <i class="fas fa-arrow-right"></i>
</a>
</li>
<li> <li>
<a href="https://github.com/dotnetcore/CAP/edit/master/docs/user-guide/design-principle.md"><i class="fab fa-github"></i> Edit on GitHub</a> <a href="https://github.com/dotnetcore/CAP/edit/master/docs/user-guide/design-principle.md"><i class="fab fa-github"></i> Edit on GitHub</a>
</li> </li>
...@@ -201,14 +211,20 @@ ...@@ -201,14 +211,20 @@
<div class="col-md-3"><div class="bs-sidebar hidden-print affix well" role="complementary"> <div class="col-md-3"><div class="bs-sidebar hidden-print affix well" role="complementary">
<ul class="nav bs-sidenav"> <ul class="nav bs-sidenav">
<li class="first-level active"><a href="#motivation">Motivation</a></li> <li class="first-level active"><a href="#design-principle">Design Principle</a></li>
<li class="first-level "><a href="#persistence">Persistence</a></li> <li class="second-level"><a href="#motivation">Motivation</a></li>
<li class="first-level "><a href="#communication-data-streams">Communication Data Streams</a></li>
<li class="first-level "><a href="#consistency">Consistency</a></li> <li class="second-level"><a href="#persistence">Persistence</a></li>
<li class="second-level"><a href="#communication-data-streams">Communication Data Streams</a></li>
<li class="second-level"><a href="#consistency">Consistency</a></li>
</ul> </ul>
</div></div> </div></div>
<div class="col-md-9" role="main"> <div class="col-md-9" role="main">
<h2 id="design-principle">Design Principle</h2>
<h3 id="motivation">Motivation</h3> <h3 id="motivation">Motivation</h3>
<p>With the popularity of microservices architecture, more and more people are trying to use microservices to architect their systems. In this we encounter problems such as distributed transactions. To solve these problems, I did not find simplicity and Easy to use solution, so I decided to create such a library to solve this problem.</p> <p>With the popularity of microservices architecture, more and more people are trying to use microservices to architect their systems. In this we encounter problems such as distributed transactions. To solve these problems, I did not find simplicity and Easy to use solution, so I decided to create such a library to solve this problem.</p>
<p>The original CAP was to solve the transaction problems in the distributed system. She used asynchronous to ensure that this weak consistency transaction mechanism achieved the eventual consistency of the distributed transaction. For more information, see section 6.</p> <p>The original CAP was to solve the transaction problems in the distributed system. She used asynchronous to ensure that this weak consistency transaction mechanism achieved the eventual consistency of the distributed transaction. For more information, see section 6.</p>
......
...@@ -97,7 +97,7 @@ ...@@ -97,7 +97,7 @@
<li > <li >
<a href="../design-principle.md.md">Design Principle</a> <a href="../design-principle/">Design Principle</a>
</li> </li>
......
...@@ -97,7 +97,7 @@ ...@@ -97,7 +97,7 @@
<li > <li >
<a href="../design-principle.md.md">Design Principle</a> <a href="../design-principle/">Design Principle</a>
</li> </li>
......
...@@ -97,7 +97,7 @@ ...@@ -97,7 +97,7 @@
<li > <li >
<a href="../design-principle.md.md">Design Principle</a> <a href="../design-principle/">Design Principle</a>
</li> </li>
...@@ -212,51 +212,63 @@ ...@@ -212,51 +212,63 @@
<div class="col-md-3"><div class="bs-sidebar hidden-print affix well" role="complementary"> <div class="col-md-3"><div class="bs-sidebar hidden-print affix well" role="complementary">
<ul class="nav bs-sidenav"> <ul class="nav bs-sidenav">
<li class="first-level active"><a href="#introduction">Introduction</a></li> <li class="first-level active"><a href="#introduction">Introduction</a></li>
<li class="first-level "><a href="#usage-scenarios">Usage Scenarios</a></li> <li class="second-level"><a href="#usage-scenarios">Usage Scenarios</a></li>
<li class="first-level "><a href="#quick-start">Quick Start</a></li>
<li class="second-level"><a href="#quick-start">Quick Start</a></li>
<li class="third-level"><a href="#nuget-package">NuGet Package</a></li>
<li class="third-level"><a href="#startup-configuration">Startup Configuration</a></li>
<li class="third-level"><a href="#usage">Usage</a></li>
</ul> </ul>
</div></div> </div></div>
<div class="col-md-9" role="main"> <div class="col-md-9" role="main">
<h3 id="introduction">Introduction</h3> <h1 id="introduction">Introduction</h1>
<p>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.</p> <p>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.</p>
<h3 id="usage-scenarios">Usage Scenarios</h3> <h2 id="usage-scenarios">Usage Scenarios</h2>
<p>The usage scenarios of CAP mainly include the following two:</p> <p>The usage scenarios of CAP mainly include the following two:</p>
<ul> <div class="bs-callout bs-callout-primary">
<li>1.The scheme of eventual consistency in distributed transactions</li> <h4>1. The scheme of eventual consistency in distributed transactions</h4><br>
</ul> 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.
<p>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.</p> <br><br>
<p>Distributed transactions are an inevitable requirement in a distributed system, and the current solution for distributed transactions is nothing more than just a few. Before understanding the CAP's distributed transaction scenarios, you can read the following [Articles] (http://www.infoq.com/en/articles/solution-of-distributed-system-transaction-consistency).</p> Distributed transactions are an inevitable requirement in a distributed system, and the current solution for distributed transactions is nothing more than just a few. Before understanding the CAP's distributed transaction scenarios, you can read the following [Articles] (http://www.infoq.com/en/articles/solution-of-distributed-system-transaction-consistency).
<p>The CAP does not use the two-phase commit (2PC) transaction mechanism, but uses the classical message implementation of the local message table + MQ, which is also called asynchronous guarantee.</p> <br><br>
<ul> The CAP does not use the two-phase commit (2PC) transaction mechanism, but uses the classical message implementation of the local message table + MQ, which is also called asynchronous guarantee.
<li>2.Highly usable EventBus</li> </div>
</ul>
<p>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.</p> <div class="bs-callout bs-callout-primary">
<p>CAP implements the publish and subscribe method of EventBus, which has all the features of EventBus. This means that you can use CAPs just like EventBus. In addition, CAP's EventBus is highly available. What does this mean?</p> <h4>2. Highly usable EventBus</h4><br>
<p>The CAP uses the local message table to persist the messages in the EventBus. This ensures that the messages sent by the EventBus are reliable. When the message queue fails or fails, the messages are not lost.</p>
<h3 id="quick-start">Quick Start</h3> 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.
<ul> <br><br>
<li><strong>Reference NuGet Package</strong></li> CAP implements the publish and subscribe method of EventBus, which has all the features of EventBus. This means that you can use CAPs just like EventBus. In addition, CAP's EventBus is highly available. What does this mean?
</ul> <br><br>
The CAP uses the local message table to persist the messages in the EventBus. This ensures that the messages sent by the EventBus are reliable. When the message queue fails or fails, the messages are not lost.
</div>
<h2 id="quick-start">Quick Start</h2>
<h3 id="nuget-package">NuGet Package</h3>
<p>Use the following command to reference the CAP NuGet package:</p> <p>Use the following command to reference the CAP NuGet package:</p>
<pre><code>PM&gt; Install-Package DotNetCore.CAP <pre><code>PM&gt; Install-Package DotNetCore.CAP
</code></pre> </code></pre>
<p>According to the different types of message queues used, different extension packages are introduced:</p> <p>According to the different types of message queues used, different extension packages are introduced:</p>
<pre><code>PM&gt; Install-Package DotNetCore.CAP.RabbitMQ <pre><code>PM&gt; Install-Package DotNetCore.CAP.RabbitMQ
PM&gt; Install-Package DotNetCore.CAP.Kafka PM&gt; Install-Package DotNetCore.CAP.Kafka
</code></pre> </code></pre>
<p>According to the different types of databases used, different extension packages are introduced:</p> <p>According to the different types of databases used, different extension packages are introduced:</p>
<pre><code>PM&gt; Install-Package DotNetCore.CAP.SqlServer <pre><code>PM&gt; Install-Package DotNetCore.CAP.SqlServer
PM&gt; Install-Package DotNetCore.CAP.MySql PM&gt; Install-Package DotNetCore.CAP.MySql
PM&gt; Install-Package DotNetCore.CAP.PostgreSql PM&gt; Install-Package DotNetCore.CAP.PostgreSql
PM&gt; Install-Package DotNetCore.CAP.MongoDB PM&gt; Install-Package DotNetCore.CAP.MongoDB
</code></pre> </code></pre>
<ul> <h3 id="startup-configuration">Startup Configuration</h3>
<li><strong>Startup Configuration</strong></li>
</ul>
<p>In an ASP.NET Core program, you can configure the services used by the CAP in the <code>Startup.cs</code> file <code>ConfigureServices()</code>:</p> <p>In an ASP.NET Core program, you can configure the services used by the CAP in the <code>Startup.cs</code> file <code>ConfigureServices()</code>:</p>
<pre><code class="cs">public void ConfigureServices(IServiceCollection services) <pre><code class="cs">public void ConfigureServices(IServiceCollection services)
{ {
...@@ -268,7 +280,8 @@ PM&gt; Install-Package DotNetCore.CAP.MongoDB ...@@ -268,7 +280,8 @@ PM&gt; Install-Package DotNetCore.CAP.MongoDB
services.AddCap(x =&gt; services.AddCap(x =&gt;
{ {
// If you are using EF, you need to add the configuration: // If you are using EF, you need to add the configuration:
x.UseEntityFramework&lt;AppDbContext&gt;(); //Options, Notice: You don't need to config x.UseSqlServer(&quot;&quot;&quot;) again! CAP can autodiscovery. //Options, Notice: You don't need to config x.UseSqlServer(&quot;&quot;&quot;) again! CAP can autodiscovery.
x.UseEntityFramework&lt;AppDbContext&gt;();
// If you are using Ado.Net, you need to add the configuration: // If you are using Ado.Net, you need to add the configuration:
x.UseSqlServer(&quot;Your ConnectionStrings&quot;); x.UseSqlServer(&quot;Your ConnectionStrings&quot;);
...@@ -285,6 +298,98 @@ PM&gt; Install-Package DotNetCore.CAP.MongoDB ...@@ -285,6 +298,98 @@ PM&gt; Install-Package DotNetCore.CAP.MongoDB
x.UseKafka(&quot;localhost&quot;); x.UseKafka(&quot;localhost&quot;);
}); });
} }
</code></pre>
<h3 id="usage">Usage</h3>
<h4 id="publish">Publish</h4>
<p>Inject <code>ICapPublisher</code> in your Controller, then use the <code>ICapPublisher</code> to send message</p>
<pre><code class="c#">public class PublishController : Controller
{
private readonly ICapPublisher _capBus;
public PublishController(ICapPublisher capPublisher)
{
_capBus = capPublisher;
}
[Route(&quot;~/adonet/transaction&quot;)]
public IActionResult AdonetWithTransaction()
{
using (var connection = new MySqlConnection(ConnectionString))
{
using (var transaction = connection.BeginTransaction(_capBus, autoCommit: true))
{
//your business logic code
_capBus.Publish(&quot;xxx.services.show.time&quot;, DateTime.Now);
}
}
return Ok();
}
[Route(&quot;~/ef/transaction&quot;)]
public IActionResult EntityFrameworkWithTransaction([FromServices]AppDbContext dbContext)
{
using (var trans = dbContext.Database.BeginTransaction(_capBus, autoCommit: true))
{
//your business logic code
_capBus.Publish(&quot;xxx.services.show.time&quot;, DateTime.Now);
}
return Ok();
}
}
</code></pre>
<h4 id="subscribe">Subscribe</h4>
<p><strong>In Controller Action</strong></p>
<p>Add the Attribute <code>[CapSubscribe()]</code> on Action to subscribe message:</p>
<pre><code class="c#">public class PublishController : Controller
{
[CapSubscribe(&quot;xxx.services.show.time&quot;)]
public void CheckReceivedMessage(DateTime datetime)
{
Console.WriteLine(datetime);
}
}
</code></pre>
<p><strong>In Business Logic Service</strong></p>
<p>If your subscribe method is not in the Controller, the service class you need to Inheritance <code>ICapSubscribe</code>:</p>
<pre><code class="c#">
namespace BusinessCode.Service
{
public interface ISubscriberService
{
public void CheckReceivedMessage(DateTime datetime);
}
public class SubscriberService: ISubscriberService, ICapSubscribe
{
[CapSubscribe(&quot;xxx.services.show.time&quot;)]
public void CheckReceivedMessage(DateTime datetime)
{
}
}
}
</code></pre>
<p>Then inject your <code>ISubscriberService</code> class in <code>Startup.cs</code></p>
<pre><code class="c#">public void ConfigureServices(IServiceCollection services)
{
//Note: The injection of services needs before of `services.AddCap()`
services.AddTransient&lt;ISubscriberService,SubscriberService&gt;();
services.AddCap(x=&gt;
{
//...
});
}
</code></pre></div> </code></pre></div>
......
...@@ -97,7 +97,7 @@ ...@@ -97,7 +97,7 @@
<li > <li >
<a href="../design-principle.md.md">Design Principle</a> <a href="../design-principle/">Design Principle</a>
</li> </li>
...@@ -189,7 +189,7 @@ ...@@ -189,7 +189,7 @@
</a> </a>
</li> </li>
<li > <li >
<a rel="next" href="../configuration/"> <a rel="next" href="../design-principle/">
<i class="fas fa-arrow-left"></i> Previous <i class="fas fa-arrow-left"></i> Previous
</a> </a>
</li> </li>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment