Quick Start¶
Step 1: Create the Context¶
Create a PipelineContext
class for your pipeline
This is a POCO that inherits from PipelineContext
and implements the IPipelineContext
interface
1 2 3 4 | public class MyApplicationContext : PipelineContext, IPipelineContext
{
// Add your properties
}
|
Step 2: Create the Coordinator¶
Create the PipelineCoordinator
class.
Your Pipeline Coordinator class simply inherits from BasePipelineCoordinator<TContext>
and
provides the following:
It specifies the type of
PipelineContext
object that will be processed. In this example it is and object of typeMyApplicationContext
It accepts two
IReadOnlyDictionary<TKey, TValue>
collections that are automatically injected by the DI container for you. Your Pipeline Coordinator class simply accepts the injected collections and passes them to the base. Nothing further is required with those collections.The
Context
property must be initialized. In this example it is the lineContext = new MyApplicationContext
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | using System;
using System.Collections.Generic;
using KnightMoves.Pipelines;
using KnightMoves.Pipelines.Interfaces;
public class MyPipelineCoordinator : BasePipelineCoordinator<MyApplicationContext>
{
public MyPipelineCoordinator(
IReadOnlyDictionary<Type, IPipelineOperation<MyApplicationContext>> operations,
IReadOnlyDictionary<Type, IPipelineOperationAsync<MyApplicationContext>> asyncOperations
)
:base(operations, asyncOperations)
{
Context = new MyApplicationContext();
}
}
|
Step 3: Create Your Operations¶
Non-Async Operations¶
Create a Marker Interface that inherits from
IPipelineOperation<T>
Inherit from
BaseOperation<T>
and implement the Marker InterfaceImplement the
Execute()
method
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | using KnightMoves.Pipelines;
using KnightMoves.Pipelines.Interfaces;
// Marker Interface
public interface IMyOperation : IPipelineOperation<MyApplicationContext> { }
public class MyOperation : BasePipelineOperation<MyApplicationContext>, IMyOperation
{
public override void Execute(MyApplicationContext context)
{
// Test for previous operation's success/failure if necessary
if(!context.Successful)
return;
// Implement operation logic here using the context as needed
// Report result
context.ResultMessages.Add("[MyOperation] Successfully executed my operation");
}
}
|
Async Operations¶
Create a Marker Interface that inherits from
IPipelineOperationAsync<T>
Inherit from
BaseOperationAsync<T>
and implement the Marker InterfaceImplement the
ExecuteAsync()
and theCompletedTaskCallback()
methods
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | using KnightMoves.Pipelines;
using KnightMoves.Pipelines.Interfaces;
// Marker Interface
public interface IMyOperationAsync : IPipelineOperationAsync<MyApplicationContext> { }
public class MyOperationAsync : BasePipelineOperationAsync<MyApplicationContext>, IMyOperationAsync
{
private readonly SomeApiClient _someApiClient;
// Constructor with injected repositories or API clients here
// No need to use async/await ... the returned Task is awaited for you
public override Task ExecuteAsync()
{
// Test for previous operation's success/failure if necessary
if(!Context.Successful)
return;
// Implement async operation logic here using the Context as needed
return _someApiClient.GetStuffAsync(Context.SomeId);
}
public override void CompletedTaskCallback(object task)
{
// Good practice to check for proper casting of the task
var t = task as Task<IEnumerable<Stuff>>;
if(t == null)
return;
IEnumerable<Stuff> stuff = t.Result;
Context.ListOfStuff = stuff;
Context.ResultMessages.Add("[MyOperationAsync] Successfully retrieved stuff");
}
}
|
Warning
If your Operation requires that another Operation be executed before it in the pipeline, then this
is an Operation-to-Operation dependency and you should add those dependencies to the Dependencies
collection in the Operation’s constructor.
Step 4: Add Registrations¶
Add Service Registrations for Dependency Injection
Use the
AddPipelineCoordinator<TOpMgr, TContext>
extension method provided with the Pipelines framework.TOpMgr
is the type of your Pipeline Coordinator. In this example it isMyPipelineCoordinator
TContext
is the type of your Pipeline Context. In this example it isMyApplicationContext
Using IServiceCollection¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | using Microsoft.Extensions.DependencyInjection;
using KnightMoves.Pipelines.DependencyInjection;
public class Startup
{
...
public void ConfigureServices(IServiceCollection services)
{
...
services.AddPipelineCoordinator<MyPipelineCoordinator, MyApplicationContext>
(
typeof(Startup).Assembly
);
...
}
}
|
Using Autofac¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | using Autofac;
using KnightMoves.Pipelines.DependencyInjection;
public class Startup
{
...
public LifetimeScope AutofacContainer { get; private set; }
public void ConfigureContainer(ContainerBuilder builder)
{
...
builder.AddPipelineCoordinator<MyPipelineCoordinator, MyApplicationContext>
(
typeof(Startup).Assembly
);
...
}
...
}
|
Tip
Step 5: Execute and Process¶
Use the Operations and process the results
To use the operations all you have to do is
Inject your Pipeline Coordinator
Execute your operations in the order that you choose
Process the resulting Context as needed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | using KnightMoves.Pipelines.Interfaces;
public class MyBusinessLogicCoordinator : IBusinessLogic
{
private readonly IPipelineCoordinator<MyApplicationContext> _pipelineCoordinator;
public MyBusinessLogicCoordinator(IPipelineCoordinator<MyApplicationContext> pipelineCoordinator)
{
_pipelineCoordinator = pipelineCoordinator;
}
public async Task<IEnumerable<Stuff>> BuildStuffAsync(int data)
{
_pipelineCoordinator.Context.Data = data;
// Use Task.Run() if BuildStuff is an Async method
await Task.Run(() =>
_pipelineCoordinator
.Execute<IMyOperation>()
.ExecuteAsync<IMyOperationAsync>()
);
return _pipelineCoordinator.Context.Stuff;
}
}
|