├── .gitignore
├── .nuget
├── NuGet.Config
└── NuGet.exe
├── FluentDataflow.Tests.Console
├── App.config
├── FluentDataflow.Tests.Console.csproj
├── Program.cs
├── Properties
│ └── AssemblyInfo.cs
└── packages.config
├── FluentDataflow.Tests.UnitTests
├── DataflowWrapperTests.cs
├── FluentDataflow.Tests.UnitTests.csproj
├── MultipleDataflowWrapperTests.cs
├── MultipleSourceDataflowBuilderTests.cs
├── PropagatorDataflowBuilderTests.cs
├── PropagatorDataflowWrapperTests.cs
├── Properties
│ └── AssemblyInfo.cs
├── SourceDataflowBuilderTests.cs
├── SourceDataflowWrapperTests.cs
├── TargetDataflowWrapperTests.cs
└── packages.config
├── FluentDataflow.sln
├── FluentDataflow
├── Assembly.cs
├── BroadcastDataflowBuilder.cs
├── BroadcastDataflowWrapper.cs
├── DataflowBatchOptions.cs
├── DataflowBuilder.cs
├── DataflowBuilderExtenions.cs
├── DataflowDefaultOptions.cs
├── DataflowFactory.cs
├── DataflowFactoryExtensions.cs
├── DataflowJoinOptions.cs
├── DataflowOptionsExtensions.cs
├── DataflowWrapper.cs
├── DataflowWriteOnceOptions.cs
├── FluentDataflow.csproj
├── FluentDataflow.nuspec
├── IDataflowBuilder.cs
├── IDataflowFactory.cs
├── LinkHelper.cs
├── MultipleSourceDataflowBuilder.cs
├── MultipleSourceDataflowWrapper.cs
├── PropagatorDataflowBuilder.cs
├── PropagatorDataflowWrapper.cs
├── ReceivablePropagatorDataflowWrapper.cs
├── ReceivableSourceDataflowWrapper.cs
├── SourceDataflowBuilder.cs
├── SourceDataflowWrapper.cs
├── TargetDataflowBuilder.cs
└── TargetDataflowWrapper.cs
├── FluentDataflowPortable
├── FluentDataflowPortable.csproj
├── FluentDataflowPortable.sln
├── Properties
│ └── AssemblyInfo.cs
└── packages.config
├── LICENSE
├── README.md
├── build.ps1
├── pack.ps1
└── push.ps1
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # User-specific files (MonoDevelop/Xamarin Studio)
11 | *.userprefs
12 |
13 | # Build results
14 | [Dd]ebug/
15 | [Dd]ebugPublic/
16 | [Rr]elease/
17 | [Rr]eleases/
18 | x64/
19 | x86/
20 | bld/
21 | [Bb]in/
22 | [Oo]bj/
23 |
24 | # Visual Studio 2015 cache/options directory
25 | .vs/
26 | # Uncomment if you have tasks that create the project's static files in wwwroot
27 | #wwwroot/
28 |
29 | # MSTest test Results
30 | [Tt]est[Rr]esult*/
31 | [Bb]uild[Ll]og.*
32 |
33 | # NUNIT
34 | *.VisualState.xml
35 | TestResult.xml
36 |
37 | # Build Results of an ATL Project
38 | [Dd]ebugPS/
39 | [Rr]eleasePS/
40 | dlldata.c
41 |
42 | # DNX
43 | project.lock.json
44 | artifacts/
45 |
46 | *_i.c
47 | *_p.c
48 | *_i.h
49 | *.ilk
50 | *.meta
51 | *.obj
52 | *.pch
53 | *.pdb
54 | *.pgc
55 | *.pgd
56 | *.rsp
57 | *.sbr
58 | *.tlb
59 | *.tli
60 | *.tlh
61 | *.tmp
62 | *.tmp_proj
63 | *.log
64 | *.vspscc
65 | *.vssscc
66 | .builds
67 | *.pidb
68 | *.svclog
69 | *.scc
70 |
71 | # Chutzpah Test files
72 | _Chutzpah*
73 |
74 | # Visual C++ cache files
75 | ipch/
76 | *.aps
77 | *.ncb
78 | *.opendb
79 | *.opensdf
80 | *.sdf
81 | *.cachefile
82 |
83 | # Visual Studio profiler
84 | *.psess
85 | *.vsp
86 | *.vspx
87 | *.sap
88 |
89 | # TFS 2012 Local Workspace
90 | $tf/
91 |
92 | # Guidance Automation Toolkit
93 | *.gpState
94 |
95 | # ReSharper is a .NET coding add-in
96 | _ReSharper*/
97 | *.[Rr]e[Ss]harper
98 | *.DotSettings.user
99 |
100 | # JustCode is a .NET coding add-in
101 | .JustCode
102 |
103 | # TeamCity is a build add-in
104 | _TeamCity*
105 |
106 | # DotCover is a Code Coverage Tool
107 | *.dotCover
108 |
109 | # NCrunch
110 | _NCrunch_*
111 | .*crunch*.local.xml
112 | nCrunchTemp_*
113 |
114 | # MightyMoose
115 | *.mm.*
116 | AutoTest.Net/
117 |
118 | # Web workbench (sass)
119 | .sass-cache/
120 |
121 | # Installshield output folder
122 | [Ee]xpress/
123 |
124 | # DocProject is a documentation generator add-in
125 | DocProject/buildhelp/
126 | DocProject/Help/*.HxT
127 | DocProject/Help/*.HxC
128 | DocProject/Help/*.hhc
129 | DocProject/Help/*.hhk
130 | DocProject/Help/*.hhp
131 | DocProject/Help/Html2
132 | DocProject/Help/html
133 |
134 | # Click-Once directory
135 | publish/
136 |
137 | # Publish Web Output
138 | *.[Pp]ublish.xml
139 | *.azurePubxml
140 | # TODO: Comment the next line if you want to checkin your web deploy settings
141 | # but database connection strings (with potential passwords) will be unencrypted
142 | *.pubxml
143 | *.publishproj
144 |
145 | # NuGet Packages
146 | *.nupkg
147 | # The packages folder can be ignored because of Package Restore
148 | **/packages/*
149 | # except build/, which is used as an MSBuild target.
150 | !**/packages/build/
151 | # Uncomment if necessary however generally it will be regenerated when needed
152 | #!**/packages/repositories.config
153 | # NuGet v3's project.json files produces more ignoreable files
154 | *.nuget.props
155 | *.nuget.targets
156 |
157 | # Microsoft Azure Build Output
158 | csx/
159 | *.build.csdef
160 |
161 | # Microsoft Azure Emulator
162 | ecf/
163 | rcf/
164 |
165 | # Microsoft Azure ApplicationInsights config file
166 | ApplicationInsights.config
167 |
168 | # Windows Store app package directory
169 | AppPackages/
170 | BundleArtifacts/
171 |
172 | # Visual Studio cache files
173 | # files ending in .cache can be ignored
174 | *.[Cc]ache
175 | # but keep track of directories ending in .cache
176 | !*.[Cc]ache/
177 |
178 | # Others
179 | ClientBin/
180 | ~$*
181 | *~
182 | *.dbmdl
183 | *.dbproj.schemaview
184 | *.pfx
185 | *.publishsettings
186 | node_modules/
187 | orleans.codegen.cs
188 |
189 | # RIA/Silverlight projects
190 | Generated_Code/
191 |
192 | # Backup & report files from converting an old project file
193 | # to a newer Visual Studio version. Backup files are not needed,
194 | # because we have git ;-)
195 | _UpgradeReport_Files/
196 | Backup*/
197 | UpgradeLog*.XML
198 | UpgradeLog*.htm
199 |
200 | # SQL Server files
201 | *.mdf
202 | *.ldf
203 |
204 | # Business Intelligence projects
205 | *.rdl.data
206 | *.bim.layout
207 | *.bim_*.settings
208 |
209 | # Microsoft Fakes
210 | FakesAssemblies/
211 |
212 | # GhostDoc plugin setting file
213 | *.GhostDoc.xml
214 |
215 | # Node.js Tools for Visual Studio
216 | .ntvs_analysis.dat
217 |
218 | # Visual Studio 6 build log
219 | *.plg
220 |
221 | # Visual Studio 6 workspace options file
222 | *.opt
223 |
224 | # Visual Studio LightSwitch build output
225 | **/*.HTMLClient/GeneratedArtifacts
226 | **/*.DesktopClient/GeneratedArtifacts
227 | **/*.DesktopClient/ModelManifest.xml
228 | **/*.Server/GeneratedArtifacts
229 | **/*.Server/ModelManifest.xml
230 | _Pvt_Extensions
231 |
232 | # Paket dependency manager
233 | .paket/paket.exe
234 |
235 | # FAKE - F# Make
236 | .fake/
237 |
238 | pingme.txt
239 | *.sqlite*
--------------------------------------------------------------------------------
/.nuget/NuGet.Config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.nuget/NuGet.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teddymacn/FluentDataflow/e281e66fb756a1607323d7cd64e5fde2274cd0b3/.nuget/NuGet.exe
--------------------------------------------------------------------------------
/FluentDataflow.Tests.Console/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/FluentDataflow.Tests.Console/FluentDataflow.Tests.Console.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {1B97E995-3FCF-4356-BCEA-91F254D6FA66}
8 | Exe
9 | FluentDataflow.Tests.Console
10 | FluentDataflow.Tests.Console
11 | v4.6.1
12 | 512
13 | true
14 |
15 |
16 | AnyCPU
17 | true
18 | full
19 | false
20 | bin\Debug\
21 | DEBUG;TRACE
22 | prompt
23 | 4
24 |
25 |
26 | AnyCPU
27 | pdbonly
28 | true
29 | bin\Release\
30 | TRACE
31 | prompt
32 | 4
33 |
34 |
35 |
36 |
37 |
38 | ..\packages\System.Threading.Tasks.Dataflow.4.8.0\lib\netstandard2.0\System.Threading.Tasks.Dataflow.dll
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 | {d339ef89-bfcf-47f1-b618-a8fcd382649b}
58 | FluentDataflow
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/FluentDataflow.Tests.Console/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Threading.Tasks;
4 | using System.Threading.Tasks.Dataflow;
5 |
6 | namespace FluentDataflow.Tests.Console
7 | {
8 | class Program
9 | {
10 | private static readonly IDataflowFactory _factory = new DataflowFactory();
11 |
12 | static void Main(string[] args)
13 | {
14 | TestIfElseBranchingAndMerging();
15 | System.Console.ReadLine();
16 | }
17 |
18 | private static ITargetBlock GetAggregatorFlow(out Dictionary result)
19 | {
20 | var splitter = new TransformBlock>(input =>
21 | {
22 | string[] splitted = input.Split('=');
23 | return new KeyValuePair(splitted[0], int.Parse(splitted[1]));
24 | });
25 |
26 | var dict = new Dictionary();
27 |
28 | var aggregater = new ActionBlock>(pair =>
29 | {
30 | int oldValue;
31 | dict[pair.Key] = dict.TryGetValue(pair.Key, out oldValue) ? oldValue + pair.Value : pair.Value;
32 | });
33 |
34 | var dataflow = _factory.FromPropagator(splitter)
35 | .LinkToTarget(aggregater)
36 | .Create();
37 |
38 | result = dict;
39 | return dataflow;
40 | }
41 |
42 | private static void TestAggregatorFlow()
43 | {
44 | var dataflow = GetAggregatorFlow(out Dictionary result);
45 | dataflow.Post("a=1");
46 | dataflow.Post("b=2");
47 | dataflow.Post("a=5");
48 | dataflow.Complete();
49 |
50 | Task.WaitAll(dataflow.Completion);
51 |
52 | System.Console.WriteLine("sum(a) = {0}", result["a"]); //prints sum(a) = 6
53 | }
54 |
55 | private static ITargetBlock GetLineAggregatorFlow(out Dictionary result)
56 | {
57 | var aggregator = GetAggregatorFlow(out result);
58 | var splitter = new TransformManyBlock(line => line.Split(' '));
59 | var dataflow = _factory.FromPropagator(splitter)
60 | .LinkToTarget(aggregator)
61 | .Create();
62 |
63 | return dataflow;
64 | }
65 |
66 | private static void TestLineAggregatorFlow()
67 | {
68 | var dataflow = GetLineAggregatorFlow(out Dictionary result);
69 | dataflow.Post("a=1 b=2 a=5");
70 | dataflow.Post("c=6 b=8");
71 | dataflow.Complete();
72 |
73 | Task.WaitAll(dataflow.Completion);
74 |
75 | System.Console.WriteLine("sum(b) = {0}", result["b"]); //prints sum(b) = 10
76 | }
77 |
78 | private static void TestAggregatorFlowOnError()
79 | {
80 | var dataflow = GetAggregatorFlow(out Dictionary result);
81 | dataflow.Post("a=1");
82 | dataflow.Post("b=2");
83 | dataflow.Post("a=badstring");
84 | dataflow.Complete();
85 |
86 | Task.WaitAll(dataflow.Completion);
87 | }
88 |
89 | private static ITargetBlock GetBroadcastFlow()
90 | {
91 | var printer1 = new ActionBlock(s => System.Console.WriteLine("Printer1: {0}", s));
92 | var printer2 = new ActionBlock(s => System.Console.WriteLine("Printer2: {0}", s));
93 | var printer3 = new ActionBlock(s => System.Console.WriteLine("Printer3: {0}", s));
94 |
95 | var dataflow = _factory.FromBroadcast()
96 | .LinkTo(printer1)
97 | .LinkTo(printer2)
98 | .LinkTo(printer3)
99 | .Create();
100 |
101 | return dataflow;
102 | }
103 |
104 | private static void TestBroadcastFlow()
105 | {
106 | var dataflow = GetBroadcastFlow();
107 | dataflow.Post("first message");
108 | dataflow.Post("second message");
109 | dataflow.Post("third message");
110 | dataflow.Complete();
111 |
112 | Task.WaitAll(dataflow.Completion);
113 | }
114 |
115 | private static void TestMultipleSourcesFlow()
116 | {
117 | // by default, with native TPL, if multiple sources link to the same target,
118 | // if set PropagateCompletion=true,
119 | // as long as one of the source complets, the target complets.
120 | // the target will miss some of the messages from the other sources.
121 |
122 | // BUT, with our dataflow factory here, when set PropagateCompletion=true,
123 | // dataflow.Complete() internally waits for all the sources to complete,
124 | // so the target is guaranteed to receive all the messages from all the sources
125 |
126 | var source1 = new BufferBlock();
127 | var source2 = new BufferBlock();
128 | var source3 = new BufferBlock();
129 | var printer = new ActionBlock(s => System.Console.WriteLine(s));
130 |
131 | var dataflow = _factory.FromMultipleSources(source1, source2, source3)
132 | .LinkToTarget(printer)
133 | .Create();
134 |
135 | for (var i = 0; i < 3; ++i)
136 | {
137 | var s = i.ToString();
138 | source1.Post(s);
139 | source2.Post(s);
140 | source3.Post(s);
141 | }
142 |
143 | dataflow.Complete();
144 |
145 | Task.WaitAll(dataflow.Completion);
146 | }
147 |
148 | private static void TestDataflowLinkWithFilter()
149 | {
150 | // the filter only accepts even numbers,
151 | // so odd numbers goes to declined printer
152 | var filter = new Predicate(i =>
153 | {
154 | return i % 2 == 0;
155 | });
156 | var printer = new ActionBlock(s => System.Console.WriteLine("printer: " + s.ToString()));
157 | var declinedPrinter = new ActionBlock(s => System.Console.WriteLine("declined: " + s.ToString()));
158 | var inputBlock = new BufferBlock();
159 |
160 | var dataflow = _factory.FromPropagator(inputBlock)
161 | .LinkToTarget(printer
162 | , filter
163 | // when linking with filter, you have to specify a declined block
164 | // otherwise, because there will be messages declined still in the queue,
165 | // the current block will not be able to COMPLETE (waits on its Completion will never return)
166 | , declinedPrinter)
167 | .Create();
168 |
169 | for (int i = 0; i < 10; ++i)
170 | {
171 | dataflow.Post(i);
172 | }
173 |
174 | dataflow.Complete();
175 |
176 | Task.WaitAll(dataflow.Completion);
177 | }
178 |
179 | private static void TestBatch()
180 | {
181 | var source = new BufferBlock();
182 | var printer = new ActionBlock>(s => System.Console.WriteLine("printer: " +string.Join("|", s)));
183 |
184 | var dataflow = _factory.FromSource(source)
185 | .Batch(2)
186 | .LinkToTarget(printer)
187 | .Create();
188 |
189 | for (var i = 0; i < 6; ++i)
190 | {
191 | var s = i.ToString();
192 | source.Post(s);
193 | }
194 |
195 | dataflow.Complete();
196 |
197 | Task.WaitAll(dataflow.Completion);
198 | }
199 |
200 | private static void TestJoin()
201 | {
202 | var source1 = new BufferBlock();
203 | var source2 = new BufferBlock();
204 | var printer = new ActionBlock>(s => System.Console.WriteLine("printer: {0},{1}", s.Item1, s.Item2));
205 |
206 | var dataflow = _factory.Join(source1, source2)
207 | .LinkToTarget(printer)
208 | .Create();
209 |
210 | for (var i = 0; i < 3; ++i)
211 | {
212 | var s = i.ToString();
213 | source1.Post(s);
214 | source2.Post(s);
215 | }
216 |
217 | dataflow.Complete();
218 |
219 | Task.WaitAll(dataflow.Completion);
220 | }
221 |
222 | private static void TestBatchedJoin()
223 | {
224 | var source1 = new BufferBlock();
225 | var source2 = new BufferBlock();
226 | var printer = new ActionBlock, IList>>(s => System.Console.WriteLine("printer: {0},{1}", string.Join("|", s.Item1), string.Join("|", s.Item2)));
227 |
228 | var dataflow = _factory.BatchedJoin(source1, source2, 2)
229 | .LinkToTarget(printer)
230 | .Create();
231 |
232 | for (var i = 0; i < 4; ++i)
233 | {
234 | var s = i.ToString();
235 | source1.Post(s);
236 | source2.Post(s);
237 | }
238 |
239 | dataflow.Complete();
240 |
241 | Task.WaitAll(dataflow.Completion);
242 | }
243 |
244 | private static void TestIfElseBranchingAndMerging()
245 | {
246 | // the ifFilter only accepts even numbers,
247 | // so odd numbers goes to elseBlock
248 | var ifFilter = new Predicate(i =>
249 | {
250 | return i % 2 == 0;
251 | });
252 | var printer = new ActionBlock(s => System.Console.WriteLine("printer: " + s.ToString()));
253 | var inputBlock = new BufferBlock();
254 | // if meet ifFilter, convert to: i -> i * 10
255 | var ifBlock = new TransformBlock(i => i * 10);
256 | // else, convert to: i -> i * 100
257 | var elseBlock = new TransformBlock(i => i * 100);
258 |
259 | var branchingDataflow = _factory.FromPropagator(inputBlock)
260 | .LinkToPropagator(ifBlock, ifFilter, elseBlock)
261 | .Create();
262 |
263 | var mergeingDataflow = _factory.FromMultipleSources(ifBlock, elseBlock)
264 | .LinkToTarget(printer)
265 | .Create();
266 |
267 | //encapsulate branchingDataflow and mergeingDataflow
268 | var dataflow = _factory.EncapsulateTargetDataflow(branchingDataflow, mergeingDataflow);
269 |
270 | for (int i = 0; i < 10; ++i)
271 | {
272 | dataflow.Post(i);
273 | }
274 |
275 | dataflow.Complete();
276 |
277 | Task.WaitAll(dataflow.Completion);
278 | }
279 |
280 | private static void TestFluentOptions()
281 | {
282 | var joinOptions = new DataflowJoinOptions(
283 | join => join.BoundedCapacity(11).EnsureOrdered().MaxNumberOfGroups(1)
284 | , target2: _ => _.Append().MaxMessages(1).PropagateCompletion());
285 |
286 | var batchOptions = new DataflowBatchOptions(
287 | batch => batch.BoundedCapacity(2).Greedy().MaxNumberOfGroups(3)
288 | , link => link.MaxMessages(1).PropagateCompletion(false)
289 | );
290 |
291 | var linkOptions = new DataflowLinkOptions().PropagateCompletion(false).MaxMessages(2);
292 | }
293 | }
294 | }
295 |
--------------------------------------------------------------------------------
/FluentDataflow.Tests.Console/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("FluentDataflow.Tests.Console")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("FluentDataflow.Tests.Console")]
13 | [assembly: AssemblyCopyright("Copyright © 2017")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("1b97e995-3fcf-4356-bcea-91f254d6fa66")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/FluentDataflow.Tests.Console/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/FluentDataflow.Tests.UnitTests/DataflowWrapperTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Microsoft.VisualStudio.TestTools.UnitTesting;
3 | using Moq;
4 | using System.Threading.Tasks.Dataflow;
5 | using System.Threading.Tasks;
6 |
7 | namespace FluentDataflow.Tests.UnitTests
8 | {
9 | [TestClass]
10 | public class DataflowWrapperTests
11 | {
12 | [TestMethod]
13 | public async Task TestDataflowWrapper()
14 | {
15 | var mockOriginalSourceBlock = new Mock();
16 | var mockCurrentSourceBlock = new Mock();
17 | var mockTargetBlock = new Mock();
18 |
19 | var target = new DataflowWrapper(mockOriginalSourceBlock.Object, mockCurrentSourceBlock.Object, mockTargetBlock.Object, true);
20 |
21 | // test target.Complete()
22 | bool originalCompleteCalled = false;
23 | mockOriginalSourceBlock.Setup(b => b.Complete()).Callback(() => originalCompleteCalled = true);
24 | target.Complete();
25 | Assert.IsTrue(originalCompleteCalled);
26 |
27 | // test target.Fault()
28 | bool originalFaultCalled = false;
29 | mockOriginalSourceBlock.Setup(b => b.Fault(It.IsAny())).Callback(ex =>
30 | {
31 | originalFaultCalled = true;
32 |
33 | Assert.IsNotNull(ex);
34 | });
35 | target.Fault(new Exception());
36 | Assert.IsTrue(originalFaultCalled);
37 |
38 | // test target.Completion without error
39 | var task = Task.FromResult(0);
40 | mockCurrentSourceBlock.Setup(b => b.Completion).Returns(task);
41 | bool targetCompleteCalled = false;
42 | mockTargetBlock.Setup(b => b.Complete()).Callback(() => targetCompleteCalled = true);
43 | var task2 = Task.FromResult(222);
44 | mockTargetBlock.Setup(b => b.Completion).Returns(task2);
45 | var resultTask = target.Completion;
46 | await resultTask;
47 | Assert.IsTrue(targetCompleteCalled);
48 | Assert.AreEqual(222, ((resultTask as Task).Result as Task).Result);
49 |
50 | // test target.Completion with error
51 | bool targetFalutCalled = false;
52 | mockTargetBlock.Setup(b => b.Fault(It.IsAny())).Callback(ex =>
53 | {
54 | targetFalutCalled = true;
55 | Assert.IsNotNull(ex);
56 | });
57 | var task3 = Task.FromException(new Exception());
58 | mockCurrentSourceBlock.Setup(b => b.Completion).Returns(task3);
59 | await target.Completion;
60 | Assert.IsTrue(targetFalutCalled);
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/FluentDataflow.Tests.UnitTests/FluentDataflow.Tests.UnitTests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {2247882D-45A4-4ADE-84AF-414C46DC394D}
8 | Library
9 | Properties
10 | FluentDataflow.Tests.UnitTests
11 | FluentDataflow.Tests.UnitTests
12 | v4.6.1
13 | 512
14 | {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
15 | 15.0
16 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
17 | $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages
18 | False
19 | UnitTest
20 |
21 |
22 |
23 |
24 | true
25 | full
26 | false
27 | bin\Debug\
28 | DEBUG;TRACE
29 | prompt
30 | 4
31 |
32 |
33 | pdbonly
34 | true
35 | bin\Release\
36 | TRACE
37 | prompt
38 | 4
39 |
40 |
41 |
42 | ..\packages\Castle.Core.4.2.1\lib\net45\Castle.Core.dll
43 |
44 |
45 | ..\packages\MSTest.TestFramework.1.1.18\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.dll
46 |
47 |
48 | ..\packages\MSTest.TestFramework.1.1.18\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions.dll
49 |
50 |
51 | ..\packages\Moq.4.7.142\lib\net45\Moq.dll
52 |
53 |
54 |
55 |
56 |
57 | ..\packages\System.Threading.Tasks.Dataflow.4.8.0\lib\netstandard2.0\System.Threading.Tasks.Dataflow.dll
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 | {d339ef89-bfcf-47f1-b618-a8fcd382649b}
77 | FluentDataflow
78 |
79 |
80 |
81 |
82 |
83 |
84 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
85 |
86 |
87 |
88 |
89 |
90 |
--------------------------------------------------------------------------------
/FluentDataflow.Tests.UnitTests/MultipleDataflowWrapperTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Microsoft.VisualStudio.TestTools.UnitTesting;
3 | using System.Threading.Tasks.Dataflow;
4 | using Moq;
5 | using System.Threading.Tasks;
6 |
7 | namespace FluentDataflow.Tests.UnitTests
8 | {
9 | [TestClass]
10 | public class MultipleDataflowWrapperTests
11 | {
12 | [TestMethod]
13 | public async Task TestMultipleDataflowWrapper()
14 | {
15 | var mockSourceBlock = new Mock();
16 |
17 | var target = new MultipleSourceDataflowWrapper(new[] { mockSourceBlock.Object });
18 |
19 | // test target.Complete()
20 | bool sourceCompleteCalled = false;
21 | mockSourceBlock.Setup(b => b.Complete()).Callback(() => sourceCompleteCalled = true);
22 | target.Complete();
23 | Assert.IsTrue(sourceCompleteCalled);
24 |
25 | // test target.Fault()
26 | bool sourceFaultCalled = false;
27 | mockSourceBlock.Setup(b => b.Fault(It.IsAny())).Callback(ex =>
28 | {
29 | sourceFaultCalled = true;
30 |
31 | Assert.IsNotNull(ex);
32 | });
33 | target.Fault(new Exception());
34 | Assert.IsTrue(sourceFaultCalled);
35 |
36 | // test target.Completion without error
37 | var task = Task.FromResult(222);
38 | mockSourceBlock.Setup(b => b.Completion).Returns(task);
39 | var resultTask = target.Completion;
40 | await resultTask;
41 | Assert.AreEqual(TaskStatus.RanToCompletion, resultTask.Status);
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/FluentDataflow.Tests.UnitTests/MultipleSourceDataflowBuilderTests.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.VisualStudio.TestTools.UnitTesting;
2 | using Moq;
3 | using System.Threading.Tasks.Dataflow;
4 |
5 | namespace FluentDataflow.Tests.UnitTests
6 | {
7 | [TestClass]
8 | public class MultipleSourceDataflowBuilderTests
9 | {
10 | [TestMethod]
11 | public void TestMultipleSourceDataflowBuilder()
12 | {
13 | var mockSourceBlock = new Mock>();
14 |
15 | var target = new MultipleSourceDataflowBuilder(new[] { mockSourceBlock.Object });
16 |
17 | // test target.LinkToTarget
18 | bool finalSourceLinkToCalled = false;
19 | var mockTargetBlock = new Mock>();
20 | mockSourceBlock.Setup(b => b.LinkTo(It.IsAny>(), It.IsAny())).Callback(() => finalSourceLinkToCalled = true);
21 | var builder1 = target.LinkToTarget(mockTargetBlock.Object, null, null) as DataflowBuilder;
22 | Assert.IsTrue(finalSourceLinkToCalled);
23 | Assert.IsNotNull(builder1);
24 | Assert.IsInstanceOfType(builder1.OriginalSourceBlock, typeof(MultipleSourceDataflowWrapper));
25 | Assert.IsInstanceOfType(builder1.CurrentSourceBlock, typeof(MultipleSourceDataflowWrapper));
26 | Assert.AreEqual(mockTargetBlock.Object, builder1.TargetBlock);
27 | Assert.IsTrue(builder1.PropagateCompletion.GetValueOrDefault());
28 |
29 | // test target.LinkToPropagator
30 | finalSourceLinkToCalled = false;
31 | var mockPropagatorBlock = new Mock>();
32 | var builder2 = target.LinkToPropagator(mockPropagatorBlock.Object, null, null) as SourceDataflowBuilder;
33 | Assert.IsTrue(finalSourceLinkToCalled);
34 | Assert.IsNotNull(builder2);
35 | Assert.IsInstanceOfType(builder2.OriginalSourceBlock, typeof(MultipleSourceDataflowWrapper));
36 | Assert.IsInstanceOfType(builder2.CurrentSourceBlock, typeof(MultipleSourceDataflowWrapper));
37 | Assert.AreEqual(mockPropagatorBlock.Object, builder2.FinalSourceBlock);
38 | Assert.IsTrue(builder2.PropagateCompletion.GetValueOrDefault());
39 |
40 | // test target.Batch
41 | finalSourceLinkToCalled = false;
42 | var builder3 = target.Batch(2, default(DataflowBatchOptions)) as SourceDataflowBuilder;
43 | Assert.IsTrue(finalSourceLinkToCalled);
44 | Assert.IsNotNull(builder3);
45 | Assert.IsInstanceOfType(builder3.OriginalSourceBlock, typeof(MultipleSourceDataflowWrapper));
46 | Assert.IsInstanceOfType(builder3.CurrentSourceBlock, typeof(MultipleSourceDataflowWrapper));
47 | Assert.IsInstanceOfType(builder3.FinalSourceBlock, typeof(BatchBlock));
48 | Assert.IsTrue(builder3.PropagateCompletion.GetValueOrDefault());
49 |
50 | // test target.WriteOnce
51 | finalSourceLinkToCalled = false;
52 | var builder4 = target.WriteOnce(i => i, default(DataflowWriteOnceOptions)) as SourceDataflowBuilder;
53 | Assert.IsTrue(finalSourceLinkToCalled);
54 | Assert.IsNotNull(builder4);
55 | Assert.IsInstanceOfType(builder4.OriginalSourceBlock, typeof(MultipleSourceDataflowWrapper));
56 | Assert.IsInstanceOfType(builder4.CurrentSourceBlock, typeof(MultipleSourceDataflowWrapper));
57 | Assert.IsInstanceOfType(builder4.FinalSourceBlock, typeof(WriteOnceBlock));
58 | Assert.IsTrue(builder4.PropagateCompletion.GetValueOrDefault());
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/FluentDataflow.Tests.UnitTests/PropagatorDataflowBuilderTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Microsoft.VisualStudio.TestTools.UnitTesting;
3 | using Moq;
4 | using System.Threading.Tasks.Dataflow;
5 |
6 | namespace FluentDataflow.Tests.UnitTests
7 | {
8 | [TestClass]
9 | public class PropagatorDataflowBuilderTests
10 | {
11 | [TestMethod]
12 | public void TestPropagatorDataflowBuilder()
13 | {
14 | var mockOriginalTargetBlock = new Mock>();
15 | var mockCurrentSourceBlock = new Mock();
16 | var mockFinalSourceBlock = new Mock>();
17 |
18 | var target = new PropagatorDataflowBuilder(mockOriginalTargetBlock.Object, mockCurrentSourceBlock.Object, mockFinalSourceBlock.Object, true);
19 |
20 | // test target.LinkToTarget
21 | bool finalSourceLinkToCalled = false;
22 | var mockTargetBlock = new Mock>();
23 | mockFinalSourceBlock.Setup(b => b.LinkTo(It.IsAny>(), It.IsAny())).Callback(() => finalSourceLinkToCalled = true);
24 | var builder1 = target.LinkToTarget(mockTargetBlock.Object, null, null) as TargetDataflowBuilder;
25 | Assert.IsTrue(finalSourceLinkToCalled);
26 | Assert.IsNotNull(builder1);
27 | Assert.AreEqual(mockOriginalTargetBlock.Object, builder1.OriginalTargetBlock);
28 | Assert.AreEqual(mockTargetBlock.Object, builder1.FinalTargetBlock);
29 |
30 | // test target.LinkToPropagator
31 | finalSourceLinkToCalled = false;
32 | var mockPropagatorBlock = new Mock>();
33 | var builder2 = target.LinkToPropagator(mockPropagatorBlock.Object, null, null) as PropagatorDataflowBuilder;
34 | Assert.IsTrue(finalSourceLinkToCalled);
35 | Assert.IsNotNull(builder2);
36 | Assert.AreEqual(mockOriginalTargetBlock.Object, builder2.OriginalTargetBlock);
37 | Assert.AreEqual(mockFinalSourceBlock.Object, builder2.CurrentSourceBlock);
38 | Assert.AreEqual(mockPropagatorBlock.Object, builder2.FinalSourceBlock);
39 | Assert.IsTrue(builder2.PropagateCompletion.GetValueOrDefault());
40 |
41 | // test target.Batch
42 | finalSourceLinkToCalled = false;
43 | var builder3 = target.Batch(2, default(DataflowBatchOptions)) as PropagatorDataflowBuilder;
44 | Assert.IsTrue(finalSourceLinkToCalled);
45 | Assert.IsNotNull(builder3);
46 | Assert.AreEqual(mockOriginalTargetBlock.Object, builder3.OriginalTargetBlock);
47 | Assert.AreEqual(mockFinalSourceBlock.Object, builder3.CurrentSourceBlock);
48 | Assert.IsInstanceOfType(builder3.FinalSourceBlock, typeof(BatchBlock));
49 | Assert.IsTrue(builder3.PropagateCompletion.GetValueOrDefault());
50 |
51 | // test target.WriteOnce
52 | finalSourceLinkToCalled = false;
53 | var builder4 = target.WriteOnce(i => i, default(DataflowWriteOnceOptions)) as PropagatorDataflowBuilder;
54 | Assert.IsTrue(finalSourceLinkToCalled);
55 | Assert.IsNotNull(builder4);
56 | Assert.AreEqual(mockOriginalTargetBlock.Object, builder4.OriginalTargetBlock);
57 | Assert.AreEqual(mockFinalSourceBlock.Object, builder4.CurrentSourceBlock);
58 | Assert.IsInstanceOfType(builder4.FinalSourceBlock, typeof(WriteOnceBlock));
59 | Assert.IsTrue(builder4.PropagateCompletion.GetValueOrDefault());
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/FluentDataflow.Tests.UnitTests/PropagatorDataflowWrapperTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Microsoft.VisualStudio.TestTools.UnitTesting;
3 | using System.Threading.Tasks;
4 | using System.Threading.Tasks.Dataflow;
5 | using Moq;
6 |
7 | namespace FluentDataflow.Tests.UnitTests
8 | {
9 | [TestClass]
10 | public class PropagatorDataflowWrapperTests
11 | {
12 | [TestMethod]
13 | public async Task TestPropagatorDataflowWrapper()
14 | {
15 | var mockOriginalTargetBlock = new Mock>();
16 | var mockCurrentSourceBlock = new Mock();
17 | var mockFinalSourceBlock = new Mock>();
18 |
19 | var target = new PropagatorDataflowWrapper(mockOriginalTargetBlock.Object, mockCurrentSourceBlock.Object, mockFinalSourceBlock.Object, true);
20 |
21 | // test target.Complete()
22 | bool originalCompleteCalled = false;
23 | mockOriginalTargetBlock.Setup(b => b.Complete()).Callback(() => originalCompleteCalled = true);
24 | target.Complete();
25 | Assert.IsTrue(originalCompleteCalled);
26 |
27 | // test target.Fault()
28 | bool originalFaultCalled = false;
29 | mockOriginalTargetBlock.Setup(b => b.Fault(It.IsAny())).Callback(ex =>
30 | {
31 | originalFaultCalled = true;
32 |
33 | Assert.IsNotNull(ex);
34 | });
35 | target.Fault(new Exception());
36 | Assert.IsTrue(originalFaultCalled);
37 |
38 | // test target.Completion without error
39 | var task = Task.FromResult(0);
40 | mockCurrentSourceBlock.Setup(b => b.Completion).Returns(task);
41 | bool finalSourceCompleteCalled = false;
42 | mockFinalSourceBlock.Setup(b => b.Complete()).Callback(() => finalSourceCompleteCalled = true);
43 | var task2 = Task.FromResult(222);
44 | mockFinalSourceBlock.Setup(b => b.Completion).Returns(task2);
45 | var resultTask = target.Completion;
46 | await resultTask;
47 | Assert.IsTrue(finalSourceCompleteCalled);
48 | Assert.AreEqual(222, ((resultTask as Task).Result as Task).Result);
49 |
50 | // test target.Completion with error
51 | bool finalSourceFalutCalled = false;
52 | mockFinalSourceBlock.Setup(b => b.Fault(It.IsAny())).Callback(ex =>
53 | {
54 | finalSourceFalutCalled = true;
55 | Assert.IsNotNull(ex);
56 | });
57 | var task3 = Task.FromException(new Exception());
58 | mockCurrentSourceBlock.Setup(b => b.Completion).Returns(task3);
59 | await target.Completion;
60 | Assert.IsTrue(finalSourceFalutCalled);
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/FluentDataflow.Tests.UnitTests/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | [assembly: AssemblyTitle("FluentDataflow.Tests.UnitTests")]
6 | [assembly: AssemblyDescription("")]
7 | [assembly: AssemblyConfiguration("")]
8 | [assembly: AssemblyCompany("")]
9 | [assembly: AssemblyProduct("FluentDataflow.Tests.UnitTests")]
10 | [assembly: AssemblyCopyright("Copyright © 2017")]
11 | [assembly: AssemblyTrademark("")]
12 | [assembly: AssemblyCulture("")]
13 |
14 | [assembly: ComVisible(false)]
15 |
16 | [assembly: Guid("2247882d-45a4-4ade-84af-414c46dc394d")]
17 |
18 | // [assembly: AssemblyVersion("1.0.*")]
19 | [assembly: AssemblyVersion("1.0.0.0")]
20 | [assembly: AssemblyFileVersion("1.0.0.0")]
21 |
--------------------------------------------------------------------------------
/FluentDataflow.Tests.UnitTests/SourceDataflowBuilderTests.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.VisualStudio.TestTools.UnitTesting;
2 | using Moq;
3 | using System.Threading.Tasks.Dataflow;
4 |
5 | namespace FluentDataflow.Tests.UnitTests
6 | {
7 | [TestClass]
8 | public class SourceDataflowBuilderTests
9 | {
10 | [TestMethod]
11 | public void TestSourceDataflowBuilder()
12 | {
13 | var mockOriginalSourceBlock = new Mock();
14 | var mockCurrentSourceBlock = new Mock();
15 | var mockFinalSourceBlock = new Mock>();
16 |
17 | var target = new SourceDataflowBuilder(mockOriginalSourceBlock.Object, mockCurrentSourceBlock.Object, mockFinalSourceBlock.Object, true);
18 |
19 | // test target.LinkToTarget
20 | bool finalSourceLinkToCalled = false;
21 | var mockTargetBlock = new Mock>();
22 | mockFinalSourceBlock.Setup(b => b.LinkTo(It.IsAny>(), It.IsAny())).Callback(() => finalSourceLinkToCalled = true);
23 | var builder1 = target.LinkToTarget(mockTargetBlock.Object, null, null) as DataflowBuilder;
24 | Assert.IsTrue(finalSourceLinkToCalled);
25 | Assert.IsNotNull(builder1);
26 | Assert.AreEqual(mockOriginalSourceBlock.Object, builder1.OriginalSourceBlock);
27 | Assert.AreEqual(mockFinalSourceBlock.Object, builder1.CurrentSourceBlock);
28 | Assert.AreEqual(mockTargetBlock.Object, builder1.TargetBlock);
29 | Assert.IsTrue(builder1.PropagateCompletion.GetValueOrDefault());
30 |
31 | // test target.LinkToPropagator
32 | finalSourceLinkToCalled = false;
33 | var mockPropagatorBlock = new Mock>();
34 | var builder2 = target.LinkToPropagator(mockPropagatorBlock.Object, null, null) as SourceDataflowBuilder;
35 | Assert.IsTrue(finalSourceLinkToCalled);
36 | Assert.IsNotNull(builder2);
37 | Assert.AreEqual(mockOriginalSourceBlock.Object, builder2.OriginalSourceBlock);
38 | Assert.AreEqual(mockFinalSourceBlock.Object, builder2.CurrentSourceBlock);
39 | Assert.AreEqual(mockPropagatorBlock.Object, builder2.FinalSourceBlock);
40 | Assert.IsTrue(builder2.PropagateCompletion.GetValueOrDefault());
41 |
42 | // test target.Batch
43 | finalSourceLinkToCalled = false;
44 | var builder3 = target.Batch(2, default(DataflowBatchOptions)) as SourceDataflowBuilder;
45 | Assert.IsTrue(finalSourceLinkToCalled);
46 | Assert.IsNotNull(builder3);
47 | Assert.AreEqual(mockOriginalSourceBlock.Object, builder3.OriginalSourceBlock);
48 | Assert.AreEqual(mockFinalSourceBlock.Object, builder3.CurrentSourceBlock);
49 | Assert.IsInstanceOfType(builder3.FinalSourceBlock, typeof(BatchBlock));
50 | Assert.IsTrue(builder3.PropagateCompletion.GetValueOrDefault());
51 |
52 | // test target.WriteOnce
53 | finalSourceLinkToCalled = false;
54 | var builder4 = target.WriteOnce(i => i, default(DataflowWriteOnceOptions)) as SourceDataflowBuilder;
55 | Assert.IsTrue(finalSourceLinkToCalled);
56 | Assert.IsNotNull(builder4);
57 | Assert.AreEqual(mockOriginalSourceBlock.Object, builder4.OriginalSourceBlock);
58 | Assert.AreEqual(mockFinalSourceBlock.Object, builder4.CurrentSourceBlock);
59 | Assert.IsInstanceOfType(builder4.FinalSourceBlock, typeof(WriteOnceBlock));
60 | Assert.IsTrue(builder4.PropagateCompletion.GetValueOrDefault());
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/FluentDataflow.Tests.UnitTests/SourceDataflowWrapperTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Microsoft.VisualStudio.TestTools.UnitTesting;
3 | using Moq;
4 | using System.Threading.Tasks.Dataflow;
5 | using System.Threading.Tasks;
6 |
7 | namespace FluentDataflow.Tests.UnitTests
8 | {
9 | [TestClass]
10 | public class SourceDataflowWrapperTests
11 | {
12 | [TestMethod]
13 | public async Task TestSourceDataflowWrapper()
14 | {
15 | var mockOriginalSourceBlock = new Mock();
16 | var mockCurrentSourceBlock = new Mock();
17 | var mockFinalSourceBlock = new Mock>();
18 |
19 | var target = new SourceDataflowWrapper(mockOriginalSourceBlock.Object, mockCurrentSourceBlock.Object, mockFinalSourceBlock.Object, true);
20 |
21 | // test target.Complete()
22 | bool originalCompleteCalled = false;
23 | mockOriginalSourceBlock.Setup(b => b.Complete()).Callback(() => originalCompleteCalled = true);
24 | target.Complete();
25 | Assert.IsTrue(originalCompleteCalled);
26 |
27 | // test target.Fault()
28 | bool originalFaultCalled = false;
29 | mockOriginalSourceBlock.Setup(b => b.Fault(It.IsAny())).Callback(ex =>
30 | {
31 | originalFaultCalled = true;
32 |
33 | Assert.IsNotNull(ex);
34 | });
35 | target.Fault(new Exception());
36 | Assert.IsTrue(originalFaultCalled);
37 |
38 | // test target.Completion without error
39 | var task = Task.FromResult(0);
40 | mockCurrentSourceBlock.Setup(b => b.Completion).Returns(task);
41 | bool finalSourceCompleteCalled = false;
42 | mockFinalSourceBlock.Setup(b => b.Complete()).Callback(() => finalSourceCompleteCalled = true);
43 | var task2 = Task.FromResult(222);
44 | mockFinalSourceBlock.Setup(b => b.Completion).Returns(task2);
45 | var resultTask = target.Completion;
46 | await resultTask;
47 | Assert.IsTrue(finalSourceCompleteCalled);
48 | Assert.AreEqual(222, ((resultTask as Task).Result as Task).Result);
49 |
50 | // test target.Completion with error
51 | bool finalSourceFalutCalled = false;
52 | mockFinalSourceBlock.Setup(b => b.Fault(It.IsAny())).Callback(ex =>
53 | {
54 | finalSourceFalutCalled = true;
55 | Assert.IsNotNull(ex);
56 | });
57 | var task3 = Task.FromException(new Exception());
58 | mockCurrentSourceBlock.Setup(b => b.Completion).Returns(task3);
59 | await target.Completion;
60 | Assert.IsTrue(finalSourceFalutCalled);
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/FluentDataflow.Tests.UnitTests/TargetDataflowWrapperTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Microsoft.VisualStudio.TestTools.UnitTesting;
3 | using System.Threading.Tasks;
4 | using System.Threading.Tasks.Dataflow;
5 | using Moq;
6 |
7 | namespace FluentDataflow.Tests.UnitTests
8 | {
9 | [TestClass]
10 | public class TargetDataflowWrapperTests
11 | {
12 | [TestMethod]
13 | public void TestTargetDataflowWrapper()
14 | {
15 | var mockOriginalTargetBlock = new Mock>();
16 | var mockFinalTargetBlock = new Mock();
17 |
18 | var target = new TargetDataflowWrapper(mockOriginalTargetBlock.Object, mockFinalTargetBlock.Object);
19 |
20 | // test target.Complete()
21 | bool originalCompleteCalled = false;
22 | mockOriginalTargetBlock.Setup(b => b.Complete()).Callback(() => originalCompleteCalled = true);
23 | target.Complete();
24 | Assert.IsTrue(originalCompleteCalled);
25 |
26 | // test target.Fault()
27 | bool originalFaultCalled = false;
28 | mockOriginalTargetBlock.Setup(b => b.Fault(It.IsAny())).Callback(ex =>
29 | {
30 | originalFaultCalled = true;
31 |
32 | Assert.IsNotNull(ex);
33 | });
34 | target.Fault(new Exception());
35 | Assert.IsTrue(originalFaultCalled);
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/FluentDataflow.Tests.UnitTests/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/FluentDataflow.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.26730.3
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FluentDataflow", "FluentDataflow\FluentDataflow.csproj", "{D339EF89-BFCF-47F1-B618-A8FCD382649B}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FluentDataflow.Tests.Console", "FluentDataflow.Tests.Console\FluentDataflow.Tests.Console.csproj", "{1B97E995-3FCF-4356-BCEA-91F254D6FA66}"
9 | EndProject
10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FluentDataflow.Tests.UnitTests", "FluentDataflow.Tests.UnitTests\FluentDataflow.Tests.UnitTests.csproj", "{2247882D-45A4-4ADE-84AF-414C46DC394D}"
11 | EndProject
12 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{BFCDCA69-55BB-4224-9E90-9674E4439544}"
13 | ProjectSection(SolutionItems) = preProject
14 | README.md = README.md
15 | EndProjectSection
16 | EndProject
17 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FluentDataflowPortable", "FluentDataflowPortable\FluentDataflowPortable.csproj", "{67F9D3A8-F71E-4428-913F-C37AE82CDB24}"
18 | EndProject
19 | Global
20 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
21 | Debug|Any CPU = Debug|Any CPU
22 | Release|Any CPU = Release|Any CPU
23 | EndGlobalSection
24 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
25 | {D339EF89-BFCF-47F1-B618-A8FCD382649B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
26 | {D339EF89-BFCF-47F1-B618-A8FCD382649B}.Debug|Any CPU.Build.0 = Debug|Any CPU
27 | {D339EF89-BFCF-47F1-B618-A8FCD382649B}.Release|Any CPU.ActiveCfg = Release|Any CPU
28 | {D339EF89-BFCF-47F1-B618-A8FCD382649B}.Release|Any CPU.Build.0 = Release|Any CPU
29 | {1B97E995-3FCF-4356-BCEA-91F254D6FA66}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
30 | {1B97E995-3FCF-4356-BCEA-91F254D6FA66}.Debug|Any CPU.Build.0 = Debug|Any CPU
31 | {1B97E995-3FCF-4356-BCEA-91F254D6FA66}.Release|Any CPU.ActiveCfg = Release|Any CPU
32 | {1B97E995-3FCF-4356-BCEA-91F254D6FA66}.Release|Any CPU.Build.0 = Release|Any CPU
33 | {2247882D-45A4-4ADE-84AF-414C46DC394D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
34 | {2247882D-45A4-4ADE-84AF-414C46DC394D}.Debug|Any CPU.Build.0 = Debug|Any CPU
35 | {2247882D-45A4-4ADE-84AF-414C46DC394D}.Release|Any CPU.ActiveCfg = Release|Any CPU
36 | {2247882D-45A4-4ADE-84AF-414C46DC394D}.Release|Any CPU.Build.0 = Release|Any CPU
37 | {67F9D3A8-F71E-4428-913F-C37AE82CDB24}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
38 | {67F9D3A8-F71E-4428-913F-C37AE82CDB24}.Debug|Any CPU.Build.0 = Debug|Any CPU
39 | {67F9D3A8-F71E-4428-913F-C37AE82CDB24}.Release|Any CPU.ActiveCfg = Release|Any CPU
40 | {67F9D3A8-F71E-4428-913F-C37AE82CDB24}.Release|Any CPU.Build.0 = Release|Any CPU
41 | EndGlobalSection
42 | GlobalSection(SolutionProperties) = preSolution
43 | HideSolutionNode = FALSE
44 | EndGlobalSection
45 | GlobalSection(ExtensibilityGlobals) = postSolution
46 | SolutionGuid = {112A5B40-8933-4453-A2C9-9BE90A0BB048}
47 | EndGlobalSection
48 | EndGlobal
49 |
--------------------------------------------------------------------------------
/FluentDataflow/Assembly.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.CompilerServices;
2 |
3 | [assembly: InternalsVisibleTo("FluentDataflow.Tests.UnitTests")]
4 |
--------------------------------------------------------------------------------
/FluentDataflow/BroadcastDataflowBuilder.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks.Dataflow;
5 |
6 | namespace FluentDataflow
7 | {
8 | internal class BroadcastDataflowBuilder : IBroadcastDataflowBuilder
9 | {
10 | private readonly BroadcastBlock _broadcastBlock;
11 | private readonly IList> _targetBlocks = new List>();
12 |
13 | public BroadcastBlock BroadcastBock => _broadcastBlock;
14 |
15 | public BroadcastDataflowBuilder(BroadcastBlock broadcastBlock, ITargetBlock targetBlock = null)
16 | {
17 | _broadcastBlock = broadcastBlock;
18 | if (targetBlock != null && !_targetBlocks.Contains(targetBlock))
19 | {
20 | _targetBlocks.Add(targetBlock);
21 | }
22 | }
23 |
24 | public ITargetBlock Create()
25 | {
26 | return new BroadcastDataflowWrapper(_broadcastBlock, _targetBlocks.ToArray());
27 | }
28 |
29 | public IBroadcastDataflowBuilder LinkTo(ITargetBlock targetBlock, DataflowLinkOptions linkOptions = null, Predicate predicate = null)
30 | {
31 | if (targetBlock == null) throw new ArgumentNullException("targetBlock");
32 |
33 | LinkHelper.Link(_broadcastBlock, targetBlock, linkOptions, predicate);
34 | return new BroadcastDataflowBuilder(_broadcastBlock, targetBlock);
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/FluentDataflow/BroadcastDataflowWrapper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Threading.Tasks;
4 | using System.Threading.Tasks.Dataflow;
5 |
6 | namespace FluentDataflow
7 | {
8 | internal class BroadcastDataflowWrapper : ITargetBlock
9 | {
10 | private readonly ITargetBlock _broadcastBlock;
11 | private readonly ITargetBlock[] _targetBlocks;
12 |
13 | public BroadcastDataflowWrapper(BroadcastBlock broadcastBlock, ITargetBlock[] targetBlocks)
14 | {
15 | _broadcastBlock = broadcastBlock;
16 | _targetBlocks = targetBlocks;
17 | }
18 |
19 | public Task Completion
20 | {
21 | get
22 | {
23 | if (_targetBlocks == null || _targetBlocks.Length == 0) return _broadcastBlock.Completion;
24 |
25 | return _broadcastBlock.Completion.ContinueWith(task =>
26 | {
27 | if (task.IsFaulted)
28 | {
29 | foreach (var targetBlock in _targetBlocks)
30 | {
31 | targetBlock.Fault(task.Exception);
32 | }
33 | }
34 | else
35 | {
36 | foreach (var targetBlock in _targetBlocks)
37 | {
38 | targetBlock.Complete();
39 | }
40 | }
41 |
42 | return Task.WhenAll(_targetBlocks.Select(b => b.Completion));
43 | });
44 | }
45 | }
46 |
47 | public void Complete()
48 | {
49 | _broadcastBlock.Complete();
50 | }
51 |
52 | public void Fault(Exception exception)
53 | {
54 | _broadcastBlock.Fault(exception);
55 | }
56 |
57 | public DataflowMessageStatus OfferMessage(DataflowMessageHeader messageHeader, T messageValue, ISourceBlock source, bool consumeToAccept)
58 | {
59 | return _broadcastBlock.OfferMessage(messageHeader, messageValue, source, consumeToAccept);
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/FluentDataflow/DataflowBatchOptions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading.Tasks.Dataflow;
3 |
4 | namespace FluentDataflow
5 | {
6 | ///
7 | /// Options for applying batching.
8 | ///
9 | public struct DataflowBatchOptions
10 | {
11 | private GroupingDataflowBlockOptions _batchOptions;
12 | private DataflowLinkOptions _linkOptions;
13 |
14 | ///
15 | /// Initializes a DataflowBatchOptions.
16 | ///
17 | ///
18 | ///
19 | public DataflowBatchOptions(Action batch = null
20 | , Action link = null)
21 | {
22 | _batchOptions = DataflowDefaultOptions.DefaultGroupingBlockOptions;
23 | _linkOptions = DataflowDefaultOptions.DefaultLinkOptions;
24 |
25 | if (batch != null) batch(_batchOptions);
26 | if (link != null) link(_linkOptions);
27 | }
28 |
29 | ///
30 | /// Block options for creating batch block.
31 | ///
32 | public GroupingDataflowBlockOptions BatchBlockOptions
33 | {
34 | get
35 | {
36 | return _batchOptions ?? (_batchOptions = DataflowDefaultOptions.DefaultGroupingBlockOptions);
37 | }
38 | set
39 | {
40 | _batchOptions = value;
41 | }
42 | }
43 |
44 | ///
45 | /// Link options for linking to the batch block.
46 | ///
47 | public DataflowLinkOptions LinkOptions
48 | {
49 | get
50 | {
51 | return _linkOptions ?? (_linkOptions = DataflowDefaultOptions.DefaultLinkOptions);
52 | }
53 | set
54 | {
55 | _linkOptions = value;
56 | }
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/FluentDataflow/DataflowBuilder.cs:
--------------------------------------------------------------------------------
1 | using FluentDataflow;
2 | using System.Threading.Tasks.Dataflow;
3 |
4 | namespace FluentDataflow
5 | {
6 | internal class DataflowBuilder : IDataflowBuilder
7 | {
8 | private readonly IDataflowBlock _originalSourceBlock;
9 | private readonly IDataflowBlock _currentSourceBlock;
10 | private readonly IDataflowBlock _targetBlock;
11 | private readonly bool? _propagateCompletion;
12 |
13 | public IDataflowBlock OriginalSourceBlock => _originalSourceBlock;
14 | public IDataflowBlock CurrentSourceBlock => _currentSourceBlock;
15 | public IDataflowBlock TargetBlock => _targetBlock;
16 | public bool? PropagateCompletion => _propagateCompletion;
17 |
18 | public DataflowBuilder(IDataflowBlock sourceBlock, IDataflowBlock targetBlock, bool? propagateCompletion = null)
19 | : this(sourceBlock, sourceBlock, targetBlock, propagateCompletion)
20 | {
21 |
22 | }
23 |
24 | public DataflowBuilder(IDataflowBlock orginalSourceBlock, IDataflowBlock currentSourceBlock, IDataflowBlock targetBlock, bool? propagateCompletion = null)
25 | {
26 | _originalSourceBlock = orginalSourceBlock;
27 | _currentSourceBlock = currentSourceBlock;
28 | _targetBlock = targetBlock;
29 | _propagateCompletion = propagateCompletion;
30 | }
31 |
32 | public IDataflowBlock Create()
33 | {
34 | return new DataflowWrapper(_originalSourceBlock, _currentSourceBlock, _targetBlock, _propagateCompletion);
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/FluentDataflow/DataflowBuilderExtenions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Threading.Tasks;
4 | using System.Threading.Tasks.Dataflow;
5 |
6 | namespace FluentDataflow
7 | {
8 | ///
9 | /// Extension methods for dataflow builders.
10 | ///
11 | public static class DataflowBuilderExtenions
12 | {
13 | #region IPropagatorDataflowBuilder link to ITargetBlock
14 |
15 | ///
16 | /// Links to target block.
17 | ///
18 | ///
19 | ///
20 | ///
21 | ///
22 | ///
23 | ///
24 | ///
25 | ///
26 | ///
27 | public static ITargetDataflowBuilder LinkToTarget(
28 | this IPropagatorDataflowBuilder builder
29 | , ITargetBlock targetBlock
30 | , DataflowLinkOptions linkOptions
31 | , Predicate predicate
32 | , ITargetBlock declinedTargetBlock
33 | , DataflowLinkOptions declinedLinkOptions)
34 | {
35 | if (builder == null) return null;
36 | if (targetBlock == null) throw new ArgumentNullException("targetBlock");
37 | if (linkOptions == null) throw new ArgumentNullException("linkOptions");
38 | if (predicate == null) throw new ArgumentNullException("predicate");
39 | if (declinedTargetBlock == null) throw new ArgumentNullException("declinedTargetBlock");
40 | if (declinedLinkOptions == null) throw new ArgumentNullException("declinedLinkOptions");
41 |
42 | var nextBuilder = builder.LinkToTarget(targetBlock, linkOptions, predicate);
43 |
44 | if (declinedTargetBlock != null)
45 | {
46 | // LinkTo declined target
47 | LinkHelper.Link((builder as PropagatorDataflowBuilder).FinalSourceBlock, declinedTargetBlock, declinedLinkOptions ?? DataflowDefaultOptions.DefaultLinkOptions);
48 | }
49 |
50 | return nextBuilder;
51 | }
52 |
53 | ///
54 | /// Links to target block.
55 | ///
56 | ///
57 | ///
58 | ///
59 | ///
60 | ///
61 | ///
62 | ///
63 | public static ITargetDataflowBuilder LinkToTarget(
64 | this IPropagatorDataflowBuilder builder
65 | , ITargetBlock targetBlock
66 | , Predicate predicate
67 | , ITargetBlock declinedTargetBlock = null)
68 | {
69 | return builder.LinkToTarget(targetBlock, DataflowDefaultOptions.DefaultLinkOptions, predicate, declinedTargetBlock, DataflowDefaultOptions.DefaultLinkOptions);
70 | }
71 |
72 | #endregion
73 |
74 | #region IPropagatorDataflowBuilder link to IPropagatorBlock
75 |
76 | ///
77 | /// Links to a propagator block.
78 | ///
79 | ///
80 | ///
81 | ///
82 | ///
83 | ///
84 | ///
85 | ///
86 | ///
87 | ///
88 | ///
89 | public static IPropagatorDataflowBuilder LinkToPropagator(
90 | this IPropagatorDataflowBuilder builder
91 | , IPropagatorBlock propagatorBlock
92 | , DataflowLinkOptions linkOptions
93 | , Predicate predicate
94 | , ITargetBlock declinedTargetBlock
95 | , DataflowLinkOptions declinedLinkOptions)
96 | {
97 | if (builder == null) return null;
98 | if (propagatorBlock == null) throw new ArgumentNullException("propagatorBlock");
99 | if (linkOptions == null) throw new ArgumentNullException("linkOptions");
100 | if (predicate == null) throw new ArgumentNullException("predicate");
101 | if (declinedTargetBlock == null) throw new ArgumentNullException("declinedTargetBlock");
102 | if (declinedLinkOptions == null) throw new ArgumentNullException("declinedLinkOptions");
103 |
104 | var nextBuilder = builder.LinkToPropagator(propagatorBlock, linkOptions, predicate);
105 |
106 | if (declinedTargetBlock != null)
107 | {
108 | // LinkTo declined target
109 | LinkHelper.Link((builder as PropagatorDataflowBuilder).FinalSourceBlock, declinedTargetBlock, declinedLinkOptions ?? DataflowDefaultOptions.DefaultLinkOptions);
110 | }
111 |
112 | return nextBuilder;
113 | }
114 |
115 | ///
116 | /// Links to a propagator block.
117 | ///
118 | ///
119 | ///
120 | ///
121 | ///
122 | ///
123 | ///
124 | ///
125 | ///
126 | public static IPropagatorDataflowBuilder LinkToPropagator(
127 | this IPropagatorDataflowBuilder builder
128 | , IPropagatorBlock propagatorBlock
129 | , Predicate predicate
130 | , ITargetBlock declinedTargetBlock = null)
131 | {
132 | return builder.LinkToPropagator(propagatorBlock, DataflowDefaultOptions.DefaultLinkOptions, predicate, declinedTargetBlock, DataflowDefaultOptions.DefaultLinkOptions);
133 | }
134 |
135 | #endregion
136 |
137 | #region ISourceDataflowBuilder link to ITargetBlock
138 |
139 | ///
140 | /// Links to a target block.
141 | ///
142 | ///
143 | ///
144 | ///
145 | ///
146 | ///
147 | ///
148 | ///
149 | ///
150 | public static IDataflowBuilder LinkToTarget(
151 | this ISourceDataflowBuilder builder
152 | , ITargetBlock targetBlock
153 | , DataflowLinkOptions linkOptions
154 | , Predicate predicate
155 | , ITargetBlock declinedTargetBlock
156 | , DataflowLinkOptions declinedLinkOptions)
157 | {
158 | if (builder == null) return null;
159 | if (targetBlock == null) throw new ArgumentNullException("targetBlock");
160 | if (linkOptions == null) throw new ArgumentNullException("linkOptions");
161 | if (predicate == null) throw new ArgumentNullException("predicate");
162 | if (declinedTargetBlock == null) throw new ArgumentNullException("declinedTargetBlock");
163 | if (declinedLinkOptions == null) throw new ArgumentNullException("declinedLinkOptions");
164 |
165 | var nextBuilder = builder.LinkToTarget(targetBlock, linkOptions, predicate);
166 |
167 | if (declinedTargetBlock != null)
168 | {
169 | // LinkTo declined target
170 | LinkHelper.Link((builder as SourceDataflowBuilder).FinalSourceBlock, declinedTargetBlock, declinedLinkOptions ?? DataflowDefaultOptions.DefaultLinkOptions);
171 | }
172 |
173 | return nextBuilder;
174 | }
175 |
176 | ///
177 | /// Links to a target block.
178 | ///
179 | ///
180 | ///
181 | ///
182 | ///
183 | ///
184 | ///
185 | public static IDataflowBuilder LinkToTarget(
186 | this ISourceDataflowBuilder builder
187 | , ITargetBlock targetBlock
188 | , Predicate predicate
189 | , ITargetBlock declinedTargetBlock = null)
190 | {
191 | return builder.LinkToTarget(targetBlock, DataflowDefaultOptions.DefaultLinkOptions, predicate, declinedTargetBlock, DataflowDefaultOptions.DefaultLinkOptions);
192 | }
193 |
194 | #endregion
195 |
196 | #region ISourceDataflowBuilder link to IPropagatorBlock
197 |
198 | ///
199 | /// Links to a propagator block.
200 | ///
201 | ///
202 | ///
203 | ///
204 | ///
205 | ///
206 | ///
207 | ///
208 | ///
209 | ///
210 | public static ISourceDataflowBuilder LinkToPropagator(
211 | this ISourceDataflowBuilder builder
212 | , IPropagatorBlock propagatorBlock
213 | , DataflowLinkOptions linkOptions
214 | , Predicate predicate
215 | , ITargetBlock declinedTargetBlock
216 | , DataflowLinkOptions declinedLinkOptions)
217 | {
218 | if (builder == null) return null;
219 | if (propagatorBlock == null) throw new ArgumentNullException("propagatorBlock");
220 | if (linkOptions == null) throw new ArgumentNullException("linkOptions");
221 | if (predicate == null) throw new ArgumentNullException("predicate");
222 | if (declinedTargetBlock == null) throw new ArgumentNullException("declinedTargetBlock");
223 | if (declinedLinkOptions == null) throw new ArgumentNullException("declinedLinkOptions");
224 |
225 | var nextBuilder = builder.LinkToPropagator(propagatorBlock, linkOptions, predicate);
226 |
227 | if (declinedTargetBlock != null)
228 | {
229 | // LinkTo declined target
230 | LinkHelper.Link((builder as SourceDataflowBuilder).FinalSourceBlock, declinedTargetBlock, declinedLinkOptions ?? DataflowDefaultOptions.DefaultLinkOptions);
231 | }
232 |
233 | return nextBuilder;
234 | }
235 |
236 | ///
237 | /// Links to a propagator block.
238 | ///
239 | ///
240 | ///
241 | ///
242 | ///
243 | ///
244 | ///
245 | ///
246 | public static ISourceDataflowBuilder LinkToPropagator(
247 | this ISourceDataflowBuilder builder
248 | , IPropagatorBlock propagatorBlock
249 | , Predicate predicate
250 | , ITargetBlock declinedTargetBlock = null)
251 | {
252 | return builder.LinkToPropagator(propagatorBlock, DataflowDefaultOptions.DefaultLinkOptions, predicate, declinedTargetBlock, DataflowDefaultOptions.DefaultLinkOptions);
253 | }
254 |
255 | #endregion
256 |
257 | #region IMultipleSourceDataflowBuilder link to TargetBlock
258 |
259 | ///
260 | /// Links to a target block.
261 | ///
262 | ///
263 | ///
264 | ///
265 | ///
266 | ///
267 | ///
268 | ///
269 | ///
270 | public static IDataflowBuilder LinkToTarget(
271 | this IMultipleSourceDataflowBuilder builder
272 | , ITargetBlock targetBlock
273 | , DataflowLinkOptions linkOptions
274 | , Predicate predicate
275 | , ITargetBlock declinedTargetBlock
276 | , DataflowLinkOptions declinedLinkOptions)
277 | {
278 | if (builder == null) return null;
279 | if (targetBlock == null) throw new ArgumentNullException("targetBlock");
280 | if (linkOptions == null) throw new ArgumentNullException("linkOptions");
281 | if (predicate == null) throw new ArgumentNullException("predicate");
282 | if (declinedTargetBlock == null) throw new ArgumentNullException("declinedTargetBlock");
283 | if (declinedLinkOptions == null) throw new ArgumentNullException("declinedLinkOptions");
284 |
285 | var nextBuilder = builder.LinkToTarget(targetBlock, linkOptions, predicate);
286 |
287 | if (declinedTargetBlock != null)
288 | {
289 | // LinkTo declined target
290 | (builder as MultipleSourceDataflowBuilder).Link(declinedTargetBlock, declinedLinkOptions ?? DataflowDefaultOptions.DefaultLinkOptions, null);
291 | }
292 |
293 | return nextBuilder;
294 | }
295 |
296 | ///
297 | /// Links to a target block.
298 | ///
299 | ///
300 | ///
301 | ///
302 | ///
303 | ///
304 | ///
305 | public static IDataflowBuilder LinkToTarget(
306 | this IMultipleSourceDataflowBuilder builder
307 | , ITargetBlock targetBlock
308 | , Predicate predicate
309 | , ITargetBlock declinedTargetBlock = null)
310 | {
311 | return builder.LinkToTarget(targetBlock, DataflowDefaultOptions.DefaultLinkOptions, predicate, declinedTargetBlock, DataflowDefaultOptions.DefaultLinkOptions);
312 | }
313 |
314 | #endregion
315 |
316 | #region IBroadcastDataflowBuilder link to ITargetBlock
317 |
318 | ///
319 | /// Links to a target block.
320 | ///
321 | ///
322 | ///
323 | ///
324 | ///
325 | ///
326 | ///
327 | ///
328 | ///
329 | public static IBroadcastDataflowBuilder LinkTo(
330 | this IBroadcastDataflowBuilder builder
331 | , ITargetBlock targetBlock
332 | , DataflowLinkOptions linkOptions
333 | , Predicate predicate
334 | , ITargetBlock declinedTargetBlock
335 | , DataflowLinkOptions declinedLinkOptions)
336 | {
337 | if (builder == null) return null;
338 | if (targetBlock == null) throw new ArgumentNullException("targetBlock");
339 | if (linkOptions == null) throw new ArgumentNullException("linkOptions");
340 | if (predicate == null) throw new ArgumentNullException("predicate");
341 | if (declinedTargetBlock == null) throw new ArgumentNullException("declinedTargetBlock");
342 | if (declinedLinkOptions == null) throw new ArgumentNullException("declinedLinkOptions");
343 |
344 | var nextBuilder = builder.LinkTo(targetBlock, linkOptions, predicate);
345 |
346 | if (declinedTargetBlock != null)
347 | {
348 | // LinkTo declined target
349 | LinkHelper.Link((builder as BroadcastDataflowBuilder).BroadcastBock, declinedTargetBlock, declinedLinkOptions ?? DataflowDefaultOptions.DefaultLinkOptions);
350 | }
351 |
352 | return nextBuilder;
353 | }
354 |
355 | ///
356 | /// Links to a target block.
357 | ///
358 | ///
359 | ///
360 | ///
361 | ///
362 | ///
363 | ///
364 | public static IBroadcastDataflowBuilder LinkTo(
365 | this IBroadcastDataflowBuilder builder
366 | , ITargetBlock targetBlock
367 | , Predicate predicate
368 | , ITargetBlock declinedTargetBlock = null)
369 | {
370 | return builder.LinkTo(targetBlock, DataflowDefaultOptions.DefaultLinkOptions, predicate, declinedTargetBlock, DataflowDefaultOptions.DefaultLinkOptions);
371 | }
372 |
373 | #endregion
374 | }
375 | }
376 |
--------------------------------------------------------------------------------
/FluentDataflow/DataflowDefaultOptions.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks.Dataflow;
2 |
3 | namespace FluentDataflow
4 | {
5 | ///
6 | /// Default dataflow options.
7 | ///
8 | public static class DataflowDefaultOptions
9 | {
10 | ///
11 | /// Default block options.
12 | ///
13 | public static ExecutionDataflowBlockOptions DefaultBlockOptions => new ExecutionDataflowBlockOptions();
14 |
15 | ///
16 | /// Default link options.
17 | ///
18 | public static DataflowLinkOptions DefaultLinkOptions => new DataflowLinkOptions { PropagateCompletion = true };
19 |
20 | ///
21 | /// Default grouping block options.
22 | ///
23 | public static GroupingDataflowBlockOptions DefaultGroupingBlockOptions => new GroupingDataflowBlockOptions();
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/FluentDataflow/DataflowFactory.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading.Tasks.Dataflow;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 |
6 | namespace FluentDataflow
7 | {
8 | ///
9 | /// The implementation of .
10 | ///
11 | public class DataflowFactory : IDataflowFactory
12 | {
13 | ///
14 | /// Creates a dataflow builder from multiple source blocks, the output of all the sources are merged into the pipeline.
15 | ///
16 | ///
17 | ///
18 | ///
19 | public IMultipleSourceDataflowBuilder FromMultipleSources(params ISourceBlock[] sourceBlocks)
20 | {
21 | if (sourceBlocks == null || sourceBlocks.Length == 0) throw new ArgumentNullException("sourceBlocks");
22 |
23 | return new MultipleSourceDataflowBuilder(sourceBlocks);
24 | }
25 |
26 | ///
27 | /// Creates a dataflow block from a propagator block.
28 | ///
29 | ///
30 | ///
31 | ///
32 | ///
33 | public IPropagatorDataflowBuilder FromPropagator(IPropagatorBlock propagatorBlock)
34 | {
35 | if (propagatorBlock == null) throw new ArgumentNullException("propagatorBlock");
36 |
37 | return new PropagatorDataflowBuilder(propagatorBlock);
38 | }
39 |
40 | ///
41 | /// Creates a dataflow builder from a source block.
42 | ///
43 | ///
44 | ///
45 | ///
46 | public ISourceDataflowBuilder FromSource(ISourceBlock sourceBlock)
47 | {
48 | if (sourceBlock == null) throw new ArgumentNullException("sourceBlock");
49 |
50 | return new SourceDataflowBuilder(sourceBlock);
51 | }
52 |
53 | ///
54 | /// Creates a dataflow builder from a target block.
55 | ///
56 | ///
57 | ///
58 | ///
59 | public ITargetDataflowBuilder FromTarget(ITargetBlock targetBlock)
60 | {
61 | if (targetBlock == null) throw new ArgumentNullException("targetBlock");
62 |
63 | return new TargetDataflowBuilder(targetBlock);
64 | }
65 |
66 | ///
67 | /// Creates a dataflow builder from a join of multiple source blocks.
68 | ///
69 | ///
70 | ///
71 | ///
72 | ///
73 | ///
74 | ///
75 | public ISourceDataflowBuilder> Join(ISourceBlock sourceBlock1, ISourceBlock sourceBlock2, DataflowJoinOptions joinOptions = default(DataflowJoinOptions))
76 | {
77 | if (sourceBlock1 == null) throw new ArgumentNullException("sourceBlock1");
78 | if (sourceBlock2 == null) throw new ArgumentNullException("sourceBlock2");
79 |
80 | var joinBlock = new JoinBlock(joinOptions.JoinBlockOptions);
81 | LinkHelper.Link(sourceBlock1, joinBlock.Target1, joinOptions.Target1LinkOptions);
82 | LinkHelper.Link(sourceBlock2, joinBlock.Target2, joinOptions.Target2LinkOptions);
83 |
84 | var multipleSourcesWrapper = new MultipleSourceDataflowWrapper(new IDataflowBlock[] { sourceBlock1, sourceBlock2 });
85 | var sourceWrapper = new ReceivableSourceDataflowWrapper>(multipleSourcesWrapper, joinBlock, joinBlock);
86 |
87 | return FromSource(sourceWrapper);
88 | }
89 |
90 | ///
91 | /// Creates a dataflow builder from a join of multiple source blocks.
92 | ///
93 | ///
94 | ///
95 | ///
96 | ///
97 | ///
98 | ///
99 | ///
100 | ///
101 | public ISourceDataflowBuilder> Join(ISourceBlock sourceBlock1, ISourceBlock sourceBlock2, ISourceBlock sourceBlock3, DataflowJoinOptions joinOptions = default(DataflowJoinOptions))
102 | {
103 | if (sourceBlock1 == null) throw new ArgumentNullException("sourceBlock1");
104 | if (sourceBlock2 == null) throw new ArgumentNullException("sourceBlock2");
105 | if (sourceBlock3 == null) throw new ArgumentNullException("sourceBlock3");
106 |
107 | var joinBlock = new JoinBlock(joinOptions.JoinBlockOptions);
108 | LinkHelper.Link(sourceBlock1, joinBlock.Target1, joinOptions.Target1LinkOptions);
109 | LinkHelper.Link(sourceBlock2, joinBlock.Target2, joinOptions.Target2LinkOptions);
110 | LinkHelper.Link(sourceBlock3, joinBlock.Target3, joinOptions.Target3LinkOptions);
111 |
112 | var multipleSourcesWrapper = new MultipleSourceDataflowWrapper(new IDataflowBlock[] { sourceBlock1, sourceBlock2, sourceBlock3 });
113 | var sourceWrapper = new ReceivableSourceDataflowWrapper>(multipleSourcesWrapper, joinBlock, joinBlock);
114 |
115 | return FromSource(sourceWrapper);
116 | }
117 |
118 | ///
119 | /// Creates a dataflow builder from a batched join of multiple source blocks.
120 | ///
121 | ///
122 | ///
123 | ///
124 | ///
125 | ///
126 | ///
127 | ///
128 | public ISourceDataflowBuilder, IList>> BatchedJoin(ISourceBlock sourceBlock1, ISourceBlock sourceBlock2, int batchSize, DataflowJoinOptions joinOptions = default(DataflowJoinOptions))
129 | {
130 | if (sourceBlock1 == null) throw new ArgumentNullException("sourceBlock1");
131 | if (sourceBlock2 == null) throw new ArgumentNullException("sourceBlock2");
132 |
133 | var batchedJoinBlock = new BatchedJoinBlock(batchSize, joinOptions.JoinBlockOptions);
134 | LinkHelper.Link(sourceBlock1, batchedJoinBlock.Target1, joinOptions.Target1LinkOptions);
135 | LinkHelper.Link(sourceBlock2, batchedJoinBlock.Target2, joinOptions.Target2LinkOptions);
136 |
137 | var multipleSourcesWrapper = new MultipleSourceDataflowWrapper(new IDataflowBlock[] { sourceBlock1, sourceBlock2 });
138 | var sourceWrapper = new ReceivableSourceDataflowWrapper, IList>>(multipleSourcesWrapper, batchedJoinBlock, batchedJoinBlock);
139 |
140 | return FromSource(sourceWrapper);
141 | }
142 |
143 | ///
144 | /// Creates a dataflow builder from a batched join of multiple source blocks.
145 | ///
146 | ///
147 | ///
148 | ///
149 | ///
150 | ///
151 | ///
152 | ///
153 | ///
154 | ///
155 | public ISourceDataflowBuilder, IList, IList>> BatchedJoin(ISourceBlock sourceBlock1, ISourceBlock sourceBlock2, ISourceBlock