Anixe.TransactionSteps 2.2.1

dotnet add package Anixe.TransactionSteps --version 2.2.1                
NuGet\Install-Package Anixe.TransactionSteps -Version 2.2.1                
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Anixe.TransactionSteps" Version="2.2.1" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add Anixe.TransactionSteps --version 2.2.1                
#r "nuget: Anixe.TransactionSteps, 2.2.1"                
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install Anixe.TransactionSteps as a Cake Addin
#addin nuget:?package=Anixe.TransactionSteps&version=2.2.1

// Install Anixe.TransactionSteps as a Cake Tool
#tool nuget:?package=Anixe.TransactionSteps&version=2.2.1                

transaction_steps

The idea is to reduce complexity of request processing by split into measurable steps, so:

  • Do you have a lot of logic in the application?
  • Do you have a deep dependency tree?
  • Do you need to know how much time took any transaction part?

Lets make it flat and simple using transaction_steps

  • Define a transaction made from steps or async steps
  public class StepsFactory
  {
    public static LinkedList<IStep> Create()
    {
     return new LinkedList<IStep>
     (
       new IStep[]
       {
         new LoadPackage(),
         new LoadStations(),
         new CreateSupplierRequests(),
         new SendRequestsToSuppliersAsync(),
         new ApplyCalculations(),
         new ApplyRuleEngineImplications(),
         new CreateTransactionResponse(),
       }
     ); 
    }
  }
  • Pass step collection to iterator and run
  public class AnyTransaction
  {
    private readonly IServiceProvider services;

    public CarsTransaction(IServiceProvider services)
    {
      this.services = services;
    }

    public async Task<ResponseModel> ProcessAsync(RequestModel request)
    {
      var ctx = new PropertyBag();
      ctx.Set<RequestModel>(request);
      ctx.Set<ResponseModel>(new ResponseModel{});
      var steps = StepsFactory.Create();
      var errorHandler = new ProcessUnhandledErrors();

      var iterator = new StepIterator<IPropertyBag>(ctx);
      await iterator.IterateAllAsync(this.services, steps, errorHandler, new CancellationToken());
      return ctx.Get<ResponseModel>();
    }
  }  
  • Stats can be collected
  var iterator = new StepIterator<IPropertyBag>(ctx);
  await iterator.IterateAllAsync(this.services, steps, errorHandler, new CancellationToken());

  var stats = iterator.Stats;
  LogIt(stats);
  • Step can be synchronous
  public class ApplyCalculations : SyncStepBase<IPropertyBag>, IStep<IPropertyBag>
  {
    public bool CanProcess()
    {
      //check if conditions to compute are valid
    }

    public void Process()
    {
      //compute something
    }
  }
  • Step can be asynchronous
  • Depenencies are resolved via well known IServiceProvider
  public class UpdateBookInSupplierAsync : AsyncStepBase<IPropertyBag>, IStep<IPropertyBag>
  {
    public bool CanProcess()
    {
      //check if conditions to compute are valid
    }

    public async Task ProcessAsync(CancellationToken token)
    {
      var httpReqest = CreateRequest();
      var client = this.Services.GetService(typeof(HttpClient)) as HttpClient;
      var httpResponse = await client.SendAsync(httpReqest);
      //do something more
    }
  }

  • Steps share context
  public class UpdateBookInSupplierAsync : AsyncStepBase<IPropertyBag>, IStep<IPropertyBag>
  {
    public bool CanProcess()
    {
      //check if conditions to compute are valid
    }

    public async Task ProcessAsync(CancellationToken token)
    {
      var httpReqest = CreateRequest();
      var client = this.Services.GetService(typeof(HttpClient)) as HttpClient; //resolve service
      var httpResponse = await client.SendAsync(httpReqest);
      var response = await ReadResponseAsync(httpResponse);
      this.Context.Set<ResponseModel>(response);//set into context
    }
  }


  public class ApplyCalculations : SyncStepBase<IPropertyBag>, IStep<IPropertyBag>
  {
    public bool CanProcess()
    {
      //check if conditions to compute are valid
    }

    public void Process()
    {
      var response = this.Context.Get<ResponseModel>(); //get from context
      ApplyCalculations(response);
    }
  }  
  • Step can be proxied
  public class StepsFactory
  {
    public static LinkedList<IStep> Create()
    {
     return new LinkedList<IStep>
     (
       new IStep[]
       {
         new ErrorLoggerProxy(new LoadPackage()),
         //more steps
       }
     ); 
    }
  }
  • Step can extend the pipeline at runtime
  public class RegisterTransactionSubmodule : SyncStepBase<IPropertyBag>, IStep<IPropertyBag>
  {
    public bool CanProcess()
    {
      //check if conditions to process are valid
    }

    public void Process()
    {
      this.Neighbourood.AddAfter(this.Current, new ProcessAdditionalLogic());
      this.Neighbourood.AddLast(new SummarizeTransaction());
    }
  }  

StepIteratorTest

Method Mean Error StdDev Gen 0 Gen 1 Gen 2 Allocated
Should_Benchmark_IterateAllAsync_Over_Sync_Steps 3.079 us 0.0303 us 0.0283 us 0.2518 - - 1.55 KB
Should_Benchmark_IterateAllAsync_Over_Async_Steps 3.280 us 0.0858 us 0.0761 us 0.4807 - - 2.95 KB
Should_Benchmark_IterateAllAsync_Over_All_Steps 6.630 us 0.0443 us 0.0370 us 0.6943 - - 4.26 KB

ValueTaskStepIteratorTest

Method Mean Error StdDev Gen 0 Gen 1 Gen 2 Allocated
Should_Benchmark_IterateAllAsync_Over_Sync_Steps 2.754 us 0.0218 us 0.0193 us 0.1755 - - 1.09 KB
Should_Benchmark_IterateAllAsync_Over_Async_Steps 3.095 us 0.0261 us 0.0231 us 0.4044 - - 2.49 KB
Should_Benchmark_IterateAllAsync_Over_All_Steps 6.175 us 0.0448 us 0.0397 us 0.5569 0.0076 - 3.43 KB

PropertyBagTest

Method Mean Error StdDev Median Gen 0 Gen 1 Gen 2 Allocated
Set_Value_Type 5.022 us 0.6291 us 1.7640 us 5.300 us - - - 856 B
Set_Reference_Type 3.356 us 0.2597 us 0.7367 us 2.900 us - - - 136 B
Get_Value_Type 3.904 us 0.2187 us 0.6169 us 4.050 us - - - -
Get_Reference_Type 2.597 us 0.1166 us 0.3030 us 2.500 us - - - -
Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 is compatible. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
2.2.1 17,309 4/1/2022
2.2.0 977 11/18/2021
2.1.0 394 11/15/2021
2.0.5 756 8/6/2021
2.0.4 411 7/12/2021
2.0.3 11,936 2/26/2020
2.0.2 972 11/7/2019
2.0.1 554 10/29/2019
2.0.0 574 10/28/2019
1.0.9 5,830 3/31/2017
1.0.8 978 3/23/2017
1.0.7 1,027 2/14/2017
1.0.6 1,151 2/13/2017

- [MINOR] Fix StepIterator.IterateAllAsync was not working with synchronous error handler