Skip to content

Instantly share code, notes, and snippets.

@benfoster
Created June 23, 2016 07:24
Show Gist options
  • Save benfoster/1281408c759e65376e3f30fb33eb2a9c to your computer and use it in GitHub Desktop.
Save benfoster/1281408c759e65376e3f30fb33eb2a9c to your computer and use it in GitHub Desktop.
c# Pipeline
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace PipelineDemo
{
// http://www.rantdriven.com/post/2009/09/16/Simple-Pipe-and-Filters-Implementation-in-C-with-Fluent-Interface-Behavior.aspx
public interface IFilter<TContext>
{
void Register(IFilter<TContext> filter);
Task Execute(TContext context);
}
public abstract class Filter<TContext> : IFilter<TContext>
{
private IFilter<TContext> next;
protected abstract Task Execute(TContext context, Func<TContext, Task> next);
public void Register(IFilter<TContext> filter)
{
if (next == null)
{
next = filter;
}
else
{
next.Register(filter);
}
}
Task IFilter<TContext>.Execute(TContext context)
{
return Execute(context, ctx => next == null
? Task.CompletedTask
: next.Execute(ctx));
}
}
public class Pipeline<T>
{
private IFilter<T> root;
public Pipeline<T> Register(IFilter<T> filter)
{
if (root == null)
{
root = filter;
}
else
{
root.Register(filter);
}
return this;
}
public Task Execute(T context)
{
return root.Execute(context);
}
}
public class PipelineBuilder<T>
{
private List<Func<IFilter<T>>> filters = new List<Func<IFilter<T>>>();
public PipelineBuilder<T> Register(Func<IFilter<T>> filter)
{
filters.Add(filter);
return this;
}
public PipelineBuilder<T> Register(IFilter<T> filter)
{
filters.Add(() => filter);
return this;
}
public IFilter<T> Build()
{
var root = filters.First().Invoke();
foreach (var filter in filters.Skip(1))
{
root.Register(filter.Invoke());
}
return root;
}
}
}
using System;
using System.Diagnostics;
using System.Threading.Tasks;
namespace PipelineDemo
{
public class Program
{
public static void Main(string[] args)
{
// var result = new Pipeline<string>()
// .Register(new UppercaseFilter())
// .Register(new WhitespaceFilter())
// .Execute("Hello World");
// Console.WriteLine(result);
var context = new HttpContext();
new Pipeline<HttpContext>()
.Register(new TimingFilter())
.Register(new LoggingFilter())
.Register(new ResponseFilter())
.Execute(context)
.Wait();
var pipeline = new PipelineBuilder<HttpContext>()
.Register(new TimingFilter())
.Register(new LoggingFilter())
.Register(new ResponseFilter())
.Build();
pipeline.Execute(context).Wait();
}
}
public class HttpContext
{
public string Response { get;set;}
}
public class ResponseFilter : Filter<HttpContext>
{
protected override Task Execute(HttpContext context, Func<HttpContext, Task> next)
{
context.Response = "<h1>Hello world</h1>";
Console.WriteLine($"Setting Response: {context.Response}");
return Task.Delay(3000);
}
}
public class LoggingFilter : Filter<HttpContext>
{
protected override async Task Execute(HttpContext context, Func<HttpContext, Task> next)
{
Console.WriteLine("Before Request");
await next(context);
Console.WriteLine("After Request");
}
}
public class TimingFilter : Filter<HttpContext>
{
protected override async Task Execute(HttpContext context, Func<HttpContext, Task> next)
{
var sw = new Stopwatch();
sw.Start();
await next(context);
sw.Stop();
Console.WriteLine($"Completed request in {sw.ElapsedMilliseconds}ms");
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment