성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] 제가 큰 실수를 했군요. ^^; Delegate를 통한 Bein...
[정성태] Working with Rust Libraries from C#...
[정성태] Detecting blocking calls using asyn...
[정성태] 아쉽게도, 커뮤니티는 아니고 개인 블로그입니다. ^^
[정성태] 질문이 잘 이해가 안 됩니다. 우선, 해당 소스코드에서 ILis...
[양승조
] var대신 dinamic으로 선언해서 해결은 했습니다. 맞는 해...
[양승조
] 또 막혔습니다. ㅠㅠ var list = props[i].Ge...
[양승조
] 아. 감사합니다. 어제는 안됐던것 같은데....정신을 차려야겠네...
[정성태] "props[i].GetValue(props[i])" 코드에서 ...
[정성태] 저렇게 조각 코드 말고, 실제로 재현이 되는 예제 프로젝트를 압...
글쓰기
제목
이름
암호
전자우편
HTML
홈페이지
유형
제니퍼 .NET
닷넷
COM 개체 관련
스크립트
VC++
VS.NET IDE
Windows
Team Foundation Server
디버깅 기술
오류 유형
개발 환경 구성
웹
기타
Linux
Java
DDK
Math
Phone
Graphics
사물인터넷
부모글 보이기/감추기
내용
<div style='display: inline'> <h1 style='font-family: Malgun Gothic, Consolas; font-size: 20pt; color: #006699; text-align: center; font-weight: bold'>C# - ASP.NET Core SignalR로 구현하는 채팅 서비스 예제</h1> <p> <a target='tab' href='https://learn.microsoft.com/ko-kr/aspnet/signalr/'>SignalR</a>은 WebSocket을 근간으로 하는 기술입니다. 추상화를 잘해 둔 탓에 그 사용법이 매우 쉬운 데요, 아래의 동영상과 공식 문서에,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 6 분산형 실시간 메시징 서비스 개발하기 with 강창훈 ; <a target='tab' href='https://www.youtube.com/watch?v=ETQHZFGOGhw'>https://www.youtube.com/watch?v=ETQHZFGOGhw</a> Tutorial: Get started with ASP.NET Core SignalR ; <a target='tab' href='https://learn.microsoft.com/en-us/aspnet/core/tutorials/signalr'>https://learn.microsoft.com/en-us/aspnet/core/tutorials/signalr</a> </pre> <br /> 채팅 서비스를 하는 예제 코드를 아주 상세하게 설명하고 있습니다. 저도 실습하면서 그대로 한번 정리해 보겠습니다.<br /> <br /> 우선 서버 측부터 구현을 할 텐데요, 이를 위해 "ASP.NET Coer Web App (Razor Pages)" 프로젝트를 만들고, SignalR Hub를 지원하기 위해 Program.cs의 WebApplication Build 과정에 다음의 코드를 추가합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > namespace WebApplication1; public class Program { public static void Main(string[] args) { var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddRazorPages(); <span style='color: blue; font-weight: bold'>builder.Services.AddSignalR();</span> var app = builder.Build(); // Configure the HTTP request pipeline. if (!app.Environment.IsDevelopment()) { app.UseExceptionHandler("/Error"); } app.UseStaticFiles(); app.UseRouting(); app.UseAuthorization(); app.MapRazorPages(); <span style='color: blue; font-weight: bold'>app.MapHub<ChatHub>("/chatHub");</span> app.Run(); } } </pre> <br /> 이렇게 SignalR Hub 지원을 추가했으면 실질적인 채팅 서비스를 담당하는 클래스를 구동할 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > using Microsoft.AspNetCore.SignalR; namespace WebApplication1; <span style='color: blue; font-weight: bold'>public class ChatHub : Hub { public async Task SendAllMessage(string user, string message) { await Clients.All.SendAsync("SendAllMessage", user, message); } public async Task JoinGroup(string group, string user) { await Groups.AddToGroupAsync(Context.ConnectionId, group); await Clients.Caller.SendAsync("JoinGroup", $"{group}에 접속"); await Clients.OthersInGroup(group).SendAsync("JoinGroup", $"{user} has joined the group {group}."); } public async Task GroupSendMessage(string group, string user, string message) { await Clients.Group(group).SendAsync("GroupSendMessage", user, message); } } </span> </pre> <br /> 서버는 이게 끝입니다. 이후 클라이언트는 어떤 언어로 만들더라도 SignalR Hub 서비스를 사용할 수 있습니다.<br /> <br /> <hr style='width: 50%' /><br /> <br /> 그래도 ^^ 테스트는 해야죠. 여기서는 간단하게 ASP.NET Core 웹 앱의 razor 페이지에 JavaScript 클라이언트를 추가해 보겠습니다.<br /> <br /> 이를 위해, SignalR용 자바스크립트 패키지 참조를 추가하는데요, <a target='tab' href='https://learn.microsoft.com/en-us/aspnet/core/tutorials/signalr'>솔루션 탐색기에서 프로젝트 노드를 우클릭 "Add" / "Client-Side Library" 메뉴를 선택</a> 후 다음과 같이 "@microsoft/signalr@latest"을 추가합니다.<br /> <br /> <img alt='websocket_signalr_1.png' src='/SysWebRes/bbs/websocket_signalr_1.png' /><br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Provider: unpkg Library: @microsoft/signalr@latest Choose specific fiels: - signalr.js - signalr.min.js Target Location: wwwroot/lib/microsoft/signalr/ </pre> <br /> 그다음 index.cshtml에 이렇게 스크립트 및 HTML을 작성합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > @page @model IndexModel @{ ViewData["Title"] = "Home page"; string userId = DateTime.Now.GetHashCode().ToString()[1..4]; } <div class="text-center"> <h1 class="display-4">Welcome</h1> <p>Learn about <a href="https://learn.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p> <div class="container"> <div class="row">&nbsp;</div> <div class="row"> <div class="col-2"> User</div> <div class="col-4"><input type="text" id="txtInput" value="user_@userId" /></div> </div> <div class="row"> <div class="col-2">Message</div> <div class="col-4"><input type="text" id="txtMessage" /></div> </div> <div class="row">&nbsp;</div> <div class="row"> <div class="col-6"> <input type="button" id="btnSend" value="Send Message" /> </div> </div> </div> <div class="row"> <div class="col-12"> <hr /> </div> </div> <div class="row"> <div class="col-6"> <ul id="lstMessage" /> </div> </div> </div> <script src="~/lib/microsoft/signalr/dist/browser/signalr.js"></script> <script> <span style='color: blue; font-weight: bold'>var connection = new signalR.HubConnectionBuilder().withUrl("/chatHub").build();</span> const groupId = "Group1"; document.getElementById("btnSend").disabled = true; <span style='color: blue; font-weight: bold'>connection.on("SendAllMessage", function (user, message) { var li = document.createElement("li"); li.textContent = `[All] ${user} says ${message}`; document.getElementById("lstMessage").appendChild(li); }); connection.on("JoinGroup", function (message) { var li = document.createElement("li"); li.textContent = message; document.getElementById("lstMessage").appendChild(li); }); connection.on("GroupSendMessage", function (user, message) { var li = document.createElement("li"); li.textContent = `[${groupId}] ${user} says ${message}`; document.getElementById("lstMessage").appendChild(li); }); connection.start().then(function () { document.getElementById("btnSend").disabled = false; var user = document.getElementById("txtInput").value; connection.invoke("JoinGroup", groupId, user).catch(function (err) { return console.error(err.toString()); }); }).catch(function (err) { return console.error(err.toString()); });</span> document.getElementById("btnSend").addEventListener("click", function (event) { var user = document.getElementById("txtInput").value; var message = document.getElementById("txtMessage").value; <span style='color: blue; font-weight: bold'>connection.invoke("SendAllMessage", user, message).catch(function (err) { return console.error(err.toString()); });</span> event.preventDefault(); }); </script> </pre> <br /> 이제 브라우저를 2개 실행시키고 저 페이지를 방문하면, 서로 채팅이 되는 것을 확인할 수 있습니다. 여기서 키가 되는 것은 connection.on의 첫 번째 인자에 메시지를 식별할 ID에 해당하는 문자열을 SignalR 서버 측의 Hub 클래스에서 정의한 메서드 이름과 같게 주면 된다는 점입니다. 별거 없이 꽤나 간단한 코드라서 더 설명할 것이 없군요. ^^<br /> <br /> <hr style='width: 50%' /><br /> <br /> 너무 간단해서 이대로 끝내기가 아쉬우니, 살펴보는 김에 닷넷 클라이언트도 구현해 볼까요? 전체적인 구현은 JavaScript와 별반 다르지 않기 때문에 보시면 그냥 알 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > using Microsoft.AspNetCore.SignalR.Client; namespace WebSocketClient; internal class Program { // Install-Package Microsoft.AspNetCore.SignalR.Clientd static async Task Main(string[] args) { string userId = "testusr"; string groupId = "Group1"; <span style='color: blue; font-weight: bold'>HubConnection connection = new HubConnectionBuilder() .WithUrl("http://localhost:5179/chatHub") .Build(); connection.On("SendAllMessage", (string user, string message) =&gt; { Console.WriteLine($"[All] {user} says {message}"); }); connection.On("JoinGroup", (string message) =&gt; { Console.WriteLine(message); }); connection.On("GroupSendMessage", (string user, string message) =&gt; { Console.WriteLine($"[{groupId}] {user} says {message}"); });</span> Console.WriteLine("Press any key to connect web socket server..."); Console.ReadLine(); <span style='color: blue; font-weight: bold'>await connection.StartAsync(); await connection.InvokeAsync("JoinGroup", groupId, userId); await connection.InvokeAsync("SendAllMessage", userId, "Hello, All!"); await connection.InvokeAsync("GroupSendMessage", groupId, userId, "Hello, Group!");</span> Console.WriteLine("Press any key to exit..."); Console.ReadLine(); <span style='color: blue; font-weight: bold'>await connection.StopAsync();</span> } } </pre> <br /> SignalR 클라이언트에 대한 마이크로소프트의 공식 지원은 위에서처럼 JavaScript, 닷넷과 함께 Java도 포함하고 있습니다. 또한, 당연히 기술 자체가 오프소스라서,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > SignalR/SignalR ; <a target='tab' href='https://github.com/SignalR/SignalR'>https://github.com/SignalR/SignalR</a> </pre> <br /> 다른 언어로도 포팅이 가능합니다. 가령 파이썬에서도 <a target='tab' href='https://pypi.org/project/signalr-client/'>signalr-client 패키지</a>를 이용해 작성할 수 있습니다.<br /> <br /> (<a target='tab' href='https://www.sysnet.pe.kr/bbs/DownloadAttachment.aspx?fid=2127&boardid=331301885'>첨부 파일은 이 글의 예제 코드를 포함</a>합니다.)<br /> </p><br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
1324
(왼쪽의 숫자를 입력해야 합니다.)