Category: retarder

Retarder–Fixed and Random strategy and Tests-part 4

Now I want to make a second strategy : the random strategy between a min and a max value. This is only to minimize the impact on the extension that uses the Random – it is good to be hidden inside. For Random Strategy it is better to re-use the Fixed Strategy – and this is the code:

using System;
using System.Threading.Tasks;

namespace NetCoreRetarderCore
{
    public class StrategyAwaitRandom : IStrategyAwait
    {
        StrategyAwaitFixed sf;
        public StrategyAwaitRandom(int min,int max)
        {
            if (min > max)
            {
                var x = min;
                min = max;
                max = min;
            }
            var random = new Random();
            var awaitTime = random.Next(min, max);
            sf = new StrategyAwaitFixed(awaitTime);
        }
        public Task<IStrategyAwait> AwaitDelayAfter()
        {
            return sf.AwaitDelayAfter();
        }

        public Task<IStrategyAwait> AwaitDelayBefore()
        {
            return sf.AwaitDelayBefore();
        }
    }
}

 

Also, I want to make some tests to verify the awaits. So I choose https://github.com/LightBDD/LightBDD and my tests looks like this:

using LightBDD.Framework;
using LightBDD.Framework.Scenarios;
using LightBDD.XUnit2;
using System;
using System.Threading.Tasks;
using Xunit;
[assembly: LightBddScope]

namespace NetCoreRetarderTest
{
    //https://github.com/LightBDD/LightBDD/wiki/Formatting-Parameterized-Steps

    [FeatureDescription(

   @"This will test just how 

will await a determined number of time
")]
    public partial class TestStrategyAwait
    {
        
        [Scenario]

        [Label("wait times fixed")]

        [Trait("Category", "Wait")]
        [InlineData(3)]
        [InlineData(1)]
        [InlineData(0)]
        [InlineData(-1)]

        public async Task WaitTime(int nrSeconds)

        {
           
            await Runner.RunScenarioAsync(

                    _ => When_Choosing_Fixed_Await_For_NRSECONDS_Seconds(nrSeconds),

                    _=> And_Await(),

                    _=> Then_Time_Ellapsed_Will_Be_NRSECONDS_Seconds(Math.Max(nrSeconds, 0))
                    )

                ;

        }
        [Scenario]

        [Label("wait times random")]

        [ScenarioCategory("Wait")]
        [InlineData(3,1)]
        [InlineData(1,2)]
        [InlineData(0,1)]
        [InlineData(-1,5)]

        public async Task WaitTimeRandom(int min,int max)

        {

            await Runner.RunScenarioAsync(

                    _ => When_Choosing_Random_Await_Between_MIN_And_MAX_Seconds(min,max),

                    _ => And_Await(),

                    _ => Then_Time_Ellapsed_Will_Be_Between_MIN_And_MAX_Seconds(Math.Max(min, 0),Math.Max(max,0))
                    )

                ;

        }
    }
}

 
You can find the code at https://github.com/ignatandrei/NetCoreRetarder/commits/version4_tests

Retarder – Making a strategy to wait–part 3

Now I want to make the await configurable. To remind , first is just a random delay ( or static delay). The others are

  1. Delay execution of some endpoints, based on how frequent are their uses

  2. Delay execution based on headers / query string /  routes
  3. Delay execution based on client IP
  4. Delay execution based on the response

The best design pattern for this is Strategy  https://en.wikipedia.org/wiki/Strategy_pattern . Also, because I want to apply multiple await types ( maybe in order, maybe to compose) , a simple Command Pattern will be enough.

So, let’s see how it looks now:

using System.Threading.Tasks;

namespace NetCoreRetarderCore
{
    public interface IStrategyAwait
    {
        Task<IStrategyAwait> AwaitDelay();
    }
}

So now let’s see the implementation of a StrategyAwaitFixed

using System;
using System.Threading.Tasks;

namespace NetCoreRetarderCore
{
    public class StrategyAwaitFixed : IStrategyAwait
    {
        private readonly int milliseconds;

        public StrategyAwaitFixed(int milliseconds)
        {
            this.milliseconds = milliseconds;
        }

        public async Task<IStrategyAwait> AwaitDelay()
        {
            Console.WriteLine($"waiting {milliseconds}");
            
            if (milliseconds < 1)
                return null;

            await Task.Delay(milliseconds);
            
            Console.WriteLine($"finished waiting {milliseconds}");
            
            return null;
        }
    }
}

Now the Retarder Middleware should apply the awaiter one by one

using Microsoft.AspNetCore.Http;
using System;
using System.Threading.Tasks;

namespace NetCoreRetarderCore
{
    public class RetarderMiddleware : IMiddleware
    {
        private IStrategyAwait strategyAwait;

        public RetarderMiddleware(IStrategyAwait strategyAwait)
        {
            this.strategyAwait = strategyAwait;
        }

        public async Task InvokeAsync(HttpContext context, RequestDelegate next)
        {
            while (strategyAwait != null)
                strategyAwait = await strategyAwait?.AwaitDelay();
            
            await next(context);
            
        }
    }
}

The code from middleware extension is modified as generating a new random each time:

using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Text;

namespace NetCoreRetarderCore
{
    public static class RetarderExtensions
    {
        public static void AddRetarder(this IServiceCollection serviceCollection)
        {
            serviceCollection
                .AddTransient<IStrategyAwait, StrategyAwaitFixed>(
                    it =>
                    {
                        var random = new Random();
                        var awaitMilliseconds = random.Next(1, 1000);
                        return new StrategyAwaitFixed(awaitMilliseconds);
                    }
                );
            serviceCollection.AddTransient<RetarderMiddleware>();
        }
        public static void UseRetarder(this IApplicationBuilder app)
        {
            app.UseMiddleware<RetarderMiddleware>();
        }

    }
}

Full Code Source at https://github.com/ignatandrei/NetCoreRetarder/commits/version3_Making_a_strategy_to_wait

Retarder- reorganizing the project to easy use- part 2

Now it is the moment to start reorganizing the project to be easy to use by other programmers. I want, instead of registering the services manually, to can use .AddRetarder and .UseRetarder. So I create a new project, NetCoreRetarderCore.csproj , and move there the RetarderMiddleware . The only new thing is the extension class RetarderExtensions

 

using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Text;

namespace NetCoreRetarderCore
{
    public static class RetarderExtensions
    {
        public static void AddRetarder(this IServiceCollection serviceCollection)
        {
            serviceCollection.AddTransient<RetarderMiddleware>();
        }
        public static void UseRetarder(this IApplicationBuilder app)
        {
            app.UseMiddleware<RetarderMiddleware>();
        }

    }
}

 

This let’s me reorganize the Startup as

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using NetCoreRetarderCore;

namespace NetCoreRetarder
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllers();
            services.AddRetarder();
        }
        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseRouting();

            app.UseAuthorization();
            app.UseRetarder();
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }
    }
}

You can find code at https://github.com/ignatandrei/NetCoreRetarder/commits/version2_reorg

Retarder- idea and POC–part 1

I was thinking about a new project in .NET Core  – Retarder ( Delayer  seems to be better , but I digress ). What about a middleware in .NET Core, that delays execution of any request with 1 second ( or something between 1 millisecond and 1 second )? That way , if someone wants to improve the project , just remove the Retarder !

Other ( better ) uses are :

  1. Delay execution of some endpoints, based on how frequent are their uses
  2. Delay execution based on headers / query string /  routes
  3. Delay execution based on client IP
  4. Delay execution based on the response

 

But for the moment just stick with the static delay of all requests.

Seems to be a good idea to play with middleware. I started a new .NET Core 3.1 project and started coding .

You can find the first version at tag : https://github.com/ignatandrei/NetCoreRetarder/commits/version_1_just_data

The code for Retarder middleware is

using Microsoft.AspNetCore.Http;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace NetCoreRetarder
{
    public class RetarderMiddleware : IMiddleware
    {

        public RetarderMiddleware()
        {
        }

        public async Task InvokeAsync(HttpContext context, RequestDelegate next)
        {
            var random = new Random();
            //var awaitMilliseconds =random.Next(10000, 100000);
            var awaitMilliseconds = random.Next(1, 1000);
            Console.WriteLine($"awaiting {awaitMilliseconds}");
            await Task.Delay(awaitMilliseconds);
            Console.WriteLine($"***awaited {awaitMilliseconds}");

            await next(context);
        }
    }
}


 

The code for using Retarder is:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

namespace NetCoreRetarder
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllers();
            //what if we comment this ?
            //services.AddSingleton<RetarderMiddleware>();
            services.AddTransient<RetarderMiddleware>();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseRouting();

            app.UseAuthorization();
            //app.UseMiddleware(typeof(RetarderMiddleware));
            app.UseMiddleware<RetarderMiddleware>();
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }
    }
}

Some questions :

1.  What is the difference if we have services.AddSingleton  vs services.AddTransient for the middleware ?

2. What if we comment both ?

3. What if we do call later ( or before ) app.UseMiddleware ?

Andrei Ignat weekly software news(mostly .NET)

* indicates required

Please select all the ways you would like to hear from me:

You can unsubscribe at any time by clicking the link in the footer of our emails. For information about our privacy practices, please visit our website.

We use Mailchimp as our marketing platform. By clicking below to subscribe, you acknowledge that your information will be transferred to Mailchimp for processing. Learn more about Mailchimp's privacy practices here.