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.19k stars 9.93k forks source link

Map hubs with attributes #48590

Open Kiryuumaru opened 1 year ago

Kiryuumaru commented 1 year ago

Is there an existing issue for this?

Is your feature request related to a problem? Please describe the problem.

I am trying to route hubs manually in programs,cs

Describe the solution you'd like

It would be great if hubs can be mapped with

[Hub]
[Route("/chathub")]
public class ChatHub : Hub

similar to controllers

[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase

instead of app.MapHub<ChatHub>("/chathub"); in programs.cs

Additional context

No response

davidfowl commented 1 year ago

We have no plans to add support for scanning for hubs via an attribute within an assembly. It should be possible to build something like this using reflection.

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SignalR;
using System.Reflection;

public static class MapAllHubsExtensions
{
    public static IEndpointConventionBuilder MapHubs(this IEndpointRouteBuilder routes)
    {
        var mapHub = typeof(HubEndpointRouteBuilderExtensions).GetMethod(nameof(HubEndpointRouteBuilderExtensions.MapHub), new[] { typeof(IEndpointRouteBuilder), typeof(string) })
            ?? throw new Exception("Could not find MapHub method");

        var group = routes.MapGroup("");

        foreach (var t in typeof(Program).Assembly.GetTypes())
        {
            if (typeof(Hub).IsAssignableFrom(t) && 
                t.IsPublic &&
                t.GetCustomAttribute<RouteAttribute>() is { } attribute)
            {
                mapHub.MakeGenericMethod(t).Invoke(null, new object[] { group, attribute.Template });
            }
        }

        return group;
    }
}

That would enable something like this:

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SignalR;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddSignalR();

var app = builder.Build();

app.MapHubs();

app.Run();

[Route("/chat")]
public class ChatHub : Hub
{

}

Assembly scanning at runtime by default will break future plans to do ahead of time compilation, we don't want this to be a part of any experience in ASP.NET Core outside of MVC (which has this unfortunate default behavior). We can revisit this once we are able to replace runtime discovery with compile time source generation.

Kiryuumaru commented 1 year ago

Oh, thankyou for this workaround