Добавьте файлы проекта.

This commit is contained in:
FrigaT
2025-09-06 00:07:08 +03:00
parent 75b03c81b3
commit eb76069adf
18 changed files with 471 additions and 0 deletions

View File

@@ -0,0 +1,6 @@
namespace PipelineFramework.Abstractions;
public interface IPipeline<TContext>
{
Task ExecuteAsync(TContext context);
}

View File

@@ -0,0 +1,7 @@
namespace PipelineFramework.Abstractions;
public interface IPipelineHook<TContext>
{
Task OnBeforeExecuteAsync(TContext context);
Task OnAfterExecuteAsync(TContext context);
}

View File

@@ -0,0 +1,6 @@
namespace PipelineFramework.Abstractions;
public interface IPipelineMiddleware<TContext>
{
Task InvokeAsync(TContext context, Func<Task> next);
}

View File

@@ -0,0 +1,8 @@
namespace PipelineFramework.Abstractions;
public interface IPipelineModule<TContext>
{
string Id { get; }
IEnumerable<string> DependsOn { get; }
Task ExecuteAsync(TContext context);
}

View File

@@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="9.0.8" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\PipelineFramework\PipelineFramework.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,20 @@
using PipelineFramework;
namespace Microsoft.Extensions.DependencyInjection;
public static class PipelineServiceCollectionExtensions
{
public static IServiceCollection AddPipeline<TContext>(this IServiceCollection services)
{
services.AddTransient<IPipeline<TContext>>(provider =>
{
var modules = provider.GetServices<IPipelineModule<TContext>>().ToList();
var middlewares = provider.GetServices<IPipelineMiddleware<TContext>>().ToList();
var hooks = provider.GetServices<IPipelineHook<TContext>>().ToList();
return new Pipeline<TContext>(modules, middlewares, hooks);
});
return services;
}
}

View File

@@ -0,0 +1,6 @@
namespace PipelineFramework;
public interface IPipeline<TContext>
{
Task RunAsync(TContext context);
}

View File

@@ -0,0 +1,8 @@
namespace PipelineFramework;
public interface IPipelineHook<TContext>
{
Task OnBeforeAsync(TContext context, IPipelineModule<TContext> module);
Task OnAfterAsync(TContext context, IPipelineModule<TContext> module);
Task OnErrorAsync(TContext context, IPipelineModule<TContext> module, Exception ex);
}

View File

@@ -0,0 +1,6 @@
namespace PipelineFramework;
public interface IPipelineMiddleware<TContext>
{
Task InvokeAsync(TContext context, Func<Task> next);
}

View File

@@ -0,0 +1,9 @@
namespace PipelineFramework;
public interface IPipelineModule<TContext>
{
string Id { get; }
IEnumerable<string> DependsOn { get; }
Task ExecuteAsync(TContext context);
}

View File

@@ -0,0 +1,70 @@
namespace PipelineFramework;
public class Pipeline<TContext> : IPipeline<TContext>
{
private readonly List<IPipelineModule<TContext>> _modules;
private readonly List<IPipelineMiddleware<TContext>> _middlewares;
private readonly List<IPipelineHook<TContext>> _hooks;
public Pipeline(
List<IPipelineModule<TContext>> modules,
List<IPipelineMiddleware<TContext>> middlewares,
List<IPipelineHook<TContext>> hooks)
{
_modules = modules;
_middlewares = middlewares;
_hooks = hooks;
}
public async Task RunAsync(TContext context)
{
var executed = new HashSet<string>();
var moduleMap = _modules.ToDictionary(m => m.Id);
Func<Task> pipeline = async () =>
{
while (executed.Count < _modules.Count)
{
var ready = _modules
.Where(m => !executed.Contains(m.Id) &&
m.DependsOn.All(dep => executed.Contains(dep)))
.ToList();
var tasks = ready.Select(m => ExecuteModuleWithHooksAsync(m, context)).ToList();
await Task.WhenAll(tasks);
foreach (var m in ready)
executed.Add(m.Id);
}
};
foreach (var middleware in _middlewares.Reverse())
{
var next = pipeline;
pipeline = () => middleware(context, next);
}
await pipeline();
}
private async Task ExecuteModuleWithHooksAsync(IPipelineModule<TContext> module, TContext context)
{
try
{
foreach (var hook in _hooks)
await hook.OnBeforeAsync(context, module);
await module.ExecuteAsync(context);
foreach (var hook in _hooks)
await hook.OnAfterAsync(context, module);
}
catch (Exception ex)
{
foreach (var hook in _hooks)
await hook.OnErrorAsync(context, module, ex);
throw;
}
}
}

View File

@@ -0,0 +1,38 @@
namespace PipelineFramework;
public abstract class PipelineBuilder<TContext>
{
private readonly List<IPipelineModule<TContext>> _modules = new();
private readonly List<Func<TContext, Func<Task>, Task>> _middlewares = new();
private readonly List<IPipelineHook<TContext>> _hooks = new();
public PipelineBuilder<TContext> AddModule(IPipelineModule<TContext> module)
{
_modules.Add(module);
return this;
}
public PipelineBuilder<TContext> UseMiddleware<T>() where T : IPipelineMiddleware<TContext>, new()
{
_middlewares.Add((ctx, next) => new T().InvokeAsync(ctx, next));
return this;
}
public PipelineBuilder<TContext> UseMiddleware(Func<TContext, Func<Task>, Task> middleware)
{
_middlewares.Add(middleware);
return this;
}
public PipelineBuilder<TContext> AddHook(IPipelineHook<TContext> hook)
{
_hooks.Add(hook);
return this;
}
protected IReadOnlyList<IPipelineModule<TContext>> Modules => _modules;
protected IReadOnlyList<Func<TContext, Func<Task>, Task>> Middlewares => _middlewares;
protected IReadOnlyList<IPipelineHook<TContext>> Hooks => _hooks;
public abstract IPipeline<TContext> Build();
}

View File

@@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>