Skip to content

HubFilter should act the same way as an API middleware  #46095

@sebastienlabine

Description

@sebastienlabine

I have an IUserResolver service and an IUserAccessor service inside my API.

When using normal API request, I have a middleware that has the job of resolving the current user and setting it in the IUserAccessor service. This middleware works well and is scoped for the current request.

However, when trying the same thing with IHubFilter, I get very different results. Here's my filter.

    public class UserResolverFilter : IHubFilter
    {
        private IUserResolverService _userResolverService;
        private IUserAccessorService _userAccessorService;
        private readonly ILogger<UserResolverFilter> _logger;
        public UserResolverFilter(IUserResolverService userResolverService, IUserAccessorService userAccessorService, ILogger<UserResolverFilter> logger)
        {
            _userResolverService = userResolverService;
            _userAccessorService = userAccessorService;
            _logger = logger;

        }

        public async ValueTask<object> InvokeMethodAsync(
            HubInvocationContext invocationContext,
            Func<HubInvocationContext, ValueTask<object>> next
            )
        {

            return await next(invocationContext);
        }

        public async Task OnConnectedAsync(HubLifetimeContext context, Func<HubLifetimeContext, Task> next)
        {
            var accessToken = await _userResolverService.ResolveAccessTokenAsync();
            var user = await _userResolverService.ResolveAsync();
            _userAccessorService.AccessToken = accessToken;
            _userAccessorService.User = user;
            if (user == null)
            {
                _logger.LogDebug($"Unauthenticated user with connectionId {context.Context.ConnectionId} connected");
            }
            else
            {
                _logger.LogDebug($"Authenticated User {_userAccessorService.User.UserName} with connectionId {context.Context.ConnectionId} connected");
            }
            await next(context);
        }

        public async Task OnDisconnectedAsync(
            HubLifetimeContext context, Exception exception, Func<HubLifetimeContext, Exception, Task> next)
        {

            if (_userAccessorService.User == null)
            {
                _logger.LogDebug($"Unauthenticated user with connectionId {context.Context.ConnectionId} disconnected");
            }
            else
            {
                _logger.LogDebug($"Authenticated User {_userAccessorService.User.UserName} with connectionId {context.Context.ConnectionId} disconnected");
            }
            await next(context, exception);
        }

And my hub

   public class SessionHub : Hub<ISessionHub>
    {
        private readonly ISessionService _sessionService;

        public classSessionHub (
            ISessionService sessionService
            )
        {
            _sessionService= sessionService;

        }


        public override async Task OnConnectedAsync()
        {
            await base.OnConnectedAsync();
            await _sessionService.CreateAsync(Context.ConnectionId);
        }

        public override async Task OnDisconnectedAsync(Exception exception)
        {
            await _sessionService.DeleteAsync(Context.ConnectionId);
            await base.OnDisconnectedAsync(exception);
        }

Now my ISessionService calls injects my IUserAccessor service and when is constructed, assings the user to a public variable. The problem is that when the constructor is called, the filter has not been executed yet, which is really different of the middleware logic, making assigning null to my user variable.

Is there a way to unify this behaviour so that we can have the same exact "middleware" DI logic for hub filters^

Metadata

Metadata

Assignees

No one assigned

    Labels

    api-suggestionEarly API idea and discussion, it is NOT ready for implementationarea-signalrIncludes: SignalR clients and servers

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions