Git Product home page Git Product logo

easy.messagehub's People

Contributors

nimaara avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

easy.messagehub's Issues

Subscribing a runtime type

I need to subscribe a runtime type which is defined with an attribute.
For example:
I have class Foo, which I want to subscribe to an Action (non-generic)
That class Foo is defined by an attribute at runtime, meaning I can't do this:

Type t = typeof(Foo);
_messageHub.Subscribe<t>({Some method})

I know this isn't valid syntax so this won't work.
Is there anyway to make this work?
I was thinking something like this, but not sure if it'll work:

Type t = typeof(Foo);
_messageHub.Subscribe(t, {Some method})

Conditional subscription

I have been using Easy MessageHub for years now and I couldn't live without - thank you!

Have you explored the idea of conditional subscriptions? ie. subscribing to not only the Type but a subset of instances by checking a field value of the object.

Guid token = hub.Subscribe<Person>(p => Console.WriteLine($"Id is: {p.Id}")); gives you all instances of Person.

If I only wanted to subscribe to Person where Gender == Male, then it would allow for more targeted subscriptions and various areas of the app would not unnecessarily receive events to then have to filter the contents - this is a lot of unnecessary processing.

I understand this could be achieved by subclassing Person but you would need to know the filter at build time. I have a case where the user can choose the filter value at runtime so it would be great to be able to add that to the subscription method.

This idea is very much inspired by Rx but didn't want to have to use that whole library for limited cases.

Thanks!

Async handlers

Hi,

Thanks for the library, it's great addition to our system. However, I was wondering - what do you think of adding support for async handlers?

We have subscription handler where we need to call async methods. Could wrap of course in some GetAwaiter magic, but was wondering about "native" support from the hub side.

Any pointers whether this could be complex to add? Probably can contrib if you give some heads up ideas.

Thanks!

Support for async actions

Hi.
If one for some reason needs to perform a call to an async method in the action callback. The global errorhandler does not work because no one await the returned task.
Is it possible to get support for this?
We can probably surround the async method call in our callback with a try/catch but the global handler are more conveniant to use

Unflexible detection of the given type

Hi,

i think my issue is related to #11.

In my scenario, every message implements the interface IMessage. The problem is, that the type detection doesn't use the real type of an object to detect the subscription, instead it uses the compiled generic parameter T.

Example:

hub.Subscribe<MyMessage>(...)
hub.Subscribe<MyOtherMessage>(...)

IMessage message;

if(something)
 message = new MyMessage();
else
 message = new MyOtherMessage();

hub.Publish(message)

The message will not be recognized for my subscriptions, because of the type 'IMessage'.
The only workarround i see, is to use reflection.
Is it possible to change this behaviour?

UnSubscribe method causes ArgumentNullException

Field _localSubscriptions is null, if Publish method is not called.
Try to Subscribe, then UnSunbscribe and bang! ArgumentNullException is here.
And it's [ThreadStatic], so on Stop event on windows service it also null.

Publish & Subscribe from different Project?

Can I use publish & subscribe from 2 projects?
I write MessageHub functions (have custom publish & subscribe function) to the library(dll) and import into PublishProject and SubscribeProject like this:
public async Task<Guid> SubscribeMsg(Func<object> MsgFunc)
public async Task<bool> PublishMsg(Func<Models.Message> MsgFunc)

In SubscribeProject, I call the SubscribeMsg function of dll and PublishProject calls the PublishMsg function.
SubscribeMsg does not receive msg from MessageHub. Plz tell me my example is right or wrong with your lib? And how can i interact Publish & Subscribe if It call from difference project.
Thanks.

Add an async publisher

We use this a lot and are very happy with it.
But there are an issue we encounter running publish from a GUI.

The publisher has no way to know many or how time consuming each action is. and sometimes this are blocking our main thread.

We have a suggestion to add a publishAsync. like the example below.
What do you think?

Code snippet *****

public async Task PublishAsync<T>(T message)
{
    var localSubscriptions = _subscriptions.GetTheLatestSubscriptions();
    var msgType = typeof(T);
#if NET_STANDARD
    var msgTypeInfo = msgType.GetTypeInfo();
#endif
     _globalHandler?.Invoke(msgType, message);

      // ReSharper disable once ForCanBeConvertedToForeach | Performance Critical
      await Task.Run(() =>
      {
           for (var idx = 0; idx < localSubscriptions.Count; idx++)
               {
                    var subscription = localSubscriptions[idx];
#if NET_STANDARD
                   if (!subscription.Type.GetTypeInfo().IsAssignableFrom(msgTypeInfo)) { continue; }
#else
                   if (!subscription.Type.IsAssignableFrom(msgType)) { continue; }
#endif
                   try
                   {
                        subscription.Handle(message);
                   }
                   catch (Exception e)
                   {
                       _globalErrorHandler?.Invoke(subscription.Token, e);
                   }
              }
          }).ConfigureAwait(false);
}    

Add async version

Thanks for the library. I use async a lot in my project, so it would be great to have async methods.

Subscriber is receiving 3 messages when publisher is only sending 1

What I'm doing is pretty basic, I have a singleton messagehub, subscriber and publisher. When the publisher publishes the message only one message is being published. For some reason however the subscriber is receiving 3 messages. I have confirmed that this is what is happening through debugging. Any ideas?

Sometimes Unsubscribe method hangs

Hi. Sometimes Unsubscribe method hangs, it looks like deadlock. It occures only on production system with high load, i can't reproduce it locally. I have a lot of internal classes that subscribe on start of windows service, and unsubscribe on stop. And on every service stopping random class hands on unsubscribe. My class looks like

    internal abstract class EasyMonitorService: IMonitorService
    {
        readonly protected Easy.MessageHub.MessageHub hub;
        readonly List<System.Guid> subscriptions;
        public bool IsStarted { get; private set; }
        public EasyMonitorService(Easy.MessageHub.MessageHub hub)
        {
            this.hub = hub;
            subscriptions = new List<Guid>(1); 
        }
        public void Start()
        {
            if (!IsStarted)
            {
                subscriptions.AddRange(OnStart());
                IsStarted = true;
            }
        }
        protected abstract IEnumerable<Guid> OnStart();
        public void Stop()
        {
            foreach (var subscribeGuid in subscriptions)
            {
                hub.Unsubscribe(subscribeGuid);
            }
            OnStop();
        }
        protected virtual void OnStop()
        {

        }
    }

InvalidCastExceptions

This is a great little library - thanks for sharing!

One issue I've run across is that PublishImpl calls Subscription.Handle for each subscriber of any message type, and relies on swallowing the InvalidCastException generated for subscribers of message types other than the one being published. With the debugger attached, this affects performance greatly. I'd suggest a cleaner way of filtering subscribers based on the message type. Thanks!

Registering IMessageHub with MessageHub

Hi,

Would it be possible to add a public constructor / non singleton implementation of MessageHub? The library seems great, but I would rather use this via the interface and not the static singleton instance.

Non-singleton instances

Would love the ability to create a non-singleton instance of MessageHub.

Use case: Blazor applications allow you to have 'scoped' dependencies which are scoped to individual users. For my application, user messages should not cross that scoped boundary. If we could just 'new up' an instance of Message Hub this scenario would be supported.

MessageHub is holding objects in Memory

The Subscriptions._localSubscriptions variable is populated during Publish, which creates a strong reference to handlers in that array. In the scenario where the thread is kept alive (eg, created on the UI thread), that collection is not updated until Publish is called again.

[ThreadStatic] private static Subscription[] _localSubscriptions;

In my code, that means MessageHub holds my object hierarchy in memory indefinitely, or until the next message is published. Is it possible to remove handlers from the _localSubscriptions during an UnRegister?

Make IMessageHub implement IDisposable

Currently MessageHub implements IDisposable this should be moved to the IMessageHub instead so that an explicit cast to IDisposable and check of the result is not required.

Publish and subscribe from different threads

Hi! I need to subscribe from the UI thread and update controls. Is there a way to "subscribe on current thread"? I know that I can use SynchronizationContext (I'm using WinForms) but that's mean to change a lot of code.

Thanks!

Available for dotnet core?

I'm currently implementing this pattern in one of my services and I was looking for a small library, that does all the hard work while keeping my application small and simple. I came across this project, but I wasn't able to install it via nuget. The error message said, that it is not available for DotNet Core. Is it possible to have this supported?

System.ObjectDisposedException: ThreadLocal object has been deleted.

Hi,

I'm maintaining legacy VB.NET project where I'm forced to close my application after some idle time when user is away from computer. In first form I initialize AutoCloseController which is

  • responsible for filtering messages
  • ticking every second to send progress information to main and all other forms. When idle time is too long, timer reaches maximum allowed time (let's say 120 seconds) and last message is sent with CurrentTime = 0 that triggers DisposeAllFormsExceptMe method.
private void StartAutoCloseService()
{
    _autoCloseToken = MessageHub.Subscribe<AutoCloseTimeElapsed>(e =>
    {
        if (IsClosing)
            return;

        if (e.CurrentTime > 0)
        {
            PbProgress.Maximum = e.MaximumTime;
            PbProgress.Value = e.CurrentTime;
        }
        else
        {
            My.Application.DisposeAllFormsExceptMe(this);
            Close();
        }
    });
    _autoCloseController = new AutoCloseController(this);
}

DisposeAllFormsExceptMe method closes all open forms in reverse order they were created.

public void DisposeAllFormsExceptMe(Form myForm)
{
    {
        var forms = My.Application.OpenForms;
        for (var i = forms.Count - 1; i >= 0; i -= 1)
        {
            if (forms.Item(i) != myForm)
            {
                forms.Item(i).Visible = true;
                forms.Item(i).Close();
            }
        }
    }
}

Probably this is a root cause of System.ObjectDisposedException: ThreadLocal object has been deleted..

In one of the grand, grand child form I subscribe to some another unrelated message type and some service publishes it. When service tries to send a message I receive System.ObjectDisposedException: ThreadLocal object has been deleted..

The stack trace:

   at System.Threading.ThreadLocal`1.GetValueSlow()
   at System.Threading.ThreadLocal`1.get_Value()
   at Easy.MessageHub.Subscriptions.GetTheLatestSubscriptions()
   at Easy.MessageHub.MessageHub.Publish[T](T message)

Veryfing MessageHub object I see AllSubscriptions list is empty.

MessageHub ObjectDisposedException

How do you propose to bypass the problem?

Get MessageHub to play nicely with Autofac in a web application

This lightweight implementation is exactly what I've been looking for for my ASP.NET MVC application. However - I have a hard time figuring out how to use it in a web application setup using AutoFac.

I can easily publish events to the hub - but my subscribers are never executed. I'm wondering if I'm trying to implement a utility that's not designed for web application use - so I thought I'd get your thoughts on this before proceeding :)

I have the following simple setup for my AutoFac container:

builder.RegisterInstance<IMessageHub>(new MessageHub());
builder.RegisterType(typeof(PublishStuff)).As<IPublishStuff>().InstancePerLifetimeScope();
builder.RegisterType(typeof(SubscribeToStuff)).As<ISubscribeToStuff>().InstancePerLifetimeScope();

And the following setup for publishing / subscribing:

public HomeController(IPublishStuff publishStuff)
{
     _publishStuff = publishStuff;
}

public void TestHub(string message)
{
    _publishStuff.PublishEvent(message);
}

And my PublishStuff / SubscribeToStuff:

public class PublishStuff : IPublishStuff
    {
        private readonly IMessageHub _hub;

        public PublishStuff(IMessageHub hub)
        {
            _hub = hub;
        }

        public void PublishEvent(string message)
        {
            _hub.Publish(new UserInviteCreatedEvent { Name = message });
        }
    }


public class SubscribeToStuff : ISubscribeToStuff
    {
        private readonly IMessageHub _hub;

        public SubscribeToStuff(IMessageHub hub)
        {
            _hub = hub;
            _hub.Subscribe<UserInviteCreatedEvent>(DoStuff);
        }

        public void DoStuff(UserInviteCreatedEvent notification)
        {
            var x = notification.Name;  // <----- THIS IS NEVER EXECUTED
            Debug.WriteLine("The name is " + x);
        }
    }

However my SubscribeToStuff remains untouched. The code is never executed.
AutoFac should be delivering the same instance of the hub every time - but since there's no reference to ISubscribeToStuff anywhere this seems to never be called.
Is there any trick to getting the hub to play nicely with AutoFac (or another IoC) in a web application setup where the functionality will be spread out across different assemblies etc.? (but initialized from the same web project).
I'm basically looking for the same functionality you'd get from Mediatr Notifications (but without the entire Mediatr setup).

Thanks a lot - I really enjoy the simplicity of the library you've created :)

NuGet package?

Can you publish it into NuGet? So that it will be easier to update in the future for the users

Cheers

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.