ASP.NET Core를 위한 SignalR에서 MessagePack 허브 프로토콜 사용

이 문서에서는 독자가 ASP.NET Core SignalR 시작에서 다룬 항목에 대해 잘 알고 있다고 가정합니다.

MessagePack이란?

MessagePack이란 빠르고 압축된 이진 직렬화 형식입니다. JSON보다 작은 메시지를 만들기 때문에 성능 및 대역폭이 중요한 경우에 유용합니다. 바이트가 MessagePack 파서를 통해 전달되지 않는 한, 네트워크 추적 및 로그를 볼 때 이진 메시지를 읽을 수 없습니다. SignalR에서는 MessagePack 형식을 기본적으로 지원하며 클라이언트 및 서버에서 사용할 수 있는 API를 제공합니다.

서버에서 MessagePack 구성

서버에서 MessagePack 허브 프로토콜을 사용하도록 설정하려면 앱에 Microsoft.AspNetCore.SignalR.Protocols.MessagePack 패키지를 설치합니다. Startup.ConfigureServices 메서드에서 서버에 대한 MessagePack 지원을 사용하도록 AddSignalR 호출에 AddMessagePackProtocol을 추가합니다.

services.AddSignalR()
    .AddMessagePackProtocol();

참고 항목

JSON이 기본적으로 사용하도록 설정됩니다. MessagePack을 추가하면 JSON 및 MessagePack 클라이언트를 모두 지원할 수 있습니다.

MessagePack에서 데이터의 형식을 지정하는 방법을 사용자 지정하려면 AddMessagePackProtocol에서 옵션을 구성하는 대리자를 사용합니다. 이 대리자에서 SerializerOptions 속성은 MessagePack 직렬화 옵션을 구성하는 데 사용됩니다. 해결 프로그램의 작동 방식에 대한 자세한 내용은 MessagePack-CSharp에서 MessagePack 라이브러리를 참조하세요. 직렬화할 개체에 특성을 사용하여 해당 특성을 처리하는 방법을 정의할 수 있습니다.

services.AddSignalR()
    .AddMessagePackProtocol(options =>
    {
        options.SerializerOptions = MessagePackSerializerOptions.Standard
            .WithResolver(new CustomResolver())
            .WithSecurity(MessagePackSecurity.UntrustedData);
    });

Warning

CVE-2020-5234를 검토하고 권장되는 패치를 적용하는 것이 좋습니다. 예를 들어 SerializerOptions를 바꿀 때 .WithSecurity(MessagePackSecurity.UntrustedData)를 호출합니다.

클라이언트에서 MessagePack 구성

참고 항목

JSON은 지원되는 클라이언트에 대해 기본적으로 사용하도록 설정됩니다. 클라이언트는 단일 프로토콜만 지원할 수 있습니다. MessagePack 지원 추가는 이전에 구성된 모든 프로토콜을 대체합니다.

.NET 클라이언트

.NET 클라이언트에서 MessagePack을 사용하도록 설정하려면 Microsoft.AspNetCore.SignalR.Protocols.MessagePack 패키지를 설치하고 HubConnectionBuilder에서 AddMessagePackProtocol을 호출합니다.

using Microsoft.AspNetCore.SignalR.Client;
using Microsoft.Extensions.DependencyInjection;

var hubConnection = new HubConnectionBuilder()
                        .WithUrl("/chathub")
                        .AddMessagePackProtocol()
                        .Build();

참고 항목

AddMessagePackProtocol 호출은 서버와 마찬가지로 옵션을 구성하기 위한 대리자를 사용합니다.

JavaScript 클라이언트

JavaScript 클라이언트에 대한 MessagePack 지원은 @microsoft/signalr-protocol-msgpack npm 패키지에서 제공됩니다. 명령 셸에서 다음 명령을 실행하여 패키지를 설치합니다.

npm install @microsoft/signalr-protocol-msgpack

npm 패키지를 설치한 후 JavaScript 모듈 로더를 통해 직접 모듈을 사용하거나 다음 파일을 참조하여 브라우저로 가져올 수 있습니다.

node_modules\@microsoft\signalr-protocol-msgpack\dist\browser\signalr-protocol-msgpack.js

다음 필수 javaScript 파일은 아래에 표시된 순서대로 참조해야 합니다.

<script src="~/lib/signalr/signalr.js"></script>
<script src="~/lib/signalr/signalr-protocol-msgpack.js"></script>

HubConnectionBuilder.withHubProtocol(new signalR.protocols.msgpack.MessagePackHubProtocol())을 추가하면 서버에 연결할 때 MessagePack 프로토콜을 사용하도록 클라이언트가 구성됩니다.

const connection = new signalR.HubConnectionBuilder()
    .withUrl("/chathub")
    .withHubProtocol(new signalR.protocols.msgpack.MessagePackHubProtocol())
    .build();

이번에는 JavaScript 클라이언트에 MessagePack 프로토콜에 대한 구성 옵션이 없습니다.

Java 클라이언트

Java에서 MessagePack을 사용하도록 설정하려면 com.microsoft.signalr.messagepack 패키지를 설치합니다. Gradle을 사용하는 경우 build.gradle 파일의 dependencies 섹션에 다음 줄을 추가합니다.

implementation 'com.microsoft.signalr.messagepack:signalr-messagepack:5.0.0'

Maven을 사용하는 경우 파일 요소 내에 <dependencies> 다음 줄을 추가합니다 pom.xml .

<dependency>
    <groupId>com.microsoft.signalr.messagepack</groupId>
    <artifactId>signalr</artifactId>
    <version>5.0.0</version>
</dependency>

HubConnectionBuilder에서 withHubProtocol(new MessagePackHubProtocol())을 호출합니다.

HubConnection messagePackConnection = HubConnectionBuilder.create("YOUR HUB URL HERE")
    .withHubProtocol(new MessagePackHubProtocol())
    .build();

MessagePack 고려 사항

MessagePack 허브 프로토콜을 사용할 때 알아야 할 몇 가지 문제가 있습니다.

MessagePack은 대/소문자를 구분합니다.

MessagePack 프로토콜은 대/소문자를 구분합니다. 예를 들어 다음 C# 클래스를 고려하세요.

public class ChatMessage
{
    public string Sender { get; }
    public string Message { get; }
}

JavaScript 클라이언트에서 전송하는 경우 대/소문자 구분이 C# 클래스와 정확하게 일치해야 하므로 PascalCased 속성 이름을 사용해야 합니다. 예시:

connection.invoke("SomeMethod", { Sender: "Sally", Message: "Hello!" });

camelCased 이름 사용은 C# 클래스에 올바르게 바인딩되지 않습니다. Key 특성을 사용하여 MessagePack 속성에 다른 이름을 지정하면 이 문제를 해결할 수 있습니다. 자세한 내용은 MessagePack-CSharp 설명서를 참조하세요.

직렬화/역직렬화할 때에는 DateTime.Kind가 유지되지 않습니다.

MessagePack 프로토콜은 DateTimeKind 값을 인코딩하는 방법을 제공하지 않습니다. 결과적으로, 날짜를 역직렬화할 때 DateTime.KindDateTimeKind.Local인 경우 MessagePack 허브 프로토콜은 UTC 형식으로 변환됩니다. 그렇지 않으면 시간을 건드리지 않고 그대로 전달됩니다. DateTime 값을 사용하여 작업하는 경우에는 값을 보내기 전에 UTC로 변환하는 것이 좋습니다. 값을 받으면 UTC에서 현지 시간으로 변환합니다.

“사전” 컴파일 환경에서 MessagePack 지원

.NET 클라이언트 및 서버에서 사용하는 MessagePack-CSharp 라이브러리는 코드 생성을 사용하여 직렬화를 최적화합니다. 따라서 “사전” 컴파일(예: Xamarin iOS 또는 Unity)을 사용하는 환경에서는 기본적으로 지원되지 않습니다. 직렬 변환기/역직렬 변환기 코드를 “미리 생성”하여 이러한 환경에서 MessagePack을 사용할 수 있습니다. 자세한 내용은 MessagePack-CSharp 설명서를 참조하세요. 직렬 변환기를 미리 생성한 후에는 AddMessagePackProtocol에 전달된 구성 대리자를 사용하여 해당 등록할 수 있습니다.

services.AddSignalR()
    .AddMessagePackProtocol(options =>
    {
        StaticCompositeResolver.Instance.Register(
            MessagePack.Resolvers.GeneratedResolver.Instance,
            MessagePack.Resolvers.StandardResolver.Instance
        );
        options.SerializerOptions = MessagePackSerializerOptions.Standard
            .WithResolver(StaticCompositeResolver.Instance)
            .WithSecurity(MessagePackSecurity.UntrustedData);
    });

MessagePack에서 형식 검사는 더 엄격합니다.

JSON 허브 프로토콜은 역직렬화 중에 형식 변환을 수행합니다. 예를 들어 들어오는 개체의 속성 값이 숫자({ foo: 42 })이지만 .NET 클래스의 속성이 string 형식인 경우 값이 변환됩니다. 그러나 MessagePack은 이 변환을 수행하지 않으며 서버 쪽 로그(및 콘솔)에서 볼 수 있는 예외를 throw합니다.

InvalidDataException: Error binding arguments. Make sure that the types of the provided values match the types of the hub method being invoked.

이 제한에 대한 자세한 내용은 GitHub 문제 aspnet/SignalR#2937을 참조하세요.

Java의 문자 및 문자열

Java 클라이언트에서 char 개체는 한 문자 String 개체로 직렬화됩니다. 이는 C# 및 JavaScript 클라이언트와 달리 short 개체로 직렬화합니다. MessagePack 사양 자체는 char 개체에 대한 동작을 정의하지 않으므로 라이브러리 작성자가 이를 직렬화하는 방법을 결정하는 것이 좋습니다. 클라이언트 간의 동작 차이는 구현에 사용한 라이브러리의 결과입니다.

추가 리소스

이 문서에서는 독자가 ASP.NET Core SignalR 시작에서 다룬 항목에 대해 잘 알고 있다고 가정합니다.

MessagePack이란?

MessagePack이란 빠르고 압축된 이진 직렬화 형식입니다. JSON보다 작은 메시지를 만들기 때문에 성능 및 대역폭이 중요한 경우에 유용합니다. 바이트가 MessagePack 파서를 통해 전달되지 않는 한, 네트워크 추적 및 로그를 볼 때 이진 메시지를 읽을 수 없습니다. SignalR에서는 MessagePack 형식을 기본적으로 지원하며 클라이언트 및 서버에서 사용할 수 있는 API를 제공합니다.

서버에서 MessagePack 구성

서버에서 MessagePack 허브 프로토콜을 사용하도록 설정하려면 앱에 Microsoft.AspNetCore.SignalR.Protocols.MessagePack 패키지를 설치합니다. Startup.ConfigureServices 메서드에서 서버에 대한 MessagePack 지원을 사용하도록 AddSignalR 호출에 AddMessagePackProtocol을 추가합니다.

참고 항목

JSON이 기본적으로 사용하도록 설정됩니다. MessagePack을 추가하면 JSON 및 MessagePack 클라이언트를 모두 지원할 수 있습니다.

services.AddSignalR()
    .AddMessagePackProtocol();

MessagePack에서 데이터의 형식을 지정하는 방법을 사용자 지정하기 위해 AddMessagePackProtocol에서는 옵션을 구성하는 대리자를 사용합니다. 이 대리자에서 SerializerOptions 속성은 MessagePack 직렬화 옵션을 구성하는 데 사용됩니다. 해결 프로그램의 작동 방식에 대한 자세한 내용은 MessagePack-CSharp에서 MessagePack 라이브러리를 참조하세요. 직렬화할 개체에 특성을 사용하여 해당 특성을 처리하는 방법을 정의할 수 있습니다.

services.AddSignalR()
    .AddMessagePackProtocol(options =>
    {
        options.SerializerOptions = MessagePackSerializerOptions.Standard
            .WithResolver(new CustomResolver())
            .WithSecurity(MessagePackSecurity.UntrustedData);
    });

Warning

CVE-2020-5234를 검토하고 권장되는 패치를 적용하는 것이 좋습니다. 예를 들어 SerializerOptions를 바꿀 때 .WithSecurity(MessagePackSecurity.UntrustedData)를 호출합니다.

클라이언트에서 MessagePack 구성

참고 항목

JSON은 지원되는 클라이언트에 대해 기본적으로 사용하도록 설정됩니다. 클라이언트는 단일 프로토콜만 지원할 수 있습니다. MessagePack 지원 추가는 이전에 구성된 모든 프로토콜을 대체합니다.

.NET 클라이언트

.NET 클라이언트에서 MessagePack을 사용하도록 설정하려면 Microsoft.AspNetCore.SignalR.Protocols.MessagePack 패키지를 설치하고 HubConnectionBuilder에서 AddMessagePackProtocol을 호출합니다.

using Microsoft.AspNetCore.SignalR.Client;
using Microsoft.Extensions.DependencyInjection;

var hubConnection = new HubConnectionBuilder()
                        .WithUrl("/chathub")
                        .AddMessagePackProtocol()
                        .Build();

참고 항목

AddMessagePackProtocol 호출은 서버와 마찬가지로 옵션을 구성하기 위한 대리자를 사용합니다.

JavaScript 클라이언트

JavaScript 클라이언트에 대한 MessagePack 지원은 @microsoft/signalr-protocol-msgpack npm 패키지에서 제공됩니다. 명령 셸에서 다음 명령을 실행하여 패키지를 설치합니다.

npm install @microsoft/signalr-protocol-msgpack

npm 패키지를 설치한 후 JavaScript 모듈 로더를 통해 직접 모듈을 사용하거나 다음 파일을 참조하여 브라우저로 가져올 수 있습니다.

node_modules\@microsoft\signalr-protocol-msgpack\dist\browser\signalr-protocol-msgpack.js

브라우저에서 msgpack5 라이브러리도 참조해야 합니다. <script> 태그를 사용하여 참조를 만듭니다. 라이브러리는 node_modules\msgpack5\dist\msgpack5.js에서 찾을 수 있습니다.

참고 항목

<script> 요소를 사용하는 경우 순서가 중요합니다. 이전에 msgpack5.js참조된 경우 signalr-protocol-msgpack.js MessagePack에 연결하려고 할 때 오류가 발생합니다. signalr.js 은 앞에도 필요합니다 signalr-protocol-msgpack.js.

<script src="~/lib/signalr/signalr.js"></script>
<script src="~/lib/msgpack5/msgpack5.js"></script>
<script src="~/lib/signalr/signalr-protocol-msgpack.js"></script>

HubConnectionBuilder.withHubProtocol(new signalR.protocols.msgpack.MessagePackHubProtocol())을 추가하면 서버에 연결할 때 MessagePack 프로토콜을 사용하도록 클라이언트가 구성됩니다.

const connection = new signalR.HubConnectionBuilder()
    .withUrl("/chathub")
    .withHubProtocol(new signalR.protocols.msgpack.MessagePackHubProtocol())
    .build();

참고 항목

이번에는 JavaScript 클라이언트에 MessagePack 프로토콜에 대한 구성 옵션이 없습니다.

Java 클라이언트

Java에서 MessagePack을 사용하도록 설정하려면 com.microsoft.signalr.messagepack 패키지를 설치합니다. Gradle을 사용하는 경우 build.gradle 파일의 dependencies 섹션에 다음 줄을 추가합니다.

implementation 'com.microsoft.signalr.messagepack:signalr-messagepack:5.0.0'

Maven을 사용하는 경우 파일 요소 내에 <dependencies> 다음 줄을 추가합니다 pom.xml .

<dependency>
    <groupId>com.microsoft.signalr.messagepack</groupId>
    <artifactId>signalr</artifactId>
    <version>5.0.0</version>
</dependency>

HubConnectionBuilder에서 withHubProtocol(new MessagePackHubProtocol())을 호출합니다.

HubConnection messagePackConnection = HubConnectionBuilder.create("YOUR HUB URL HERE")
    .withHubProtocol(new MessagePackHubProtocol())
    .build();

MessagePack 고려 사항

MessagePack 허브 프로토콜을 사용할 때 알아야 할 몇 가지 문제가 있습니다.

MessagePack은 대/소문자를 구분합니다.

MessagePack 프로토콜은 대/소문자를 구분합니다. 예를 들어 다음 C# 클래스를 고려하세요.

public class ChatMessage
{
    public string Sender { get; }
    public string Message { get; }
}

JavaScript 클라이언트에서 전송하는 경우 대/소문자 구분이 C# 클래스와 정확하게 일치해야 하므로 PascalCased 속성 이름을 사용해야 합니다. 예시:

connection.invoke("SomeMethod", { Sender: "Sally", Message: "Hello!" });

camelCased 이름 사용은 C# 클래스에 올바르게 바인딩되지 않습니다. Key 특성을 사용하여 MessagePack 속성에 다른 이름을 지정하면 이 문제를 해결할 수 있습니다. 자세한 내용은 MessagePack-CSharp 설명서를 참조하세요.

직렬화/역직렬화할 때에는 DateTime.Kind가 유지되지 않습니다.

MessagePack 프로토콜은 DateTimeKind 값을 인코딩하는 방법을 제공하지 않습니다. 결과적으로, 날짜를 역직렬화할 때 DateTime.KindDateTimeKind.Local인 경우 MessagePack 허브 프로토콜은 UTC 형식으로 변환됩니다. 그렇지 않으면 시간을 건드리지 않고 그대로 전달됩니다. DateTime 값을 사용하여 작업하는 경우에는 값을 보내기 전에 UTC로 변환하는 것이 좋습니다. 값을 받으면 UTC에서 현지 시간으로 변환합니다.

DateTime.MinValue는 JavaScript의 MessagePack에서 지원되지 않습니다.

SignalR JavaScript 클라이언트에서 사용하는 msgpack5 라이브러리는 MessagePack의 timestamp96 형식을 지원하지 않습니다. 이 형식은 매우 큰 날짜 값(매우 먼 과거 또는 매우 먼 미래)을 인코딩하는 데 사용됩니다. DateTime.MinValue의 값은 January 1, 0001이며 timestamp96 값으로 인코딩해야 합니다. 따라서 JavaScript 클라이언트로 DateTime.MinValue를 보내는 것은 지원되지 않습니다. DateTime.MinValue가 JavaScript 클라이언트에서 수신되면 다음 오류가 throw됩니다.

Uncaught Error: unable to find ext type 255 at decoder.js:427

일반적으로 DateTime.MinValue는 “missing” 또는 null 값을 인코딩하는 데 사용됩니다. MessagePack에서 해당 값을 인코딩해야 하는 경우 null을 허용하는 DateTime 값(DateTime?)을 사용하거나 날짜가 있는지를 나타내는 별도의 bool 값을 인코딩합니다.

이 제한에 대한 자세한 내용은 GitHub 문제 aspnet/SignalR#2228을 참조하세요.

“사전” 컴파일 환경에서 MessagePack 지원

.NET 클라이언트 및 서버에서 사용하는 MessagePack-CSharp 라이브러리는 코드 생성을 사용하여 직렬화를 최적화합니다. 따라서 “사전” 컴파일(예: Xamarin iOS 또는 Unity)을 사용하는 환경에서는 기본적으로 지원되지 않습니다. 직렬 변환기/역직렬 변환기 코드를 “미리 생성”하여 이러한 환경에서 MessagePack을 사용할 수 있습니다. 자세한 내용은 MessagePack-CSharp 설명서를 참조하세요. 직렬 변환기를 미리 생성한 후에는 AddMessagePackProtocol에 전달된 구성 대리자를 사용하여 해당 등록할 수 있습니다.

services.AddSignalR()
    .AddMessagePackProtocol(options =>
    {
        StaticCompositeResolver.Instance.Register(
            MessagePack.Resolvers.GeneratedResolver.Instance,
            MessagePack.Resolvers.StandardResolver.Instance
        );
        options.SerializerOptions = MessagePackSerializerOptions.Standard
            .WithResolver(StaticCompositeResolver.Instance)
            .WithSecurity(MessagePackSecurity.UntrustedData);
    });

MessagePack에서 형식 검사는 더 엄격합니다.

JSON 허브 프로토콜은 역직렬화 중에 형식 변환을 수행합니다. 예를 들어 들어오는 개체의 속성 값이 숫자({ foo: 42 })이지만 .NET 클래스의 속성이 string 형식인 경우 값이 변환됩니다. 그러나 MessagePack은 이 변환을 수행하지 않으며 서버 쪽 로그(및 콘솔)에서 볼 수 있는 예외를 throw합니다.

InvalidDataException: Error binding arguments. Make sure that the types of the provided values match the types of the hub method being invoked.

이 제한에 대한 자세한 내용은 GitHub 문제 aspnet/SignalR#2937을 참조하세요.

Java의 문자 및 문자열

Java 클라이언트에서 char 개체는 한 문자 String 개체로 직렬화됩니다. 이는 C# 및 JavaScript 클라이언트와 달리 short 개체로 직렬화합니다. MessagePack 사양 자체는 char 개체에 대한 동작을 정의하지 않으므로 라이브러리 작성자가 이를 직렬화하는 방법을 결정하는 것이 좋습니다. 클라이언트 간의 동작 차이는 구현에 사용한 라이브러리의 결과입니다.

추가 리소스

이 문서에서는 독자가 ASP.NET Core SignalR 시작에서 다룬 항목에 대해 잘 알고 있다고 가정합니다.

MessagePack이란?

MessagePack이란 빠르고 압축된 이진 직렬화 형식입니다. JSON보다 작은 메시지를 만들기 때문에 성능 및 대역폭이 중요한 경우에 유용합니다. 바이트가 MessagePack 파서를 통해 전달되지 않는 한, 네트워크 추적 및 로그를 볼 때 이진 메시지를 읽을 수 없습니다. SignalR에서는 MessagePack 형식을 기본적으로 지원하며 클라이언트 및 서버에서 사용할 수 있는 API를 제공합니다.

서버에서 MessagePack 구성

서버에서 MessagePack 허브 프로토콜을 사용하도록 설정하려면 앱에 Microsoft.AspNetCore.SignalR.Protocols.MessagePack 패키지를 설치합니다. Startup.ConfigureServices 메서드에서 서버에 대한 MessagePack 지원을 사용하도록 AddSignalR 호출에 AddMessagePackProtocol을 추가합니다.

참고 항목

JSON이 기본적으로 사용하도록 설정됩니다. MessagePack을 추가하면 JSON 및 MessagePack 클라이언트를 모두 지원할 수 있습니다.

services.AddSignalR()
    .AddMessagePackProtocol();

MessagePack에서 데이터의 형식을 지정하는 방법을 사용자 지정하기 위해 AddMessagePackProtocol에서는 옵션을 구성하는 대리자를 사용합니다. 이 대리자에서 FormatterResolvers 속성은 MessagePack 직렬화 옵션을 구성하는 데 사용됩니다. 해결 프로그램의 작동 방식에 대한 자세한 내용은 MessagePack-CSharp에서 MessagePack 라이브러리를 참조하세요. 직렬화할 개체에 특성을 사용하여 해당 특성을 처리하는 방법을 정의할 수 있습니다.

services.AddSignalR()
    .AddMessagePackProtocol(options =>
    {
        options.FormatterResolvers = new List<MessagePack.IFormatterResolver>()
        {
            MessagePack.Resolvers.StandardResolver.Instance
        };
    });

Warning

CVE-2020-5234를 검토하고 권장되는 패치를 적용하는 것이 좋습니다. 예를 들어 MessagePackSecurity.Active 정적 속성을 MessagePackSecurity.UntrustedData로 설정합니다. MessagePackSecurity.Active를 설정하려면 1.9.x 버전의 MessagePack을 수동으로 설치해야 합니다. MessagePack 1.9. x를 설치하면 SignalR에서 사용하는 버전이 업그레이드됩니다. MessagePack 버전 2.x는 주요 변경 내용을 도입했으며 SignalR 버전 3.1 및 이전 버전과 호환되지 않습니다. MessagePackSecurity.ActiveMessagePackSecurity.UntrustedData로 설정되지 않은 경우 악의적인 클라이언트로 인해 서비스 거부가 발생할 수 있습니다. 다음 코드와 같이 Program.MainMessagePackSecurity.Active를 설정합니다.

using MessagePack;

public static void Main(string[] args)
{
  MessagePackSecurity.Active = MessagePackSecurity.UntrustedData;

  CreateHostBuilder(args).Build().Run();
}

클라이언트에서 MessagePack 구성

참고 항목

JSON은 지원되는 클라이언트에 대해 기본적으로 사용하도록 설정됩니다. 클라이언트는 단일 프로토콜만 지원할 수 있습니다. MessagePack 지원 추가는 이전에 구성된 모든 프로토콜을 대체합니다.

.NET 클라이언트

.NET 클라이언트에서 MessagePack을 사용하도록 설정하려면 Microsoft.AspNetCore.SignalR.Protocols.MessagePack 패키지를 설치하고 HubConnectionBuilder에서 AddMessagePackProtocol을 호출합니다.

using Microsoft.AspNetCore.SignalR.Client;
using Microsoft.Extensions.DependencyInjection;

var hubConnection = new HubConnectionBuilder()
                        .WithUrl("/chathub")
                        .AddMessagePackProtocol()
                        .Build();

참고 항목

AddMessagePackProtocol 호출은 서버와 마찬가지로 옵션을 구성하기 위한 대리자를 사용합니다.

JavaScript 클라이언트

JavaScript 클라이언트에 대한 MessagePack 지원은 @microsoft/signalr-protocol-msgpack npm 패키지에서 제공됩니다. 명령 셸에서 다음 명령을 실행하여 패키지를 설치합니다.

npm install @microsoft/signalr-protocol-msgpack

npm 패키지를 설치한 후 JavaScript 모듈 로더를 통해 직접 모듈을 사용하거나 다음 파일을 참조하여 브라우저로 가져올 수 있습니다.

node_modules\@microsoft\signalr-protocol-msgpack\dist\browser\signalr-protocol-msgpack.js

브라우저에서 msgpack5 라이브러리도 참조해야 합니다. <script> 태그를 사용하여 참조를 만듭니다. 라이브러리는 node_modules\msgpack5\dist\msgpack5.js에서 찾을 수 있습니다.

참고 항목

<script> 요소를 사용하는 경우 순서가 중요합니다. 이전에 msgpack5.js참조된 경우 signalr-protocol-msgpack.js MessagePack에 연결하려고 할 때 오류가 발생합니다. signalr.js 은 앞에도 필요합니다 signalr-protocol-msgpack.js.

<script src="~/lib/signalr/signalr.js"></script>
<script src="~/lib/msgpack5/msgpack5.js"></script>
<script src="~/lib/signalr/signalr-protocol-msgpack.js"></script>

HubConnectionBuilder.withHubProtocol(new signalR.protocols.msgpack.MessagePackHubProtocol())을 추가하면 서버에 연결할 때 MessagePack 프로토콜을 사용하도록 클라이언트가 구성됩니다.

const connection = new signalR.HubConnectionBuilder()
    .withUrl("/chathub")
    .withHubProtocol(new signalR.protocols.msgpack.MessagePackHubProtocol())
    .build();

참고 항목

이번에는 JavaScript 클라이언트에 MessagePack 프로토콜에 대한 구성 옵션이 없습니다.

MessagePack 고려 사항

MessagePack 허브 프로토콜을 사용할 때 알아야 할 몇 가지 문제가 있습니다.

MessagePack은 대/소문자를 구분합니다.

MessagePack 프로토콜은 대/소문자를 구분합니다. 예를 들어 다음 C# 클래스를 고려하세요.

public class ChatMessage
{
    public string Sender { get; }
    public string Message { get; }
}

JavaScript 클라이언트에서 전송하는 경우 대/소문자 구분이 C# 클래스와 정확하게 일치해야 하므로 PascalCased 속성 이름을 사용해야 합니다. 예시:

connection.invoke("SomeMethod", { Sender: "Sally", Message: "Hello!" });

camelCased 이름 사용은 C# 클래스에 올바르게 바인딩되지 않습니다. Key 특성을 사용하여 MessagePack 속성에 다른 이름을 지정하면 이 문제를 해결할 수 있습니다. 자세한 내용은 MessagePack-CSharp 설명서를 참조하세요.

직렬화/역직렬화할 때에는 DateTime.Kind가 유지되지 않습니다.

MessagePack 프로토콜은 DateTimeKind 값을 인코딩하는 방법을 제공하지 않습니다. 결과적으로, 날짜를 역직렬화할 때 MessagePack 허브 프로토콜은 들어오는 날짜가 UTC 형식인 것으로 가정합니다. 현지 시간인 DateTime 값을 사용하여 작업하는 경우에는 값을 보내기 전에 UTC로 변환하는 것이 좋습니다. 값을 받으면 UTC에서 현지 시간으로 변환합니다.

이 제한에 대한 자세한 내용은 GitHub 문제 aspnet/SignalR#2632를 참조하세요.

DateTime.MinValue는 JavaScript의 MessagePack에서 지원되지 않습니다.

SignalR JavaScript 클라이언트에서 사용하는 msgpack5 라이브러리는 MessagePack의 timestamp96 형식을 지원하지 않습니다. 이 형식은 매우 큰 날짜 값(매우 먼 과거 또는 매우 먼 미래)을 인코딩하는 데 사용됩니다. DateTime.MinValue의 값은 January 1, 0001이며 timestamp96 값으로 인코딩해야 합니다. 따라서 JavaScript 클라이언트로 DateTime.MinValue를 보내는 것은 지원되지 않습니다. DateTime.MinValue가 JavaScript 클라이언트에서 수신되면 다음 오류가 throw됩니다.

Uncaught Error: unable to find ext type 255 at decoder.js:427

일반적으로 DateTime.MinValue는 “missing” 또는 null 값을 인코딩하는 데 사용됩니다. MessagePack에서 해당 값을 인코딩해야 하는 경우 null을 허용하는 DateTime 값(DateTime?)을 사용하거나 날짜가 있는지를 나타내는 별도의 bool 값을 인코딩합니다.

이 제한에 대한 자세한 내용은 GitHub 문제 aspnet/SignalR#2228을 참조하세요.

“사전” 컴파일 환경에서 MessagePack 지원

.NET 클라이언트 및 서버에서 사용하는 MessagePack-CSharp 라이브러리는 코드 생성을 사용하여 직렬화를 최적화합니다. 따라서 “사전” 컴파일(예: Xamarin iOS 또는 Unity)을 사용하는 환경에서는 기본적으로 지원되지 않습니다. 직렬 변환기/역직렬 변환기 코드를 “미리 생성”하여 이러한 환경에서 MessagePack을 사용할 수 있습니다. 자세한 내용은 MessagePack-CSharp 설명서를 참조하세요. 직렬 변환기를 미리 생성한 후에는 AddMessagePackProtocol에 전달된 구성 대리자를 사용하여 해당 등록할 수 있습니다.

services.AddSignalR()
    .AddMessagePackProtocol(options =>
    {
        options.FormatterResolvers = new List<MessagePack.IFormatterResolver>()
        {
            MessagePack.Resolvers.GeneratedResolver.Instance,
            MessagePack.Resolvers.StandardResolver.Instance
        };
    });

MessagePack에서 형식 검사는 더 엄격합니다.

JSON 허브 프로토콜은 역직렬화 중에 형식 변환을 수행합니다. 예를 들어 들어오는 개체의 속성 값이 숫자({ foo: 42 })이지만 .NET 클래스의 속성이 string 형식인 경우 값이 변환됩니다. 그러나 MessagePack은 이 변환을 수행하지 않으며 서버 쪽 로그(및 콘솔)에서 볼 수 있는 예외를 throw합니다.

InvalidDataException: Error binding arguments. Make sure that the types of the provided values match the types of the hub method being invoked.

이 제한에 대한 자세한 내용은 GitHub 문제 aspnet/SignalR#2937을 참조하세요.

추가 리소스

이 문서에서는 독자가 ASP.NET Core SignalR 시작에서 다룬 항목에 대해 잘 알고 있다고 가정합니다.

MessagePack이란?

MessagePack이란 빠르고 압축된 이진 직렬화 형식입니다. JSON보다 작은 메시지를 만들기 때문에 성능 및 대역폭이 중요한 경우에 유용합니다. 바이트가 MessagePack 파서를 통해 전달되지 않는 한, 네트워크 추적 및 로그를 볼 때 이진 메시지를 읽을 수 없습니다. SignalR에서는 MessagePack 형식을 기본적으로 지원하며 클라이언트 및 서버에서 사용할 수 있는 API를 제공합니다.

서버에서 MessagePack 구성

서버에서 MessagePack 허브 프로토콜을 사용하도록 설정하려면 앱에 Microsoft.AspNetCore.SignalR.Protocols.MessagePack 패키지를 설치합니다. Startup.ConfigureServices 메서드에서 서버에 대한 MessagePack 지원을 사용하도록 AddSignalR 호출에 AddMessagePackProtocol을 추가합니다.

참고 항목

JSON이 기본적으로 사용하도록 설정됩니다. MessagePack을 추가하면 JSON 및 MessagePack 클라이언트를 모두 지원할 수 있습니다.

services.AddSignalR()
    .AddMessagePackProtocol();

MessagePack에서 데이터의 형식을 지정하는 방법을 사용자 지정하기 위해 AddMessagePackProtocol에서는 옵션을 구성하는 대리자를 사용합니다. 이 대리자에서 FormatterResolvers 속성은 MessagePack 직렬화 옵션을 구성하는 데 사용됩니다. 해결 프로그램의 작동 방식에 대한 자세한 내용은 MessagePack-CSharp에서 MessagePack 라이브러리를 참조하세요. 직렬화할 개체에 특성을 사용하여 해당 특성을 처리하는 방법을 정의할 수 있습니다.

services.AddSignalR()
    .AddMessagePackProtocol(options =>
    {
        options.FormatterResolvers = new List<MessagePack.IFormatterResolver>()
        {
            MessagePack.Resolvers.StandardResolver.Instance
        };
    });

Warning

CVE-2020-5234를 검토하고 권장되는 패치를 적용하는 것이 좋습니다. 예를 들어 MessagePackSecurity.Active 정적 속성을 MessagePackSecurity.UntrustedData로 설정합니다. MessagePackSecurity.Active를 설정하려면 1.9.x 버전의 MessagePack을 수동으로 설치해야 합니다. MessagePack 1.9. x를 설치하면 SignalR에서 사용하는 버전이 업그레이드됩니다. MessagePackSecurity.ActiveMessagePackSecurity.UntrustedData로 설정되지 않은 경우 악의적인 클라이언트로 인해 서비스 거부가 발생할 수 있습니다. 다음 코드와 같이 Program.MainMessagePackSecurity.Active를 설정합니다.

using MessagePack;

public static void Main(string[] args)
{
  MessagePackSecurity.Active = MessagePackSecurity.UntrustedData;

  CreateHostBuilder(args).Build().Run();
}

클라이언트에서 MessagePack 구성

참고 항목

JSON은 지원되는 클라이언트에 대해 기본적으로 사용하도록 설정됩니다. 클라이언트는 단일 프로토콜만 지원할 수 있습니다. MessagePack 지원 추가는 이전에 구성된 모든 프로토콜을 대체합니다.

.NET 클라이언트

.NET 클라이언트에서 MessagePack을 사용하도록 설정하려면 Microsoft.AspNetCore.SignalR.Protocols.MessagePack 패키지를 설치하고 HubConnectionBuilder에서 AddMessagePackProtocol을 호출합니다.

using Microsoft.AspNetCore.SignalR.Client;
using Microsoft.Extensions.DependencyInjection;

var hubConnection = new HubConnectionBuilder()
                        .WithUrl("/chathub")
                        .AddMessagePackProtocol()
                        .Build();

참고 항목

AddMessagePackProtocol 호출은 서버와 마찬가지로 옵션을 구성하기 위한 대리자를 사용합니다.

JavaScript 클라이언트

JavaScript 클라이언트에 대한 MessagePack 지원은 @aspnet/signalr-protocol-msgpack npm 패키지에서 제공됩니다. 명령 셸에서 다음 명령을 실행하여 패키지를 설치합니다.

npm install @aspnet/signalr-protocol-msgpack

npm 패키지를 설치한 후 JavaScript 모듈 로더를 통해 직접 모듈을 사용하거나 다음 파일을 참조하여 브라우저로 가져올 수 있습니다.

node_modules\@aspnet\signalr-protocol-msgpack\dist\browser\signalr-protocol-msgpack.js

브라우저에서 msgpack5 라이브러리도 참조해야 합니다. <script> 태그를 사용하여 참조를 만듭니다. 라이브러리는 node_modules\msgpack5\dist\msgpack5.js에서 찾을 수 있습니다.

참고 항목

<script> 요소를 사용하는 경우 순서가 중요합니다. 이전에 msgpack5.js참조된 경우 signalr-protocol-msgpack.js MessagePack에 연결하려고 할 때 오류가 발생합니다. signalr.js 은 앞에도 필요합니다 signalr-protocol-msgpack.js.

<script src="~/lib/signalr/signalr.js"></script>
<script src="~/lib/msgpack5/msgpack5.js"></script>
<script src="~/lib/signalr/signalr-protocol-msgpack.js"></script>

HubConnectionBuilder.withHubProtocol(new signalR.protocols.msgpack.MessagePackHubProtocol())을 추가하면 서버에 연결할 때 MessagePack 프로토콜을 사용하도록 클라이언트가 구성됩니다.

const connection = new signalR.HubConnectionBuilder()
    .withUrl("/chathub")
    .withHubProtocol(new signalR.protocols.msgpack.MessagePackHubProtocol())
    .build();

참고 항목

이번에는 JavaScript 클라이언트에 MessagePack 프로토콜에 대한 구성 옵션이 없습니다.

MessagePack 고려 사항

MessagePack 허브 프로토콜을 사용할 때 알아야 할 몇 가지 문제가 있습니다.

MessagePack은 대/소문자를 구분합니다.

MessagePack 프로토콜은 대/소문자를 구분합니다. 예를 들어 다음 C# 클래스를 고려하세요.

public class ChatMessage
{
    public string Sender { get; }
    public string Message { get; }
}

JavaScript 클라이언트에서 전송하는 경우 대/소문자 구분이 C# 클래스와 정확하게 일치해야 하므로 PascalCased 속성 이름을 사용해야 합니다. 예시:

connection.invoke("SomeMethod", { Sender: "Sally", Message: "Hello!" });

camelCased 이름 사용은 C# 클래스에 올바르게 바인딩되지 않습니다. Key 특성을 사용하여 MessagePack 속성에 다른 이름을 지정하면 이 문제를 해결할 수 있습니다. 자세한 내용은 MessagePack-CSharp 설명서를 참조하세요.

직렬화/역직렬화할 때에는 DateTime.Kind가 유지되지 않습니다.

MessagePack 프로토콜은 DateTimeKind 값을 인코딩하는 방법을 제공하지 않습니다. 결과적으로, 날짜를 역직렬화할 때 MessagePack 허브 프로토콜은 들어오는 날짜가 UTC 형식인 것으로 가정합니다. 현지 시간인 DateTime 값을 사용하여 작업하는 경우에는 값을 보내기 전에 UTC로 변환하는 것이 좋습니다. 값을 받으면 UTC에서 현지 시간으로 변환합니다.

이 제한에 대한 자세한 내용은 GitHub 문제 aspnet/SignalR#2632를 참조하세요.

DateTime.MinValue는 JavaScript의 MessagePack에서 지원되지 않습니다.

SignalR JavaScript 클라이언트에서 사용하는 msgpack5 라이브러리는 MessagePack의 timestamp96 형식을 지원하지 않습니다. 이 형식은 매우 큰 날짜 값(매우 먼 과거 또는 매우 먼 미래)을 인코딩하는 데 사용됩니다. DateTime.MinValue의 값은 January 1, 0001이며 timestamp96 값으로 인코딩해야 합니다. 따라서 JavaScript 클라이언트로 DateTime.MinValue를 보내는 것은 지원되지 않습니다. DateTime.MinValue가 JavaScript 클라이언트에서 수신되면 다음 오류가 throw됩니다.

Uncaught Error: unable to find ext type 255 at decoder.js:427

일반적으로 DateTime.MinValue는 “missing” 또는 null 값을 인코딩하는 데 사용됩니다. MessagePack에서 해당 값을 인코딩해야 하는 경우 null을 허용하는 DateTime 값(DateTime?)을 사용하거나 날짜가 있는지를 나타내는 별도의 bool 값을 인코딩합니다.

이 제한에 대한 자세한 내용은 GitHub 문제 aspnet/SignalR#2228을 참조하세요.

“사전” 컴파일 환경에서 MessagePack 지원

.NET 클라이언트 및 서버에서 사용하는 MessagePack-CSharp 라이브러리는 코드 생성을 사용하여 직렬화를 최적화합니다. 따라서 “사전” 컴파일(예: Xamarin iOS 또는 Unity)을 사용하는 환경에서는 기본적으로 지원되지 않습니다. 직렬 변환기/역직렬 변환기 코드를 “미리 생성”하여 이러한 환경에서 MessagePack을 사용할 수 있습니다. 자세한 내용은 MessagePack-CSharp 설명서를 참조하세요. 직렬 변환기를 미리 생성한 후에는 AddMessagePackProtocol에 전달된 구성 대리자를 사용하여 해당 등록할 수 있습니다.

services.AddSignalR()
    .AddMessagePackProtocol(options =>
    {
        options.FormatterResolvers = new List<MessagePack.IFormatterResolver>()
        {
            MessagePack.Resolvers.GeneratedResolver.Instance,
            MessagePack.Resolvers.StandardResolver.Instance
        };
    });

MessagePack에서 형식 검사는 더 엄격합니다.

JSON 허브 프로토콜은 역직렬화 중에 형식 변환을 수행합니다. 예를 들어 들어오는 개체의 속성 값이 숫자({ foo: 42 })이지만 .NET 클래스의 속성이 string 형식인 경우 값이 변환됩니다. 그러나 MessagePack은 이 변환을 수행하지 않으며 서버 쪽 로그(및 콘솔)에서 볼 수 있는 예외를 throw합니다.

InvalidDataException: Error binding arguments. Make sure that the types of the provided values match the types of the hub method being invoked.

이 제한에 대한 자세한 내용은 GitHub 문제 aspnet/SignalR#2937을 참조하세요.

추가 리소스