허브 외부에서 메시지 보내기

SignalR 허브는 SignalR 서버에 연결된 클라이언트에 메시지를 보내기 위한 핵심 추상화입니다. 또한 IHubContext 서비스를 사용하여 앱의 다른 위치에서 메시지를 보낼 수도 있습니다. 이 문서에서는 SignalRIHubContext에 액세스하여 허브 외부에서 클라이언트에 알림을 보내는 방법을 설명합니다.

참고 항목

IHubContext는 클라이언트에 알림을 보내기 위한 것이며 Hub에서 메서드를 호출하는 데 사용되지 않습니다.

샘플 코드 보기 및 다운로드(다운로드 방법)

IHubContext의 인스턴스 가져오기

ASP.NET Core SignalR에서 종속성 주입을 통해 IHubContext의 인스턴스에 액세스할 수 있습니다. IHubContext의 인스턴스를 컨트롤러, 미들웨어 또는 기타 DI 서비스에 삽입할 수 있습니다. 인스턴스를 사용하여 클라이언트에 메시지를 보냅니다.

IHubContext의 인스턴스를 컨트롤러에 삽입합니다.

IHubContext의 인스턴스를 생성자에 추가하여 컨트롤러에 삽입할 수 있습니다.

public class HomeController : Controller
{
    private readonly IHubContext<NotificationHub> _hubContext;

    public HomeController(IHubContext<NotificationHub> hubContext)
    {
        _hubContext = hubContext;
    }
}

IHubContext의 인스턴스에 대한 액세스 권한을 사용하여 허브 자체에 있는 것처럼 클라이언트 메서드를 호출합니다.

public async Task<IActionResult> Index()
{
    await _hubContext.Clients.All.SendAsync("Notify", $"Home page loaded at: {DateTime.Now}");
    return View();
}

미들웨어에서 IHubContext의 인스턴스 가져오기

다음과 같이 미들웨어 파이프라인 내에서 IHubContext에 액세스합니다.

app.Use(async (context, next) =>
{
    var hubContext = context.RequestServices
                            .GetRequiredService<IHubContext<ChatHub>>();
    //...
    
    if (next != null)
    {
        await next.Invoke();
    }
});

참고 항목

클라이언트 메서드가 Hub 클래스 외부에서 호출되면 호출과 연결된 호출자가 없습니다. 따라서 ConnectionId, CallerOthers 속성에 액세스할 수 없습니다.

사용자를 연결 ID에 매핑하고 매핑을 유지해야 하는 앱은 다음 중 하나를 수행할 수 있습니다.

  • 단일 또는 여러 연결의 매핑을 그룹으로 유지합니다. 자세한 내용은 그룹을 SignalR 참조하세요.
  • Singleton 서비스를 통해 연결 및 사용자 정보를 유지합니다. 자세한 내용은 허브에 서비스 삽입을 참조하세요. 싱글톤 서비스는 다음과 같은 모든 스토리지 메서드를 사용할 수 있습니다.
    • 사전의 메모리 내 스토리지입니다.
    • 영구 외부 스토리지. 예를 들어 Azure.Data.Tables NuGet 패키지를 사용하는 데이터베이스 또는 Azure Table Storage입니다.
  • 클라이언트 간에 연결 ID를 전달합니다.

IHost에서 IHubContext의 인스턴스 가져오기

웹 호스트에서 IHubContext에 액세스하는 것은 ASP.NET Core 외부 영역(예: 타사 종속성 주입 프레임워크 사용)과 통합하는 데 유용합니다.

    public class Program
    {
        public static void Main(string[] args)
        {
            var host = CreateHostBuilder(args).Build();
            var hubContext = host.Services.GetService(typeof(IHubContext<ChatHub>));
            host.Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder => {
                    webBuilder.UseStartup<Startup>();
                });
    }

강력한 형식의 HubContext 삽입

강력한 형식의 HubContext를 삽입하려면 허브가 Hub<T>에서 상속되는지 확인합니다. IHubContext<THub> 대신 IHubContext<THub, T> 인터페이스를 사용하여 삽입합니다.

public class ChatController : Controller
{
    public IHubContext<ChatHub, IChatClient> _strongChatHubContext { get; }

    public ChatController(IHubContext<ChatHub, IChatClient> chatHubContext)
    {
        _strongChatHubContext = chatHubContext;
    }

    public async Task SendMessage(string user, string message)
    {
        await _strongChatHubContext.Clients.All.ReceiveMessage(user, message);
    }
}

자세한 내용은 강력한 형식의 허브를 참조하세요.

제네릭 코드의 IHubContext 사용

삽입된 IHubContext<THub> 인스턴스는 제네릭 Hub 형식을 지정하지 않고 IHubContext로 캐스팅할 수 있습니다.

class MyHub : Hub
{ }

class MyOtherHub : Hub
{ }

app.Use(async (context, next) =>
{
    var myHubContext = context.RequestServices
                            .GetRequiredService<IHubContext<MyHub>>();
    var myOtherHubContext = context.RequestServices
                            .GetRequiredService<IHubContext<MyOtherHub>>();
    await CommonHubContextMethod((IHubContext)myHubContext);
    await CommonHubContextMethod((IHubContext)myOtherHubContext);

    await next.Invoke();
}

async Task CommonHubContextMethod(IHubContext context)
{
    await context.Clients.All.SendAsync("clientMethod", new Args());
}

이 방법은 다음과 같은 경우 유용합니다.

  • 앱에서 사용하는 특정 Hub 형식에 대한 참조가 없는 라이브러리를 작성하는 경우
  • 제네릭이며 여러 다른 Hub 구현에 적용할 수 있는 코드를 작성하는 경우

추가 리소스