├── .gitignore
├── .idea
└── .idea.MemBus
│ └── .idea
│ ├── indexLayout.xml
│ └── vcs.xml
├── MemBus.Tests.Performance
├── CompositeSubscriptionPerformanceTest.cs
├── Helper.cs
├── IScenario.cs
├── MemBus.Tests.Performance.csproj
├── Program.cs
├── Properties
│ └── AssemblyInfo.cs
├── Simple.cs
└── app.config
├── MemBus.Tests
├── Help
│ ├── AssertExtensions.cs
│ ├── FakeBus.cs
│ ├── Helpers.cs
│ ├── IClassicIHandleStuffI.cs
│ ├── ItfNonGenericForHandles.cs
│ ├── MessageA.cs
│ ├── Messages.cs
│ ├── MockSubscription.cs
│ ├── NamedSubscription.cs
│ ├── PublishPipelineTester.cs
│ ├── RxBasedFooObservable.cs
│ ├── SampleClass.cs
│ ├── SimpleResolver.cs
│ ├── SomeCrazyHandler.cs
│ ├── SomeHandler.cs
│ ├── SubscriptionThatFakesHandles.cs
│ └── TestShaper.cs
├── Integration
│ ├── IntegrationScenarioInteractionWithSubscriber.cs
│ ├── UnexpectedDisposalOfSubscriptions.cs
│ ├── When_using_disposable_buses.cs
│ ├── When_using_ioc_support.cs
│ ├── When_using_the_bus.cs
│ ├── When_using_the_bus_in_the_ui.cs
│ └── When_using_the_bus_with_flexible_subscriptions.cs
├── MemBus.Tests.csproj
├── Properties
│ └── AssemblyInfo.cs
├── Publishing
│ ├── Awaitable_Publish.cs
│ ├── Using_Publish_Pipeline.cs
│ └── Using_publishing_methods.cs
├── Rx
│ ├── Observable_As_Publish.cs
│ ├── Observable_As_Timer.cs
│ └── When_MemBus_is_used_as_Observable.cs
├── Subscribing
│ ├── FSA_Consuming_Observables.cs
│ ├── FSA_Reacting_To_Messages_And_Sending.cs
│ ├── FSA_Using_Interface_Based_Subscribing.cs
│ ├── FSA_Using_Predicate_Based_Subscribing.cs
│ ├── FlexibleSubscribingIntegrationContext.cs
│ ├── Using_Composite_Subscription.cs
│ ├── Using_SubscriptionAdapter_Service.cs
│ ├── Using_disposable_method_subscription.cs
│ ├── Using_subscription_shapes.cs
│ ├── When_Resolving_Subscriptions.cs
│ └── When_subscribing.cs
├── When_using_standard_resolver.cs
└── packages.config
├── MemBus.sln
├── MemBus
├── Bus.cs
├── CompositeResolver.cs
├── CompositeSubscription.cs
├── Configurators
│ ├── AsyncConfiguration.cs
│ ├── Conservative.cs
│ ├── Fast.cs
│ ├── IoCSupport.cs
│ └── RichClientFrontend.cs
├── IBus.cs
├── ISubscription.cs
├── ISubscriptionResolver.cs
├── IoCBasedResolver.cs
├── IocAdapter.cs
├── MemBus.csproj
├── MessageInfo.cs
├── MessageObservable.cs
├── Messages
│ ├── ExceptionOccurred.cs
│ └── MessageStreamCompleted.cs
├── Properties
│ └── AssemblyInfo.cs
├── Publishing
│ ├── DeferredPublishPipelineMember.cs
│ ├── FireAndForgetPublisher.cs
│ ├── IPublishPipelineMember.cs
│ ├── ObservableRelay.cs
│ ├── ParallelBlockingPublisher.cs
│ ├── ParallelNonBlockingPublisher.cs
│ ├── PublishChain.cs
│ ├── PublishChainCasing.cs
│ ├── PublishToken.cs
│ └── SequentialPublisher.cs
├── RxEnabledObservable.cs
├── Setup
│ ├── AdHocConfigurator.cs
│ ├── BusSetup.cs
│ ├── IConfigurableBus.cs
│ ├── IConfigurablePublishing.cs
│ ├── IConfigurableSubscribing.cs
│ └── ISetup.cs
├── Subscriber.cs
├── Subscribing
│ ├── Adapter
│ │ ├── ConstructSubscriptionExtension.cs
│ │ ├── FlexibleSubscribeAdapter.cs
│ │ ├── IMethodInfoScanner.cs
│ │ ├── InterfaceBasedBuilder.cs
│ │ ├── MessageEndpointsBuilder.cs
│ │ └── MethodBasedBuilder.cs
│ ├── DisposableSubscription.cs
│ ├── FilteredSubscription.cs
│ ├── IAcceptDisposeToken.cs
│ ├── IDenyShaper.cs
│ ├── IKnowsSubscribedInstance.cs
│ ├── ISubscriptionShaper.cs
│ ├── MethodInvocation.cs
│ ├── PublishingMethodInvocation.cs
│ ├── ShapeToDispose.cs
│ ├── ShapeToFilter.cs
│ ├── ShapeToPassthrough.cs
│ ├── ShapeToUIDispatch.cs
│ ├── SubscriptionCustomizer.cs
│ ├── SubscriptionPipeline.cs
│ ├── SubscriptionShaperAggregate.cs
│ └── UiDispatchingSubscription.cs
└── Support
│ ├── AbstractServices.cs
│ ├── DisposeContainer.cs
│ ├── IRequireServices.cs
│ ├── IServices.cs
│ ├── MemBusException.cs
│ ├── Publish.cs
│ ├── ReflectionExtensions.cs
│ ├── SubscriptionCandidatesExtensions.cs
│ └── UsefulExtensions.cs
└── readme.md
/.gitignore:
--------------------------------------------------------------------------------
1 | obj
2 | bin
3 | out
4 | NDependOut*
5 | _cache
6 | _ReSharper.*
7 | *.user
8 | *.resharper
9 | *.ReSharper
10 | *.suo
11 | *.cache
12 | *.~
13 | *.pidb
14 | *.userprefs
15 | TestResults
16 | test-results
17 | MemBus_mm_cache.bin
18 | packages
19 | Nuget/MemBus/lib
20 | Nuget/MemBus/readme.md
21 | *.swp
22 | *.nupkg
23 | *.Dotsettings
24 | *.pfx
25 | *.DS_Store
26 | .vs
27 | AppPackages
28 | readme.html
29 | .vscode
30 | # Common IntelliJ Platform excludes
31 |
32 | # User specific
33 | **/.idea/**/workspace.xml
34 | **/.idea/**/tasks.xml
35 | **/.idea/shelf/*
36 | **/.idea/dictionaries
37 |
38 | # Sensitive or high-churn files
39 | **/.idea/**/dataSources/
40 | **/.idea/**/dataSources.ids
41 | **/.idea/**/dataSources.xml
42 | **/.idea/**/dataSources.local.xml
43 | **/.idea/**/sqlDataSources.xml
44 | **/.idea/**/dynamic.xml
45 |
46 | # Rider
47 |
48 | # Rider auto-generates .iml files, and contentModel.xml
49 | **/.idea/**/*.iml
50 | **/.idea/**/contentModel.xml
51 | **/.idea/**/modules.xml
--------------------------------------------------------------------------------
/.idea/.idea.MemBus/.idea/indexLayout.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.idea/.idea.MemBus/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/MemBus.Tests.Performance/CompositeSubscriptionPerformanceTest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Threading;
6 | using MemBus.Support;
7 |
8 | namespace MemBus.Tests.Performance
9 | {
10 | public class CompositeSubscriptionPerformanceTest : IScenario
11 | {
12 | private static readonly Random R = new Random();
13 | private const int DisposalProbability = 7000;
14 | private const int NumberOfStartingSubscriptions = 1500;
15 | private const int NumberOfMessagesSent = 5000;
16 |
17 | private readonly Dictionary> _subBuilders = new Dictionary>
18 | {
19 | {1, () => new ASubOf()},
20 | {2, () => new ASubOf()},
21 | {3, () => new ASubOf()}
22 | };
23 | private readonly Dictionary> _messageBuilders = new Dictionary>
24 | {
25 | {0, () => new MessageA()},
26 | {1, () => new MessageB()},
27 | {2, () => new MessageC()}
28 | };
29 |
30 | private CompositeSubscription _cSub;
31 | private ISubscriptionResolver _cRes;
32 | private bool _alreadyRun;
33 | private static int _disposeCount;
34 |
35 | public void Reset()
36 | {
37 | _alreadyRun = true;
38 | _disposeCount = 0;
39 | }
40 |
41 | public void Run(IBus bus, TextWriter writer)
42 | {
43 | if(!_alreadyRun)
44 | writer.WriteLine("Disposalprob - 1 in {0}, Starting subs {1}, Messages sent: {2}", DisposalProbability, NumberOfStartingSubscriptions, NumberOfMessagesSent);
45 | SetupCompositeSubscription(writer);
46 |
47 | var threadCounter1 = 0;
48 | var threadCounter2 = 0;
49 |
50 | var t1 = new Timer(_ =>
51 | {
52 | threadCounter1++;
53 | AddSubscription();
54 | }, null, 0, 1);
55 |
56 | var t2 = new Timer(_ =>
57 | {
58 | threadCounter2++;
59 | AddSubscription();
60 | }, null, 0, 1);
61 |
62 | PumpMessages();
63 |
64 | if (!_alreadyRun)
65 | ListSubscriptions(writer, _cSub);
66 | t1.Dispose();
67 | t2.Dispose();
68 | writer.WriteLine("ThreadCounter1: " + threadCounter1 + ", ThreadCounter2: " + threadCounter2 + ", DisposeCounter: " + _disposeCount);
69 | }
70 |
71 |
72 | private void SetupCompositeSubscription(TextWriter writer)
73 | {
74 | var subs = Enumerable.Repeat(1, NumberOfStartingSubscriptions).Select(_ => NextSubBuilderIndex).Select(i => _subBuilders[i]()).ToList();
75 |
76 | if (!_alreadyRun)
77 | ListSubscriptions(writer, subs);
78 |
79 | _cSub = new CompositeSubscription(subs);
80 | _cRes = _cSub;
81 | }
82 |
83 | private void AddSubscription()
84 | {
85 | _cSub.Add(_subBuilders[NextSubBuilderIndex]());
86 | }
87 |
88 | private void PumpMessages()
89 | {
90 | for (var i = 0; i < NumberOfMessagesSent; i++)
91 | {
92 | var msg = _messageBuilders[i%3]();
93 | var subs = _cRes.GetSubscriptionsFor(msg);
94 | foreach(var s in subs)
95 | s.Push(msg);
96 | }
97 | }
98 |
99 | private static void ListSubscriptions(TextWriter writer, IEnumerable subs)
100 | {
101 | var groupCount = subs.GroupBy(sub => sub.GetType())
102 | .Select(grp => new {Type = grp.Key.GetGenericArguments()[0].Name, Count = grp.Count()})
103 | .ToList();
104 | foreach (var g in groupCount)
105 | writer.WriteLine("Got " + g.Count + " subscriptions for " + g.Type);
106 | }
107 |
108 | private static int NextSubBuilderIndex
109 | {
110 | get { return R.Next(1, 4); }
111 | }
112 |
113 | private static bool ShouldDispose()
114 | {
115 | return R.Next(DisposalProbability) == 1;
116 | }
117 |
118 | public class ASubOf : IDisposableSubscription, IDisposable
119 | {
120 | public void Push(object message)
121 | {
122 | if (ShouldDispose())
123 | {
124 | _disposeCount++;
125 | Disposed.Raise(this);
126 | }
127 | }
128 |
129 | public bool Handles(Type messageType)
130 | {
131 | return typeof (T).IsAssignableFrom(messageType);
132 | }
133 |
134 | public IDisposable GetDisposer()
135 | {
136 | return this;
137 | }
138 |
139 | public bool IsDisposed { get; private set; }
140 | public event EventHandler Disposed;
141 |
142 | void IDisposable.Dispose()
143 | {
144 | IsDisposed = true;
145 | }
146 | }
147 |
148 | private class MessageA { }
149 | private class MessageB { }
150 | private class MessageC { }
151 |
152 | }
153 | }
--------------------------------------------------------------------------------
/MemBus.Tests.Performance/Helper.cs:
--------------------------------------------------------------------------------
1 | namespace MemBus.Tests.Performance
2 | {
3 | public class Helper
4 | {
5 |
6 | }
7 | }
--------------------------------------------------------------------------------
/MemBus.Tests.Performance/IScenario.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 |
3 | namespace MemBus.Tests.Performance
4 | {
5 | public interface IScenario
6 | {
7 | void Run(IBus bus, TextWriter writer);
8 | void Reset();
9 | }
10 | }
--------------------------------------------------------------------------------
/MemBus.Tests.Performance/MemBus.Tests.Performance.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | x86
6 | 8.0.30703
7 | 2.0
8 | {F3A4F168-8958-430A-94DD-7689EB12553F}
9 | Exe
10 | Properties
11 | MemBus.Tests.Performance
12 | MemBus.Tests.Performance
13 | v4.5
14 |
15 |
16 | 512
17 | ..\..\MemBus\
18 | true
19 |
20 |
21 | x86
22 | true
23 | full
24 | false
25 | bin\Debug\
26 | DEBUG;TRACE
27 | prompt
28 | 4
29 | false
30 |
31 |
32 | x86
33 | pdbonly
34 | true
35 | bin\Release\
36 | TRACE
37 | prompt
38 | 4
39 | false
40 |
41 |
42 | AnyCPU
43 | bin\Debug\
44 | false
45 |
46 |
47 | AnyCPU
48 | bin\Release\
49 | false
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 | {9657a125-569e-4f7e-9370-1bf581c7fa0c}
74 | MemBus.Pcl
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
--------------------------------------------------------------------------------
/MemBus.Tests.Performance/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 | using System.Threading;
4 | using MemBus.Configurators;
5 |
6 | namespace MemBus.Tests.Performance
7 | {
8 | class Program
9 | {
10 | private static void Main()
11 | {
12 | var bus = BusSetup.StartWith().Construct();
13 | var s = new CompositeSubscriptionPerformanceTest();
14 | for (var i = 0; i < 10;i++)
15 | Run(s, bus);
16 | Console.ReadLine();
17 | }
18 |
19 | private static void Run(IScenario s, IBus bus)
20 | {
21 | var sw = Stopwatch.StartNew();
22 | s.Run(bus, Console.Out);
23 | Console.WriteLine("Done in " + sw.Elapsed.TotalSeconds + " seconds");
24 | Console.WriteLine("--");
25 | s.Reset();
26 | }
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/MemBus.Tests.Performance/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("MemBus.Tests.Performance")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("Microsoft")]
12 | [assembly: AssemblyProduct("MemBus.Tests.Performance")]
13 | [assembly: AssemblyCopyright("Copyright © Microsoft 2010")]
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("3a4fb1a2-1374-43f5-aa7a-9fd779c7a00c")]
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 |
--------------------------------------------------------------------------------
/MemBus.Tests.Performance/Simple.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.IO;
5 | using System.Threading;
6 | using MemBus.Support;
7 |
8 | namespace MemBus.Tests.Performance
9 | {
10 | public class Simple : IScenario
11 | {
12 | private int _aCount;
13 | private int _bCount;
14 | private int _cCount;
15 |
16 | private readonly DisposeContainer _c = new DisposeContainer();
17 |
18 | public void Run(IBus bus, TextWriter w)
19 | {
20 | _c.Add(bus.Subscribe(OnMessageA));
21 | _c.Add(bus.Subscribe(OnMessageB));
22 | _c.Add(bus.Subscribe(OnMessageC));
23 |
24 | var r = new Random();
25 | var dict = new Dictionary>
26 | {
27 | {0, () => new MessageA()},
28 | {1, () => new MessageB()},
29 | {2, () => new MessageC()},
30 | };
31 | int count = 0;
32 | var sw = Stopwatch.StartNew();
33 | while (count < 100000)
34 | {
35 | bus.Publish(dict[r.Next(0, 3)]());
36 | count++;
37 | }
38 |
39 | w.WriteLine("Through {0}", sw.ElapsedMilliseconds);
40 |
41 | while (_aCount != MessageA.Count && _bCount != MessageB.Count && _cCount != MessageC.Count)
42 | {
43 | WriteInfo(w);
44 | Thread.Sleep(1000);
45 | }
46 | WriteInfo(w);
47 | }
48 |
49 | private void WriteInfo(TextWriter w)
50 | {
51 | w.WriteLine("From MsgA:{0}({1}), B:{2}({3}), C:{4}({5})", _aCount, MessageA.Count, _bCount,
52 | MessageB.Count, _cCount, MessageC.Count);
53 | }
54 |
55 | public void Reset()
56 | {
57 | _c.Dispose();
58 | MessageA.Reset();
59 | MessageB.Reset();
60 | MessageC.Reset();
61 | _aCount = 0;
62 | _bCount = 0;
63 | _cCount = 0;
64 | }
65 |
66 | private void OnMessageC(MessageC obj)
67 | {
68 | Interlocked.Increment(ref _cCount);
69 | }
70 |
71 | private void OnMessageB(MessageB obj)
72 | {
73 | //Thread.Sleep(1);
74 | Interlocked.Increment(ref _bCount);
75 | }
76 |
77 | private void OnMessageA(MessageA obj)
78 | {
79 | Interlocked.Increment(ref _aCount);
80 | }
81 |
82 | class MessageA
83 | {
84 | public static int Count;
85 |
86 | public static void Reset()
87 | {
88 | Count = 0;
89 | }
90 |
91 | public MessageA()
92 | {
93 | Interlocked.Increment(ref Count);
94 | }
95 | }
96 |
97 | class MessageB
98 | {
99 | public static int Count;
100 |
101 | public static void Reset()
102 | {
103 | Count = 0;
104 | }
105 |
106 | public MessageB()
107 | {
108 | Interlocked.Increment(ref Count);
109 | }
110 | }
111 |
112 | class MessageC
113 | {
114 | public static int Count;
115 |
116 | public static void Reset()
117 | {
118 | Count = 0;
119 | }
120 |
121 | public MessageC()
122 | {
123 | Interlocked.Increment(ref Count);
124 | }
125 | }
126 | }
127 | }
--------------------------------------------------------------------------------
/MemBus.Tests.Performance/app.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/MemBus.Tests/Help/AssertExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using Xunit;
6 |
7 | namespace MemBus.Tests.Help
8 | {
9 | public static class AssertExtensions
10 | {
11 | public static void ShouldHaveCount(this IEnumerable collection, int expectedCount)
12 | {
13 | var actual = collection.Cast