<?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: Akash Lomas</title>
    <description>The latest articles on DEV Community by Akash Lomas (@akash_lomas_ns).</description>
    <link>https://dev.to/akash_lomas_ns</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%2F3865207%2F45a56a44-9dcd-4ee0-a726-e330af8be434.png</url>
      <title>DEV Community: Akash Lomas</title>
      <link>https://dev.to/akash_lomas_ns</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/akash_lomas_ns"/>
    <language>en</language>
    <item>
      <title>Architectural Collapse: How Extension Poisoning, Node Vulnerabilities, and Infrastructure Fog Enabled the GitHub Repository Breach</title>
      <dc:creator>Akash Lomas</dc:creator>
      <pubDate>Mon, 25 May 2026 07:22:24 +0000</pubDate>
      <link>https://dev.to/akash_lomas_ns/architectural-collapse-how-extension-poisoning-node-vulnerabilities-and-infrastructure-fog-i84</link>
      <guid>https://dev.to/akash_lomas_ns/architectural-collapse-how-extension-poisoning-node-vulnerabilities-and-infrastructure-fog-i84</guid>
      <description>&lt;p&gt;Enterprise perimeter defenses are fundamentally built on an obsolete assumption that, the developer's workstation is a secure, trusted anchor point. The massive security breach executed by the threat group &lt;strong&gt;TeamPCP&lt;/strong&gt;, resulting in the exfiltration of &lt;strong&gt;3,800 internal GitHub source code repositories&lt;/strong&gt;, completely shattered this illusion.&lt;/p&gt;

&lt;p&gt;This was not a standalone exploit. It was a multi-vector convergence where vulnerabilities in the Node/NPM ecosystem, the systemic ungoverned architecture of the Visual Studio Code Marketplace, and the tactical "fog of war" caused by a period of historic GitHub infrastructure instability came together to create the perfect attack.&lt;/p&gt;

&lt;h2&gt;
  
  
  Phase 1: The Root Exploitation (Node/NPM and the TanStack Supply Chain Pivot)
&lt;/h2&gt;

&lt;p&gt;The kill chain did not begin at GitHub, it originated deep within the modern JavaScript developer tool-chain. TeamPCP executed a localized supply chain compromise targeting upstream open-source utilities, specifically targeting contributors to &lt;strong&gt;TanStack&lt;/strong&gt; npm packages (a widely relied-upon suite for state management and routing).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[TanStack NPM Compromise] 
          │
          ▼
[Stolen 'gh' CLI Tokens] 
          │
          ▼
[Nx Console Pipeline Hijack (No Multi-Admin Approval)]
          │
          ▼
[Malicious Extension Version 18.95.0 Published]

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

&lt;/div&gt;



&lt;p&gt;By injecting malicious code into these highly trusted downstream dependencies, the attackers performed targeted local credential harvesting. Their primary target was not production application code, but the development environments of the maintainers themselves.&lt;/p&gt;

&lt;p&gt;The exploit successfully extracted long-lived GitHub CLI (&lt;code&gt;gh&lt;/code&gt;) authentication tokens from a legitimate core developer who maintained both TanStack and the &lt;strong&gt;Nx Console&lt;/strong&gt; ecosystem. Because these developer access tokens lacked granular scoping restrictions, they provided direct administrative write access to the main release pipelines of secondary repositories.&lt;/p&gt;

&lt;h2&gt;
  
  
  Phase 2: VS Code Extension Poisoning (The Nx Console Triage (CVE-2026-48027))
&lt;/h2&gt;

&lt;p&gt;Armed with the stolen &lt;code&gt;gh&lt;/code&gt; tokens, TeamPCP bypassed standard perimeter security by pivoting to the Visual Studio Marketplace. On May 18, version &lt;strong&gt;18.95.0&lt;/strong&gt; of &lt;strong&gt;Nx Console&lt;/strong&gt; (a heavily utilized Monorepo orchestration extension with over 2.2 million installs) was maliciously built and uploaded.&lt;/p&gt;

&lt;p&gt;The deployment revealed two fatal flaws within modern developer workflows,&lt;/p&gt;

&lt;h3&gt;
  
  
  1. The Single-Factor Release Pipeline
&lt;/h3&gt;

&lt;p&gt;The malicious version was uploaded directly to both the Visual Studio Marketplace and the open-source OpenVSX registry. Because the Nx Console publishing architecture lacked a "two-admin manual validation mandate" for automated releases, the publishing pipeline accepted the stolen developer token at face value without triggering a secondary verification gate.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. The "Silent Killer": Marketplace Metrics vs. Background Sync
&lt;/h3&gt;

&lt;p&gt;Microsoft’s public marketplace logs initially registered a negligible &lt;strong&gt;28 manual downloads&lt;/strong&gt; before the package was identified and yanked 18 minutes later. However, Nx's internal telemetry revealed that &lt;strong&gt;~6,000 extension activation's&lt;/strong&gt; occurred simultaneously.&lt;/p&gt;

&lt;p&gt;This massive discrepancy highlights the danger of &lt;strong&gt;VS Code's background auto-update synchronization&lt;/strong&gt;. Thousands of developer environments pulled down, unzipped, and executed the malicious version automatically while the developers' IDEs were running in the background.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Example&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;target&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;parameters&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;within&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;compromised&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;developer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;workspaces&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"extensions.autoUpdate"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;The&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;default&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;vulnerability&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;exploited&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;by&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;TeamPCP&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"terminal.integrated.profiles.osx"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"malicious-hook"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/bin/bash"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"-c"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"python3 ~/.local/share/kitty/cat.py &amp;amp;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  The Node Execution Layer
&lt;/h3&gt;

&lt;p&gt;Upon extension activation, the poisoned payload immediately dropped an obfuscated Node.js post-install hook. Operating completely within user space to evade basic Endpoint Detection and Response (EDR) behavioral hooks, it set an environmental marker (&lt;code&gt;__DAEMONIZED=1&lt;/code&gt;) and spawned a background Python process (&lt;code&gt;cat.py&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;The malware systemically scanned local paths for,&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Infrastructure Configuration:&lt;/strong&gt; Plaintext HashiCorp Vault tokens (&lt;code&gt;~/.vault-token&lt;/code&gt;), local Kubernetes &lt;code&gt;kubeconfig&lt;/code&gt; files, and AWS/Azure IAM metadata endpoint hashes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ecosystem Identity:&lt;/strong&gt; Plaintext &lt;code&gt;.npmrc&lt;/code&gt; registry tokens and active GitHub tokens (&lt;code&gt;ghp_&lt;/code&gt;, &lt;code&gt;gho_&lt;/code&gt;, &lt;code&gt;ghs_&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Active Memory Subsystems:&lt;/strong&gt; Contents of 1Password vaults via the &lt;code&gt;op&lt;/code&gt; CLI by hijacking active, unlocked terminal sessions.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Phase 3: The Climax (The Internal GitHub Breach)
&lt;/h2&gt;

&lt;p&gt;The payload achieved its ultimate goal when an internal GitHub software engineer, who utilized Nx Console for local workflow management, had their workstation pull down the background update.&lt;/p&gt;

&lt;p&gt;The malware executed on the engineer's local machine, scraped their active internal enterprise session tokens, and exfiltrated them to a remote command-and-control (C2) server. TeamPCP then used these highly privileged internal access credentials to bypass GitHub's corporate identity perimeters entirely.&lt;/p&gt;

&lt;p&gt;Because internal repository boundaries operate on flat network access structures once an authenticated developer endpoint is cleared, the threat actors systematically cloned and exfiltrated &lt;strong&gt;3,800 proprietary internal GitHub source code repositories&lt;/strong&gt; before the endpoint could be isolated.&lt;/p&gt;

&lt;h2&gt;
  
  
  Phase 4: The Tactical Fog of War (GitHub's Infrastructure Instability)
&lt;/h2&gt;

&lt;p&gt;The velocity and stealth of this attack were significantly aided by an ongoing reliability crisis within GitHub’s core infrastructure. During the 12-month window surrounding the breach, GitHub recorded a massive spike in service degradation.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Total Tracked Incidents:&lt;/strong&gt; 257 distinct technical incidents.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Major Outages:&lt;/strong&gt; 48 major service shutdowns, totaling &lt;strong&gt;112 hours and 18 minutes&lt;/strong&gt; of total downtime.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Primary Failure Vector:&lt;/strong&gt; GitHub Actions experienced 57 outages—three times the incidence rate of core Git storage operations.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Outage Date&lt;/th&gt;
&lt;th&gt;Primary Root Cause&lt;/th&gt;
&lt;th&gt;Security Alert Fallout&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;October 29&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Outage in compute dependency (Microsoft Azure), 90% error rate across Codespaces/ Actions.&lt;/td&gt;
&lt;td&gt;Telemetry gaps, security monitoring systems failed to track cross-border API token replication.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;February 2&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Configuration failure in user settings caching, cascading failures in the Git HTTPS proxy.&lt;/td&gt;
&lt;td&gt;High volume of synchronous cache writes generated a deluge of network errors, masking anomalous Git clone calls.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;February 12&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Authorization claim changes in core networking dependencies,, 90% Codespace provisioning failure.&lt;/td&gt;
&lt;td&gt;Security alerts failed to populate due to misclassified severity ratings, delaying incident detection by hours.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  The Alert Fatigue Vulnerability
&lt;/h3&gt;

&lt;p&gt;This constant infrastructural noise created an ideal tactical environment for the attackers. SecOps and DevSecOps teams were caught in a continuous state of &lt;strong&gt;alert fatigue&lt;/strong&gt; dealing with broken GitHub Actions pipelines, Elasticsearch cluster degradation, and database timeouts.&lt;/p&gt;

&lt;p&gt;When TeamPCP’s automated scripts began running rapid API queries and pulling massive volumes of repository data using the compromised engineer's token, the unusual spikes in data transfer blended into the background noise of an infrastructure already struggling with systemic capacity and networking failures.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hard Takeaways: How Developers Must Harden Their Environments
&lt;/h2&gt;

&lt;p&gt;If your environment was active or using automated tools during this period, you must shift your development machine from an implied trust zone to a completely zero-trust environment.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Kill IDE Auto-Updates Globally
&lt;/h3&gt;

&lt;p&gt;Never allow your IDE to pull un-vetted code in the background. Explicitly configure your editor to require manual permission before updating any third-party extension.&lt;/p&gt;

&lt;p&gt;In VS Code's global &lt;code&gt;settings.json&lt;/code&gt;, enforce:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"extensions.autoUpdate"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"extensions.autoCheckUpdates"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Isolate Development Runtimes
&lt;/h3&gt;

&lt;p&gt;Stop running compilers, package managers, and complex IDE extensions directly on your bare-metal operating system.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Utilize isolated, ephemeral development environments (e.g., containerized &lt;strong&gt;Dev containers&lt;/strong&gt; or heavily scoped virtual environments) where local file-system access is completely decoupled from your master &lt;code&gt;~/.ssh/&lt;/code&gt;, &lt;code&gt;~/.aws/&lt;/code&gt;, or &lt;code&gt;.npmrc&lt;/code&gt; configuration folders.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Implement Strict Token Volatility
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Eliminate long-lived personal access tokens (&lt;code&gt;ghp_&lt;/code&gt;). Switch entirely to fine-grained personal access tokens configured with strict, single-repository scope constraints and maximum 7-day expiration dates.&lt;/li&gt;
&lt;li&gt;Explicitly configure your local password managers and authentication tools to require biological verification (e.g., TouchID/FaceID) or short timeout windows for &lt;em&gt;every&lt;/em&gt; individual call executed via the terminal command line (&lt;code&gt;op signin --timeout&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>vulnerabilities</category>
      <category>github</category>
      <category>vscode</category>
      <category>npm</category>
    </item>
    <item>
      <title>Moving Beyond MediatR: Implementing Cross-Cutting Concerns with Native .NET Dependency Injection</title>
      <dc:creator>Akash Lomas</dc:creator>
      <pubDate>Fri, 22 May 2026 03:45:18 +0000</pubDate>
      <link>https://dev.to/akash_lomas_ns/moving-beyond-mediatr-implementing-cross-cutting-concerns-with-native-net-dependency-injection-4ej5</link>
      <guid>https://dev.to/akash_lomas_ns/moving-beyond-mediatr-implementing-cross-cutting-concerns-with-native-net-dependency-injection-4ej5</guid>
      <description>&lt;p&gt;For years, the MediatR package has been a default inclusion in almost every new .NET project template. It is frequently hailed as the gold standard for decoupling controllers or minimal APIs from business logic and implementing Clean Architecture or CQRS patterns.&lt;/p&gt;

&lt;p&gt;However, as ASP.NET Core has matured, many of the architectural justifications for adding MediatR as a heavy third-party dependency have faded. If you are building standard CRUD or even moderately complex enterprise APIs, it might be time to ask yourself,&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Why am I routing my HTTP requests through an abstract in-memory bus when native alternatives exist?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let’s explore why MediatR might be an unnecessary abstraction in your codebase and how you can replace its most beloved feature Pipeline Behaviors using pure .NET Dependency Injection (DI) plumbing and the Decorator pattern.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Core Critique of MediatR
&lt;/h3&gt;

&lt;p&gt;While MediatR provides an elegant mechanism for decoupling, it introduces specific friction points into a code-base,&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Obfuscated Control Flow: Because handlers are resolved dynamically, it is impossible to use standard “Go to Definition” (F12) in your IDE to trace execution directly from an endpoint to its handler. You are forced to search for the corresponding IRequestHandler type implementation.&lt;/li&gt;
&lt;li&gt;Debugging Overhead: Stepping through code becomes a tedious exercise of bypassing internal library code generator stacks instead of moving sequentially through your business logic.&lt;/li&gt;
&lt;li&gt;Unnecessary Architecture: In standard Web APIs, the mapping between an endpoint and its handler is almost always 1:1. Introducing a mediator pattern for a direct request-response cycle over complicates the system with minimal structural payback.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you are using Minimal APIs or standard Controllers, you already have powerful endpoint routing. So why use MediatR? The answer almost always boils down to one critical feature, Pipeline Behaviors.&lt;/p&gt;

&lt;h3&gt;
  
  
  The “Killer Feature”: Cross-Cutting Concerns
&lt;/h3&gt;

&lt;p&gt;Developers love MediatR because it makes addressing cross-cutting concerns, such as centralized logging, validation pipelines (e.g., using FluentValidation), metrics collection, and OpenTelemetry tracking incredibly clean.&lt;/p&gt;

&lt;p&gt;Instead of cluttering every single business handler with repetitive try-catch blocks or explicit validation calls, MediatR lets you define a generic middleware pipeline around your requests:&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="c1"&gt;// The classic MediatR approach&lt;/span&gt;
&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddMediatR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cfg&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RegisterServicesFromAssembly&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Program&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;Assembly&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddOpenBehavior&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LoggingBehavior&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;,&amp;gt;));&lt;/span&gt;
    &lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddOpenBehavior&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ValidationBehavior&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;,&amp;gt;));&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is a fantastic architectural model, but you do not need a third-party package to achieve it. Modern .NET allows you to implement this exact pattern natively using compile-time type-safe decorators.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Native Alternative: DI-Based Decoration
&lt;/h3&gt;

&lt;p&gt;Instead of an abstract pipeline behavior model, we can leverage the Decorator Pattern natively supported by the Microsoft.Extensions.DependencyInjection container. This allows us to transparently wrap any standard interface registration with cross-cutting behaviors.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Defining a Domain-Driven Request Handler Interface&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;First, let’s establish our own lightweight, explicit handler contract. This preserves your CQRS separation without binding your domain to external packages.&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;interface&lt;/span&gt; &lt;span class="nc"&gt;IRequestHandler&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;TRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TResponse&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TResponse&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;HandleAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TRequest&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;cancellationToken&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;default&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;ul&gt;
&lt;li&gt;Creating a Concrete Business Handler&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Your concrete query or command handlers remain pristine. They are entirely unaware of logging, telemetry, or validation logic, adhering perfectly to the Single Responsibility Principle.&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;record&lt;/span&gt; &lt;span class="nc"&gt;CreateProductCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;decimal&lt;/span&gt; &lt;span class="n"&gt;Price&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IRequest&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CreateProductHandler&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IRequestHandler&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;CreateProductCommand&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Guid&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;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;IProductRepository&lt;/span&gt; &lt;span class="n"&gt;_repository&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;CreateProductHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IProductRepository&lt;/span&gt; &lt;span class="n"&gt;repository&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_repository&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;repository&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="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Guid&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;HandleAsync&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;  &lt;span class="n"&gt;CreateProductCommand&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
         &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;cancellationToken&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;)&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;id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Guid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;NewGuid&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="c1"&gt;// Core business logic goes here...&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;id&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;ul&gt;
&lt;li&gt;Implementing the Cross-Cutting Decorator&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, let’s implement a generic decorator that intercepts the request execution. It implements the same interface but accepts the inner concrete handler as a dependency, wrapping it with infrastructure logic.&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;LoggingHandlerDecorator&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TResponse&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IRequestHandler&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TResponse&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;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;IRequestHandler&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TResponse&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_inner&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;readonly&lt;/span&gt; &lt;span class="n"&gt;ILogger&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;LoggingHandlerDecorator&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TResponse&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_logger&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;LoggingHandlerDecorator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;IRequestHandler&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TResponse&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;inner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="n"&gt;ILogger&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;LoggingHandlerDecorator&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TResponse&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_inner&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;inner&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;_logger&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logger&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="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TResponse&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;HandleAsync&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TRequest&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;cancellationToken&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;)&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;requestName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TRequest&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;_logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LogInformation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Executing request: {RequestName}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;requestName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;try&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;response&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_inner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;HandleAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cancellationToken&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;_logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LogInformation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Successfully executed request: {RequestName}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;requestName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Exception&lt;/span&gt; &lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;_logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LogError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Request failed: {RequestName}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;requestName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;throw&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;h3&gt;
  
  
  Wiring It Together Natively in Program.cs
&lt;/h3&gt;

&lt;p&gt;To register these decorators without external help, we can write a clean extension method using the native DI container’s service factory capabilities. This gives us full architectural control over which handlers get decorated and in what order.&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;static&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RequestHandlerRegistrationExtensions&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;IServiceCollection&lt;/span&gt; &lt;span class="n"&gt;AddDecoratedRequestHandler&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TResponse&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;THandler&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="n"&gt;IServiceCollection&lt;/span&gt; &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
        &lt;span class="k"&gt;where&lt;/span&gt; &lt;span class="n"&gt;THandler&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;IRequestHandler&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TResponse&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// 1. Register the concrete handler with its own concrete type&lt;/span&gt;
        &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddTransient&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;THandler&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;

        &lt;span class="c1"&gt;// 2. Register the interface using a factory method that constructs the decorator chain&lt;/span&gt;
        &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddTransient&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IRequestHandler&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TResponse&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;sp&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&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;concreteHandler&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetRequiredService&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;THandler&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;logger&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetRequiredService&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ILogger&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;LoggingHandlerDecorator&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TResponse&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&amp;gt;();&lt;/span&gt;

            &lt;span class="c1"&gt;// Wrap the core handler with our logging decorator&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;LoggingHandlerDecorator&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TResponse&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;concreteHandler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;services&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;blockquote&gt;
&lt;p&gt;Pro-Tip: If manual registration feels too verbose for thousands of handlers, you can use assembly scanning utilities like Scrutor to dynamically apply the .Decorate() method across your entire service collection automatically.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Your application endpoints remain perfectly clean, directly consuming the generic interface via native dependency injection:&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="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MapPost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/products"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;CreateProductCommand&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="n"&gt;IRequestHandler&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;CreateProductCommand&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Guid&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&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;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;HandleAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&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;h3&gt;
  
  
  Architectural Advantages
&lt;/h3&gt;

&lt;p&gt;By shifting from an in-memory mediator library to native DI decoration, you unlock major engineering benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No Black Boxes: Your execution pathway is clear. If you place a breakpoint inside your API endpoint and step into handler.HandleAsync(), you will sequentially enter the LoggingDecorator, step through any validation layers, and land cleanly inside your actual business logic handler.&lt;/li&gt;
&lt;li&gt;Zero Third-Party Vendor Lock-in: Your core business logic blocks do not depend on external packages. Upgrading your framework version will never be delayed due to a breaking change in an open-source messaging mediator.&lt;/li&gt;
&lt;li&gt;Granular Structural Control: Unlike globally forced middleware pipelines, you can explicitly choose which command or query handlers receive specific decorators. If a high-throughput endpoint requires raw performance without validation overhead, you can register it without its decorator wrap.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;MediatR has served the .NET community exceptionally well over the last decade. However, frameworks evolve. With modern ASP.NET Core DI plumbing, we can maintain clean separation of concerns, enforce CQRS principles, and leverage pipeline behaviors seamlessly using standard patterns built straight into the runtime.&lt;/p&gt;

&lt;p&gt;Evaluate your current architecture.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Is MediatR solving a foundational problem for you, or is it merely acting as boilerplate code that your native framework can already handle?&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>mediatr</category>
      <category>microservices</category>
      <category>dotnet</category>
      <category>cqrs</category>
    </item>
  </channel>
</rss>
