Skip to content

Commit 548e3ba

Browse files
authored
Merge pull request #34 from DevJasperNL/feature/ServiceProviderPipeline
Implemented specific class to be used for DI.
2 parents cb3c0db + d656357 commit 548e3ba

File tree

5 files changed

+181
-31
lines changed

5 files changed

+181
-31
lines changed

src/AutomationPipelines/Extensions/ServiceCollectionExtensions.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ public static class ServiceCollectionExtensions
1313
public static IServiceCollection AddAutomationPipelines(this IServiceCollection serviceCollection)
1414
{
1515
return serviceCollection
16-
.AddTransient(typeof(IPipeline<>), typeof(Pipeline<>))
17-
.AddTransient(typeof(Pipeline<>), typeof(Pipeline<>));
16+
.AddTransient(typeof(IPipeline<>), typeof(ServiceProviderPipeline<>))
17+
.AddTransient(typeof(Pipeline<>), typeof(ServiceProviderPipeline<>))
18+
.AddTransient(typeof(ServiceProviderPipeline<>), typeof(ServiceProviderPipeline<>));
1819
}
1920
}

src/AutomationPipelines/IPipeline.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,14 @@ public interface IPipeline<TState> : IPipelineNode<TState>
1111
IPipeline<TState> SetDefault(TState state);
1212

1313
/// <summary>
14-
/// Registers a new node in the pipeline. The node will be created using the service provider.
14+
/// Registers a new node in the pipeline.
1515
/// </summary>
1616
IPipeline<TState> RegisterNode<TNode>() where TNode : IPipelineNode<TState>;
1717

1818
/// <summary>
1919
/// Registers a new node in the pipeline. The node is passed as a parameter.
2020
/// </summary>
21-
IPipeline<TState> RegisterNode<TNode>(TNode node) where TNode : IPipelineNode<TState>;
21+
IPipeline<TState> RegisterNode(IPipelineNode<TState> node);
2222

2323
/// <summary>
2424
/// Sets the output handler for the pipeline. This handler will be called whenever a new output is produced by the pipeline.

src/AutomationPipelines/Pipeline.cs

Lines changed: 83 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
using Microsoft.Extensions.DependencyInjection;
2-
using Microsoft.Extensions.Logging;
1+
using Microsoft.Extensions.Logging;
2+
using System.Xml.Linq;
33

44
namespace AutomationPipelines;
55

@@ -9,24 +9,92 @@ namespace AutomationPipelines;
99
public class Pipeline<TState> : PipelineNode<TState>, IPipeline<TState>
1010
{
1111
private readonly List<IPipelineNode<TState>> _nodes = new();
12-
private ILogger<Pipeline<TState>>? _logger;
12+
private readonly ILogger<Pipeline<TState>>? _logger;
1313

1414
private bool _callActionDistinct = true;
1515
private Action<TState>? _action;
1616
private IDisposable? _subscription;
17-
private readonly IServiceProvider _serviceProvider;
1817

19-
/// <inheritdoc />
20-
public Pipeline(IServiceProvider serviceProvider)
18+
/// <summary>
19+
/// Initializes a new, empty pipeline with no nodes.
20+
/// </summary>
21+
public Pipeline()
2122
{
22-
_serviceProvider = serviceProvider;
2323
}
2424

25-
/// <inheritdoc />
26-
public Pipeline(IServiceProvider serviceProvider, ILogger<Pipeline<TState>>? logger)
25+
/// <summary>
26+
/// Initializes a new pipeline with the specified nodes.
27+
/// </summary>
28+
public Pipeline(IEnumerable<IPipelineNode<TState>> nodes)
29+
: this(nodes, null)
30+
{
31+
}
32+
33+
/// <summary>
34+
/// Initializes a new pipeline with the specified default state, nodes, and output handler.
35+
/// </summary>
36+
public Pipeline(TState defaultState, IEnumerable<IPipelineNode<TState>> nodes, Action<TState> outputHandlerAction)
37+
: this(defaultState, nodes, outputHandlerAction, null)
38+
{
39+
}
40+
41+
/// <summary>
42+
/// Initializes a new pipeline with the specified nodes.
43+
/// </summary>
44+
public Pipeline(params IPipelineNode<TState>[] nodes)
45+
{
46+
foreach (var node in nodes)
47+
{
48+
RegisterNode(node);
49+
}
50+
}
51+
52+
/// <summary>
53+
/// Initializes a new pipeline with the specified default state and nodes.
54+
/// </summary>
55+
public Pipeline(TState defaultState, params IPipelineNode<TState>[] nodes)
56+
{
57+
foreach (var node in nodes)
58+
{
59+
RegisterNode(node);
60+
}
61+
62+
SetDefault(defaultState);
63+
}
64+
65+
/// <summary>
66+
/// Initializes a new, empty pipeline with an optional logger.
67+
/// </summary>
68+
public Pipeline(ILogger<Pipeline<TState>>? logger)
69+
{
70+
_logger = logger;
71+
}
72+
73+
/// <summary>
74+
/// Initializes a new pipeline with the specified nodes and an optional logger.
75+
/// </summary>
76+
public Pipeline(IEnumerable<IPipelineNode<TState>> nodes, ILogger<Pipeline<TState>>? logger)
77+
{
78+
_logger = logger;
79+
foreach (var node in nodes)
80+
{
81+
RegisterNode(node);
82+
}
83+
}
84+
85+
/// <summary>
86+
/// Initializes a new pipeline with the specified default state, nodes, output handler, and an optional logger.
87+
/// </summary>
88+
public Pipeline(TState defaultState, IEnumerable<IPipelineNode<TState>> nodes, Action<TState> outputHandlerAction, ILogger<Pipeline<TState>>? logger)
2789
{
28-
_serviceProvider = serviceProvider;
2990
_logger = logger;
91+
foreach (var node in nodes)
92+
{
93+
RegisterNode(node);
94+
}
95+
96+
SetDefault(defaultState);
97+
SetOutputHandler(outputHandlerAction);
3098
}
3199

32100
/// <inheritdoc />
@@ -36,14 +104,16 @@ public IPipeline<TState> SetDefault(TState state)
36104
return this;
37105
}
38106

39-
/// <inheritdoc />
107+
/// <summary>
108+
/// Registers a new node in the pipeline. The node will be created using the type's parameterless constructor.
109+
/// </summary>
40110
public IPipeline<TState> RegisterNode<TNode>() where TNode : IPipelineNode<TState>
41111
{
42-
return RegisterNode(ActivatorUtilities.CreateInstance<TNode>(_serviceProvider));
112+
return RegisterNode((TNode)Activator.CreateInstance(typeof(TNode))!);
43113
}
44114

45115
/// <inheritdoc />
46-
public IPipeline<TState> RegisterNode<TNode>(TNode node) where TNode : IPipelineNode<TState>
116+
public IPipeline<TState> RegisterNode(IPipelineNode<TState> node)
47117
{
48118
_subscription?.Dispose(); // Dispose old subscription if any.
49119
_subscription = node.OnNewOutput.Subscribe(SetOutputAndCallActionWhenApplicable);
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
using Microsoft.Extensions.DependencyInjection;
2+
using Microsoft.Extensions.Logging;
3+
4+
namespace AutomationPipelines;
5+
6+
/// <summary>
7+
/// Represents a pipeline of nodes.
8+
/// This pipeline implementation can use the service provider to resolve nodes.
9+
/// </summary>
10+
public class ServiceProviderPipeline<TState> : Pipeline<TState>
11+
{
12+
private readonly IServiceProvider _serviceProvider;
13+
14+
/// <inheritdoc />
15+
public ServiceProviderPipeline(IServiceProvider serviceProvider)
16+
{
17+
_serviceProvider = serviceProvider;
18+
}
19+
20+
/// <inheritdoc />
21+
public ServiceProviderPipeline(IServiceProvider serviceProvider, IEnumerable<IPipelineNode<TState>> nodes)
22+
: base(nodes)
23+
{
24+
_serviceProvider = serviceProvider;
25+
}
26+
27+
/// <inheritdoc />
28+
public ServiceProviderPipeline(
29+
IServiceProvider serviceProvider,
30+
TState defaultState,
31+
IEnumerable<IPipelineNode<TState>> nodes,
32+
Action<TState> outputHandlerAction)
33+
: base(defaultState, nodes, outputHandlerAction)
34+
{
35+
_serviceProvider = serviceProvider;
36+
}
37+
38+
/// <inheritdoc />
39+
public ServiceProviderPipeline(IServiceProvider serviceProvider, params IPipelineNode<TState>[] nodes)
40+
: base(nodes)
41+
{
42+
_serviceProvider = serviceProvider;
43+
}
44+
45+
/// <inheritdoc />
46+
public ServiceProviderPipeline(IServiceProvider serviceProvider, TState defaultState, params IPipelineNode<TState>[] nodes)
47+
: base(defaultState, nodes)
48+
{
49+
_serviceProvider = serviceProvider;
50+
}
51+
52+
/// <inheritdoc />
53+
public ServiceProviderPipeline(IServiceProvider serviceProvider, ILogger<Pipeline<TState>>? logger) : base(logger)
54+
{
55+
_serviceProvider = serviceProvider;
56+
}
57+
58+
/// <inheritdoc />
59+
public ServiceProviderPipeline(IServiceProvider serviceProvider, IEnumerable<IPipelineNode<TState>> nodes, ILogger<Pipeline<TState>>? logger)
60+
: base(nodes, logger)
61+
{
62+
_serviceProvider = serviceProvider;
63+
}
64+
65+
/// <inheritdoc />
66+
public ServiceProviderPipeline(
67+
IServiceProvider serviceProvider,
68+
TState defaultState,
69+
IEnumerable<IPipelineNode<TState>> nodes,
70+
Action<TState> outputHandlerAction, ILogger<Pipeline<TState>>? logger)
71+
: base(defaultState, nodes, outputHandlerAction, logger)
72+
{
73+
_serviceProvider = serviceProvider;
74+
}
75+
76+
/// <summary>
77+
/// Registers a new node in the pipeline. The node will be created using the service provider.
78+
/// </summary>
79+
public new IPipeline<TState> RegisterNode<TNode>() where TNode : IPipelineNode<TState>
80+
{
81+
return RegisterNode(ActivatorUtilities.CreateInstance<TNode>(_serviceProvider));
82+
}
83+
}

tests/AutomationPipelines.Tests/PipelineTests.cs

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ namespace AutomationPipelines.Tests;
55
[TestClass]
66
public sealed class PipelineTests
77
{
8-
private readonly IServiceProvider _serviceProvider = new Mock<IServiceProvider>().Object;
9-
108
[TestMethod]
119
public void DefaultValue()
1210
{
@@ -15,7 +13,7 @@ public void DefaultValue()
1513

1614
string? emittedOutput = null;
1715

18-
var pipeline = new Pipeline<string>(_serviceProvider);
16+
var pipeline = new Pipeline<string>();
1917
pipeline.OnNewOutput.Subscribe(o => emittedOutput = o);
2018

2119
// Act
@@ -34,8 +32,7 @@ public void OutputHandler_ExecutesDefaultValue()
3432
string? emittedOutput = null;
3533
string? outputHandlerResult = null;
3634

37-
var serviceProvider = new Mock<IServiceProvider>().Object;
38-
var pipeline = new Pipeline<string>(serviceProvider);
35+
var pipeline = new Pipeline<string>();
3936
pipeline.OnNewOutput.Subscribe(o => emittedOutput = o);
4037

4138
pipeline.SetDefault(defaultValue);
@@ -57,8 +54,7 @@ public void OutputHandler_UpdatedByDefaultValue()
5754
string? emittedOutput = null;
5855
string? outputHandlerResult = null;
5956

60-
var serviceProvider = new Mock<IServiceProvider>().Object;
61-
var pipeline = new Pipeline<string>(serviceProvider);
57+
var pipeline = new Pipeline<string>();
6258
pipeline.OnNewOutput.Subscribe(o => emittedOutput = o);
6359
pipeline.SetOutputHandler(s => outputHandlerResult = s);
6460

@@ -80,7 +76,7 @@ public void OutputHandler_ExecutesNodeValue()
8076
string? emittedOutput = null;
8177
string? outputHandlerResult = null;
8278

83-
var pipeline = new Pipeline<string>(_serviceProvider);
79+
var pipeline = new Pipeline<string>();
8480
pipeline.OnNewOutput.Subscribe(o => emittedOutput = o);
8581

8682
pipeline.SetDefault(defaultValue);
@@ -105,7 +101,7 @@ public void OutputHandler_UpdatedWithNewNode()
105101
string? emittedOutput = null;
106102
string? outputHandlerResult = null;
107103

108-
var pipeline = new Pipeline<string>(_serviceProvider);
104+
var pipeline = new Pipeline<string>();
109105
pipeline.OnNewOutput.Subscribe(o => emittedOutput = o);
110106
pipeline.SetOutputHandler(s => outputHandlerResult = s);
111107

@@ -135,7 +131,7 @@ public void OutputHandler_UpdatedWithNewNodeValue()
135131
string? emittedOutput = null;
136132
string? outputHandlerResult = null;
137133

138-
var pipeline = new Pipeline<string>(_serviceProvider);
134+
var pipeline = new Pipeline<string>();
139135
pipeline.OnNewOutput.Subscribe(o => emittedOutput = o);
140136
pipeline.SetOutputHandler(s => outputHandlerResult = s);
141137

@@ -167,7 +163,7 @@ public void OutputHandler_Distinct()
167163
string? emittedOutput = null;
168164
List<string> outputHandlerResults = new();
169165

170-
var pipeline = new Pipeline<string>(_serviceProvider);
166+
var pipeline = new Pipeline<string>();
171167
pipeline.OnNewOutput.Subscribe(o => emittedOutput = o);
172168

173169
pipeline.SetOutputHandler(outputHandlerResults.Add, callActionDistinct: true);
@@ -191,7 +187,7 @@ public void OutputHandler_NotDistinct()
191187
string? emittedOutput = null;
192188
List<string> outputHandlerResults = new();
193189

194-
var pipeline = new Pipeline<string>(_serviceProvider);
190+
var pipeline = new Pipeline<string>();
195191
pipeline.OnNewOutput.Subscribe(o => emittedOutput = o);
196192

197193
pipeline.SetOutputHandler(outputHandlerResults.Add, callActionDistinct: false);
@@ -215,7 +211,7 @@ public void PassThroughNode_ChangesOutputToDefault()
215211
string? emittedOutput = null;
216212
string? outputHandlerResult = null;
217213

218-
var pipeline = new Pipeline<string>(_serviceProvider);
214+
var pipeline = new Pipeline<string>();
219215
pipeline.OnNewOutput.Subscribe(o => emittedOutput = o);
220216
pipeline.SetOutputHandler(s => outputHandlerResult = s);
221217

@@ -248,7 +244,7 @@ public void PassThroughNode_ChangesOutputToPreviousNodeOutput()
248244
string? emittedOutput = null;
249245
string? outputHandlerResult = null;
250246

251-
var pipeline = new Pipeline<string>(_serviceProvider);
247+
var pipeline = new Pipeline<string>();
252248
pipeline.OnNewOutput.Subscribe(o => emittedOutput = o);
253249
pipeline.SetOutputHandler(s => outputHandlerResult = s);
254250

0 commit comments

Comments
 (0)