dotnet / aspnetcore

ASP.NET Core is a cross-platform .NET framework for building modern cloud-based web applications on Windows, Mac, or Linux.
https://asp.net
MIT License
35.34k stars 9.98k forks source link

IHubClient : using [HubMethodName] #SignalR #Feature #8601

Closed lobster2012-user closed 5 years ago

lobster2012-user commented 5 years ago

Add using of [HubMethodName] for client proxy

//TypeClientBuilder
//  private static void BuildMethod(TypeBuilder type, MethodInfo interfaceMethodInfo, FieldInfo proxyField)
// The first argument to IClientProxy.SendCoreAsync is this method's name  
          generator.Emit(OpCodes.Ldstr, interfaceMethodInfo.Name);

Thank you.

BrennanConroy commented 5 years ago

I'm not sure why we would want to do this. The [HubMethodName] attribute is for the name of hub methods that the client invokes.

interfaceMethodInfo.Name is the name of methods you call on the client.

lobster2012-user commented 5 years ago

You can use the new attribute with a suitable name.

analogrelay commented 5 years ago

This isn't something we intend to do for 3.0.

slavanap commented 5 years ago

How to make SignalR ignore specific method in a Hub (not expose it to JS)? Is there any attribute supported for that purpose?

analogrelay commented 5 years ago

I don't believe there is an attribute for that at this point, you can use a private or internal method though, which won't be exposed. Is there a scenario you have in which you want to have a public Hub method that is not exposed to the client?

slavanap commented 5 years ago

Is there a scenario you have in which you want to have a public Hub method that is not exposed to the client?

@anurse It looks I'm not, but though my scenario is simple it involves clunky code. I want to broadcast the data on timely manner (every minute), but for clients who had subscribed for these broadcasts, I want to call their callback method the moment they subscribed with the cached data from previous broadcast. Here's the implementation

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.SignalR;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Threading.Tasks;

namespace CoreApp.Services.Hubs {

    // Methods to be called on a client from server side
    public interface IInfoHubClient {
        Task DataBroadcast(object data);
    }

    [Authorize]
    public class InfoHub : Hub<IInfoHubClient> {

        const string _DataGroupName = "Data";
        static readonly ConcurrentDictionary<string, bool> _DataSubscribers =
            new ConcurrentDictionary<string, bool>();

        static readonly object _defaultDataBroadcast = new { };
        static object _DataBroadcast = _defaultDataBroadcast;
        static public bool DataSubscribed { get {
                var empty = _DataSubscribers.IsEmpty;
                if (empty)
                    _DataBroadcast = _defaultDataBroadcast;
                return !empty;
            } }

        static public Task BroadcastData(
            object newBroadcast,
            IHubContext<InfoHub, IInfoHubClient> hub
        )
        {
            _DataBroadcast = newBroadcast ?? throw new NullReferenceException();
            return hub.Clients.Group(_DataGroupName).DataBroadcast(newBroadcast);
        }

        public override Task OnDisconnectedAsync(Exception exception) {
            _DataSubscribers.TryRemove(Context.ConnectionId, out bool temp);
            return base.OnDisconnectedAsync(exception);
        }

        public async Task DataSubscription(bool enable) {
            if (enable) {
                await Clients.Caller.DataBroadcast(_DataBroadcast);
                _DataSubscribers.TryAdd(Context.ConnectionId, true);
                await Groups.AddToGroupAsync(Context.ConnectionId, _DataGroupName);
            }
            else {
                await Groups.RemoveFromGroupAsync(Context.ConnectionId, _DataGroupName);
                _DataSubscribers.TryRemove(Context.ConnectionId, out bool temp);
            }
        }

    }

    /* in broadcaster function:
            readonly IHubContext<InfoHub, IInfoHubClient> _hub; // from dependency injection

            if (InfoHub.DataSubscribed) {
                object data = null;
                /* very heavy data computation */
                await InfoHub.BroadcastData(data, _hub);
            }
    */

}
lobster2012-user commented 5 years ago

@slavanap I will close this issue. As for your problem, it seems to me that it does not exist. In any case, you can open a new issue or describe it on stackoverflow.