빠른 시작: C#을 통해 SignalR Service와 Azure Functions로 GitHub 별모양 개수를 표시하는 앱 만들기
이 문서에서는 SignalR Service 및 Azure Functions를 사용하여 C#으로 서버리스 애플리케이션을 빌드하여 클라이언트에 메시지를 브로드캐스트하는 방법을 알아봅니다.
참고 항목
이 문서에 언급된 코드는 GitHub에서 가져올 수 있습니다.
Important
원시 연결 문자열 데모용으로만 이 문서에 표시됩니다.
연결 문자열에는 애플리케이션이 Azure Web PubSub 서비스에 액세스하는 데 필요한 권한 부여 정보가 포함됩니다. 연결 문자열 내의 액세스 키는 서비스의 루트 암호와 비슷합니다. 프로덕션 환경에서는 항상 액세스 키를 보호합니다. Azure Key Vault를 사용하여 키를 안전하게 관리 및 회전하고 Microsoft Entra ID를 사용하여 연결 문자열 보호합니다.
액세스 키를 다른 사용자에게 배포하거나 하드 코딩하거나 다른 사용자가 액세스할 수 있는 일반 텍스트로 저장하지 않도록 합니다. 키가 손상되었다고 생각되면 키를 교체하세요.
필수 조건
이 빠른 시작에는 다음 필수 구성 요소가 필요합니다.
- Visual Studio Code 또는 기타 코드 편집기. 아직 Visual Studio Code를 설치하지 않은 경우 여기에서 Visual Studio Code를 다운로드합니다.
- Azure 구독 Azure 구독이 아직 없는 경우 시작하기 전에 무료 구독을 만듭니다.
- Azure Functions Core Tools
- .NET Core SDK
Azure SignalR Service 인스턴스 만들기
이 섹션에서는 앱에 사용할 기본 Azure SignalR 인스턴스를 만듭니다. 다음 단계에서는 Azure Portal을 사용하여 새 인스턴스를 만들지만 Azure CLI를 사용할 수도 있습니다. 자세한 내용은 Azure SignalR Service CLI 참조에서 az signalr create 명령을 참조하세요.
- Azure Portal에 로그인합니다.
- 페이지의 왼쪽 상단에서 + 리소스 만들기를 선택합니다.
- 리소스 만들기 페이지의 검색 서비스 및 마켓플레이스 텍스트 상자에 signalr을 입력한 다음, 목록에서 SignalR Service를 선택합니다.
- SignalR Service 페이지에서 만들기를 선택합니다.
- 기본 사항 탭에서 새 SignalR Service 인스턴스에 대한 필수 정보를 입력합니다. 다음 값을 입력합니다.
필드 | 제안 값 | 설명 |
---|---|---|
구독 | 구독 선택 | 새 SignalR Service 인스턴스를 만드는 데 사용할 구독을 선택합니다. |
리소스 그룹 | SignalRTestResources라는 리소스 그룹 만들기 | SignalR 리소스에 대한 리소스 그룹을 선택하거나 만듭니다. 기존 리소스 그룹을 사용하는 대신 이 자습서에 대한 새 리소스 그룹을 만드는 것이 유용합니다. 자습서를 완료한 후 리소스를 확보하려면 리소스 그룹을 삭제합니다. 리소스 그룹을 삭제하면 해당 그룹에 속한 리소스도 모두 삭제됩니다. 이 작업은 취소할 수 없습니다. 리소스 그룹을 삭제하기 전에 유지하려는 리소스가 포함되어 있지 않은지 확인합니다. 자세한 내용은 리소스 그룹을 사용하여 Azure 리소스 관리를 참조하세요. |
리소스 이름 | testsignalr | SignalR 리소스에 사용할 고유한 리소스 이름을 입력합니다. 해당 지역에서 이미 testsignalr을 사용하고 있는 경우 이름이 고유해질 때까지 숫자나 문자를 추가합니다. 이름은 1~63자의 문자열로, 숫자, 영문자 및 하이픈( - ) 문자만 포함할 수 있습니다. 이름은 하이픈 문자로 시작하거나 끝날 수 없고 연속되는 하이픈 문자는 유효하지 않습니다. |
지역 | 지역 선택 | 새 SignalR Service 인스턴스에 적합한 지역을 선택합니다. Azure SignalR Service는 현재 일부 지역에서 사용할 수 없습니다. 자세한 내용은 Azure SignalR Service 지역 가용성을 참조하세요. |
가격 책정 계층 | 변경을 선택한 다음, 무료(개발/테스트 전용)를 선택합니다. 선택을 선택하여 선택한 가격 책정 계층을 확인합니다. | Azure SignalR Service에는 무료, 표준 및 프리미엄의 세 가지 가격 책정 계층이 있습니다. 자습서는 필수 구성 요소에 달리 명시되지 않는 한 무료 계층을 사용합니다. 계층과 가격 책정 간의 기능 차이에 대한 자세한 내용은 Azure SignalR Service 가격 책정을 참조하세요. |
서비스 모드 | 적절한 서비스 모드를 선택합니다. | 웹앱에서 SignalR 허브 논리를 호스팅하고 SignalR 서비스를 프록시로 사용하는 경우 기본값을 사용합니다. Azure Functions와 같은 서버리스 기술을 사용하여 SignalR 허브 논리를 호스팅하는 경우 서버리스를 사용합니다. 클래식 모드는 이전 버전과의 호환성만을 위한 것이므로 사용하지 않는 것이 좋습니다. 자세한 내용은 Azure SignalR Service의 서비스 모드를 참조하세요. |
SignalR 자습서의 네트워킹 및 태그 탭에서 설정을 변경할 필요가 없습니다.
- 기본 탭의 아래쪽에서 검토 + 만들기 단추를 선택합니다.
- 검토 + 만들기 탭에서 해당 값을 검토한 다음, 만들기를 선택합니다. 배포가 완료되는 데 몇 분 정도 걸립니다.
- 배포가 완료되면 리소스로 이동 단추를 선택합니다.
- SignalR 리소스 페이지의 Settings 아래 왼쪽 메뉴에서 Keys를 선택합니다.
- 기본 키의 연결 문자열을 복사합니다. 이 자습서의 뒷부분에서 앱을 구성하려면 이 연결 문자열이 필요합니다.
Azure Function을 로컬로 설정 및 실행
이 단계에는 Azure Functions Core Tools가 필요합니다.
빈 디렉터리를 만들고 명령줄을 사용하여 디렉터리로 변경합니다.
새 프로젝트를 초기화합니다.
# Initialize a function project func init --worker-runtime dotnet # Add SignalR Service package reference to the project dotnet add package Microsoft.Azure.WebJobs.Extensions.SignalRService
코드 편집기를 사용하여 이름이 Function.cs인 새 파일을 만듭니다. Function.cs에 다음 코드를 추가합니다.
using System; using System.IO; using System.Linq; using System.Net.Http; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.Azure.WebJobs; using Microsoft.Azure.WebJobs.Extensions.Http; using Microsoft.Azure.WebJobs.Extensions.SignalRService; using Newtonsoft.Json; namespace CSharp { public static class Function { private static HttpClient httpClient = new HttpClient(); private static string Etag = string.Empty; private static string StarCount = "0"; [FunctionName("index")] public static IActionResult GetHomePage([HttpTrigger(AuthorizationLevel.Anonymous)]HttpRequest req, ExecutionContext context) { var path = Path.Combine(context.FunctionAppDirectory, "content", "index.html"); return new ContentResult { Content = File.ReadAllText(path), ContentType = "text/html", }; } [FunctionName("negotiate")] public static SignalRConnectionInfo Negotiate( [HttpTrigger(AuthorizationLevel.Anonymous)] HttpRequest req, [SignalRConnectionInfo(HubName = "serverless")] SignalRConnectionInfo connectionInfo) { return connectionInfo; } [FunctionName("broadcast")] public static async Task Broadcast([TimerTrigger("*/5 * * * * *")] TimerInfo myTimer, [SignalR(HubName = "serverless")] IAsyncCollector<SignalRMessage> signalRMessages) { var request = new HttpRequestMessage(HttpMethod.Get, "https://api.github.com/repos/azure/azure-signalr"); request.Headers.UserAgent.ParseAdd("Serverless"); request.Headers.Add("If-None-Match", Etag); var response = await httpClient.SendAsync(request); if (response.Headers.Contains("Etag")) { Etag = response.Headers.GetValues("Etag").First(); } if (response.StatusCode == System.Net.HttpStatusCode.OK) { var result = JsonConvert.DeserializeObject<GitResult>(await response.Content.ReadAsStringAsync()); StarCount = result.StarCount; } await signalRMessages.AddAsync( new SignalRMessage { Target = "newMessage", Arguments = new[] { $"Current star count of https://github.com/Azure/azure-signalr is: {StarCount}" } }); } private class GitResult { [JsonRequired] [JsonProperty("stargazers_count")] public string StarCount { get; set; } } } }
Function.cs의 코드에는 세 가지 함수가 있습니다.
GetHomePage
는 웹 사이트를 클라이언트로 가져오는 데 사용됩니다.Negotiate
는 클라이언트가 액세스 토큰을 가져오기 위해 사용합니다.Broadcast
는 주기적으로 호출되어 GitHub에서 별 개수를 가져온 다음 메시지를 모든 클라이언트에 브로드캐스트합니다.
이 샘플의 클라이언트 인터페이스는 웹 페이지입니다. content/index.html 파일에서 HTML 콘텐츠를 읽어
GetHomePage
함수를 사용하여 웹 페이지를 렌더링합니다. 이제 다음 콘텐츠를 사용하여content
하위 디렉터리 아래에 이 index.html을 만들어 보겠습니다.<html> <body> <h1>Azure SignalR Serverless Sample</h1> <div id="messages"></div> <script src="https://cdnjs.cloudflare.com/ajax/libs/microsoft-signalr/3.1.7/signalr.min.js"></script> <script> let messages = document.querySelector('#messages'); const apiBaseUrl = window.location.origin; const connection = new signalR.HubConnectionBuilder() .withUrl(apiBaseUrl + '/api') .configureLogging(signalR.LogLevel.Information) .build(); connection.on('newMessage', (message) => { document.getElementById("messages").innerHTML = message; }); connection.start() .catch(console.error); </script> </body> </html>
*.csproj
를 업데이트하여 빌드 출력 폴더에 콘텐츠 페이지를 만듭니다.<ItemGroup> <None Update="content/index.html"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </None> </ItemGroup>
Azure Functions가 작동하려면 스토리지 계정이 필요합니다. Azure Storage Emulator를 설치하고 실행할 수 있습니다. 또는 다음 명령으로 실제 스토리지 계정을 사용하는 설정을 업데이트할 수 있습니다.
func settings add AzureWebJobsStorage "<storage-connection-string>"
이제 거의 완료되었습니다. 마지막 단계는 Azure Function 설정에 SignalR Service의 연결 문자열을 설정하는 것입니다.
포털 위쪽의 검색 상자에서 해당 이름을 검색하여 SignalR Service 인스턴스가 성공적으로 만들어졌는지 확인합니다. 인스턴스를 선택하여 엽니다.
SignalR Service 인스턴스의 연결 문자열을 보려면 키를 선택합니다.
기본 연결 문자열 복사한 다음, 다음 명령을 실행합니다.
원시 연결 문자열 데모용으로만 이 문서에 표시됩니다. 프로덕션 환경에서는 항상 액세스 키를 보호합니다. Azure Key Vault를 사용하여 키를 안전하게 관리 및 회전하고 Microsoft Entra ID를 사용하여 연결 문자열 보호합니다.
func settings add AzureSignalRConnectionString "<signalr-connection-string>"
로컬에서 Azure Function 실행:
func start
Azure 함수가 로컬에서 실행된 후
http://localhost:7071/api/index
를 열면 현재 별 개수를 볼 수 있습니다. GitHub에서 별 표시 또는 별 표시 해제를 수행하면 몇 초마다 별 개수가 새로 고쳐집니다.
리소스 정리
이 앱을 계속 사용하지 않으려면 다음 단계에 따라 이 빠른 시작에서 만든 리소스를 모두 삭제하세요. 요금은 발생되지 않습니다.
Azure Portal에서 맨 왼쪽에 있는 리소스 그룹을 선택한 다음, 만든 리소스 그룹을 선택합니다. 또는 검색 상자를 사용하여 이름으로 리소스 그룹을 찾을 수 있습니다.
열린 창에서 리소스 그룹을 선택한 다음, 리소스 그룹 삭제를 클릭합니다.
새 창에서 삭제할 리소스 그룹의 이름을 입력한 다음, 삭제를 클릭합니다.
문제가 있나요? 문제 해결 가이드를 사용해 보거나 알려주세요.
다음 단계
이 빠른 시작에서는 로컬로 실시간 서버리스 애플리케이션을 빌드하고 실행했습니다. 다음으로 Azure SignalR Service를 사용하여 클라이언트와 Azure Functions 간의 양방향 통신에 대해 자세히 알아봅니다.