<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Mediator Pattern asp net core &#8211; ASP.NET Hosting Reviews and Guides</title>
	<atom:link href="https://topreviewhostingasp.net/tag/mediator-pattern-asp-net-core/feed/" rel="self" type="application/rss+xml" />
	<link>https://topreviewhostingasp.net</link>
	<description>ASP.NET Hosting &#124; Reviews &#124; Tips &#38; Tutorial</description>
	<lastBuildDate>Thu, 05 Nov 2020 04:48:03 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	

<image>
	<url>https://topreviewhostingasp.net/wp-content/uploads/2017/01/cropped-trhaico-32x32.png</url>
	<title>Mediator Pattern asp net core &#8211; ASP.NET Hosting Reviews and Guides</title>
	<link>https://topreviewhostingasp.net</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>How to Implement Mediator Pattern in ASP.NET Core 3.1</title>
		<link>https://topreviewhostingasp.net/how-to-implement-mediator-pattern-in-asp-net-core-3-1/</link>
					<comments>https://topreviewhostingasp.net/how-to-implement-mediator-pattern-in-asp-net-core-3-1/#respond</comments>
		
		<dc:creator><![CDATA[Jacques Hunt]]></dc:creator>
		<pubDate>Thu, 05 Nov 2020 04:40:13 +0000</pubDate>
				<category><![CDATA[Hosting Tips]]></category>
		<category><![CDATA[asp net core 3.1]]></category>
		<category><![CDATA[asp net core 3.1 hosting]]></category>
		<category><![CDATA[asp net core 3.1 tips]]></category>
		<category><![CDATA[asp net core 3.1 tutorial]]></category>
		<category><![CDATA[Mediator Pattern asp net core]]></category>
		<guid isPermaLink="false">https://topreviewhostingasp.net/?p=2775</guid>

					<description><![CDATA[For the last few years, Command Query Responsibility Segregation (CQRS) and Event Sourcing (ES) emerged as patterns that can help implement large scale systems, with some risky complexity, by having different models to read or mutate data while also using events as a single source of truth. The mediator pattern is meant to split responsibilities between a caller and [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>For the last few years, <strong>Command Query Responsibility Segregation (CQRS) </strong>and <strong>Event Sourcing (ES)</strong> emerged as patterns that can help implement large scale systems, with some risky complexity, by having different models to read or mutate data while also using events as a single source of truth.</p>



<p>The mediator pattern is meant to split responsibilities between a caller and the callee. So instead of having an instance of a class and calling a method directly on it, you ask the mediator to do this for you. While this might sound a lot like doing dependency injection, it actually goes a step further. You don’t even know the interface of the callee. This makes it even more decoupled than you’d have with dependency injection.</p>



<p>The result is that the objects are loosely coupled. They only know about the mediator object, not about each other. Besides the mediator object they’ll likely also have some kind of data transfer object to send parameters for the callee.</p>



<p>For a comparison in the real world, imagine only being able to communicatie with someone or a department through their secretary. You give them a message (the data transfer object) and they pass it on to who you want to reach. Once there’s an answer, the secretary will give it back to you. This way you have no knowledge of who actually answered it.</p>



<h2 class="wp-block-heading" id="advantages-and-disadvantages-of-the-mediator-pattern">Advantages and Disadvantages of the Mediator Pattern</h2>



<p>The mediator pattern brings a couple of advantages:</p>



<ul>
<li>Less coupling: Since the classes don’t have dependencies on each other, they are less coupled.</li>
<li>Easier reuse: Fewer dependencies also helps to reuse classes.</li>
<li>Single Responsibility Principle: The services don’t have any logic to call other services, therefore they only do one thing.</li>
<li>Open/closed principle: Adding new mediators can be done without changing the existing code.</li>
</ul>



<p>There is also one big disadvantage of the mediator pattern:</p>



<ul>
<li>The mediator can become such a crucial factor in your application that it is called a “god class”</li>
</ul>



<h2 class="wp-block-heading">How to Implement Mediator Pattern ASP.NET Core 3.1</h2>



<p>Start by opening Visual Studio and creating an <strong>ASP.NET Core 3.1 Web Application</strong> with a name and at any location.</p>



<figure class="wp-block-image size-large"><img fetchpriority="high" decoding="async" width="700" height="444" class="wp-image-2776" src="https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_1.png" alt="" srcset="https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_1.png 700w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_1-300x190.png 300w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_1-50x32.png 50w" sizes="(max-width: 700px) 100vw, 700px" /></figure>



<p>Choose an empty project since this is just a demo.</p>



<figure class="wp-block-image size-large"><img decoding="async" width="700" height="466" class="wp-image-2777" src="https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_2.png" alt="" srcset="https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_2.png 700w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_2-300x200.png 300w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_2-50x33.png 50w" sizes="(max-width: 700px) 100vw, 700px" /></figure>



<p>Install the Nuget <code>Swashbuckle.AspNetCore</code> so we can use Swagger to test the API:</p>



<figure class="wp-block-image size-large"><img decoding="async" width="700" height="170" class="wp-image-2778" src="https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_3.png" alt="" srcset="https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_3.png 700w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_3-300x73.png 300w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_3-50x12.png 50w" sizes="(max-width: 700px) 100vw, 700px" /></figure>



<p>Open the file <code>Startup.cs</code> and configure both MVC and Swagger, making it easier to test our web API.</p>



<pre class="wp-block-code"><code>    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc();

            services.AddSwaggerGen();
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            app.UseDeveloperExceptionPage();

            app.UseSwagger();

            app.UseSwaggerUI(c =&gt;
            {
                c.SwaggerEndpoint("/swagger/v1/swagger.json", "Mediator ExampleApi V1");
            });

            app.UseRouting();

            app.UseEndpoints(endpoints =&gt;
            {
                endpoints.MapControllers();
            });
        }
    }.</code></pre>



<div class="wp-block-image">
<figure class="aligncenter size-large"><a href="https://www.asphostportal.com"><img loading="lazy" decoding="async" width="300" height="271" class="wp-image-2584 aligncenter" src="https://topreviewhostingasp.net/wp-content/uploads/2018/11/ahp-banner-aspnet-01.png" alt="" srcset="https://topreviewhostingasp.net/wp-content/uploads/2018/11/ahp-banner-aspnet-01.png 300w, https://topreviewhostingasp.net/wp-content/uploads/2018/11/ahp-banner-aspnet-01-50x45.png 50w" sizes="(max-width: 300px) 100vw, 300px" /></a></figure>
</div>



<h1 class="wp-block-heading" id="5622">The web API</h1>



<p id="f5e2">Since the objective of this article is to show the mediator pattern, a simple endpoint to manage products should be enough:</p>



<ul>
<li>GET /products — search for products using some filters;</li>
<li>GET /products/{id} — get a product by its unique identifier;</li>
<li>POST /products — create a product;</li>
<li>PUT /products/{id} — update a product by its unique identifier;</li>
<li>DELETE /products/{id} — delete a product by its unique identifier;</li>
</ul>



<p id="5ac4">Create a <code>Controllers</code> folder with another <code>Products</code> folder inside, a <code>ProductsController</code> and the following models:</p>



<pre class="wp-block-code"><code>    [Route("products")]
    public class ProductsController : ControllerBase
    {
        [HttpGet]
        public async Task&lt;IEnumerable&lt;ProductModel&gt;&gt; SearchAsync([FromQuery] string filterQ, [FromQuery] int? skip, [FromQuery] int? take, CancellationToken ct)
        {
            throw new NotImplementedException();
        }

        [HttpGet("{id:guid}")]
        public async Task&lt;ProductModel&gt; GetByIdAsync([FromRoute] Guid id, CancellationToken ct)
        {
            throw new NotImplementedException();
        }

        [HttpPost]
        public async Task&lt;CreateProductResultModel&gt; CreateAsync([FromBody] CreateProductModel model, CancellationToken ct)
        {
            throw new NotImplementedException();
        }

        [HttpPut("{id:guid}")]
        public async Task UpdateAsync([FromRoute] Guid id, [FromBody] UpdateProductModel model, CancellationToken ct)
        {
            throw new NotImplementedException();
        }

        [HttpDelete("{id:guid}")]
        public async Task DeleteAsync([FromRoute] Guid id, CancellationToken ct)
        {
            throw new NotImplementedException();
        }
    }

    public class CreateProductModel
    {
        public string Code { get; set; }

        public string Name { get; set; }

        public decimal Price { get; set; }
    }

    public class CreateProductResultModel
    {
        public Guid Id { get; set; }
    }

    public class ProductModel
    {
        public Guid Id { get; set; }

        public string Code { get; set; }

        public string Name { get; set; }

        public decimal Price { get; set; }
    }

    public class UpdateProductModel
    {
        public string Code { get; set; }

        public string Name { get; set; }

        public decimal Price { get; set; }
    }</code></pre>



<p>The project should look as follows:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="340" height="295" class="wp-image-2779" src="https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_4.png" alt="" srcset="https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_4.png 340w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_4-300x260.png 300w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_4-50x43.png 50w" sizes="(max-width: 340px) 100vw, 340px" /></figure>



<p>Open the Swagger endpoint (ex: https://localhost:44380/swagger/index.html) and you should see your products endpoint with all the actions:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="615" height="461" class="wp-image-2780" src="https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_5.png" alt="" srcset="https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_5.png 615w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_5-300x225.png 300w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_5-50x37.png 50w" sizes="(max-width: 615px) 100vw, 615px" /></figure>



<h2 class="wp-block-heading" id="7b0a">The database model</h2>



<p id="286a">For demo purposes we are going to use <strong>Entity Framework Core</strong> with data stored in-memory.</p>



<p id="dcdb">Install the Nuget <code>Microsoft.EntityFrameworkCore.InMemory</code>:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="700" height="141" class="wp-image-2781" src="https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_6.png" alt="" srcset="https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_6.png 700w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_6-300x60.png 300w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_6-50x10.png 50w" sizes="(max-width: 700px) 100vw, 700px" /></figure>



<p>Create a <code>Database</code> folder, the following database context and a product entity:</p>



<pre class="wp-block-code"><code>    public class ApiDbContext : DbContext
    {
        public ApiDbContext(DbContextOptions&lt;ApiDbContext&gt; options) : base(options)
        {

        }

        protected override void OnModelCreating(ModelBuilder builder)
        {
            base.OnModelCreating(builder);

            builder.Entity&lt;ProductEntity&gt;(cfg =&gt;
            {
                cfg.HasKey(e =&gt; e.Id);
                cfg.HasAlternateKey(e =&gt; e.ExternalId);

                cfg.HasIndex(e =&gt; e.Code).IsUnique();

                cfg.Property(e =&gt; e.ExternalId)
                    .IsRequired();
                cfg.Property(e =&gt; e.Code)
                    .IsRequired()
                    .HasMaxLength(8);
                cfg.Property(e =&gt; e.Name)
                    .IsRequired()
                    .HasMaxLength(128);
                cfg.Property(e =&gt; e.Price)
                    .IsRequired();
            });
        }
    }

    public class ProductEntity
    {
        public long Id { get; set; }

        public Guid ExternalId { get; set; }

        public string Code { get; set; }

        public string Name { get; set; }

        public decimal Price { get; set; }
    }</code></pre>



<p>Open the <code>Startup.cs</code> file and add the context into the container as an in-memory database:</p>



<pre class="wp-block-code"><code>services.AddDbContext&lt;ApiDbContext&gt;(o =&gt;
{
    o.UseInMemoryDatabase("ApiDbContext");
});</code></pre>



<p>The project should look as follows:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="339" height="342" class="wp-image-2782" src="https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_7.png" alt="" srcset="https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_7.png 339w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_7-297x300.png 297w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_7-150x150.png 150w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_7-50x50.png 50w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_7-70x70.png 70w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_7-127x127.png 127w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_7-125x125.png 125w" sizes="(max-width: 339px) 100vw, 339px" /></figure>



<h1 class="wp-block-heading" id="eca5">The mediator</h1>



<p id="0adb">Now that we have created the demo endpoint, models and database, its time to configure the mediator.</p>



<p id="bce7">Install the Nuget <code>SimpleSoft.Mediator.Microsoft.Extensions</code> which is a specialized package for projects using <code>Microsoft.Extensions.*</code>:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="700" height="140" class="wp-image-2783" src="https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_8.png" alt="" srcset="https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_8.png 700w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_8-300x60.png 300w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_8-50x10.png 50w" sizes="(max-width: 700px) 100vw, 700px" /></figure>



<p>Open the <code>Startup.cs</code> file and add the mediator into the container, scanning the current assembly for all classes implementing <code>ICommandHandler</code>, <code>IQueryHandler</code> and <code>IEventHandler</code>:</p>



<pre class="wp-block-code"><code>services.AddMediator(o =&gt;
{
    o.AddHandlersFromAssemblyOf&lt;Startup&gt;();
});</code></pre>



<p>Open the <code>ProductsController.cs</code> file and inject into the constructor the <code>IMediator</code> instance:</p>



<pre class="wp-block-code"><code>private readonly IMediator _mediator;
public ProductsController(IMediator mediator)
{
    _mediator = mediator;
}</code></pre>



<h1 class="wp-block-heading" id="a34c">The handlers</h1>



<p id="f409">We now have everything we need to start implementing the business logic.</p>



<p id="9537">To keep it simple, we are not going to use the mediator pipelines, only focusing on commands, queries, events and their handlers. I’ll demonstrate more complex scenarios in future articles.</p>



<p id="6baf">Start by creating a folder named <code>Handlers</code> with another inside <code>Products</code> in which we are going to put our POCOs and their handlers.</p>



<p id="b39b"><em>As a note, remember this is a demo article and this project structure </em><strong><em>should not be seen as a valid way to organize your solution</em></strong><em> in your private projects. Commands, queries, events and their handlers should be, at minimum, in different folders.</em></p>



<h2 class="wp-block-heading" id="998d">CreateProductComand</h2>



<p id="7eb1">We need data so lets create a command that allows that and will be sent when a request for POST /products is received.</p>



<p id="102f">Create a class <code>CreateProductResult</code> that will be returned by the handler with the product unique identifier and a <code>CreateProductCommand</code>, implementing the class <code>Command&lt;CreateProductResult&gt;</code>:</p>



<pre class="wp-block-code"><code>    public class CreateProductCommand : Command&lt;CreateProductResult&gt;
    {
        public string Code { get; set; }

        public string Name { get; set; }

        public decimal Price { get; set; }
    }

    public class CreateProductResult
    {
        public Guid Id { get; set; }
    }</code></pre>



<p>Open the <code>ProductsController.cs</code> file and inside the method <code>CreateAsync</code> send the command into the mediator and map its result:</p>



<pre class="wp-block-code"><code>[HttpPost]
public async Task&lt;CreateProductResultModel&gt; CreateAsync([FromBody] CreateProductModel model, CancellationToken ct)
{
    var result = await _mediator.SendAsync(new CreateProductCommand
    {
        Code = model.Code,
        Name = model.Name,
        Price = model.Price
    }, ct);
    return new CreateProductResultModel
    {
        Id = result.Id
    };
}</code></pre>



<p id="f2ac">If we now invoked the endpoint, we would receive an exception saying that no <code>ICommandHandler&lt;CreateProductCommand, CreateProductResult&gt;</code> was found by the container.</p>



<p id="5fc5">We will fix that by creating the class <code>CreateProductCommandHandler</code> with the business logic for this action. For this demo, an <code>InvalidOperationException</code> with a custom message will be thrown when a duplicated code is received:</p>



<pre class="wp-block-code"><code>    public class CreateProductCommandHandler : ICommandHandler&lt;CreateProductCommand, CreateProductResult&gt;
    {
        private readonly ApiDbContext _context;

        public CreateProductCommandHandler(ApiDbContext context)
        {
            _context = context;
        }

        public async Task&lt;CreateProductResult&gt; HandleAsync(CreateProductCommand cmd, CancellationToken ct)
        {
            var products = _context.Set&lt;ProductEntity&gt;();

            if (await products.AnyAsync(p =&gt; p.Code == cmd.Code, ct))
            {
                throw new InvalidOperationException($"Product code '{cmd.Code}' already exists");
            }

            var externalId = Guid.NewGuid();
            await products.AddAsync(new ProductEntity
            {
                ExternalId = externalId,
                Code = cmd.Code,
                Name = cmd.Name,
                Price = cmd.Price
            }, ct);

            await _context.SaveChangesAsync(ct);

            return new CreateProductResult
            {
                Id = externalId
            };
        }
    }</code></pre>



<p id="0a2d">If you now try to create a product using the Swagger endpoint, you will receive the response with the unique identifier or an internal server error indicating a duplicated code.</p>



<p id="2987">The project should look as follows:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="320" height="422" class="wp-image-2784" src="https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_9.png" alt="" srcset="https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_9.png 320w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_9-227x300.png 227w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_9-38x50.png 38w" sizes="(max-width: 320px) 100vw, 320px" /></figure>



<h2 class="wp-block-heading" id="4c1e">GetProductByIdQuery</h2>



<p id="b808">Time to return a product when a GET /products/:id is received by the web API.</p>



<p id="2303">Inside the <code>Handlers/Products</code> folder, create a <code>Product</code>, the <code>GetProductByIdQuery</code> and its corresponding handler, <code>GetProductByIdQueryHandler</code>. Like in the previous handler, for this demo, we are going to throw an <code>InvalidOperationException</code> if the id is unknown:</p>



<pre class="wp-block-code"><code>    public class GetProductByIdQuery : Query&lt;Product&gt;
    {
        public Guid ProductId { get; set; }
    }

    public class Product
    {
        public Guid Id { get; set; }

        public string Code { get; set; }

        public string Name { get; set; }

        public decimal Price { get; set; }
    }

    public class GetProductByIdQueryHandler : IQueryHandler&lt;GetProductByIdQuery, Product&gt;
    {
        private readonly IQueryable&lt;ProductEntity&gt; _products;

        public GetProductByIdQueryHandler(ApiDbContext context)
        {
            _products = context.Set&lt;ProductEntity&gt;();
        }

        public async Task&lt;Product&gt; HandleAsync(GetProductByIdQuery query, CancellationToken ct)
        {
            var product = await _products.SingleOrDefaultAsync(p =&gt; p.ExternalId == query.ProductId, ct);

            if (product == null)
            {
                throw new InvalidOperationException($"Product '{query.ProductId}' not found");
            }

            return new Product
            {
                Id = product.ExternalId,
                Code = product.Code,
                Name = product.Name,
                Price = product.Price
            };
        }
    }</code></pre>



<p>Open the <code>ProductsController.cs</code> file and inside the method <code>GetByIdAsync</code> fetch the query from the mediator and map its result:.</p>



<pre class="wp-block-code"><code>[HttpGet("{id:guid}")]
public async Task&lt;ProductModel&gt; GetByIdAsync([FromRoute] Guid id, CancellationToken ct)
{
    var result = await _mediator.FetchAsync(new GetProductByIdQuery
    {
        ProductId = id
    }, ct);
    return new ProductModel
    {
        Id = result.Id,
        Code = result.Code,
        Name = result.Name,
        Price = result.Price
    };
}</code></pre>



<p id="a987">If you now try to get a product using the Swagger endpoint, you will receive the product or an internal server error indicating an unknown identifier.</p>



<h2 class="wp-block-heading" id="1f12">CreatedProductEvent</h2>



<p id="3451">Finally, we are going to create an event that will be broadcast when a product is successfully created.</p>



<p id="eae3">Just like the previous ones, create a <code>CreateProductEvent</code> and the handler <code>CreateProductEventHandler</code>. This time we are just going to log that a product was created:</p>



<pre class="wp-block-code"><code>    public class CreatedProductEvent : Event
    {
        public Guid ExternalId { get; set; }

        public string Code { get; set; }

        public string Name { get; set; }

        public decimal Price { get; set; }
    }

    public class CreatedProductEventHandler : IEventHandler&lt;CreatedProductEvent&gt;
    {
        private readonly ILogger&lt;CreatedProductEventHandler&gt; _logger;

        public CreatedProductEventHandler(ILogger&lt;CreatedProductEventHandler&gt; logger)
        {
            _logger = logger;
        }

        public Task HandleAsync(CreatedProductEvent evt, CancellationToken ct)
        {
            _logger.LogInformation("The product '{externalId}' has been created", evt.ExternalId);

            return Task.CompletedTask;
        }
    }</code></pre>



<p>Open the <code>CreateProductCommandHandler</code> file, inject the <code>IMediator</code> instance and after saving the changes just broadcast the event:</p>



<pre class="wp-block-code"><code>    public class CreateProductCommandHandler : ICommandHandler&lt;CreateProductCommand, CreateProductResult&gt;
    {
        private readonly ApiDbContext _context;
        private readonly IMediator _mediator;

        public CreateProductCommandHandler(ApiDbContext context, IMediator mediator)
        {
            _context = context;
            _mediator = mediator;
        }

        public async Task&lt;CreateProductResult&gt; HandleAsync(CreateProductCommand cmd, CancellationToken ct)
        {
            var products = _context.Set&lt;ProductEntity&gt;();

            if (await products.AnyAsync(p =&gt; p.Code == cmd.Code, ct))
            {
                throw new InvalidOperationException($"Product code '{cmd.Code}' already exists");
            }

            var externalId = Guid.NewGuid();
            await products.AddAsync(new ProductEntity
            {
                ExternalId = externalId,
                Code = cmd.Code,
                Name = cmd.Name,
                Price = cmd.Price
            }, ct);

            await _context.SaveChangesAsync(ct);

            await _mediator.BroadcastAsync(new CreatedProductEvent
            {
                ExternalId = externalId,
                Code = cmd.Code,
                Name = cmd.Name,
                Price = cmd.Price
            }, ct);

            return new CreateProductResult
            {
                Id = externalId
            };
        }
    }</code></pre>



<p>The project should look as follows:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="335" height="517" class="wp-image-2785" src="https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_10.png" alt="" srcset="https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_10.png 335w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_10-194x300.png 194w, https://topreviewhostingasp.net/wp-content/uploads/2020/11/image_10-32x50.png 32w" sizes="(max-width: 335px) 100vw, 335px" /></figure>



<h1 class="wp-block-heading" id="73e9">Conclusion</h1>



<p id="6b22">I hope this article gave you a good idea on how to use the mediator to implement the <strong>CQRS</strong> and <strong>ES</strong> patterns even if you are implementing an <strong>MVP</strong> and can’t spend much time thinking about the architecture but you still want something that can be maintained and extended for some time.</p>



<p id="f569">Soon I’ll be explaining more advanced scenarios, like using the mediator pipeline to validate commands before reaching the handler, managing database transactions or even implementing transversal auditing into you application.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://topreviewhostingasp.net/how-to-implement-mediator-pattern-in-asp-net-core-3-1/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
