create account

Execution pipeline in plug-and-play architecture in Asp.NET 5 by dotnetguru

View this thread on: hive.blogpeakd.comecency.com
· @dotnetguru ·
$0.31
Execution pipeline in plug-and-play architecture in Asp.NET 5
This blog post is the last of the series **Plug-and-play architecture in Asp.NET 5** and we will see how we can actually implement the plug-and-play execution pipeline.

# Execution context vs execution pipeline?
**Execution context** is the metadata that every request comes with. As we discussed in the [previous blog post](https://ecency.com/hive-169321/@dotnetguru/execution-context-in-plug-and) the context can hold data for a request id, principal, and everything else that we might need as part of each request.

https://wakeupandcode.com/wp-content/uploads/2019/04/Blog-Diagram-Middleware-Pipeline.png

<center>*[source](https://wakeupandcode.com/middleware-in-asp-net-core/)*</center>

**Execution pipeline** on the other hand is a series of steps that each request goes through. Depending on the configuration we usually see a pipeline in the MVC architecture as described in the image above. We need to implement a pipeline for both queries and commands that implicitly will do some things for us, like logging exceptions or logging commands/events.

First let's configure a pipeline interface that we will use to create the pipeline middlewares:

```
using PlugAndPlayExample.Infrastructure.Logging;
using System;
using System.Collections.Generic;
using System.Linq;

namespace PlugAndPlayExample.Services.Infrastructure
{
    public interface IPipeline
    {
        TResponse Execute<TResponse>(Func<TResponse> inner) where TResponse : Response;
        IPipeline Next { get; set; }
    }
}
```
And lets create two different middlewares that we will use:
```
using PlugAndPlayExample.Infrastructure.Logging;
using System;
using System.Collections.Generic;
using System.Linq;

namespace PlugAndPlayExample.Services.Infrastructure
{
    public class LoggingPipeline : IPipeline
    {
        public IPipeline Next { get; set; }

        private readonly ILogger logger;

        public LoggingPipeline(ILogger logger)
        {
            this.logger = logger;
        }

        public TResponse Execute<TResponse>(Func<TResponse> inner) where TResponse : Response
        {
            try
            {
                return Next.Execute(inner);
            }
            catch (Exception ex)
            {
                logger.Error(ex.Message, ex);
                throw;
            }
        }
    }

    public class RunnerPipeline : IPipeline
    {
        public IPipeline Next { get; set; }

        public TResponse Execute<TResponse>(Func<TResponse> inner) where TResponse : Response
        {
            return inner();
        }
    }
}
```

The **logging** middleware executes a function and if it throws an exception, it logs it. The **runner** middleware just runs the function and we always use it as the last middleware with no <code>Next</code> property.

Now we need to implement the command and query middleware configuration and order:
```
using PlugAndPlayExample.Infrastructure.Logging;
using System;
using System.Collections.Generic;
using System.Linq;

namespace PlugAndPlayExample.Services.Infrastructure
{
    public interface ICommandPipeline
    {
        TResponse Execute<TResponse>(Func<TResponse> inner) where TResponse : Response;
    }

    public interface IQueryPipeline
    {
        TResponse Execute<TResponse>(Func<TResponse> inner) where TResponse : Response;
    }

    public class CommandPipeline : ICommandPipeline
    {
        private List<IPipeline> pipelines;

        public CommandPipeline(IServiceProvider serviceProvider)
        {
            pipelines = new List<IPipeline>();
            pipelines.Add(serviceProvider.GetService(typeof(LoggingPipeline)) as LoggingPipeline);
            pipelines.Add(serviceProvider.GetService(typeof(RunnerPipeline)) as RunnerPipeline);

            for (int i = 0; i < pipelines.Count - 1; i++)
            {
                pipelines[i].Next = pipelines[i + 1];
            }
        }

        public TResponse Execute<TResponse>(Func<TResponse> inner) where TResponse : Response
        {
            return pipelines.FirstOrDefault()?.Execute(inner);
        }
    }

    public class QueryPipeline : IQueryPipeline
    {
        private List<IPipeline> pipelines;

        public QueryPipeline(IServiceProvider serviceProvider)
        {
            pipelines = new List<IPipeline>();
            pipelines.Add(serviceProvider.GetService(typeof(RunnerPipeline)) as RunnerPipeline);

            for (int i = 0; i < pipelines.Count - 1; i++)
            {
                pipelines[i].Next = pipelines[i + 1];
            }
        }

        public TResponse Execute<TResponse>(Func<TResponse> inner) where TResponse : Response
        {
            return pipelines.FirstOrDefault()?.Execute(inner);
        }
    }
}

```

We are finally ready to start using this middlewares in our mediator and have our plug and play architecture:

```
using System;

namespace PlugAndPlayExample.Services.Infrastructure
{
    public class Mediator
    {
        private readonly IServiceProvider serviceProvider;
        private readonly IQueryPipeline queryPipeline;
        private readonly ICommandPipeline commandPipeline;

        public Mediator(IServiceProvider serviceProvider, IQueryPipeline queryPipeline, ICommandPipeline commandPipeline)
        {
            this.serviceProvider = serviceProvider;
            this.queryPipeline = queryPipeline;
            this.commandPipeline = commandPipeline;
        }

        public TResult Dispatch<TCommand, TResult>(TCommand command)
            where TCommand : ICommand
            where TResult : Response
        {
            var commandHandler = serviceProvider.GetService(typeof(ICommandHandler<TCommand, TResult>)) as ICommandHandler<TCommand, TResult>;

            return commandPipeline.Execute(() => commandHandler.Handle(command));
        }

        public TResult Get<TQuery, TResult>(TQuery query)
            where TQuery : IQuery
            where TResult : Response
        {
            var queryHandler = serviceProvider.GetService(typeof(IQueryHandler<TQuery, TResult>)) as IQueryHandler<TQuery, TResult>;

            return queryPipeline.Execute(() => queryHandler.Handle(query));
        }
    }
}
```

Finally let's not forget to register everything in the service container:
```
using Microsoft.Extensions.DependencyInjection;
using PlugAndPlayExample.Infrastructure.Caching;
using PlugAndPlayExample.Infrastructure.Logging;
using PlugAndPlayExample.Services.Infrastructure;
using System.IO;

namespace PlugAndPlayExample.Configuration
{
    public static class RegisterInfrastructureAspectsExtension
    {
        public static IServiceCollection RegisterInfrastructureAspects(this IServiceCollection services)
        {
            services.AddSingleton<ICache, InMemoryCache>();
            services.AddSingleton<ILogger, FileLogger>(provider => new FileLogger(new FileInfo("my_log_file.log")));

            services.AddSingleton<IQueryPipeline, QueryPipeline>();
            services.AddSingleton<ICommandPipeline, CommandPipeline>();

            services.AddSingleton<RunnerPipeline>();
            services.AddSingleton<LoggingPipeline>();

            return services;
        }
    }
}
```

Hope you found this blog post helpful. 😄

_Happy coding,_
_DotNetGuru_



👍  , , , , , , , , , , , , , , , , ,
properties (23)
authordotnetguru
permlinkexecution-pipeline-in-plug-and
categoryhive-169321
json_metadata{"links":["https://ecency.com/hive-169321/@dotnetguru/execution-context-in-plug-and","https://wakeupandcode.com/middleware-in-asp-net-core/"],"image":["https://wakeupandcode.com/wp-content/uploads/2019/04/Blog-Diagram-Middleware-Pipeline.png"],"thumbnails":["https://wakeupandcode.com/wp-content/uploads/2019/04/Blog-Diagram-Middleware-Pipeline.png"],"tags":["hive-169321","development","desing-patterns","programming"],"app":"ecency/3.0.20-vision","format":"markdown+html"}
created2022-01-12 16:45:36
last_update2022-01-12 16:45:36
depth0
children6
last_payout2022-01-19 16:45:36
cashout_time1969-12-31 23:59:59
total_payout_value0.160 HBD
curator_payout_value0.147 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length7,266
author_reputation380,629,995,451
root_title"Execution pipeline in plug-and-play architecture in Asp.NET 5"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd0
post_id109,414,412
net_rshares195,914,271,256
author_curate_reward""
vote details (18)
@cmplxty ·
I see you are writing some pretty great and helpful posts. I suggest you leave some comments though, those are critical for long-term success here. I know you are having issues with resource credits right now, I see that you are currently at .50% which is tough but if you spend time on comments, people will be more willing to help you out with some delegation of credits so you can keep it up. Hopefully you can take that into consideration!
properties (22)
authorcmplxty
permlinkre-dotnetguru-r5xers
categoryhive-169321
json_metadata{"tags":["hive-169321"],"app":"peakd/2021.12.1"}
created2022-01-18 22:07:06
last_update2022-01-18 22:07:06
depth1
children4
last_payout2022-01-25 22:07:06
cashout_time1969-12-31 23:59:59
total_payout_value0.000 HBD
curator_payout_value0.000 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length443
author_reputation783,785,300,628,314
root_title"Execution pipeline in plug-and-play architecture in Asp.NET 5"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id109,620,363
net_rshares0
@dotnetguru ·
$0.02
Thanks for the advice, I was on vacation for 6 days, but I will try to be more engaging with the community in the future. At this moment I'm preparing a post about the importance of algorithms and where to practice. I hope it will bring value to somebody. 😄
👍  
properties (23)
authordotnetguru
permlinkre-cmplxty-2022120t22350420z
categoryhive-169321
json_metadata{"tags":["hive-169321"],"app":"ecency/3.0.20-vision","format":"markdown+html"}
created2022-01-20 21:35:00
last_update2022-01-20 21:35:00
depth2
children3
last_payout2022-01-27 21:35:00
cashout_time1969-12-31 23:59:59
total_payout_value0.010 HBD
curator_payout_value0.010 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length257
author_reputation380,629,995,451
root_title"Execution pipeline in plug-and-play architecture in Asp.NET 5"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id109,699,813
net_rshares19,761,493,986
author_curate_reward""
vote details (1)
@cmplxty ·
That's great, no worries! Vacation is critical in my opinion lol I'm glad you responded! If you run out of resource credits and the blockchain yells at you let me know and I can delegate you some more! It takes a few weeks to get enough credits to be able to post and comment consistently. Usually around 50 Hive Power is good enough for whatever you need to do.
properties (22)
authorcmplxty
permlinkre-dotnetguru-r613ku
categoryhive-169321
json_metadata{"tags":["hive-169321"],"app":"peakd/2021.12.1"}
created2022-01-20 21:55:42
last_update2022-01-20 21:55:42
depth3
children2
last_payout2022-01-27 21:55:42
cashout_time1969-12-31 23:59:59
total_payout_value0.000 HBD
curator_payout_value0.000 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length362
author_reputation783,785,300,628,314
root_title"Execution pipeline in plug-and-play architecture in Asp.NET 5"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id109,700,227
net_rshares0
@hivebuzz ·
Congratulations @dotnetguru! You have completed the following achievement on the Hive blockchain and have been rewarded with new badge(s):

<table><tr><td><img src="https://images.hive.blog/60x70/http://hivebuzz.me/@dotnetguru/payout.png?202201131948"></td><td>You received more than 10 HP as payout for your posts and comments.<br>Your next payout target is 50 HP.<br><sub>The unit is Hive Power equivalent because your rewards can be split into HP and HBD</sub></td></tr>
</table>

<sub>_You can view your badges on [your board](https://hivebuzz.me/@dotnetguru) and compare yourself to others in the [Ranking](https://hivebuzz.me/ranking)_</sub>
<sub>_If you no longer want to receive notifications, reply to this comment with the word_ `STOP`</sub>



**Check out the last post from @hivebuzz:**
<table><tr><td><a href="/hivebuzz/@hivebuzz/pum-202201-10"><img src="https://images.hive.blog/64x128/https://i.imgur.com/SLXQX7g.png"></a></td><td><a href="/hivebuzz/@hivebuzz/pum-202201-10">Hive Power Up Month - Feedback from day 10</a></td></tr></table>

###### Support the HiveBuzz project. [Vote](https://hivesigner.com/sign/update_proposal_votes?proposal_ids=%5B%22199%22%5D&approve=true) for [our proposal](https://peakd.com/me/proposals/199)!
properties (22)
authorhivebuzz
permlinknotify-dotnetguru-20220113t195507
categoryhive-169321
json_metadata{"image":["http://hivebuzz.me/notify.t6.png"]}
created2022-01-13 19:55:03
last_update2022-01-13 19:55:03
depth1
children0
last_payout2022-01-20 19:55:03
cashout_time1969-12-31 23:59:59
total_payout_value0.000 HBD
curator_payout_value0.000 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length1,248
author_reputation369,424,823,437,015
root_title"Execution pipeline in plug-and-play architecture in Asp.NET 5"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id109,456,215
net_rshares0