-
Notifications
You must be signed in to change notification settings - Fork 4
Home
PipelineRD is a library that implements the chain of responsability pattern and brings to you many features to make your code more resilient, readable and easier to maintain. Supports netstandard2.0
and netstandard2.1
.
This library is an improved version of the PipelineR, refactored and better to use it.
Install the package via NuGet first:
Install-Package PipelineRD
PipelineRD has some dependencies such as:
- Polly: used to implement the retry policy to the steps.
- Serilog: to log a possible pipeline error.
PipelineRD has only one dependency:
- Fluent Validation: to add a validator to the pipeline and use it to implement the fail fast principle.
You will need to configure the pipeline using the extension method IServiceCollection.UsePipelineRD
. It's action methods allow you to register the type of cache that you will use, the dependency injection of all pipeline services and the documentation that will be generated after each run.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.UsePipelineRD(x =>
{
// ...
});
}
You can use two types of cache, in memory and redis. Both cache settings contains a TTLInMinutes
property that will hold the value to how many minutes the cache will get hold in place and a KeyPreffix
that will be used to preffix the cache data key. The redis settings contains a connection string property that will be used to connect.
For now, the usage of cache is obrigatory, because the pipeline uses it to go back to a previous state based on a hash that is generated by the json serialized request concatenated with the name of the pipeline.
services.UsePipelineRD(x =>
{
x.SetupCache(new PipelineRDCacheSettings()
{
KeyPreffix = "pipelinerdsample",
TTLInMinutes = 5
});
});
If you prefer, the library contains a built in automatic service injection to the .NET dependency container. You can choose individually which service type to inject. Of course, you can choose to inject all of them at the same time.
All services will be injected with the lifetime scoped, but the validators are singleton.
services.UsePipelineRD(x =>
{
x.AddPipelineServices(x =>
{
x.InjectContexts();
x.InjectHandlers();
x.InjectPipelines();
// Or all
x.InjectAll();
});
});
You can either use by dependency injection IPipeline
or directly instanciation Pipeline
. The way you build the pipeline is using fluent methods.
Method that will add a new handler in to the pipeline. It will handle a step that implements the inherits the class Handler<,>
.
Method that proceeds the method WithHandler
. It will receive a lambda that handles the context object of the pipeline and you can create conditions to execute the handler defined previously.
Method that will start the execution of the pipeline. It receives a object that can be of any type and will be used by the pipeline step as the main model.
Simple one step pipeline initialization
var result = await Pipeline
.WithHandler<CustomHandler>()
.Execute(model);
Multiple steps pipeline initialization
var result = await Pipeline
.WithHandler<CustomOneHandler>()
.WithHandler<CustomTwoHandler>()
.Execute(model);
Multiple conditional steps pipeline initialization
var result = await Pipeline
.WithHandler<CustomOneHandler>()
.WithHandler<CustomTwoHandler>()
.When(b => b.Id == "testOne")
.WithHandler<CustomTwoHandler>()
.When(b => b.Id == "testTwo")
.Execute(model);
It is a shared model between the pipeline steps. You can use to share variables. It needs to implement the abstract class BaseContext
.
You can define a handler by inheriting the classe Handler<TContext, TRequest>
.
Method that handles the advance of the pipeline. It will be used when you want to proceed to the next handler.
Method that handles the abortion of the pipeline. It will be used when you want to abort the execution. It is used together with the return keyword and receives the object HandlerError
.
Method that handles the ending of the pipeline. It will be used when you want to end the execution and return a result. It is used together with the return keyword.
Simple sync request step
public class SimpleCustomHandler : Handler<CustomContext, RequestModel>
{
public override Task<HandlerResult> Handle(RequestModel request)
{
Console.WriteLine("SimpleCustomHandler ");
// ...
return Proceed();
}
}
Request step with abort
public class SimpleCustomHandler : Handler<CustomContext, RequestModel>
{
public override Task<HandlerResult> Handle(RequestModel request)
{
Console.WriteLine("SimpleCustomHandler ");
// ...
if(model.type == "inactive")
{
var error = new HandlerError("Inactive");
return Abort(error, HttpStatusCode.BadRequest);
}
return Proceed();
}
}
Request step with finish
public class SimpleCustomHandler : : Handler<CustomContext, RequestModel>
{
public override Task<HandlerResult> Handle(RequestModel request)
{
Console.WriteLine("SimpleCustomHandler");
// ...
if (model.type == "inactive")
{
var error = new HandlerError("Inactive");
return Abort(error, HttpStatusCode.BadRequest);
}
var result = new CustomResultModel();
return Finish(result, HttpStatusCode.OK);
}
}