-
Notifications
You must be signed in to change notification settings - Fork 48
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Discussion] Improve developer experience for strongly typed hub proxies #279
Comments
To try and explain the issue a little better. This would be the current implementation of a // Consumed client-side:
// var myHub = conn.GetProxy<IMyHub>();
// myHub.Broadcast("Hello World!");
public interface IMyHub
{
Task Broadcast(string message);
Task SendToGroup(string groupName, string message);
Task SendToUser(string userName, string message);
Task SendToConnection(string connectionId, string message);
Task JoinGroup(string connectionId, string groupId);
Task LeaveGroup(string connectionId, string groupId);
Task JoinUserToGroup(string userName, string groupId);
Task LeaveUserFromGroup(string userName, string groupId);
}
public class SimpleChat : ServerlessHub // Cannot simply extend IMyHub
{
[FunctionAuthorize]
[FunctionName(nameof(Broadcast))]
public async Task Broadcast([SignalRTrigger]InvocationContext invocationContext, string message, ILogger logger)
{
await Clients.All.SendAsync(NewMessageTarget, new NewMessage(invocationContext, message));
logger.LogInformation($"{invocationContext.ConnectionId} broadcast {message}");
}
[FunctionName(nameof(SendToGroup))]
public async Task SendToGroup([SignalRTrigger]InvocationContext invocationContext, string groupName, string message)
{
await Clients.Group(groupName).SendAsync(NewMessageTarget, new NewMessage(invocationContext, message));
}
[FunctionName(nameof(SendToUser))]
public async Task SendToUser([SignalRTrigger]InvocationContext invocationContext, string userName, string message)
{
await Clients.User(userName).SendAsync(NewMessageTarget, new NewMessage(invocationContext, message));
}
[FunctionName(nameof(SendToConnection))]
public async Task SendToConnection([SignalRTrigger]InvocationContext invocationContext, string connectionId, string message)
{
await Clients.Client(connectionId).SendAsync(NewMessageTarget, new NewMessage(invocationContext, message));
}
[FunctionName(nameof(JoinGroup))]
public async Task JoinGroup([SignalRTrigger]InvocationContext invocationContext, string connectionId, string groupName)
{
await Groups.AddToGroupAsync(connectionId, groupName);
}
[FunctionName(nameof(LeaveGroup))]
public async Task LeaveGroup([SignalRTrigger]InvocationContext invocationContext, string connectionId, string groupName)
{
await Groups.RemoveFromGroupAsync(connectionId, groupName);
}
[FunctionName(nameof(JoinUserToGroup))]
public async Task JoinUserToGroup([SignalRTrigger]InvocationContext invocationContext, string userName, string groupName)
{
await UserGroups.AddToGroupAsync(userName, groupName);
}
[FunctionName(nameof(LeaveUserFromGroup))]
public async Task LeaveUserFromGroup([SignalRTrigger]InvocationContext invocationContext, string userName, string groupName)
{
await UserGroups.RemoveFromGroupAsync(userName, groupName);
}
} |
Thank you @lfshr, now I understand your question better. |
@lfshr /// <summary>
/// This is a function scoped instance.
/// </summary>
public abstract class FunctionHub
{
/// <summary>
/// Gets the context of the function, such as logger.
/// </summary>
public FunctionContext FunctionContext { get; }
/// <summary>
/// Gets the client invocation context such as the connection id, user name,
/// </summary>
public InvocationContext InvocationContext { get; }
public virtual Task OnConnectedAsync()
{
return Task.CompletedTask;
}
public virtual Task OnDisconnectedAsync(Exception? exception)
{
return Task.CompletedTask;
}
}
public class MyHub : FunctionHub, IMyHub
{
/// <summary>
/// You could even get dependencies injected from the constructor.
/// </summary>
public MyHub()
{
}
public Task Broadcast(string message)
{
throw new NotImplementedException();
}
public Task SendToGroup(string groupName, string message)
{
throw new NotImplementedException();
}
public Task SendToUser(string userName, string message)
{
throw new NotImplementedException();
}
}
public class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
builder.Services.AddFunctionHub<MyHub>(); //register the hub
}
} Each client invocation comes, a The problem with this design is that it is not function-styled and cannot be used in other functions. |
SignalR strongly typed hub proxies are a work in progress right now. Not to be confused with strongly typed clients, a strongly typed hub proxy will allow clients to invoke server methods with the same level of inference as servers can currently invoke client methods.
I thought it would be an idea to discuss what could be done on the Azure Functions side in preparation for this feature becoming available. As it stands I don't believe this feature could be easily implemented as Function triggers are part of the method signatures.
Since the proxy is implemented on the client, there isn't any need to wait for the PR to be completed. The primary constraint is that serverless hubs must implement SignalR message handlers that satisfy the contract of the hub interface; which can be achieved today.
The text was updated successfully, but these errors were encountered: