├── .gitignore ├── DSoft.MessageBus.Core ├── Collections │ ├── LogListernersCollection.shared.cs │ └── MessageBusEventHandlerCollection.shared.cs ├── Constants │ └── Channels.shared.cs ├── Contracts │ ├── ILogListener.shared.cs │ └── IMessageBusService.cs ├── DSoft.MessageBus.Core.csproj ├── DSoft.snk ├── Enums │ ├── LogBroadcastMode.shared.cs │ └── LogSeverity.shared.cs ├── LogEvent.shared.cs ├── MessageBusEvent.shared.cs └── MessageBusEventHandler.shared.cs ├── DSoft.Messaging ├── DSoft.MessageBus.csproj ├── DSoft.snk ├── Extensions │ ├── MessageBusExtensions.shared.cs │ └── ServicesCollectionExtensions.shared.cs ├── MessageBus.shared.cs ├── MessageBusService.shared.cs ├── ThreadControl.android.cs ├── ThreadControl.ios.mac.tvos.watchos.cs ├── ThreadControl.netstandard.cs ├── ThreadControl.shared.cs ├── ThreadControl.tizen.cs ├── ThreadControl.uwp.winui.cs └── ThreadControl.wpf.cs ├── Directory.Build.props ├── LICENSE ├── MessageBus.sln ├── README.md ├── UnitTest ├── BaseTest.cs ├── Events │ ├── TestMessageEvents.cs │ └── TestMessageEventsTwo.cs ├── MessageBusTest.cs └── UnitTest.csproj ├── WPFSample ├── App.xaml ├── App.xaml.cs ├── AssemblyInfo.cs ├── MainViewModel.cs ├── MainWindow.xaml ├── MainWindow.xaml.cs └── WPFSample.csproj ├── azure-pipelines-mergetest.yml └── azure-pipelines-release.yml /.gitignore: -------------------------------------------------------------------------------- 1 | .xpkg/ 2 | /bin/ 3 | bin 4 | obj 5 | .vs 6 | 7 | *.xam 8 | 9 | *.userprefs 10 | 11 | *.userprefs 12 | /src/MessageBus/*.userprefs 13 | samples/iOS/MessageBusiOS.userprefs 14 | *.user 15 | -------------------------------------------------------------------------------- /DSoft.MessageBus.Core/Collections/LogListernersCollection.shared.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Collections.ObjectModel; 4 | using System.Linq; 5 | using System.Text; 6 | 7 | namespace DSoft.MessageBus 8 | { 9 | public class LogListernersCollection : Collection 10 | { 11 | public void Register(ILogListener instance) 12 | { 13 | if (this.Contains(instance)) 14 | return; 15 | 16 | if (instance.Channels == null || instance.Channels.Count() == 0) 17 | throw new Exception($"Cannot register {instance.GetType().FullName} as an ILogListener as it has no channels to listen too"); 18 | 19 | this.Add(instance); 20 | } 21 | 22 | public IEnumerable FindAll(string channelName) 23 | { 24 | var results = from item in this.Items 25 | where item.Channels.Contains(channelName, StringComparer.OrdinalIgnoreCase) 26 | select item; 27 | 28 | 29 | return results; 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /DSoft.MessageBus.Core/Collections/MessageBusEventHandlerCollection.shared.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Collections.ObjectModel; 4 | using System.Collections.Generic; 5 | 6 | namespace DSoft.MessageBus 7 | { 8 | /// 9 | /// Collection of messagebuseventhandlers 10 | /// 11 | public class MessageBusEventHandlerCollection : Collection 12 | { 13 | #region Methods 14 | 15 | /// 16 | /// Handlers for event. 17 | /// 18 | /// The event identifier. 19 | /// 20 | public MessageBusEventHandler[] HandlersForEvent (String EventId) 21 | { 22 | var results = from item in this.Items 23 | where !String.IsNullOrWhiteSpace (item.EventId) 24 | where item.EventId.ToLower ().Equals (EventId.ToLower ()) 25 | where item.EventAction != null 26 | select item; 27 | 28 | var array = results.ToArray (); 29 | return array; 30 | } 31 | 32 | /// 33 | /// Handlerses for event type 34 | /// 35 | /// The for event. 36 | /// Event type. 37 | public MessageBusEventHandler[] HandlersForEvent (Type EventType) 38 | { 39 | var results = from item in this.Items 40 | where item is TypedMessageBusEventHandler 41 | where item.EventAction != null 42 | select item; 43 | 44 | var list = new List (); 45 | 46 | foreach (TypedMessageBusEventHandler item in results.ToArray()) 47 | { 48 | if (item.EventType != null && item.EventType.Equals (EventType)) 49 | { 50 | list.Add (item); 51 | } 52 | } 53 | 54 | return list.ToArray (); 55 | } 56 | 57 | /// 58 | /// Returns the event handlers for the specified Generic MessageBusEvent Type 59 | /// 60 | /// The for event. 61 | /// The 1st type parameter. 62 | public MessageBusEventHandler[] HandlersForEvent () where T : MessageBusEvent 63 | { 64 | return HandlersForEvent (typeof(T)); 65 | } 66 | 67 | #endregion 68 | } 69 | } 70 | 71 | -------------------------------------------------------------------------------- /DSoft.MessageBus.Core/Constants/Channels.shared.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace DSoft.MessageBus 6 | { 7 | /// 8 | /// Channels class 9 | /// 10 | public class Channels 11 | { 12 | /// 13 | /// Listen for all Messages 14 | /// 15 | public const string All = "41a09dda-65e5-4263-ac8a-7bd5f4d2df78"; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /DSoft.MessageBus.Core/Contracts/ILogListener.shared.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace DSoft.MessageBus 6 | { 7 | /// 8 | /// ILogListener Interface 9 | /// 10 | public interface ILogListener 11 | { 12 | /// 13 | /// Gets the channels. 14 | /// 15 | /// The channels. 16 | IEnumerable Channels { get; } 17 | 18 | /// 19 | /// Called when [message recieved]. 20 | /// 21 | /// The message. 22 | void OnMessageRecieved(LogEvent message); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /DSoft.MessageBus.Core/Contracts/IMessageBusService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace DSoft.MessageBus.Contracts 6 | { 7 | /// 8 | /// Interface for MessageBusService 9 | /// 10 | public interface IMessageBusService 11 | { 12 | #region Post 13 | 14 | /// 15 | /// Post the specified Event to the Default MessageBus 16 | /// 17 | /// Event. 18 | public void Post(MessageBusEvent busEvent); 19 | 20 | /// 21 | /// Posts the event to the Default MessageBus 22 | /// 23 | /// Event identifier. 24 | public void Post(string eventId); 25 | 26 | /// 27 | /// Post the specified EventId and Sender to the Default MessageBus 28 | /// 29 | /// Event identifier. 30 | /// Sender. 31 | public void Post(string eventId, object Sender); 32 | 33 | /// 34 | /// Post the specified EventId, Sender and Data to the Default MessageBus 35 | /// 36 | /// Event identifier. 37 | /// Sender. 38 | /// Data. 39 | public void Post(string eventId, object Sender, params object[] Data); 40 | 41 | /// 42 | /// Post the specified EventId and Data packet to the Default MessageBus 43 | /// 44 | /// Event identifier. 45 | /// Data. 46 | public void PostData(string eventId, params object[] Data); 47 | 48 | #region Async 49 | 50 | /// 51 | /// Post the specified Event to the Default MessageBus 52 | /// 53 | /// Event. 54 | public Task PostAsync(MessageBusEvent busEvent); 55 | 56 | /// 57 | /// Posts the event to the Default MessageBus 58 | /// 59 | /// Event identifier. 60 | public Task PostAsync(string eventId); 61 | 62 | /// 63 | /// Post the specified EventId and Sender to the Default MessageBus 64 | /// 65 | /// Event identifier. 66 | /// Sender. 67 | public Task PostAsync(string eventId, object Sender); 68 | 69 | /// 70 | /// Post the specified EventId, Sender and Data to the Default MessageBus 71 | /// 72 | /// Event identifier. 73 | /// Sender. 74 | /// Data. 75 | public Task PostAsync(string eventId, object Sender, params object[] Data); 76 | 77 | /// 78 | /// Post the specified EventId and Data packet to the Default MessageBus 79 | /// 80 | /// Event identifier. 81 | /// Data. 82 | public Task PostDataAsync(string eventId, params object[] Data); 83 | 84 | #endregion 85 | #endregion 86 | 87 | #region Unsubscribe 88 | 89 | /// 90 | /// Unsubscribe a previously registered handler for the specified event id 91 | /// 92 | /// Event identifier. 93 | /// Handler action 94 | public void Unsubscribe(string eventId, Action action); 95 | 96 | /// 97 | /// Unsubscribe a previously registered event handler 98 | /// 99 | /// The event handler instance 100 | public void Unsubscribe(MessageBusEventHandler EventHandler); 101 | 102 | 103 | /// 104 | /// Unsubscribe the event action for a Generic message bus type 105 | /// 106 | /// Type of MessageBusEvent to unsubscribe from 107 | /// The action to remove 108 | public void Unsubscribe(Action Action) where T : MessageBusEvent; 109 | 110 | /// 111 | /// Unsubscribes all handlers for the specified event id 112 | /// 113 | /// Event identifier 114 | public void Unsubscribe(string eventId); 115 | 116 | #endregion 117 | 118 | #region Subscribe 119 | /// 120 | /// Subscribe to the event with an parameterless action 121 | /// 122 | /// Event Id 123 | /// Action to execute on the event occuring 124 | public void Subscribe(string evenId, Action action); 125 | 126 | /// 127 | /// Subscribe to the event with an action that recieve the data object from the event 128 | /// 129 | /// Event Id 130 | /// Action to execute on the event occuring 131 | public void Subscribe(string evenId, Action action); 132 | 133 | /// 134 | /// Subscribe to the event with an action 135 | /// 136 | /// Event Id 137 | /// Action to execute on the event occuring 138 | public void Subscribe(string eventId, Action action); 139 | 140 | /// 141 | /// Subscribe to the specified event handler. 142 | /// 143 | /// The event handler. 144 | public void Subscribe(MessageBusEventHandler EventHandler); 145 | /// 146 | /// Subscribe for notifications of a specific a type of MessageBusEvent 147 | /// 148 | /// The 1st type parameter. 149 | public void Subscribe(Action Action) where T : MessageBusEvent, new(); 150 | 151 | #endregion 152 | 153 | #region Logging 154 | 155 | /// 156 | /// Send out a log message 157 | /// 158 | /// The title of the log entry 159 | /// The message. 160 | /// The severity. 161 | public void Log(string title, string? message = null, LogSeverity severity = LogSeverity.Notification); 162 | 163 | /// 164 | ///Send out a log message to the specified channel only 165 | /// 166 | /// Name of the channel. 167 | /// The title of the log entry 168 | /// The message. 169 | /// The severity. 170 | public void Log(string channelName, string title, string? message = null, LogSeverity severity = LogSeverity.Notification); 171 | 172 | /// 173 | /// Register a class instance that implements ILogListener to listen for log messages 174 | /// 175 | /// The instance of the class 176 | public void Listen(ILogListener instance); 177 | 178 | /// 179 | /// Stops listening to the log channel 180 | /// 181 | /// The instance. 182 | public void StopListening(ILogListener instance); 183 | #endregion 184 | } 185 | } 186 | -------------------------------------------------------------------------------- /DSoft.MessageBus.Core/DSoft.MessageBus.Core.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0 5 | enable 6 | $(AssemblyName) ($(TargetFramework)) 7 | DSoft.MessageBus.Core 8 | Core classes and contractrs for DSoft.MessageBus 9 | © DSoft Developments. All rights reserved. 10 | DSoft.MessageBus 11 | README.md 12 | Reverted minimum .NETStandard to 2.0 so it will work with .NET Framework 4.7.2 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /DSoft.MessageBus.Core/DSoft.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/newky2k/MessageBus/ea5ceca60b81ad1efb7000157a1ab4efc6a0a2b7/DSoft.MessageBus.Core/DSoft.snk -------------------------------------------------------------------------------- /DSoft.MessageBus.Core/Enums/LogBroadcastMode.shared.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace DSoft.MessageBus 6 | { 7 | /// 8 | /// LogBroadcastMode Enum 9 | /// 10 | public enum LogBroadcastMode 11 | { 12 | /// 13 | /// When a message is sent without a channel name it will go to all registered log recievers 14 | /// 15 | Implicit, 16 | /// 17 | /// When a message is sent without a channel name it will only goto to recievers that have registered for All messages, i'e without specifying a ChannelName 18 | /// 19 | Explicit, 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /DSoft.MessageBus.Core/Enums/LogSeverity.shared.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace DSoft.MessageBus 6 | { 7 | /// 8 | /// LogSeverity Enum 9 | /// 10 | public enum LogSeverity 11 | { 12 | /// 13 | /// Notification 14 | /// 15 | Notification, 16 | /// 17 | /// Warning 18 | /// 19 | Warning, 20 | /// 21 | /// Error 22 | /// 23 | Error, 24 | /// 25 | /// Critical 26 | /// 27 | Critical, 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /DSoft.MessageBus.Core/LogEvent.shared.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace DSoft.MessageBus 6 | { 7 | /// 8 | /// LogEvent 9 | /// 10 | public struct LogEvent 11 | { 12 | /// 13 | /// Gets or sets the channel. 14 | /// 15 | /// The channel. 16 | public string Channel { get; set; } 17 | 18 | /// 19 | /// Gets or sets the title. 20 | /// 21 | /// The title. 22 | public string Title { get; set; } 23 | 24 | /// 25 | /// Gets or sets the message. 26 | /// 27 | /// The message. 28 | public string Message { get; set; } 29 | 30 | /// 31 | /// Gets or sets the severity. 32 | /// 33 | /// The severity. 34 | public LogSeverity Severity { get; set; } 35 | 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /DSoft.MessageBus.Core/MessageBusEvent.shared.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace DSoft.MessageBus 4 | { 5 | /// 6 | /// Message bus event class 7 | /// 8 | public abstract class MessageBusEvent 9 | { 10 | #region Properties 11 | 12 | /// 13 | /// Gets or sets the event identifier. 14 | /// 15 | /// The event identifier. 16 | public abstract String EventId { get; } 17 | 18 | /// 19 | /// Sender of the event 20 | /// 21 | public object Sender { get; set; } 22 | 23 | /// 24 | /// Data to pass with the event 25 | /// 26 | public object[] Data { get; set; } 27 | 28 | #endregion 29 | 30 | #region Constructors 31 | 32 | /// 33 | /// Initializes a new instance of the class. 34 | /// 35 | public MessageBusEvent () 36 | { 37 | } 38 | 39 | /// 40 | /// Initializes a new instance of the class. 41 | /// 42 | /// Sender. 43 | /// Data. 44 | public MessageBusEvent (object Sender, object[] Data) 45 | { 46 | this.Sender = Sender; 47 | this.Data = Data; 48 | } 49 | 50 | #endregion 51 | } 52 | 53 | /// 54 | /// Standard MessageBusEvent class 55 | /// 56 | public sealed class CoreMessageBusEvent : MessageBusEvent 57 | { 58 | #region Fields 59 | 60 | private String mEventID; 61 | 62 | #endregion 63 | 64 | #region Properties 65 | 66 | /// 67 | /// Gets or sets the event identifier. Will generate a new Guid based Id if not set 68 | /// 69 | /// The event identifier. 70 | public override String EventId { 71 | get 72 | { 73 | if (String.IsNullOrWhiteSpace (mEventID)) 74 | { 75 | mEventID = Guid.NewGuid ().ToString (); 76 | } 77 | 78 | return mEventID; 79 | } 80 | 81 | } 82 | 83 | #endregion 84 | 85 | #region Constructors 86 | 87 | /// 88 | /// Initializes a new instance of the class. 89 | /// 90 | public CoreMessageBusEvent () : base () 91 | { 92 | 93 | } 94 | 95 | /// 96 | /// Initializes a new instance of the class. 97 | /// 98 | /// Event Identifier. 99 | public CoreMessageBusEvent (String EventID) 100 | : this () 101 | { 102 | mEventID = EventID; 103 | } 104 | 105 | /// 106 | /// Initializes a new instance of the class. 107 | /// 108 | /// Sender. 109 | /// Event I. 110 | /// Data. 111 | public CoreMessageBusEvent (object Sender, String EventID, object[] Data) 112 | : base (Sender, Data) 113 | { 114 | mEventID = EventID; 115 | } 116 | 117 | #endregion 118 | } 119 | } 120 | 121 | -------------------------------------------------------------------------------- /DSoft.MessageBus.Core/MessageBusEventHandler.shared.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace DSoft.MessageBus 4 | { 5 | /// 6 | /// Message bus event handler. 7 | /// 8 | public class MessageBusEventHandler 9 | { 10 | #region Properties 11 | 12 | /// 13 | /// Event Id 14 | /// 15 | public string EventId { get; set; } 16 | 17 | /// 18 | /// Action to perform on event 19 | /// 20 | public Action EventAction { get; set; } 21 | 22 | #endregion 23 | 24 | #region Constructors 25 | 26 | /// 27 | /// Initializes a new instance of the class. 28 | /// 29 | public MessageBusEventHandler () 30 | { 31 | EventId = string.Empty; 32 | } 33 | 34 | /// 35 | /// Initializes a new instance of the class. 36 | /// 37 | /// Event identifier. 38 | /// Action. 39 | public MessageBusEventHandler (string EventId, Action Action) 40 | { 41 | this.EventId = EventId; 42 | this.EventAction = Action; 43 | } 44 | 45 | #endregion 46 | } 47 | 48 | /// 49 | /// Typed message bus event handler. 50 | /// 51 | public class TypedMessageBusEventHandler : MessageBusEventHandler 52 | { 53 | #region Properties 54 | 55 | /// 56 | /// Gets or sets the type of the event. 57 | /// 58 | /// The type of the event. 59 | public Type EventType { get; set; } 60 | 61 | #endregion 62 | 63 | #region Constructors 64 | 65 | /// 66 | /// Initializes a new instance of the class. 67 | /// 68 | public TypedMessageBusEventHandler () 69 | { 70 | 71 | } 72 | 73 | #endregion 74 | } 75 | } 76 | 77 | -------------------------------------------------------------------------------- /DSoft.Messaging/DSoft.MessageBus.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | netstandard2.1;net8.0;net8.0-ios;net8.0-macos;net8.0-maccatalyst;net8.0-tvos;net8.0-android;net9.0;net9.0-ios;net9.0-macos;net9.0-maccatalyst;net9.0-tvos;net9.0-android; 4 | $(TargetFrameworks);net472;net8.0-windows7.0;net8.0-windows10.0.19041;net9.0-windows7.0;net9.0-windows10.0.19041; 5 | DSoft.MessageBus 6 | 1.3.4 7 | DSoft.MessageBus 8 | DSoft Developments 9 | $(AssemblyName) ($(TargetFramework)) 10 | DSoft.MessageBus 11 | MessageBus is a cross platform EventBus system similar to NSNoticationCenter on iOS and otto on Android 12 | © DSoft Developments. All rights reserved. 13 | 1.3.5.0 14 | 1.3.5.0 15 | false 16 | 1.3.4.0 17 | MessageBus 18 | false 19 | $(DefineConstants); 20 | Debug;Release; 21 | README.md 22 | true 23 | true 24 | 14.2 25 | 14.0 26 | 21.0 27 | 6.5 28 | 11.0 29 | 11.0 30 | $(NoWarn);NETSDK1206;CA1416; 31 | Re-Added .NET framework 4.7.2 support 32 | Added generic "Post" method 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 10.0.17763.0 42 | true 43 | 10.0.17763.0 44 | win-x86;win-x64;win-arm64; 45 | $(DefineConstants);WINUI 46 | 47 | 48 | 49 | true 50 | 51 | 52 | 53 | true 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /DSoft.Messaging/DSoft.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/newky2k/MessageBus/ea5ceca60b81ad1efb7000157a1ab4efc6a0a2b7/DSoft.Messaging/DSoft.snk -------------------------------------------------------------------------------- /DSoft.Messaging/Extensions/MessageBusExtensions.shared.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace DSoft.MessageBus 4 | { 5 | /// 6 | /// MessageBus object extensions 7 | /// 8 | public static class MessageBusExtensions 9 | { 10 | /// 11 | /// Posts the event. 12 | /// 13 | /// Sender. 14 | /// Event Id 15 | public static void PostEvent (this object Sender, string EventId) => Sender.PostEvent(EventId, null); 16 | 17 | /// 18 | /// Posts the event. 19 | /// 20 | /// Sender. 21 | /// Event Id 22 | /// Additonal data 23 | public static void PostEvent (this object Sender, string EventId, object[] Data) => MessageBus.Post(EventId, Sender, Data); 24 | } 25 | } 26 | 27 | -------------------------------------------------------------------------------- /DSoft.Messaging/Extensions/ServicesCollectionExtensions.shared.cs: -------------------------------------------------------------------------------- 1 | using DSoft.MessageBus; 2 | using DSoft.MessageBus.Contracts; 3 | using Microsoft.Extensions.DependencyInjection; 4 | using Microsoft.Extensions.DependencyInjection.Extensions; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Text; 8 | 9 | namespace Microsoft.Extensions.DependencyInjection 10 | { 11 | /// 12 | /// Services Collection Extensions 13 | /// 14 | public static class ServicesCollectionExtensions 15 | { 16 | /// 17 | /// Registers the DSoft.MessageBus DI Services 18 | /// 19 | /// The services. 20 | /// 21 | public static IServiceCollection RegisterMessageBus(this IServiceCollection services) 22 | { 23 | services.TryAddSingleton(); 24 | 25 | return services; 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /DSoft.Messaging/MessageBus.shared.cs: -------------------------------------------------------------------------------- 1 |  2 | using System; 3 | using System.Collections.Generic; 4 | using System.Threading.Tasks; 5 | using System.Threading; 6 | using System.Diagnostics; 7 | 8 | namespace DSoft.MessageBus 9 | { 10 | /// 11 | /// Static Wrapper for MessageBusService 12 | /// 13 | public static class MessageBus 14 | { 15 | #region Fields 16 | private static Lazy _service = new Lazy(() => new MessageBusService()); 17 | #endregion 18 | 19 | #region Properties 20 | 21 | /// 22 | /// Gets the internal instance of MessageBusService 23 | /// 24 | /// 25 | /// The service. 26 | /// 27 | private static MessageBusService Service => _service.Value; 28 | 29 | /// 30 | /// Execute Post action on a seperate task using Task.Run 31 | /// 32 | public static bool RunPostOnSeperateTask 33 | { 34 | get => Service.RunPostOnSeperateTask; 35 | set => Service.RunPostOnSeperateTask = value; 36 | } 37 | 38 | #endregion 39 | 40 | #region Static Methods 41 | 42 | #region Post 43 | 44 | /// 45 | /// Post the specified Event to the Default MessageBus 46 | /// 47 | /// Event. 48 | public static void Post (MessageBusEvent busEvent) => Service.Post(busEvent); 49 | 50 | /// 51 | /// Posts the event to the Default MessageBus 52 | /// 53 | /// Event identifier. 54 | public static void Post (string eventId) => Service.Post(eventId); 55 | 56 | /// 57 | /// Post the specified EventId and Sender to the Default MessageBus 58 | /// 59 | /// Event identifier. 60 | /// Sender. 61 | public static void Post (string eventId, object Sender) => Service.Post(eventId, Sender); 62 | 63 | /// 64 | /// Post the specified EventId, Sender and Data to the Default MessageBus 65 | /// 66 | /// Event identifier. 67 | /// Sender. 68 | /// Data. 69 | public static void Post (string eventId, object Sender, params object[] Data) => Service.Post(eventId, Sender, Data); 70 | 71 | /// 72 | /// Post the specified EventId and Data packet to the Default MessageBus 73 | /// 74 | /// Event identifier. 75 | /// Data. 76 | public static void Post(string eventId, params object[] Data) => Service.PostData(eventId, Data); 77 | 78 | /// 79 | ///Post the specified event Type to the Default MessageBus 80 | /// 81 | /// 82 | public static void Post() where T : MessageBusEvent, new() 83 | { 84 | var newEvent = new T(); 85 | 86 | Post(newEvent); 87 | } 88 | #endregion 89 | 90 | #region Unsubscribe 91 | 92 | /// 93 | /// Unsubscribe a previously registered handler for the specified event id 94 | /// 95 | /// Event identifier. 96 | /// Handler action 97 | public static void Unsubscribe(string eventId, Action action) => Service.Unsubscribe(eventId, action); 98 | 99 | /// 100 | /// Unsubscribe a previously registered event handler 101 | /// 102 | /// The event handler instance 103 | public static void Unsubscribe(MessageBusEventHandler EventHandler) => Service.Unsubscribe(EventHandler); 104 | 105 | 106 | /// 107 | /// Unsubscribe the event action for a Generic message bus type 108 | /// 109 | /// Type of MessageBusEvent to unsubscribe from 110 | /// The action to remove 111 | public static void Unsubscribe(Action Action) where T : MessageBusEvent => Service.Unsubscribe(Action); 112 | 113 | /// 114 | /// Unsubscribes all handlers for the specified event id 115 | /// 116 | /// Event identifier 117 | public static void Unsubscribe(string eventId) => Unsubscribe(eventId); 118 | 119 | #endregion 120 | 121 | #region Subscribe 122 | /// 123 | /// Subscribe to the event with an parameterless action 124 | /// 125 | /// Event Id 126 | /// Action to execute on the event occuring 127 | public static void Subscribe(string evenId, Action action) => Service.Subscribe(evenId, action); 128 | 129 | /// 130 | /// Subscribe to the event with an action that recieve the data object from the event 131 | /// 132 | /// Event Id 133 | /// Action to execute on the event occuring 134 | public static void Subscribe(string evenId, Action action) => Service.Subscribe(evenId, action); 135 | 136 | /// 137 | /// Subscribe to the event with an action 138 | /// 139 | /// Event Id 140 | /// Action to execute on the event occuring 141 | public static void Subscribe(string eventId, Action action) => Service.Subscribe(eventId, action); 142 | 143 | /// 144 | /// Subscribe to the specified event handler. 145 | /// 146 | /// The event handler. 147 | public static void Subscribe(MessageBusEventHandler EventHandler) => Service.Subscribe(EventHandler); 148 | /// 149 | /// Subscribe for notifications of a specific a type of MessageBusEvent 150 | /// 151 | /// The 1st type parameter. 152 | public static void Subscribe(Action Action) where T : MessageBusEvent, new() => Service.Subscribe(Action); 153 | 154 | #endregion 155 | 156 | #region Logging 157 | 158 | /// 159 | /// Send out a log message 160 | /// 161 | /// The title of the log entry 162 | /// The message. 163 | /// The severity. 164 | public static void Log(string title, string message = null, LogSeverity severity = LogSeverity.Notification) => Service.Log(Channels.All, title, message); 165 | 166 | /// 167 | ///Send out a log message to the specified channel only 168 | /// 169 | /// Name of the channel. 170 | /// The title of the log entry 171 | /// The message. 172 | /// The severity. 173 | public static void Log(string channelName, string title, string message = null, LogSeverity severity = LogSeverity.Notification) => Service.Log(channelName, title, message, severity); 174 | 175 | /// 176 | /// Register a class instance that implements ILogListener to listen for log messages 177 | /// 178 | /// The instance of the class 179 | public static void Listen(ILogListener instance) => Service.Listen(instance); 180 | 181 | /// 182 | /// Stops listening to the log channel 183 | /// 184 | /// The instance. 185 | public static void StopListening(ILogListener instance) => Service.StopListening(instance); 186 | #endregion 187 | 188 | #endregion 189 | 190 | } 191 | } 192 | 193 | -------------------------------------------------------------------------------- /DSoft.Messaging/MessageBusService.shared.cs: -------------------------------------------------------------------------------- 1 | using DSoft.MessageBus.Contracts; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | 6 | namespace DSoft.MessageBus 7 | { 8 | internal class MessageBusService : IMessageBusService 9 | { 10 | /// 11 | /// Execute Post action on a seperate task using Task.Run 12 | /// 13 | public bool RunPostOnSeperateTask { get; set; } = false; 14 | 15 | #region Fields 16 | private Lazy _eventHandlers = new Lazy(() => new MessageBusEventHandlerCollection()); 17 | private Lazy _logListeners = new Lazy(() => new LogListernersCollection()); 18 | #endregion 19 | 20 | #region Properties 21 | 22 | /// 23 | /// Gets the registered event handlers. 24 | /// 25 | /// The event handlers. 26 | private MessageBusEventHandlerCollection EventHandlers => _eventHandlers.Value; 27 | 28 | /// 29 | /// Gets the register log listeners 30 | /// 31 | /// 32 | /// The current log listeners 33 | /// 34 | private LogListernersCollection LogListeners => _logListeners.Value; 35 | #endregion 36 | 37 | #region Constructors 38 | 39 | /// 40 | /// Constructor 41 | /// 42 | public MessageBusService() 43 | { 44 | 45 | } 46 | 47 | #endregion 48 | 49 | #region Methods 50 | 51 | #region Private Methods 52 | 53 | private void Execute(Action Action, object Sender, MessageBusEvent Evnt) 54 | { 55 | Action(Sender, Evnt); 56 | } 57 | 58 | private IEnumerable FindHandlersForEvent(string eventId) 59 | { 60 | if (string.IsNullOrWhiteSpace(eventId)) 61 | throw new Exception("EventId cannot be null or blank"); 62 | 63 | var results = EventHandlers.HandlersForEvent(eventId); 64 | 65 | return results; 66 | } 67 | #endregion 68 | 69 | #region Public Methods 70 | 71 | #region Post 72 | 73 | private void PostInternal(MessageBusEvent busEvent) 74 | { 75 | if (!(busEvent is CoreMessageBusEvent)) 76 | { 77 | foreach (var item in EventHandlers.HandlersForEvent(busEvent.GetType())) 78 | { 79 | if (item.EventAction != null) 80 | { 81 | Execute(item.EventAction, busEvent.Sender, busEvent); 82 | } 83 | } 84 | } 85 | 86 | //find all the registered handlers 87 | foreach (var item in EventHandlers.HandlersForEvent(busEvent.EventId)) 88 | { 89 | if (item.EventAction != null) 90 | { 91 | Execute(item.EventAction, busEvent.Sender, busEvent); 92 | } 93 | } 94 | } 95 | 96 | /// 97 | /// Post the specified Event to the Default MessageBus 98 | /// 99 | /// Event. 100 | public void Post(MessageBusEvent busEvent) 101 | { 102 | if (RunPostOnSeperateTask == true) 103 | { 104 | Task.Run(() => 105 | { 106 | PostInternal(busEvent); 107 | }); 108 | } 109 | else 110 | { 111 | PostInternal(busEvent); 112 | } 113 | 114 | 115 | } 116 | 117 | /// 118 | /// Posts the event to the Default MessageBus 119 | /// 120 | /// Event identifier. 121 | public void Post(string eventId) 122 | { 123 | PostData(eventId, null); 124 | } 125 | 126 | /// 127 | /// Post the specified EventId and Sender to the Default MessageBus 128 | /// 129 | /// Event identifier. 130 | /// Sender. 131 | public void Post(string eventId, object Sender) 132 | { 133 | Post(eventId, Sender, null); 134 | } 135 | 136 | /// 137 | /// Post the specified EventId, Sender and Data to the Default MessageBus 138 | /// 139 | /// Event identifier. 140 | /// Sender. 141 | /// Data. 142 | public void Post(string eventId, object Sender, params object[] Data) 143 | { 144 | var aEvent = new CoreMessageBusEvent(eventId) 145 | { 146 | Sender = Sender, 147 | Data = Data, 148 | }; 149 | 150 | Post(aEvent); 151 | } 152 | 153 | /// 154 | /// Post the specified EventId and Data packet to the Default MessageBus 155 | /// 156 | /// Event identifier. 157 | /// Data. 158 | public void PostData(string eventId, params object[] Data) 159 | { 160 | Post(eventId, null, Data); 161 | } 162 | 163 | #region Async 164 | 165 | private Task PostInternalAsync(MessageBusEvent busEvent) 166 | { 167 | return Task.Run(() => 168 | { 169 | PostInternal(busEvent); 170 | }); 171 | 172 | } 173 | 174 | /// 175 | /// Post the specified Event to the Default MessageBus 176 | /// 177 | /// Event. 178 | public Task PostAsync(MessageBusEvent busEvent) => PostInternalAsync(busEvent); 179 | 180 | /// 181 | /// Posts the event to the Default MessageBus 182 | /// 183 | /// Event identifier. 184 | public Task PostAsync(string eventId) => PostDataAsync(eventId, null); 185 | 186 | /// 187 | /// Post the specified EventId and Sender to the Default MessageBus 188 | /// 189 | /// Event identifier. 190 | /// Sender. 191 | public Task PostAsync(string eventId, object Sender) => PostAsync(eventId, Sender, null); 192 | 193 | /// 194 | /// Post the specified EventId, Sender and Data to the Default MessageBus 195 | /// 196 | /// Event identifier. 197 | /// Sender. 198 | /// Data. 199 | public Task PostAsync(string eventId, object Sender, params object[] Data) 200 | { 201 | var aEvent = new CoreMessageBusEvent(eventId) 202 | { 203 | Sender = Sender, 204 | Data = Data, 205 | }; 206 | 207 | return PostAsync(aEvent); 208 | } 209 | 210 | /// 211 | /// Post the specified EventId and Data packet to the Default MessageBus 212 | /// 213 | /// Event identifier. 214 | /// Data. 215 | public Task PostDataAsync(string eventId, params object[] Data) => PostAsync(eventId, null, Data); 216 | 217 | #endregion 218 | 219 | #endregion 220 | 221 | #region Unsubscribe 222 | 223 | /// 224 | /// Unsubscribe a previously registered handler for the specified event id 225 | /// 226 | /// Event identifier. 227 | /// Handler action 228 | public void Unsubscribe(string eventId, Action action) 229 | { 230 | foreach (var item in FindHandlersForEvent(eventId)) 231 | { 232 | if (item.EventAction.Equals(action)) 233 | { 234 | EventHandlers.Remove(item); 235 | } 236 | } 237 | } 238 | 239 | /// 240 | /// Unsubscribe a previously registered event handler 241 | /// 242 | /// The event handler instance 243 | public void Unsubscribe(MessageBusEventHandler EventHandler) 244 | { 245 | if (EventHandlers.Contains(EventHandler)) 246 | { 247 | EventHandlers.Remove(EventHandler); 248 | } 249 | } 250 | 251 | 252 | /// 253 | /// Unsubscribe the event action for a Generic message bus type 254 | /// 255 | /// Type of MessageBusEvent to unsubscribe from 256 | /// The action to remove 257 | public void Unsubscribe(Action Action) where T : MessageBusEvent 258 | { 259 | var results = new List(EventHandlers.HandlersForEvent()); 260 | 261 | foreach (var item in results) 262 | { 263 | if (item.EventAction == Action) 264 | { 265 | EventHandlers.Remove(item); 266 | } 267 | } 268 | } 269 | 270 | /// 271 | /// Unsubscribes all handlers for the specified event id 272 | /// 273 | /// Event identifier 274 | public void Unsubscribe(string eventId) 275 | { 276 | foreach (var item in FindHandlersForEvent(eventId)) 277 | { 278 | EventHandlers.Remove(item); 279 | } 280 | } 281 | #endregion 282 | 283 | #region Subscribe 284 | /// 285 | /// Subscribe to the event with an parameterless action 286 | /// 287 | /// Event Id 288 | /// Action to execute on the event occuring 289 | public void Subscribe(string evenId, Action action) 290 | { 291 | Subscribe(evenId, (obj, evt) => 292 | { 293 | action(); 294 | 295 | }); 296 | } 297 | 298 | /// 299 | /// Subscribe to the event with an action that recieve the data object from the event 300 | /// 301 | /// Event Id 302 | /// Action to execute on the event occuring 303 | public void Subscribe(string evenId, Action action) 304 | { 305 | Subscribe(evenId, (obj, evt) => 306 | { 307 | action(evt.Data); 308 | 309 | }); 310 | } 311 | 312 | /// 313 | /// Subscribe to the event with an action 314 | /// 315 | /// Event Id 316 | /// Action to execute on the event occuring 317 | public void Subscribe(string eventId, Action action) 318 | { 319 | Subscribe(new MessageBusEventHandler(eventId, action)); 320 | } 321 | 322 | /// 323 | /// Subscribe to the specified event handler. 324 | /// 325 | /// The event handler. 326 | public void Subscribe(MessageBusEventHandler EventHandler) 327 | { 328 | if (EventHandler == null) 329 | return; 330 | 331 | if (!EventHandlers.Contains(EventHandler)) 332 | { 333 | EventHandlers.Add(EventHandler); 334 | } 335 | } 336 | /// 337 | /// Subscribe for notifications of a specific a type of MessageBusEvent 338 | /// 339 | /// The 1st type parameter. 340 | public void Subscribe(Action Action) where T : MessageBusEvent, new() 341 | { 342 | var aType = typeof(T); 343 | 344 | var typeHandler = new TypedMessageBusEventHandler() 345 | { 346 | EventType = aType, 347 | EventAction = Action, 348 | }; 349 | 350 | Subscribe(typeHandler); 351 | 352 | 353 | } 354 | #endregion 355 | 356 | #region Logging 357 | 358 | /// 359 | /// Send out a log message 360 | /// 361 | /// The title of the log entry 362 | /// The message. 363 | /// The severity. 364 | public void Log(string title, string message = null, LogSeverity severity = LogSeverity.Notification) => Log(Channels.All, title, message); 365 | 366 | /// 367 | ///Send out a log message to the specified channel only 368 | /// 369 | /// Name of the channel. 370 | /// The title of the log entry 371 | /// The message. 372 | /// The severity. 373 | public void Log(string channelName, string title, string message = null, LogSeverity severity = LogSeverity.Notification) 374 | { 375 | 376 | if (RunPostOnSeperateTask == true) 377 | { 378 | Task.Run(() => 379 | { 380 | LogInternal(channelName, title, message, severity); 381 | 382 | }); 383 | } 384 | else 385 | { 386 | LogInternal(channelName, title, message, severity); 387 | } 388 | 389 | } 390 | 391 | private void LogInternal(string channelName, string title, string message = null, LogSeverity severity = LogSeverity.Notification) 392 | { 393 | var newLog = new LogEvent() 394 | { 395 | Channel = channelName, 396 | Title = title, 397 | Message = message, 398 | Severity = severity, 399 | }; 400 | 401 | var listeners = LogListeners.FindAll(channelName); 402 | 403 | foreach (var listener in listeners) 404 | listener.OnMessageRecieved(newLog); 405 | } 406 | 407 | /// 408 | /// Register a class instance that implements ILogListener to listen for log messages 409 | /// 410 | /// The instance of the class 411 | public void Listen(ILogListener instance) 412 | { 413 | LogListeners.Register(instance); 414 | 415 | } 416 | 417 | /// 418 | /// Stops listening to the log channel 419 | /// 420 | /// The instance. 421 | public void StopListening(ILogListener instance) 422 | { 423 | if (LogListeners == null) 424 | return; 425 | 426 | LogListeners.Remove(instance); 427 | } 428 | #endregion 429 | 430 | #endregion 431 | 432 | #endregion 433 | } 434 | } 435 | -------------------------------------------------------------------------------- /DSoft.Messaging/ThreadControl.android.cs: -------------------------------------------------------------------------------- 1 | using Android.OS; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | 6 | namespace DSoft.MessageBus 7 | { 8 | public partial class ThreadControl 9 | { 10 | static volatile Handler handler; 11 | 12 | static bool PlatformIsMainThread 13 | { 14 | get 15 | { 16 | if ((int)Build.VERSION.SdkInt > (int)BuildVersionCodes.M) 17 | return Looper.MainLooper.IsCurrentThread; 18 | 19 | return Looper.MyLooper() == Looper.MainLooper; 20 | } 21 | } 22 | 23 | static void PlatformBeginInvokeOnMainThread(Action action) 24 | { 25 | if (handler?.Looper != Looper.MainLooper) 26 | handler = new Handler(Looper.MainLooper); 27 | 28 | handler.Post(action); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /DSoft.Messaging/ThreadControl.ios.mac.tvos.watchos.cs: -------------------------------------------------------------------------------- 1 | using Foundation; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | 6 | namespace DSoft.MessageBus 7 | { 8 | public partial class ThreadControl 9 | { 10 | static bool PlatformIsMainThread => NSThread.Current.IsMainThread; 11 | 12 | static void PlatformBeginInvokeOnMainThread(Action action) 13 | { 14 | NSRunLoop.Main.BeginInvokeOnMainThread(action.Invoke); 15 | } 16 | 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /DSoft.Messaging/ThreadControl.netstandard.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace DSoft.MessageBus 6 | { 7 | public partial class ThreadControl 8 | { 9 | static void PlatformBeginInvokeOnMainThread(Action action) => throw new Exception("Not supportered on this platform"); 10 | 11 | static bool PlatformIsMainThread => throw new Exception("Not supportered on this platform"); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /DSoft.Messaging/ThreadControl.shared.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Threading; 5 | using System.Threading.Tasks; 6 | 7 | namespace DSoft.MessageBus 8 | { 9 | /// 10 | /// ThreadControl. 11 | /// 12 | public partial class ThreadControl 13 | { 14 | /// 15 | /// Gets a value indicating whether this instance is main thread. 16 | /// 17 | /// true if this instance is main thread; otherwise, false. 18 | public static bool IsMainThread => PlatformIsMainThread; 19 | 20 | /// 21 | /// Execute the action on the UI thread 22 | /// 23 | /// Action. 24 | public static void RunOnMainThread(Action action) 25 | { 26 | if (IsMainThread) 27 | { 28 | action(); 29 | } 30 | else 31 | { 32 | PlatformBeginInvokeOnMainThread(action); 33 | } 34 | } 35 | 36 | /// 37 | /// Runs the on main thread asynchronous. 38 | /// 39 | /// The action. 40 | /// Task. 41 | public static Task RunOnMainThreadAsync(Action action) 42 | { 43 | if (IsMainThread) 44 | { 45 | action(); 46 | 47 | return Task.CompletedTask; 48 | } 49 | 50 | var tcs = new TaskCompletionSource(); 51 | 52 | RunOnMainThread(() => 53 | { 54 | try 55 | { 56 | action(); 57 | tcs.TrySetResult(true); 58 | } 59 | catch (Exception ex) 60 | { 61 | tcs.TrySetException(ex); 62 | } 63 | }); 64 | 65 | return tcs.Task; 66 | } 67 | 68 | /// 69 | /// Get main task scheduler as an asynchronous operation. 70 | /// 71 | /// A Task<TaskScheduler> representing the asynchronous operation. 72 | public static async Task GetMainTaskSchedulerAsync() 73 | { 74 | TaskScheduler ret = null; 75 | await RunOnMainThreadAsync(() => 76 | ret = TaskScheduler.Current).ConfigureAwait(false); 77 | return ret; 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /DSoft.Messaging/ThreadControl.tizen.cs: -------------------------------------------------------------------------------- 1 | using ElmSharp; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | 6 | namespace DSoft.MessageBus 7 | { 8 | public partial class ThreadControl 9 | { 10 | static void PlatformBeginInvokeOnMainThread(Action action) 11 | { 12 | if (PlatformIsMainThread) 13 | action(); 14 | else 15 | EcoreMainloop.PostAndWakeUp(action); 16 | } 17 | 18 | static bool PlatformIsMainThread 19 | => EcoreMainloop.IsMainThread; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /DSoft.Messaging/ThreadControl.uwp.winui.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Text; 5 | using System.Threading; 6 | using System.Threading.Tasks; 7 | using Windows.ApplicationModel.Core; 8 | using Windows.Foundation; 9 | using Windows.UI.Core; 10 | 11 | namespace DSoft.MessageBus 12 | { 13 | public partial class ThreadControl 14 | { 15 | static bool PlatformIsMainThread 16 | { 17 | get 18 | { 19 | // if there is no main window, then this is either a service 20 | // or the UI is not yet constructed, so the main thread is the 21 | // current thread 22 | try 23 | { 24 | if (CoreApplication.MainView?.CoreWindow == null) 25 | return true; 26 | } 27 | catch (Exception ex) 28 | { 29 | Debug.WriteLine($"Unable to validate MainView creation. {ex.Message}"); 30 | return true; 31 | } 32 | 33 | return CoreApplication.MainView.CoreWindow.Dispatcher?.HasThreadAccess ?? false; 34 | } 35 | } 36 | 37 | static void PlatformBeginInvokeOnMainThread(Action action) 38 | { 39 | var dispatcher = CoreApplication.MainView?.CoreWindow?.Dispatcher; 40 | 41 | if (dispatcher == null) 42 | throw new InvalidOperationException("Unable to find main thread."); 43 | dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => action()).WatchForError(); 44 | } 45 | } 46 | 47 | internal static partial class MainThreadExtensions 48 | { 49 | internal static void WatchForError(this IAsyncAction self) => 50 | self.AsTask().WatchForError(); 51 | 52 | internal static void WatchForError(this IAsyncOperation self) => 53 | self.AsTask().WatchForError(); 54 | 55 | internal static void WatchForError(this Task self) 56 | { 57 | var context = SynchronizationContext.Current; 58 | if (context == null) 59 | return; 60 | 61 | self.ContinueWith( 62 | t => 63 | { 64 | var exception = t.Exception.InnerExceptions.Count > 1 ? t.Exception : t.Exception.InnerException; 65 | 66 | context.Post(e => { throw (Exception)e; }, exception); 67 | }, CancellationToken.None, 68 | TaskContinuationOptions.OnlyOnFaulted, 69 | TaskScheduler.Default); 70 | } 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /DSoft.Messaging/ThreadControl.wpf.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Text; 5 | using System.Threading; 6 | using System.Windows; 7 | 8 | namespace DSoft.MessageBus 9 | { 10 | public partial class ThreadControl 11 | { 12 | static bool PlatformIsMainThread 13 | { 14 | get 15 | { 16 | 17 | return (Thread.CurrentThread == Application.Current.Dispatcher.Thread); 18 | 19 | } 20 | } 21 | 22 | static void PlatformBeginInvokeOnMainThread(Action action) 23 | { 24 | if (PlatformIsMainThread) 25 | { 26 | action(); 27 | } 28 | else 29 | { 30 | Application.Current.Dispatcher.Invoke(action); 31 | } 32 | } 33 | 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | true 4 | true 5 | false 6 | https://github.com/newky2k/MessageBus 7 | https://github.com/newky2k/MessageBus 8 | git 9 | enable 10 | Latest 11 | 1701;1702;CS8002;CS8653;CS8600;CS1591;CS8603;CS8602;CS8765;CS8618;CS8604; 12 | 13 | 14 | 15 | true 16 | 17 | 18 | 19 | 20 | true 21 | 22 | true 23 | 24 | $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | true 33 | 34 | 35 | 36 | True 37 | $(MSBuildProjectDirectory)\DSoft.snk 38 | 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /MessageBus.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.0.32014.148 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DSoft.MessageBus", "DSoft.Messaging\DSoft.MessageBus.csproj", "{59BFF815-1B16-485D-BA2A-22ADF9B4C8F7}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WPFSample", "WPFSample\WPFSample.csproj", "{DFFF869B-D948-45E7-9F8E-F8136B29F38F}" 9 | EndProject 10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".ci", ".ci", "{0CD3B62F-A04B-40E3-808B-D480F5825CD9}" 11 | ProjectSection(SolutionItems) = preProject 12 | azure-pipelines-mergetest.yml = azure-pipelines-mergetest.yml 13 | azure-pipelines-release.yml = azure-pipelines-release.yml 14 | Directory.Build.props = Directory.Build.props 15 | README.md = README.md 16 | EndProjectSection 17 | EndProject 18 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DSoft.MessageBus.Core", "DSoft.MessageBus.Core\DSoft.MessageBus.Core.csproj", "{CA4764B0-F994-454D-AB55-DB9B5DD53670}" 19 | EndProject 20 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{E3D5273D-28D2-4B94-850C-31E2DBA0A140}" 21 | EndProject 22 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTest", "UnitTest\UnitTest.csproj", "{39B7C537-2438-4D22-A1BF-A979299CFD09}" 23 | EndProject 24 | Global 25 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 26 | Ad-Hoc|Any CPU = Ad-Hoc|Any CPU 27 | Ad-Hoc|iPhone = Ad-Hoc|iPhone 28 | Ad-Hoc|iPhoneSimulator = Ad-Hoc|iPhoneSimulator 29 | AppStore|Any CPU = AppStore|Any CPU 30 | AppStore|iPhone = AppStore|iPhone 31 | AppStore|iPhoneSimulator = AppStore|iPhoneSimulator 32 | Debug|Any CPU = Debug|Any CPU 33 | Debug|iPhone = Debug|iPhone 34 | Debug|iPhoneSimulator = Debug|iPhoneSimulator 35 | Release|Any CPU = Release|Any CPU 36 | Release|iPhone = Release|iPhone 37 | Release|iPhoneSimulator = Release|iPhoneSimulator 38 | EndGlobalSection 39 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 40 | {59BFF815-1B16-485D-BA2A-22ADF9B4C8F7}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU 41 | {59BFF815-1B16-485D-BA2A-22ADF9B4C8F7}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU 42 | {59BFF815-1B16-485D-BA2A-22ADF9B4C8F7}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU 43 | {59BFF815-1B16-485D-BA2A-22ADF9B4C8F7}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU 44 | {59BFF815-1B16-485D-BA2A-22ADF9B4C8F7}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU 45 | {59BFF815-1B16-485D-BA2A-22ADF9B4C8F7}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU 46 | {59BFF815-1B16-485D-BA2A-22ADF9B4C8F7}.AppStore|Any CPU.ActiveCfg = Release|Any CPU 47 | {59BFF815-1B16-485D-BA2A-22ADF9B4C8F7}.AppStore|Any CPU.Build.0 = Release|Any CPU 48 | {59BFF815-1B16-485D-BA2A-22ADF9B4C8F7}.AppStore|iPhone.ActiveCfg = Debug|Any CPU 49 | {59BFF815-1B16-485D-BA2A-22ADF9B4C8F7}.AppStore|iPhone.Build.0 = Debug|Any CPU 50 | {59BFF815-1B16-485D-BA2A-22ADF9B4C8F7}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU 51 | {59BFF815-1B16-485D-BA2A-22ADF9B4C8F7}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU 52 | {59BFF815-1B16-485D-BA2A-22ADF9B4C8F7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 53 | {59BFF815-1B16-485D-BA2A-22ADF9B4C8F7}.Debug|Any CPU.Build.0 = Debug|Any CPU 54 | {59BFF815-1B16-485D-BA2A-22ADF9B4C8F7}.Debug|iPhone.ActiveCfg = Debug|Any CPU 55 | {59BFF815-1B16-485D-BA2A-22ADF9B4C8F7}.Debug|iPhone.Build.0 = Debug|Any CPU 56 | {59BFF815-1B16-485D-BA2A-22ADF9B4C8F7}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU 57 | {59BFF815-1B16-485D-BA2A-22ADF9B4C8F7}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU 58 | {59BFF815-1B16-485D-BA2A-22ADF9B4C8F7}.Release|Any CPU.ActiveCfg = Release|Any CPU 59 | {59BFF815-1B16-485D-BA2A-22ADF9B4C8F7}.Release|Any CPU.Build.0 = Release|Any CPU 60 | {59BFF815-1B16-485D-BA2A-22ADF9B4C8F7}.Release|iPhone.ActiveCfg = Release|Any CPU 61 | {59BFF815-1B16-485D-BA2A-22ADF9B4C8F7}.Release|iPhone.Build.0 = Release|Any CPU 62 | {59BFF815-1B16-485D-BA2A-22ADF9B4C8F7}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU 63 | {59BFF815-1B16-485D-BA2A-22ADF9B4C8F7}.Release|iPhoneSimulator.Build.0 = Release|Any CPU 64 | {DFFF869B-D948-45E7-9F8E-F8136B29F38F}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU 65 | {DFFF869B-D948-45E7-9F8E-F8136B29F38F}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU 66 | {DFFF869B-D948-45E7-9F8E-F8136B29F38F}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU 67 | {DFFF869B-D948-45E7-9F8E-F8136B29F38F}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU 68 | {DFFF869B-D948-45E7-9F8E-F8136B29F38F}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU 69 | {DFFF869B-D948-45E7-9F8E-F8136B29F38F}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU 70 | {DFFF869B-D948-45E7-9F8E-F8136B29F38F}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU 71 | {DFFF869B-D948-45E7-9F8E-F8136B29F38F}.AppStore|Any CPU.Build.0 = Debug|Any CPU 72 | {DFFF869B-D948-45E7-9F8E-F8136B29F38F}.AppStore|iPhone.ActiveCfg = Debug|Any CPU 73 | {DFFF869B-D948-45E7-9F8E-F8136B29F38F}.AppStore|iPhone.Build.0 = Debug|Any CPU 74 | {DFFF869B-D948-45E7-9F8E-F8136B29F38F}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU 75 | {DFFF869B-D948-45E7-9F8E-F8136B29F38F}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU 76 | {DFFF869B-D948-45E7-9F8E-F8136B29F38F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 77 | {DFFF869B-D948-45E7-9F8E-F8136B29F38F}.Debug|Any CPU.Build.0 = Debug|Any CPU 78 | {DFFF869B-D948-45E7-9F8E-F8136B29F38F}.Debug|iPhone.ActiveCfg = Debug|Any CPU 79 | {DFFF869B-D948-45E7-9F8E-F8136B29F38F}.Debug|iPhone.Build.0 = Debug|Any CPU 80 | {DFFF869B-D948-45E7-9F8E-F8136B29F38F}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU 81 | {DFFF869B-D948-45E7-9F8E-F8136B29F38F}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU 82 | {DFFF869B-D948-45E7-9F8E-F8136B29F38F}.Release|Any CPU.ActiveCfg = Release|Any CPU 83 | {DFFF869B-D948-45E7-9F8E-F8136B29F38F}.Release|Any CPU.Build.0 = Release|Any CPU 84 | {DFFF869B-D948-45E7-9F8E-F8136B29F38F}.Release|iPhone.ActiveCfg = Release|Any CPU 85 | {DFFF869B-D948-45E7-9F8E-F8136B29F38F}.Release|iPhone.Build.0 = Release|Any CPU 86 | {DFFF869B-D948-45E7-9F8E-F8136B29F38F}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU 87 | {DFFF869B-D948-45E7-9F8E-F8136B29F38F}.Release|iPhoneSimulator.Build.0 = Release|Any CPU 88 | {CA4764B0-F994-454D-AB55-DB9B5DD53670}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU 89 | {CA4764B0-F994-454D-AB55-DB9B5DD53670}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU 90 | {CA4764B0-F994-454D-AB55-DB9B5DD53670}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU 91 | {CA4764B0-F994-454D-AB55-DB9B5DD53670}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU 92 | {CA4764B0-F994-454D-AB55-DB9B5DD53670}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU 93 | {CA4764B0-F994-454D-AB55-DB9B5DD53670}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU 94 | {CA4764B0-F994-454D-AB55-DB9B5DD53670}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU 95 | {CA4764B0-F994-454D-AB55-DB9B5DD53670}.AppStore|Any CPU.Build.0 = Debug|Any CPU 96 | {CA4764B0-F994-454D-AB55-DB9B5DD53670}.AppStore|iPhone.ActiveCfg = Debug|Any CPU 97 | {CA4764B0-F994-454D-AB55-DB9B5DD53670}.AppStore|iPhone.Build.0 = Debug|Any CPU 98 | {CA4764B0-F994-454D-AB55-DB9B5DD53670}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU 99 | {CA4764B0-F994-454D-AB55-DB9B5DD53670}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU 100 | {CA4764B0-F994-454D-AB55-DB9B5DD53670}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 101 | {CA4764B0-F994-454D-AB55-DB9B5DD53670}.Debug|Any CPU.Build.0 = Debug|Any CPU 102 | {CA4764B0-F994-454D-AB55-DB9B5DD53670}.Debug|iPhone.ActiveCfg = Debug|Any CPU 103 | {CA4764B0-F994-454D-AB55-DB9B5DD53670}.Debug|iPhone.Build.0 = Debug|Any CPU 104 | {CA4764B0-F994-454D-AB55-DB9B5DD53670}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU 105 | {CA4764B0-F994-454D-AB55-DB9B5DD53670}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU 106 | {CA4764B0-F994-454D-AB55-DB9B5DD53670}.Release|Any CPU.ActiveCfg = Release|Any CPU 107 | {CA4764B0-F994-454D-AB55-DB9B5DD53670}.Release|Any CPU.Build.0 = Release|Any CPU 108 | {CA4764B0-F994-454D-AB55-DB9B5DD53670}.Release|iPhone.ActiveCfg = Release|Any CPU 109 | {CA4764B0-F994-454D-AB55-DB9B5DD53670}.Release|iPhone.Build.0 = Release|Any CPU 110 | {CA4764B0-F994-454D-AB55-DB9B5DD53670}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU 111 | {CA4764B0-F994-454D-AB55-DB9B5DD53670}.Release|iPhoneSimulator.Build.0 = Release|Any CPU 112 | {39B7C537-2438-4D22-A1BF-A979299CFD09}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU 113 | {39B7C537-2438-4D22-A1BF-A979299CFD09}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU 114 | {39B7C537-2438-4D22-A1BF-A979299CFD09}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU 115 | {39B7C537-2438-4D22-A1BF-A979299CFD09}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU 116 | {39B7C537-2438-4D22-A1BF-A979299CFD09}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU 117 | {39B7C537-2438-4D22-A1BF-A979299CFD09}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU 118 | {39B7C537-2438-4D22-A1BF-A979299CFD09}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU 119 | {39B7C537-2438-4D22-A1BF-A979299CFD09}.AppStore|Any CPU.Build.0 = Debug|Any CPU 120 | {39B7C537-2438-4D22-A1BF-A979299CFD09}.AppStore|iPhone.ActiveCfg = Debug|Any CPU 121 | {39B7C537-2438-4D22-A1BF-A979299CFD09}.AppStore|iPhone.Build.0 = Debug|Any CPU 122 | {39B7C537-2438-4D22-A1BF-A979299CFD09}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU 123 | {39B7C537-2438-4D22-A1BF-A979299CFD09}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU 124 | {39B7C537-2438-4D22-A1BF-A979299CFD09}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 125 | {39B7C537-2438-4D22-A1BF-A979299CFD09}.Debug|Any CPU.Build.0 = Debug|Any CPU 126 | {39B7C537-2438-4D22-A1BF-A979299CFD09}.Debug|iPhone.ActiveCfg = Debug|Any CPU 127 | {39B7C537-2438-4D22-A1BF-A979299CFD09}.Debug|iPhone.Build.0 = Debug|Any CPU 128 | {39B7C537-2438-4D22-A1BF-A979299CFD09}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU 129 | {39B7C537-2438-4D22-A1BF-A979299CFD09}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU 130 | {39B7C537-2438-4D22-A1BF-A979299CFD09}.Release|Any CPU.ActiveCfg = Release|Any CPU 131 | {39B7C537-2438-4D22-A1BF-A979299CFD09}.Release|Any CPU.Build.0 = Release|Any CPU 132 | {39B7C537-2438-4D22-A1BF-A979299CFD09}.Release|iPhone.ActiveCfg = Release|Any CPU 133 | {39B7C537-2438-4D22-A1BF-A979299CFD09}.Release|iPhone.Build.0 = Release|Any CPU 134 | {39B7C537-2438-4D22-A1BF-A979299CFD09}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU 135 | {39B7C537-2438-4D22-A1BF-A979299CFD09}.Release|iPhoneSimulator.Build.0 = Release|Any CPU 136 | EndGlobalSection 137 | GlobalSection(SolutionProperties) = preSolution 138 | HideSolutionNode = FALSE 139 | EndGlobalSection 140 | GlobalSection(NestedProjects) = preSolution 141 | {39B7C537-2438-4D22-A1BF-A979299CFD09} = {E3D5273D-28D2-4B94-850C-31E2DBA0A140} 142 | EndGlobalSection 143 | GlobalSection(ExtensibilityGlobals) = postSolution 144 | SolutionGuid = {6CFD17BF-4F82-4FFE-94AD-9DFD67403C69} 145 | EndGlobalSection 146 | GlobalSection(MonoDevelopProperties) = preSolution 147 | StartupItem = DSoft.Messaging\DSoft.Messaging.csproj 148 | version = 1.3 149 | EndGlobalSection 150 | EndGlobal 151 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MessageBus 2 | MessageBus is a cross platform EventBus system similar to `NSNoticationCenter` on iOS and `otto` on Android that allow you to decouple your code, whilst still allowing your applications components to communicate with each other. MessageBus can be used instead of events, can be used to communicate between objects that are not directly linked. 3 | 4 | # Features 5 | 6 | * Cross-platform 7 | * .NETStandard 2.1, .NET 8+ including iOS, TVOS, Android, UWP, Mac and Windows with support for WPF and WinUI 8 | * Small footprint 9 | * Simple API 10 | * Create custom events to easily pass additional data 11 | * Allows you to decouple objects and classes within your projects 12 | * New in 3.1 - Dependency Injection support 13 | 14 | ## Usage 15 | 16 | To use Dependency Injection follow these steps. 17 | 18 | Add package `DSoft.MessageBus` to your main application and call `RegisterMessageBus` to register the services. 19 | 20 | private static void ConfigureServices(IServiceCollection services) 21 | { 22 | services.RegisterMessageBus(); 23 | } 24 | 25 | You can then inject `IMessageBusService` into your own services. 26 | 27 | Please check the Unit tests and sample WPF app for examples of usage 28 | 29 | ### Attribution 30 | 31 | `ThreadControl` contains portions of code from [Xamarin.Essentials](https://github.com/xamarin/Essentials/tree/master/Xamarin.Essentials/MainThread), specifically the `MainThread` functionality 32 | -------------------------------------------------------------------------------- /UnitTest/BaseTest.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace UnitTest 9 | { 10 | [TestClass] 11 | public abstract class BaseTest 12 | { 13 | public static ServiceProvider Provider { get; private set; } 14 | 15 | [AssemblyInitialize] 16 | public static void AssemblyInit(TestContext context) 17 | { 18 | var services = new ServiceCollection(); 19 | 20 | ConfigureServices(services); 21 | 22 | Provider = services.BuildServiceProvider(); 23 | } 24 | 25 | private static void ConfigureServices(IServiceCollection services) 26 | { 27 | services.RegisterMessageBus(); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /UnitTest/Events/TestMessageEvents.cs: -------------------------------------------------------------------------------- 1 | using DSoft.MessageBus; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace UnitTest.Events 9 | { 10 | /// 11 | /// 12 | /// 13 | /// 14 | internal class TestMessageEvents : MessageBusEvent 15 | { 16 | public override string EventId => "123456"; 17 | 18 | public TestMessageEvents() { } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /UnitTest/Events/TestMessageEventsTwo.cs: -------------------------------------------------------------------------------- 1 | using DSoft.MessageBus; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace UnitTest.Events 9 | { 10 | /// 11 | /// 12 | /// 13 | /// 14 | internal class TestMessageEventsTwo : MessageBusEvent 15 | { 16 | public override string EventId => "94848484838181"; 17 | 18 | public TestMessageEventsTwo() { } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /UnitTest/MessageBusTest.cs: -------------------------------------------------------------------------------- 1 | using DSoft.MessageBus; 2 | using DSoft.MessageBus.Contracts; 3 | using Microsoft.Extensions.DependencyInjection; 4 | using UnitTest.Events; 5 | 6 | namespace UnitTest 7 | { 8 | [TestClass] 9 | public class MessageBusTest : BaseTest 10 | { 11 | public MessageBusTest() : base() { } 12 | 13 | [TestMethod] 14 | public void CanReturnDI() 15 | { 16 | var messageBus = Provider.GetRequiredService(); 17 | } 18 | 19 | #region Subscribe 20 | 21 | 22 | [TestMethod] 23 | public void CanSubscribeWithEventHandler() 24 | { 25 | var messageBus = Provider.GetRequiredService(); 26 | 27 | var newMessage = new TestMessageEvents(); 28 | 29 | var wasCalled = false; 30 | 31 | Action action = (sender, evt) => 32 | { 33 | wasCalled = true; 34 | }; 35 | 36 | var messageHandler = new MessageBusEventHandler() 37 | { 38 | EventId = newMessage.EventId, 39 | EventAction = action, 40 | }; 41 | messageBus.Subscribe(messageHandler); 42 | 43 | messageBus.Post(newMessage); 44 | 45 | Assert.IsTrue(wasCalled); 46 | 47 | } 48 | 49 | [TestMethod] 50 | public void CanSubscribeWithEventId() 51 | { 52 | var messageBus = Provider.GetRequiredService(); 53 | 54 | var eventId = "12009636"; 55 | 56 | var wasCalled = false; 57 | 58 | Action action = (sender, evt) => 59 | { 60 | wasCalled = true; 61 | }; 62 | 63 | messageBus.Subscribe(eventId, action); 64 | 65 | messageBus.Post(eventId); 66 | 67 | Assert.IsTrue(wasCalled); 68 | 69 | } 70 | 71 | [TestMethod] 72 | public void CanSubscribeWithEventIdAndSender() 73 | { 74 | var messageBus = Provider.GetRequiredService(); 75 | 76 | var eventId = "78909187363"; 77 | 78 | var wasCalled = false; 79 | 80 | Action action = (sender, evt) => 81 | { 82 | wasCalled = true; 83 | }; 84 | 85 | messageBus.Subscribe(eventId, action); 86 | 87 | messageBus.Post(eventId, this); 88 | 89 | Assert.IsTrue(wasCalled); 90 | 91 | } 92 | 93 | [TestMethod] 94 | public void CanSubscribeWithEventIdAndSenderAndData() 95 | { 96 | var messageBus = Provider.GetRequiredService(); 97 | 98 | var eventId = "89537373"; 99 | 100 | var wasCalled = false; 101 | 102 | var someData = "WBYCBOZSAEuflPLXzGKPtg=="; 103 | 104 | Action action = (sender, evt) => 105 | { 106 | wasCalled = true; 107 | }; 108 | 109 | messageBus.Subscribe(eventId, action); 110 | 111 | messageBus.Post(eventId, this, someData); 112 | 113 | Assert.IsTrue(wasCalled); 114 | 115 | } 116 | 117 | [TestMethod] 118 | public void CanSubscribeWithEventIdAndData() 119 | { 120 | var messageBus = Provider.GetRequiredService(); 121 | 122 | var eventId = "12894725271"; 123 | 124 | var wasCalled = false; 125 | 126 | var someData = "WBYCBOZSAEuflPLXzGKPtg=="; 127 | 128 | Action action = (sender, evt) => 129 | { 130 | wasCalled = true; 131 | }; 132 | 133 | messageBus.Subscribe(eventId, action); 134 | 135 | messageBus.PostData(eventId, Data: someData); 136 | 137 | Assert.IsTrue(wasCalled); 138 | 139 | } 140 | 141 | [TestMethod] 142 | public void CanSubscribeWithSimpleAction() 143 | { 144 | var messageBus = Provider.GetRequiredService(); 145 | 146 | var eventId = "1937191885"; 147 | 148 | var wasCalled = false; 149 | 150 | var someData = "WBYCBOZSAEuflPLXzGKPtg=="; 151 | 152 | var action = () => 153 | { 154 | wasCalled = true; 155 | }; 156 | 157 | messageBus.Subscribe(eventId, action); 158 | 159 | messageBus.Post(eventId, this, someData); 160 | 161 | Assert.IsTrue(wasCalled); 162 | 163 | } 164 | 165 | [TestMethod] 166 | public void CanSubscribeWithObjectsAction() 167 | { 168 | var messageBus = Provider.GetRequiredService(); 169 | 170 | var eventId = "1937191885"; 171 | 172 | var wasCalled = false; 173 | 174 | var someData = "WBYCBOZSAEuflPLXzGKPtg=="; 175 | 176 | Action action = (data) => 177 | { 178 | wasCalled = true; 179 | }; 180 | 181 | messageBus.Subscribe(eventId, action); 182 | 183 | messageBus.Post(eventId, this, someData); 184 | 185 | Assert.IsTrue(wasCalled); 186 | 187 | } 188 | 189 | [TestMethod] 190 | public void CanSubscribeWithSubscribeEventHandler() 191 | { 192 | var messageBus = Provider.GetRequiredService(); 193 | 194 | var newMessage = new TestMessageEventsTwo(); 195 | 196 | var wasCalled = false; 197 | 198 | Action action = (sender, evt) => 199 | { 200 | wasCalled = true; 201 | }; 202 | 203 | var messageHandler = new MessageBusEventHandler() 204 | { 205 | EventId = newMessage.EventId, 206 | EventAction = action, 207 | }; 208 | messageBus.Subscribe(action); 209 | 210 | 211 | messageBus.Post(newMessage); 212 | 213 | Assert.IsTrue(wasCalled); 214 | 215 | } 216 | 217 | #endregion 218 | 219 | #region Unsubscribe 220 | 221 | [TestMethod] 222 | public void CanUnsubscribeWithEventHandler() 223 | { 224 | var messageBus = Provider.GetRequiredService(); 225 | 226 | var newMessage = new TestMessageEvents(); 227 | 228 | var wasCalled = false; 229 | 230 | Action action = (sender, evt) => 231 | { 232 | wasCalled = true; 233 | }; 234 | 235 | var messageHandler = new MessageBusEventHandler() 236 | { 237 | EventId = newMessage.EventId, 238 | EventAction = action, 239 | }; 240 | messageBus.Subscribe(messageHandler); 241 | 242 | messageBus.Unsubscribe(messageHandler); 243 | 244 | messageBus.Post(newMessage); 245 | 246 | Assert.IsFalse(wasCalled); 247 | 248 | } 249 | 250 | [TestMethod] 251 | public void CanUnsubscribeWithEventId() 252 | { 253 | var messageBus = Provider.GetRequiredService(); 254 | 255 | var eventId = "12009636"; 256 | 257 | var wasCalled = false; 258 | 259 | Action action = (sender, evt) => 260 | { 261 | wasCalled = true; 262 | }; 263 | 264 | messageBus.Subscribe(eventId, action); 265 | 266 | messageBus.Unsubscribe(eventId, action); 267 | 268 | messageBus.Post(eventId); 269 | 270 | Assert.IsFalse(wasCalled); 271 | 272 | } 273 | 274 | [TestMethod] 275 | public void CanUnsubscribeWithEventIdOnly() 276 | { 277 | var messageBus = Provider.GetRequiredService(); 278 | 279 | var eventId = "3366558899"; 280 | 281 | var wasCalled = false; 282 | 283 | Action action = (sender, evt) => 284 | { 285 | wasCalled = true; 286 | }; 287 | 288 | messageBus.Subscribe(eventId, action); 289 | 290 | messageBus.Unsubscribe(eventId); 291 | 292 | messageBus.Post(eventId); 293 | 294 | Assert.IsFalse(wasCalled); 295 | 296 | } 297 | 298 | [TestMethod] 299 | public void CanUnsubscribeWithSubscribeEventHandler() 300 | { 301 | var messageBus = Provider.GetRequiredService(); 302 | 303 | var newMessage = new TestMessageEventsTwo(); 304 | 305 | var wasCalled = false; 306 | 307 | Action action = (sender, evt) => 308 | { 309 | wasCalled = true; 310 | }; 311 | 312 | var messageHandler = new MessageBusEventHandler() 313 | { 314 | EventId = newMessage.EventId, 315 | EventAction = action, 316 | }; 317 | messageBus.Subscribe(action); 318 | 319 | messageBus.Unsubscribe(action); 320 | 321 | messageBus.Post(newMessage); 322 | 323 | Assert.IsFalse(wasCalled); 324 | 325 | } 326 | #endregion 327 | } 328 | } -------------------------------------------------------------------------------- /UnitTest/UnitTest.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net9.0 5 | enable 6 | enable 7 | False 8 | False 9 | false 10 | true 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /WPFSample/App.xaml: -------------------------------------------------------------------------------- 1 |  6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /WPFSample/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Configuration; 4 | using System.Data; 5 | using System.Linq; 6 | using System.Threading.Tasks; 7 | using System.Windows; 8 | 9 | namespace WPFSample 10 | { 11 | /// 12 | /// Interaction logic for App.xaml 13 | /// 14 | public partial class App : Application 15 | { 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /WPFSample/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | 3 | [assembly: ThemeInfo( 4 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located 5 | //(used if a resource is not found in the page, 6 | // or application resource dictionaries) 7 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located 8 | //(used if a resource is not found in the page, 9 | // app, or any theme specific resource dictionaries) 10 | )] 11 | -------------------------------------------------------------------------------- /WPFSample/MainViewModel.cs: -------------------------------------------------------------------------------- 1 | using DSoft.MessageBus; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Mvvm; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using System.Windows.Input; 9 | 10 | namespace WPFSample 11 | { 12 | public class MainViewModel : ViewModel 13 | { 14 | private const string EventId = "42B65ED9-62CB-4AC7-A1B9-2A879C6BB8F6"; 15 | 16 | private string _messageLog; 17 | 18 | public string MessageLog 19 | { 20 | get { return _messageLog; } 21 | set { _messageLog = value; NotifyPropertyChanged(nameof(MessageLog)); } 22 | } 23 | 24 | public ICommand BeginCommand 25 | { 26 | get 27 | { 28 | return new DelegateCommand(() => 29 | { 30 | MessageBus.RunPostOnSeperateTask = true; 31 | 32 | MessageLog = string.Empty; 33 | 34 | var startTime = DateTime.Now; 35 | 36 | for (var loop = 0; loop < 1000; loop++) 37 | { 38 | MessageBus.Post(EventId); 39 | } 40 | 41 | var ednTime = DateTime.Now; 42 | 43 | var diff = ednTime - startTime; 44 | 45 | MessageLog += $"Total time: {diff.TotalSeconds}"; 46 | 47 | NotifyOnComplete(true); 48 | 49 | }); 50 | } 51 | } 52 | 53 | //Total time: 3.3507754 54 | public MainViewModel() 55 | { 56 | MessageBus.Subscribe(EventId, () => 57 | { 58 | MessageLog += "Tick" + Environment.NewLine; 59 | 60 | }); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /WPFSample/MainWindow.xaml: -------------------------------------------------------------------------------- 1 |  10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /WPFSample/MainWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows; 7 | using System.Windows.Controls; 8 | using System.Windows.Data; 9 | using System.Windows.Documents; 10 | using System.Windows.Input; 11 | using System.Windows.Media; 12 | using System.Windows.Media.Imaging; 13 | using System.Windows.Navigation; 14 | using System.Windows.Shapes; 15 | 16 | namespace WPFSample 17 | { 18 | /// 19 | /// Interaction logic for MainWindow.xaml 20 | /// 21 | public partial class MainWindow : Window 22 | { 23 | private int updateCount = 0; 24 | 25 | private MainViewModel _viewModel; 26 | 27 | public MainViewModel ViewModel 28 | { 29 | get { return _viewModel; } 30 | set { _viewModel = value; DataContext = _viewModel; } 31 | } 32 | 33 | public MainWindow() 34 | { 35 | InitializeComponent(); 36 | 37 | ViewModel = new MainViewModel(); 38 | 39 | ViewModel.OnComplete += OnComplete; 40 | } 41 | 42 | private void OnComplete(object sender, bool e) 43 | { 44 | Dispatcher.Invoke(()=> 45 | { 46 | txtLog.ScrollToEnd(); 47 | }); 48 | } 49 | 50 | private void OnTextChanged(object sender, TextChangedEventArgs e) 51 | { 52 | if (sender is TextBox) 53 | { 54 | if (updateCount > 50) 55 | { 56 | updateCount = 0; 57 | 58 | ((TextBox)sender).ScrollToEnd(); 59 | } 60 | 61 | } 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /WPFSample/WPFSample.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | WinExe 5 | net9.0-windows 6 | true 7 | False 8 | False 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /azure-pipelines-mergetest.yml: -------------------------------------------------------------------------------- 1 | # .NET Desktop 2 | # Build and run tests for .NET Desktop or Windows classic desktop solutions. 3 | # Add steps that publish symbols, save build artifacts, and more: 4 | # https://docs.microsoft.com/azure/devops/pipelines/apps/windows/dot-net 5 | 6 | trigger: none 7 | 8 | pool: 9 | vmImage: 'windows-latest' 10 | 11 | variables: 12 | solution: '**/*.sln' 13 | buildPlatform: 'Any CPU' 14 | buildConfiguration: 'Release' 15 | netVersion: '9.x' 16 | 17 | steps: 18 | - task: NuGetToolInstaller@1 19 | displayName: Install Latest Nuget 20 | 21 | - task: UseDotNet@2 22 | displayName: 'Install .NET sdk' 23 | inputs: 24 | packageType: 'sdk' 25 | version: $(netVersion) 26 | 27 | - task: Bash@3 28 | displayName: Install MAUI 29 | inputs: 30 | targetType: 'inline' 31 | script: 32 | dotnet workload install android ios maccatalyst tvos macos maui wasm-tools 33 | 34 | - task: NuGetCommand@2 35 | displayName: Nuget Restore 36 | inputs: 37 | restoreSolution: '$(solution)' 38 | 39 | - task: DotNetCoreCLI@2 40 | displayName: dotnet build 41 | inputs: 42 | projects: '$(solution)' 43 | arguments: '--configuration=$(buildConfiguration) /p:Platform="$(buildPlatform)"' -------------------------------------------------------------------------------- /azure-pipelines-release.yml: -------------------------------------------------------------------------------- 1 | # .NET Desktop 2 | # Build and run tests for .NET Desktop or Windows classic desktop solutions. 3 | # Add steps that publish symbols, save build artifacts, and more: 4 | # https://docs.microsoft.com/azure/devops/pipelines/apps/windows/dot-net 5 | 6 | trigger: 7 | batch: true 8 | branches: 9 | include: 10 | - main 11 | paths: 12 | exclude: 13 | - '*.yml' 14 | 15 | pool: 16 | vmImage: 'windows-latest' 17 | 18 | variables: 19 | solution: '**/*.sln' 20 | buildPlatform: 'Any CPU' 21 | buildConfiguration: 'Release' 22 | netVersion: '9.x' 23 | releaseSuffix: '' 24 | 25 | name: 4.2.$(date:yyMM).$(date:dd)$(rev:r) 26 | steps: 27 | - task: NuGetToolInstaller@1 28 | displayName: Install Latest Nuget 29 | 30 | - task: UseDotNet@2 31 | displayName: 'Install .NET sdk' 32 | inputs: 33 | packageType: 'sdk' 34 | version: $(netVersion) 35 | 36 | - task: Bash@3 37 | displayName: Install MAUI 38 | inputs: 39 | targetType: 'inline' 40 | script: 41 | dotnet workload install android ios maccatalyst tvos macos maui wasm-tools 42 | 43 | - task: NuGetCommand@2 44 | displayName: Nuget Restore 45 | inputs: 46 | restoreSolution: '$(solution)' 47 | 48 | - task: DotNetCoreCLI@2 49 | displayName: dotnet build 50 | inputs: 51 | projects: '$(solution)' 52 | arguments: '--configuration=$(buildConfiguration) /p:Platform="$(buildPlatform)" /p:Version=$(Build.BuildNumber)$(releaseSuffix) /p:AssemblyVersion=$(Build.BuildNumber) /p:FileVersion=$(Build.BuildNumber) ' 53 | 54 | - task: CopyFiles@2 55 | displayName: Copy Files to $(build.artifactstagingdirectory) 56 | inputs: 57 | SourceFolder: '$(system.defaultworkingdirectory)' 58 | Contents: '**/Dsoft.*.nupkg' 59 | TargetFolder: '$(build.artifactstagingdirectory)' 60 | flattenFolders: true 61 | 62 | - task: PublishBuildArtifacts@1 63 | displayName: Publish Artifacts drop 64 | inputs: 65 | PathtoPublish: '$(Build.ArtifactStagingDirectory)' 66 | ArtifactName: 'drop' 67 | publishLocation: 'Container' 68 | --------------------------------------------------------------------------------