<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Tharindu Lakshan</title>
    <description>The latest articles on DEV Community by Tharindu Lakshan (@coorayntl).</description>
    <link>https://dev.to/coorayntl</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F947488%2Fee6f985e-242c-43f9-8d21-9d31d00756e4.jpg</url>
      <title>DEV Community: Tharindu Lakshan</title>
      <link>https://dev.to/coorayntl</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/coorayntl"/>
    <language>en</language>
    <item>
      <title>Saga Orchestration in .NET with CQRS, Event Sourcing, Hydration &amp; Event Propagation</title>
      <dc:creator>Tharindu Lakshan</dc:creator>
      <pubDate>Mon, 08 Dec 2025 09:32:10 +0000</pubDate>
      <link>https://dev.to/coorayntl/saga-orchestration-in-net-with-cqrs-event-sourcing-hydration-event-propagation-2nof</link>
      <guid>https://dev.to/coorayntl/saga-orchestration-in-net-with-cqrs-event-sourcing-hydration-event-propagation-2nof</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxra1viaa9dt386p1377d.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxra1viaa9dt386p1377d.jpg" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  🧩 &lt;strong&gt;Saga Orchestration in .NET with CQRS, Event Sourcing, Hydration &amp;amp; Event Propagation&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;A beginner-friendly explanation&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Modern distributed systems often need to coordinate long-running workflows such as order processing, payment authorization, inventory reservation, and shipping. These workflows involve multiple microservices communicating asynchronously. To manage this safely, we use &lt;strong&gt;Sagas&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This article explains how Sagas work in .NET and how they combine naturally with &lt;strong&gt;CQRS&lt;/strong&gt;, &lt;strong&gt;Event Sourcing&lt;/strong&gt;, and &lt;strong&gt;event propagation&lt;/strong&gt; using tools like &lt;strong&gt;RabbitMQ&lt;/strong&gt; and &lt;strong&gt;MassTransit&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⭐ 1. What is a Saga?
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;Saga&lt;/strong&gt; is a pattern for managing &lt;strong&gt;long-running, multi-step business processes&lt;/strong&gt; that span multiple services.&lt;/p&gt;

&lt;p&gt;A Saga helps you coordinate a workflow like:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create Order&lt;/li&gt;
&lt;li&gt;Reserve Inventory&lt;/li&gt;
&lt;li&gt;Process Payment&lt;/li&gt;
&lt;li&gt;Arrange Shipment&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And it also defines &lt;strong&gt;compensation steps&lt;/strong&gt; when something fails:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If payment fails → release inventory&lt;/li&gt;
&lt;li&gt;If shipping fails → refund payment&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A Saga ensures the full workflow completes &lt;strong&gt;successfully&lt;/strong&gt;, or the system gracefully &lt;strong&gt;rolls back using compensating actions&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⭐ 2. How CQRS fits into a Saga
&lt;/h2&gt;

&lt;p&gt;CQRS splits the system into two sides:&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Write Side (Commands)&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Each step of a Saga is triggered by a &lt;strong&gt;command&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ReserveInventoryCommand&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ProcessPaymentCommand&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ShipOrderCommand&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Commands change state inside aggregates and generate events.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Read Side (Queries)&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The read side builds projections of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Saga state (current step, status)&lt;/li&gt;
&lt;li&gt;Order status&lt;/li&gt;
&lt;li&gt;Payment status&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This helps each service know what stage the workflow is in.&lt;/p&gt;

&lt;p&gt;CQRS gives clarity and removes the need for shared databases between services.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⭐ 3. How Event Sourcing supports a Saga
&lt;/h2&gt;

&lt;p&gt;With Event Sourcing, every state change is saved as an event:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;OrderCreated&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;InventoryReserved&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PaymentAuthorized&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ShipmentScheduled&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each event becomes a reliable message that the Saga listens to.&lt;/p&gt;

&lt;p&gt;The Saga then decides the &lt;strong&gt;next action&lt;/strong&gt; based on the event.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;OrderCreated → Start Saga → Send ReserveInventoryCommand
InventoryReserved → Send ProcessPaymentCommand
PaymentAuthorized → Send ShipOrderCommand
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If anything fails:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PaymentFailed → Send ReleaseInventoryCommand → Mark Saga as Failed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  ⭐ 4. Hydration: rebuilding Saga state when needed
&lt;/h2&gt;

&lt;p&gt;Because events are stored chronologically, the Saga can rebuild its state—this is called &lt;strong&gt;hydration&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;When a Saga instance loads:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;events&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;eventStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LoadStream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sagaId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;events&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;saga&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Apply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hydration ensures:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You don’t need to store complex Saga state in SQL&lt;/li&gt;
&lt;li&gt;The full workflow history is always available&lt;/li&gt;
&lt;li&gt;You can rebuild state anytime&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  ⭐ 5. Event Propagation: how services communicate
&lt;/h2&gt;

&lt;p&gt;After the write side stores events, they must be propagated so other services can react.&lt;/p&gt;

&lt;p&gt;There are &lt;strong&gt;two types of propagation&lt;/strong&gt;:&lt;/p&gt;

&lt;h3&gt;
  
  
  🔹 Internal propagation (inside same service)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Use MediatR Notifications&lt;/li&gt;
&lt;li&gt;Update projections&lt;/li&gt;
&lt;li&gt;Trigger in-process handlers&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🔹 External propagation (between microservices)
&lt;/h3&gt;

&lt;p&gt;Use messaging systems such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;MassTransit&lt;/strong&gt; (preferred in .NET; high-level abstraction)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;RabbitMQ&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Kafka&lt;/li&gt;
&lt;li&gt;Azure Service Bus&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Flow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Aggregate emits events&lt;/li&gt;
&lt;li&gt;Event store saves them&lt;/li&gt;
&lt;li&gt;Event Publisher sends them to exchanges/topics&lt;/li&gt;
&lt;li&gt;Other services/processes receive and react&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Example with RabbitMQ:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;bus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Publish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;InventoryReserved&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;orderId&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example with MassTransit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_publishEndpoint&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Publish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PaymentAuthorized&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;orderId&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These messages trigger the next command in the Saga.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⭐ 6. Saga Orchestration Flow (Simple Example)
&lt;/h2&gt;

&lt;p&gt;Let’s use a basic e-commerce workflow.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Step 1 — Order Created&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Saga starts&lt;/li&gt;
&lt;li&gt;Saga publishes &lt;code&gt;ReserveInventoryCommand&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Step 2 — Inventory Reserved&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Saga publishes &lt;code&gt;ProcessPaymentCommand&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Step 3 — Payment Authorized&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Saga publishes &lt;code&gt;ShipOrderCommand&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;If Something Fails&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Saga sends compensating commands:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ReleaseInventoryCommand&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CancelOrderCommand&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;RefundPaymentCommand&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;This ensures the system is always consistent.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⭐ 7. Saga State Machine (MassTransit Example)
&lt;/h2&gt;

&lt;p&gt;MassTransit offers built-in Saga state machine features.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OrderState&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;SagaStateMachineInstance&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Guid&lt;/span&gt; &lt;span class="n"&gt;CorrelationId&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;CurrentState&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Saga state machine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OrderSaga&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;MassTransitStateMachine&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;OrderState&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;State&lt;/span&gt; &lt;span class="n"&gt;InventoryReserved&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;State&lt;/span&gt; &lt;span class="n"&gt;PaymentCompleted&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Event&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;OrderCreated&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;OrderCreated&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;OrderSaga&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;InstanceState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CurrentState&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nf"&gt;Initially&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nf"&gt;When&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OrderCreated&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* start saga */&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TransitionTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;InventoryReserved&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Publish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ReserveInventoryCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OrderId&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;MassTransit handles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Saga persistence&lt;/li&gt;
&lt;li&gt;Message routing&lt;/li&gt;
&lt;li&gt;Correlation IDs&lt;/li&gt;
&lt;li&gt;Retries&lt;/li&gt;
&lt;li&gt;Error handling&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  ⭐ 8. Why use Saga + CQRS + ES together?
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Benefit&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Event Sourcing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Full history, hydration, audit trail&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;CQRS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Clean separation of writes/reads&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Saga&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Manage long workflows with compensation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;RabbitMQ/MassTransit&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Reliable async communication&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Event Propagation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Each service reacts without tight coupling&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;They form a strong pattern for distributed systems.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⭐ Final Summary
&lt;/h2&gt;

&lt;p&gt;Saga orchestration becomes powerful when combined with CQRS and Event Sourcing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;CQRS&lt;/strong&gt; handles clear separation of commands and queries&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Event Sourcing&lt;/strong&gt; makes state changes traceable and rebuildable&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hydration&lt;/strong&gt; recreates the saga state from events&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Event Propagation&lt;/strong&gt; uses RabbitMQ or MassTransit to connect microservices&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  * &lt;strong&gt;Sagas&lt;/strong&gt; coordinate multi-step workflows and ensure consistency through compensation
&lt;/h2&gt;




&lt;p&gt;&lt;strong&gt;Sample GitHub Project&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://github.com/CoorayNTL/MiniCommercePlatform" rel="noopener noreferrer"&gt;https://github.com/CoorayNTL/MiniCommercePlatform&lt;/a&gt;
&lt;/h2&gt;

</description>
    </item>
    <item>
      <title>Inversion of Control (IoC)</title>
      <dc:creator>Tharindu Lakshan</dc:creator>
      <pubDate>Thu, 05 Dec 2024 13:35:52 +0000</pubDate>
      <link>https://dev.to/coorayntl/inversion-of-control-ioc-explained-2lfa</link>
      <guid>https://dev.to/coorayntl/inversion-of-control-ioc-explained-2lfa</guid>
      <description>&lt;h2&gt;
  
  
  &lt;strong&gt;Explained&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Inversion of Control is a design principle where the flow of control in a system is inverted. This means that the control over the flow of execution is taken away from the user (developer) and is instead controlled by an external component (such as a framework or an IoC container).&lt;/p&gt;

&lt;p&gt;In simpler terms: Instead of the application controlling when and how various actions occur, the external framework or system controls the flow and triggers the necessary actions.&lt;/p&gt;

&lt;h3&gt;
  
  
  furthermore
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Inversion of Control (IoC or IOC) describes a system that follows the &lt;strong&gt;Hollywood Principle&lt;/strong&gt;. That is, the flow of control within the application is not controlled by the application itself, but rather by the underlying framework.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Code Example for IoC
&lt;/h3&gt;

&lt;p&gt;For this concept, let's look at a hypothetical task processor and task service. The task processor (&lt;code&gt;TaskProcessor&lt;/code&gt;) will get called in the main application to perform a task. Then, it will get an injected implementation of the interface, and it will call the &lt;code&gt;PerformTask()&lt;/code&gt; on the injected implementation. The task processor doesn't have a specific implementation in its code - it just knows that it needs an implementation that fulfills a specific interface. The main application is responsible for injecting in the specific implementation.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MainProgram is the starting participant that creates an instance of &lt;code&gt;TaskProcessor&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;TaskProcessor is activated, indicating that it is in the process of being executed.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;TaskProcessor&lt;/code&gt;then injects an instance of &lt;code&gt;ITaskService&lt;/code&gt;into itself, provided by MainProgram. In this example, it could be an instance of &lt;code&gt;TaskService&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;TaskProcessor calls the &lt;em&gt;PerformTask()&lt;/em&gt; method on the injected &lt;code&gt;ITaskService&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;TaskService is activated to execute the &lt;em&gt;PerformTask()&lt;/em&gt; method.
&lt;code&gt;TaskService&lt;/code&gt;returns the result to &lt;code&gt;TaskProcessor&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Finally, &lt;code&gt;TaskProcessor&lt;/code&gt;returns the result to MainProgram, and it is deactivated.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Flow of IoC&lt;br&gt;
Let's look at this situation with a sequence diagram.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9lxjs5lucmsh8bwiji30.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9lxjs5lucmsh8bwiji30.gif" alt="Image description" width="794" height="570"&gt;&lt;/a&gt;&lt;br&gt;
In this sequence diagram:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In this example:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;ITaskService&lt;/code&gt;is an interface representing a service with a PerformTask() method.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;TaskService&lt;/code&gt;is a concrete implementation of &lt;code&gt;ITaskService&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;TaskProcessor&lt;/code&gt;is a class that depends on &lt;code&gt;ITaskService&lt;/code&gt;. Instead of creating an instance of &lt;code&gt;TaskService&lt;/code&gt;within &lt;code&gt;TaskProcessor&lt;/code&gt;, it receives an instance of &lt;code&gt;ITaskService&lt;/code&gt;through constructor injection.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In the Main() method, an instance of &lt;code&gt;TaskService&lt;/code&gt;is created and passed to the constructor of &lt;code&gt;TaskProcessor&lt;/code&gt;. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The control flow is inverted because &lt;code&gt;TaskProcessor&lt;/code&gt;doesn't create or manage its dependencies; they are injected from the outside&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Code Sample of IoC&lt;br&gt;
This is a sample of what inversion of control could look like using &lt;code&gt;C#&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;using System;

// Interface defining the task service
public interface ITaskService
{
    string PerformTask(); 
}

// Concrete implementation of the task service
public class TaskService : ITaskService
{
    public string PerformTask()
    {
        // Task logic here
        return "Task completed";
    }
}

// Class that depends on ITaskService
public class TaskProcessor
{
    private readonly ITaskService taskService;

    // Constructor injection of the dependency
    public TaskProcessor(ITaskService taskService)
    {
        this.taskService = taskService;
    }

    public string ProcessTask()
    {
        // Using the injected dependency
        return taskService.PerformTask();
    }
}


class Program
{
    static void Main()
    {
        // Setting up the dependency manually (IoC container can replace this)
        ITaskService taskService = new TaskService();
        TaskProcessor taskProcessor = new TaskProcessor(taskService);

        // Using the TaskProcessor without worrying about creating its dependencies
        string result = taskProcessor.ProcessTask();
        Console.WriteLine(result);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  The Hollywood Principle
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyptl90i6exgpa1h6jtt4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyptl90i6exgpa1h6jtt4.png" alt="Image description" width="768" height="247"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;Hollywood Principle&lt;/strong&gt; is a key concept in software design, particularly in frameworks, where control &lt;strong&gt;over the flow of execution&lt;/strong&gt; is delegated to an external system. Instead of the developer's code explicitly dictating what happens and when, the system (framework, library, or container) decides the flow and invokes developer-defined methods or events as needed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This principle closely relates to the Dependency Inversion Principle (DIP) and emphasizes Inversion of Control (IoC)&lt;/strong&gt;, where high-level code does not depend on low-level details but instead interacts through abstractions.&lt;/p&gt;

&lt;h4&gt;
  
  
  Key Characteristics
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Event-Driven Programming&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Code responds to external events (like HTTP requests, button clicks, or lifecycle hooks).&lt;/li&gt;
&lt;li&gt;The developer provides methods or handlers that are triggered by the system at the appropriate times.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Control Delegation&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The framework owns the execution flow, and the developer writes code to plug into predefined hooks or events.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Decouples&lt;/strong&gt;: application logic from the underlying execution mechanism, enabling flexibility, reusability, and extensibility.&lt;/p&gt;

&lt;h4&gt;
  
  
  Example: ASP.NET Framework and the Hollywood Principle
&lt;/h4&gt;

&lt;p&gt;In ASP.NET Web Forms, the Hollywood Principle is evident in the use of event-driven programming. Developers write code in response to lifecycle events (like &lt;code&gt;Page_Load&lt;/code&gt;) and user actions (like &lt;code&gt;Button_Click&lt;/code&gt;), but they do not control the flow of execution themselves. The ASP.NET framework handles request routing, lifecycle management, and event triggering.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ASP.NET Web Forms Example:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;using System;

public partial class WebForm1 : System.Web.UI.Page
{
    // Respond to the Page_Load event
    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            // Initial page load logic
            lblMessage.Text = "Welcome to the Hollywood Principle Example!";
        }
    }

    // Respond to a Button Click event
    protected void btnSubmit_Click(object sender, EventArgs e)
    {
        string name = txtName.Text;
        lblMessage.Text = $"Hello, {name}! This response is triggered by a button click.";
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;strong&gt;Key Points:&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Framework-Controlled Flow:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The ASP.NET framework controls when &lt;code&gt;Page_Load&lt;/code&gt;and &lt;code&gt;btnSubmit_Click&lt;/code&gt;are called.&lt;/li&gt;
&lt;li&gt;The developer doesn’t explicitly invoke these methods; they are wired to events managed by the framework.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Event Handlers:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The developer writes event handlers (&lt;code&gt;Page_Load&lt;/code&gt;, &lt;code&gt;btnSubmit_Click&lt;/code&gt;) that are triggered when specific events occur, like the page loading or a button being clicked&lt;/li&gt;
&lt;/ul&gt;




&lt;blockquote&gt;
&lt;p&gt;How do the major C# DI/IoC frameworks compare ?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In &lt;code&gt;C#&lt;/code&gt;, &lt;code&gt;Dependency Injection (DI)&lt;/code&gt; and &lt;code&gt;Inversion of Control (IoC)&lt;/code&gt; are central concepts in modern application design, especially in frameworks built around ASP.NET Core and other enterprise applications. There are several DI/IoC frameworks available in the .NET ecosystem.&lt;/p&gt;

&lt;h1&gt;
  
  
  DI Containers Comparison
&lt;/h1&gt;

&lt;p&gt;Here's a comparison of some popular Dependency Injection (DI) containers for C# and their use cases:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;DI Container&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Best For&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Pros&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Cons&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Microsoft.Extensions.DependencyInjection&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;General-purpose apps, ASP.NET Core&lt;/td&gt;
&lt;td&gt;Lightweight, fast, easy to use, well-integrated with ASP.NET Core&lt;/td&gt;
&lt;td&gt;Lacks advanced features like interception, more complex configuration&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Autofac&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Large applications, enterprise projects&lt;/td&gt;
&lt;td&gt;Powerful, flexible, supports advanced features like interception, decorators, fine-grained control&lt;/td&gt;
&lt;td&gt;Higher complexity, more performance overhead&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Ninject&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Legacy systems, simple apps&lt;/td&gt;
&lt;td&gt;Easy to use, convention-based setup&lt;/td&gt;
&lt;td&gt;Outdated, slower performance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Castle Windsor&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Enterprise apps needing dynamic proxies and AOP&lt;/td&gt;
&lt;td&gt;Advanced features, flexible configuration&lt;/td&gt;
&lt;td&gt;Steep learning curve, slower performance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Simple Injector&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Performance-critical apps, smaller projects&lt;/td&gt;
&lt;td&gt;Fast, simple, easy to use&lt;/td&gt;
&lt;td&gt;Lacks advanced features like property injection&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;StructureMap&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Legacy systems needing flexible DI&lt;/td&gt;
&lt;td&gt;Flexible, supports conventions and lifecycle management&lt;/td&gt;
&lt;td&gt;Slow performance, outdated&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Microsoft.Extensions.DependencyInjection&lt;/strong&gt; is the default choice for most &lt;strong&gt;ASP.NET Core&lt;/strong&gt; apps and general-purpose applications.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Autofac&lt;/strong&gt; is ideal for &lt;strong&gt;enterprise-level&lt;/strong&gt; applications that require &lt;strong&gt;advanced DI features&lt;/strong&gt; like interception and fine-grained control.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ninject&lt;/strong&gt; is suitable for &lt;strong&gt;legacy systems&lt;/strong&gt; or simpler apps but is now &lt;strong&gt;outdated&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Castle Windsor&lt;/strong&gt; is powerful for &lt;strong&gt;enterprise apps&lt;/strong&gt; needing dynamic proxies and AOP, but has a &lt;strong&gt;steep learning curve&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Simple Injector&lt;/strong&gt; is great for &lt;strong&gt;performance-critical apps&lt;/strong&gt; where simplicity and speed are key, though it lacks advanced features.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;StructureMap&lt;/strong&gt; is flexible but should mainly be considered for &lt;strong&gt;legacy systems&lt;/strong&gt;, as it has become &lt;strong&gt;outdated&lt;/strong&gt; and slower compared to others.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>dotnet</category>
      <category>interview</category>
      <category>career</category>
      <category>development</category>
    </item>
  </channel>
</rss>
