ASP.NET Core SignalR을 사용한 실시간 웹앱
이 항목에서는 두 가지 모두에 대한 응용 프로그램을 만드는 방법을 살펴봅니다 스트리밍 그리고 수신 데이터를 ASP.NET Core 신호R.
필요한 것:
- ASP.NET Core와 Angular에 대한 기본 지식 .
- .NET Core 3.1이 설치되어 있고 Visual Studio와 같은 IDE가 설치되어 있습니다.
이 글이 끝나면 알게 될 내용은 다음과 같습니다.
- SignalR을 추가하고 사용하는 방법.
- 클라이언트 연결을 열고 메소드 호출 개념을 사용하여 클라이언트별로 데이터를 스트리밍하는 방법.
- Observables를 사용하여 Angular 애플리케이션에서 SignalR 서비스를 사용하는 방법.
SignalR은 여러 전송을 활용하고 클라이언트와 서버의 기능(WebSocket, 서버 전송 이벤트 또는 Long-polling)에 따라 사용 가능한 최상의 전송을 자동으로 선택합니다.
클라이언트가 서버에 실시간으로 연결되어 있을 때 WebSocket (SSE 및 Long-polling 제외) 측면에서 이야기할 때, 어떤 일이 발생할 때마다 서버는 해당 WebSocket을 통해 클라이언트에 다시 메시지를 보내는 것을 알게 됩니다. 구식 클라이언트 및 서버에서는 Long-polling 전송이 사용됩니다.
이것이 SignalR이 최신 클라이언트와 서버를 처리하는 방법이며, 사용 가능한 경우 내부적으로 WebSocket을 사용하고 그렇지 않은 경우 다른 기술 및 기술로 우아하게 대체됩니다.

이는 악수와 같습니다. 클라이언트와 서버는 무엇을 사용할지에 동의하고 이를 사용합니다. 이를 프로세스 협상 이라고 합니다.

SignalR Example
이 데모의 목적은 ASP.NET Core SignalR을 사용하여 실시간 데이터 스트림이 있는 금융 스크린 보드를 선보이는 것입니다.
SignalR Server Configuration
Create ASP.NET Core App
ASP.NET Core SignalR 애플리케이션을 설정하는 방법을 살펴보겠습니다. Visual Studio의 파일 >> 새 프로젝트에서 웹 응용 프로그램을 선택하고 설정을 따릅니다 ASP.NET Core. 구성에 문제가 있는 경우 공식 Microsoft 설명서 자습서를 자유롭게 따르십시오.

SignalR Config Setup
Startup.cs 파일에 다음 코드를 추가합니다.
- Endpoint part of the
Configuremethod.
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapHub<StreamHub>("/streamHub");
});
- Add SignalR usage to the
ConfigureServicesmethod.
services.AddSignalR(options =>
{
options.EnableDetailedErrors = true;
});
위의 변경 내용은 ASP.NET Core 종속성 주입 및 라우팅 시스템에 SignalR을 추가하는 것입니다.
이제 추가적인 기본 구성을 설정해 보겠습니다. Properties/launchSettings.json 파일을 열고 그에 따라 수정합니다.
"profiles": {
"WebAPI": {
"commandName": "Project",
"launchBrowser": false,
"applicationUrl": "https://localhost:5001;http://localhost:5000",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
Our server-side project will run on localhost:5001 and the client side will run on localhost:4200, so in order to establish communication between those two, we need to enable CORS. Let’s open the Startup.cs class and modify it:
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy("CorsPolicy", builder => builder
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials()
.WithOrigins("http://localhost:4200"));
});
...
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
...
app.UseCors("CorsPolicy");
...
원본 간 리소스 공유를 활성화하는 데 특정 문제가 발생하는 경우 공식 Microsoft 항목을 확인하세요.
SignalR Hub Setup
SignalR 허브가 무엇인지부터 설명해 보겠습니다. SignalR Hub API를 사용하면 서버에서 연결된 클라이언트의 메서드를 호출할 수 있습니다. 서버 코드에서는 클라이언트가 호출하는 메서드를 정의합니다. SignalR에는 Invocation 이라는 개념이 있습니다. 실제로 특정 메서드를 사용하여 클라이언트에서 허브를 호출할 수 있습니다. 클라이언트 코드에서는 서버에서 호출되는 메서드를 정의합니다.
The actual hub lives on the server-side. Imagine you have Clients and the Hub is between all of them. You can say something to all the Clients with Clients.All.doWork() by invoking a method on the hub. This will goes to all connected clients. Also, you can communicate with only one client, which is the Caller, because he is the caller of that particular method.

연결, 그룹 및 메시징 관리를 담당하는 기본 Hub 클래스를 상속하는 StreamHub 클래스를 만들었습니다. Hub 클래스는 상태 비저장이며 특정 메서드를 새로 호출할 때마다 이 클래스의 새 인스턴스에 있다는 점을 명심하는 것이 좋습니다. 인스턴스 속성에 상태를 저장하는 것은 쓸모가 없습니다. 오히려 정적 속성을 사용하는 것이 좋습니다. 우리의 경우 정적 키-값 쌍 컬렉션을 사용하여 연결된 각 클라이언트에 대한 데이터를 저장합니다.
이 클래스의 다른 유용한 속성은 Clients, Context 및 Groups 입니다. 고유한 ConnectionID를 기반으로 특정 동작을 관리하는 데 도움이 될 수 있습니다. 또한 이 클래스는 다음과 같은 유용한 메서드를 제공합니다.
- OnConnectedAsync() - 허브와 새 연결이 설정되면 호출됩니다.
- OnDisconnectedAsync(Exception) - 허브와의 연결이 종료되면 호출됩니다.
이를 통해 연결이 설정되거나 닫힐 때 추가 논리를 수행할 수 있습니다. 우리 애플리케이션에는 컨텍스트 연결 ID를 가져오고 이를 사용하여 특정 간격으로 데이터를 다시 보내는 UpdateParameters 메서드도 추가했습니다. 보시다시피 우리는 다른 클라이언트의 스트리밍 개입을 방지하는 고유한 ConnectionID를 통해 통신합니다.
public async void UpdateParameters(int interval, int volume, bool live = false, bool updateAll = true)
{
...
var connection = Context.ConnectionId;
var clients = Clients;
...
if (!clientConnections.ContainsKey(connection))
{
clientConnections.Add(connection, new TimerManager(async() =>
{
...
await Send(newDataArray, client, connection);
}, interval));
} else
{
clientConnections[connection].Stop();
clientConnections[connection] = new TimerManager(async () =>
{
var client = clients.Client(connection);
..
await Send(newDataArray, client, connection);
}, interval);
}
...
}
When the data is ready we transfer it by emitting a transferdata event with the help of SendAsync Method.
public async Task Send(FinancialData[] array, IClientProxy client, string connection)
{
await client.SendAsync("transferdata", array);
}
...
// Called when a connection with the hub is terminated
public override Task OnDisconnectedAsync(Exception exception)
{
StopTimer();
clientConnections.Remove(Context.ConnectionId);
return base.OnDisconnectedAsync(exception);
}
클라이언트 애플리케이션은 등록된 이벤트를 수신합니다.
private registerSignalEvents() {
this.hubConnection.onclose(() => {
this.hasRemoteConnection = false;
});
this.hubConnection.on('transferdata', (data) => {
this.data.next(data);
})
}
ASP.NET Core 애플리케이션의 공용 GitHub 리포지토리는 여기에서 찾을 수 있습니다.
Create SignalR Client Library
We will create an Angular project in order to consume the SignalR service. The GitHub repository with the actual application can be found in the igniteui-angular-samples repository.
First, start by installing SignalR:
npm install @microsoft/signalr
HTTP 요청을 서버로 보낼 것이므로 HttpClientModule도 필요하다는 점을 명심하세요.
아래에서는 허브 연결 빌더를 처리하는 signal-r.service.ts 파일을 찾을 수 있습니다.
export class SignalRService implements OnDestroy {
public data: BehaviorSubject<any[]>;
public hasRemoteConnection: boolean;
private hubConnection: signalR.HubConnection;
...
constructor(private zone: NgZone, private http: HttpClient) {
this.data = new BehaviorSubject([]);
}
...
// Start Hub Connection and Register events
public startConnection = (interval = 500, volume = 1000, live = false, updateAll = true) => {
this.hubConnection = new signalR.HubConnectionBuilder()
.configureLogging(signalR.LogLevel.Trace)
.withUrl('https://ko.infragistics.com/angular-apis/webapi/streamHub')
.build();
this.hubConnection
.start()
.then(() => {
...
this.registerSignalEvents();
this.broadcastParams(interval, volume, live, updateAll);
})
.catch(() => { ... });
}
// Change the broadcast parameters like frequency and data volume
public broadcastParams = (frequency, volume, live, updateAll = true) => {
this.hubConnection.invoke('updateparameters', frequency, volume, live, updateAll)
.then(() => console.log('requestLiveData', volume))
.catch(err => {
console.error(err);
});
}
// Register events
private registerSignalEvents() {
this.hubConnection.onclose(() => {
this.hasRemoteConnection = false;
});
this.hubConnection.on('transferdata', (data) => {
this.data.next(data);
});
}
...
In your app.component add use the newly created startConnection method
constructor(public dataService: SignalRService) {}
public ngOnInit() {
this.dataService.startConnection(this.frequency, this.dataVolume, true, false);
}
...
Grid Data Binding
As we have seen so far in our client code we set up a listener for transferdata event, which receives as an argument the updated data array. To pass the newly received data to our grid we use an observable. To set that, we need to bind the grid's data source to the data observable like so:
<igx-grid [data]='data | async'> ... </igx-grid>
Every time when new data is received from the server to the client we call the next() method of the data observable.
this.hubConnection.on('transferdata', (data) => {
this.data.next(data);
})
Topic Takeaways
애플리케이션을 새로 고치지 않고 데이터가 업데이트되는 시기만 확인하려는 경우 SignalR ASP.NET Core 고려해야 합니다. 데이터가 크다고 생각하거나 끝없는 스피너를 표시하여 클라이언트를 차단하지 않고 원활한 사용자 경험을 원할 때 스트리밍 콘텐츠를 사용하는 것이 좋습니다.
SignalR Hub 통신은 쉽고 직관적이며 Angular Observables의 도움으로 WebSocket을 사용하여 데이터 스트리밍을 사용하는 강력한 애플리케이션을 만들 수 있습니다.