Use Hub methods from controller?

2020-02-09 07:02发布

问题:

I am using SignalR 2 and I can not figure out how I can use my Hub methods e.g from inside a controller action.

I know I can do the following:

var hub = GlobalHost.ConnectionManager.GetHubContext<T>();
hub.Clients.All.clientSideMethod(param);

But that executes the method directly on the client side.

What if I have business logic inside my server side ClientSideMethod(param) method I want to call from my controller the same way as when it is called from the client side?

At the moment I use public static void ClientSideMethod(param) inside my hub and in that method I use the IHubContext from the ConnectionManager.

Is there no better was of doing this?

The following is not working (anymore in SignalR 2?):

var hubManager = new DefaultHubManager(GlobalHost.DependencyResolver);
instance = hubManager.ResolveHub(typeof(T).Name) as T;
instance.ClientSideMethod(param);

There I get a "Hub not created via Hub pipeline not supported" exception, when accessing the Clients.

回答1:

It might work to create a "helper" class that implements your business rules and is called by both your Hub and your Controller:

public class MyHub : Hub
{
    public void DoSomething()
    {
        var helper = new HubHelper(this);
        helper.DoStuff("hub stuff");
    }
}

public class MyController : Controller
{
    public ActionResult Something()
    {
        var hub = GlobalHost.ConnectionManager.GetHubContext<MyHub>();
        var helper = new HubHelper(hub);
        helper.DoStuff("controller stuff");
    }
}

public class HubHelper
{
    private IHubConnectionContext hub;

    public HubHelper(IHubConnectionContext hub)
    {
        this.hub = hub;
    }

    public DoStuff(string param)
    {
        //business rules ...

        hub.Clients.All.clientSideMethod(param);
    }
}


回答2:

As I did not find a "good solution" I am using @michael.rp's solution with some improvements:

I did create the following base class:

public abstract class Hub<T> : Hub where T : Hub
{
    private static IHubContext hubContext;
    /// <summary>Gets the hub context.</summary>
    /// <value>The hub context.</value>
    public static IHubContext HubContext
    {
        get
        {
            if (hubContext == null)
                hubContext = GlobalHost.ConnectionManager.GetHubContext<T>();
            return hubContext;
        }
    }
}

And then in the actual Hub (e.g. public class AdminHub : Hub<AdminHub>) I have (static) methods like the following:

/// <summary>Tells the clients that some item has changed.</summary>
public async Task ItemHasChangedFromClient()
{
    await ItemHasChangedAsync().ConfigureAwait(false);
}
/// <summary>Tells the clients that some item has changed.</summary>
public static async Task ItemHasChangedAsync()
{
    // my custom logic
    await HubContext.Clients.All.itemHasChanged();
}