ASPNET Core SignalR 을 이용한 Push Server 구현 - 1

2023. 6. 26. 00:00ASPNET/SignalR

반응형

signalR core  는 dotnet core 에서 실시간 통신을 위해 내놓은 비동기 양방향 통신 frameworks 이다.

aspnet core 위에서 돌아가는 형태 이다. 

 

https://yogingang.tistory.com/404

 

Rest API Template 만들기 - EP 01 (Create , Swagger, Logging)

Create visual studio 2022 를 실행하고 Create a new project 를 선택한다. asp.net core web api 선택 Project name 정하기 Additional Information 설정 Create 하면 Project 가 생성된다. F5 를 누르면 실행 된다. 위와 같이 swagger

yogingang.tistory.com

위 강좌를 보고 간단한 rest api 를 만들고 추가 할 수도 있다. 참고 바란다. 

 

어쨌든 rest api 또는 blazor, mvc 등을 이용하여 간단한 project 를 생성 했다고 가정 하자.

signalR core 는 dotnet core 에 포함되어 있으니 따로 설치를 할 필요는 없다. (aspnet core 7 기준)

 

이제 아주 간단한 Push server 를 구현해보자

createChannel 을 이용해 channel 을 생성하고

해당 channel 에 join 한 client 들에 message 를 전달할 것이다.

 

signalR 에서 method 를 구현 하려면 Hub 를 상속하여야 한다. 

ChannelHub.cs

public class ChannelHub : Hub
{
    private readonly ILogger<ChannelHub> _logger;

    public ChannelHub(ILogger<ChannelHub> logger)
    {
        _logger = logger;
    }

    [HubMethodName("sendMessage")]
    public async Task SendMessage(string channelId, string message)
    {
        _logger.LogInformation($"{Context.User}");

        await Clients.OthersInGroup(channelId).SendAsync("receiveMessage",message);
    }


    // 하나는 channel 을 관리하기 위한 group
    // 다른 하나는 client 를 관리하기 위한 group 
    [HubMethodName("create")]
    public async Task<Create.Response> CreateChannel()
    {
        var channelId = Guid.NewGuid().ToAlphaNumeric();
        var joinId = Guid.NewGuid().ToAlphaNumeric();
        await Groups.AddToGroupAsync(Context.ConnectionId, channelId);
        await Groups.AddToGroupAsync(Context.ConnectionId, joinId);
        return new Create.Response { ChannelId = channelId, JoinId = joinId };
    }


    // 하나는 channel 을 관리하기 위한 group
    // 다른 하나는 client 를 관리하기 위한 group 
    [HubMethodName("join")]
    public async Task<Join.Response> JoinChannel(string channelId)
    {
        var joinId = Guid.NewGuid().ToAlphaNumeric();
        await Groups.AddToGroupAsync(Context.ConnectionId, channelId);
        await Groups.AddToGroupAsync(Context.ConnectionId, joinId);
        return new Join.Response { JoinId =joinId };
    }

    [HubMethodName("left")]
    public async Task LeftChannel(string channelId, string joinId)
    {
        await Groups.RemoveFromGroupAsync(Context.ConnectionId, channelId);
        await Groups.RemoveFromGroupAsync(Context.ConnectionId, joinId);
    }
}

 

Groups.AddToGroupAsync 를 이용해 client 를 등록한다. 

위에서 두번 등록 하는 이유는 하나는 channel 을 통해 send한 caller 를 제외하고 모든 group member 들에게 message 를 전달하기 위한 것이고 다른 하나는 joinId 를 통해 직접 한 사람에게 message 를 전달하기 위해서 이다. 

 

Response class

public class Create
{
    public class Response
    {
        public string ChannelId { get; set; } = string.Empty;
        public string JoinId { get; set; } = string.Empty;
    }
}

public class Join
{
    public class Response
    {
        public string JoinId { get; set; } = string.Empty;
    }
}

Program.cs

 

 

...
app.MapHub<ChannelHub>("/channel", options=>
{
    options.Transports = Microsoft.AspNetCore.Http.Connections.HttpTransportType.WebSockets;
    
});
...

이렇게 하면 server 는 준비가 된 것이다.

 

 

이제 위에 접속하기 위해 console project 를 아무거나 하나 만들자

그리고 nuget 에서 다음 package 를 추가 하자

dotnet add package Microsoft.AspNetCore.SignalR.Client

 

Program.cs

// See https://aka.ms/new-console-template for more information
using Microsoft.AspNetCore.SignalR.Client;

Console.WriteLine("Hello, World!");

HubConnection InitSignalRClient()
{
	// signalR 접속 url
    var url = $"https://localhost:5004/channel";

    var connection = new HubConnectionBuilder()
        .WithUrl(url, options =>
        {
            options.SkipNegotiation = true;
            options.Transports = Microsoft.AspNetCore.Http.Connections.HttpTransportType.WebSockets;
        })
        .WithAutomaticReconnect()
        .Build();
    return connection;
}

// connection1 생성
var connection1 = InitSignalRClient();

// server 접속
await connection1.StartAsync();

// server 의 create method 를 이용해 channel create
// channelId 및 joinId 를 return 한다.
var createResponse =  await connection1.InvokeAsync<Create.Response>("create");
// receiveMessage 를 method 로 정의 하여 server 로 부터 message 를 전달 받을 수 있도록 대기 한다.
connection1.On<string>("receiveMessage", message => Console.WriteLine($"connection1 received : {message}"));

var connection2 = InitSignalRClient();
await connection2.StartAsync();
// connection2 는 channel 에 join 하고 joinId 를 reutrn 받는다.
var joinResponse = await connection2.InvokeAsync<Join.Response>("join", createResponse.ChannelId);
// receiveMessage 를 method 로 정의 하여 server 로 부터 message 를 전달 받을 수 있도록 대기 한다.
connection2.On<string>("receiveMessage", message => Console.WriteLine($"connection2 received : {message}"));

// connection 1 로 message 전달
await connection2.SendAsync("sendMessage", createResponse.ChannelId, "hello im connection2");
// connection 2 로 message 전달
await connection1.SendAsync("sendMessage", createResponse.ChannelId, "hello im connection1");




Console.ReadLine();

 

이제 server 를 실행하고 client 를 실행하면 connection1 과 connection2 가 data 를 주고 받는걸 확인 할 수 있을 것이다.

console 을 여러게 만들고 connection 을 하나씩만 유지 하여 test 해봐도 된다. 

 

 

관련영상

https://youtu.be/zxX7SSL62MY

 

 

반응형