Split MsgPack into separate assembly (#1274)

This commit is contained in:
Andrew Stanton-Nurse 2018-01-10 14:20:57 -08:00 committed by GitHub
parent 50fe88195e
commit 144984e599
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
45 changed files with 522 additions and 203 deletions

View File

@ -88,6 +88,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JwtClientSample", "samples\
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.SignalR.Tests.Utils", "test\Microsoft.AspNetCore.SignalR.Tests.Utils\Microsoft.AspNetCore.SignalR.Tests.Utils.csproj", "{0A0A6135-EA24-4307-95C2-CE1B7E164A5E}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.SignalR.Tests.Utils", "test\Microsoft.AspNetCore.SignalR.Tests.Utils\Microsoft.AspNetCore.SignalR.Tests.Utils.csproj", "{0A0A6135-EA24-4307-95C2-CE1B7E164A5E}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNetCore.SignalR.Protocols.MsgPack", "src\Microsoft.AspNetCore.SignalR.Protocols.MsgPack\Microsoft.AspNetCore.SignalR.Protocols.MsgPack.csproj", "{55DB4B6F-12E5-4A27-97F4-E97E135470FF}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNetCore.SignalR.MsgPack", "src\Microsoft.AspNetCore.SignalR.MsgPack\Microsoft.AspNetCore.SignalR.MsgPack.csproj", "{FDDB4E1F-2FD2-49E8-B0FF-874B0931369A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNetCore.SignalR.Client.MsgPack", "src\Microsoft.AspNetCore.SignalR.Client.MsgPack\Microsoft.AspNetCore.SignalR.Client.MsgPack.csproj", "{4DBF918E-BD37-4309-B448-BA68C935944D}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@ -206,6 +212,18 @@ Global
{0A0A6135-EA24-4307-95C2-CE1B7E164A5E}.Debug|Any CPU.Build.0 = Debug|Any CPU {0A0A6135-EA24-4307-95C2-CE1B7E164A5E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0A0A6135-EA24-4307-95C2-CE1B7E164A5E}.Release|Any CPU.ActiveCfg = Release|Any CPU {0A0A6135-EA24-4307-95C2-CE1B7E164A5E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0A0A6135-EA24-4307-95C2-CE1B7E164A5E}.Release|Any CPU.Build.0 = Release|Any CPU {0A0A6135-EA24-4307-95C2-CE1B7E164A5E}.Release|Any CPU.Build.0 = Release|Any CPU
{55DB4B6F-12E5-4A27-97F4-E97E135470FF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{55DB4B6F-12E5-4A27-97F4-E97E135470FF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{55DB4B6F-12E5-4A27-97F4-E97E135470FF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{55DB4B6F-12E5-4A27-97F4-E97E135470FF}.Release|Any CPU.Build.0 = Release|Any CPU
{FDDB4E1F-2FD2-49E8-B0FF-874B0931369A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FDDB4E1F-2FD2-49E8-B0FF-874B0931369A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FDDB4E1F-2FD2-49E8-B0FF-874B0931369A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FDDB4E1F-2FD2-49E8-B0FF-874B0931369A}.Release|Any CPU.Build.0 = Release|Any CPU
{4DBF918E-BD37-4309-B448-BA68C935944D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4DBF918E-BD37-4309-B448-BA68C935944D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4DBF918E-BD37-4309-B448-BA68C935944D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4DBF918E-BD37-4309-B448-BA68C935944D}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@ -239,6 +257,9 @@ Global
{6A7491D3-3C97-49BD-A71C-433AED657F30} = {C4BC9889-B49F-41B6-806B-F84941B2549B} {6A7491D3-3C97-49BD-A71C-433AED657F30} = {C4BC9889-B49F-41B6-806B-F84941B2549B}
{1A953296-E869-4DE2-A693-FD5FCDE27057} = {C4BC9889-B49F-41B6-806B-F84941B2549B} {1A953296-E869-4DE2-A693-FD5FCDE27057} = {C4BC9889-B49F-41B6-806B-F84941B2549B}
{0A0A6135-EA24-4307-95C2-CE1B7E164A5E} = {6A35B453-52EC-48AF-89CA-D4A69800F131} {0A0A6135-EA24-4307-95C2-CE1B7E164A5E} = {6A35B453-52EC-48AF-89CA-D4A69800F131}
{55DB4B6F-12E5-4A27-97F4-E97E135470FF} = {DA69F624-5398-4884-87E4-B816698CDE65}
{FDDB4E1F-2FD2-49E8-B0FF-874B0931369A} = {DA69F624-5398-4884-87E4-B816698CDE65}
{4DBF918E-BD37-4309-B448-BA68C935944D} = {DA69F624-5398-4884-87E4-B816698CDE65}
EndGlobalSection EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {7945A4E4-ACDB-4F6E-95CA-6AC6E7C2CD59} SolutionGuid = {7945A4E4-ACDB-4F6E-95CA-6AC6E7C2CD59}

View File

@ -1,3 +1,6 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Attributes;
using Microsoft.AspNetCore.SignalR.Internal; using Microsoft.AspNetCore.SignalR.Internal;

View File

@ -8,6 +8,7 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.SignalR.Core\Microsoft.AspNetCore.SignalR.Core.csproj" /> <ProjectReference Include="..\..\src\Microsoft.AspNetCore.SignalR.Core\Microsoft.AspNetCore.SignalR.Core.csproj" />
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.SignalR.Common\Microsoft.AspNetCore.SignalR.Common.csproj" /> <ProjectReference Include="..\..\src\Microsoft.AspNetCore.SignalR.Common\Microsoft.AspNetCore.SignalR.Common.csproj" />
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.SignalR.Protocols.MsgPack\Microsoft.AspNetCore.SignalR.Protocols.MsgPack.csproj" />
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Sockets\Microsoft.AspNetCore.Sockets.csproj" /> <ProjectReference Include="..\..\src\Microsoft.AspNetCore.Sockets\Microsoft.AspNetCore.Sockets.csproj" />
<PackageReference Include="BenchmarkDotNet" Version="$(BenchmarkDotNetPackageVersion)" /> <PackageReference Include="BenchmarkDotNet" Version="$(BenchmarkDotNetPackageVersion)" />
<PackageReference Include="Microsoft.AspNetCore.BenchmarkRunner.Sources" Version="$(MicrosoftAspNetCoreBenchmarkRunnerSourcesPackageVersion)" /> <PackageReference Include="Microsoft.AspNetCore.BenchmarkRunner.Sources" Version="$(MicrosoftAspNetCoreBenchmarkRunnerSourcesPackageVersion)" />

View File

@ -23,11 +23,13 @@ namespace Microsoft.AspNetCore.SignalR.Test.Server
public void ConfigureServices(IServiceCollection services) public void ConfigureServices(IServiceCollection services)
{ {
services.AddSockets(); services.AddSockets();
services.AddSignalR(options => { services.AddSignalR()
// we are running the same tests with JSON and MsgPack protocols and having .AddJsonProtocol(options =>
// consistent casing makes it cleaner to verify results {
options.JsonSerializerSettings.ContractResolver = new DefaultContractResolver(); // we are running the same tests with JSON and MsgPack protocols and having
}); // consistent casing makes it cleaner to verify results
options.PayloadSerializerSettings.ContractResolver = new DefaultContractResolver();
});
services.AddAuthorization(options => services.AddAuthorization(options =>
{ {

View File

@ -1,16 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace SocketsSample.Hubs
{
public class Person
{
public string Name { get; set; }
public long Age { get; set; }
}
}

View File

@ -5,6 +5,7 @@ using System;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json.Serialization;
using SocketsSample.EndPoints; using SocketsSample.EndPoints;
using SocketsSample.Hubs; using SocketsSample.Hubs;

View File

@ -1,11 +1,10 @@
// Copyright (c) .NET Foundation. All rights reserved. // Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using Microsoft.AspNetCore.SignalR.Internal.Protocol; using Microsoft.AspNetCore.SignalR.Internal.Protocol;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using MsgPack.Serialization; using Microsoft.Extensions.Options;
using Newtonsoft.Json;
namespace Microsoft.AspNetCore.SignalR.Client namespace Microsoft.AspNetCore.SignalR.Client
{ {
@ -22,29 +21,9 @@ namespace Microsoft.AspNetCore.SignalR.Client
return hubConnectionBuilder.WithHubProtocol(new JsonHubProtocol()); return hubConnectionBuilder.WithHubProtocol(new JsonHubProtocol());
} }
public static IHubConnectionBuilder WithJsonProtocol(this IHubConnectionBuilder hubConnectionBuilder, JsonSerializerSettings serializerSettings) public static IHubConnectionBuilder WithJsonProtocol(this IHubConnectionBuilder hubConnectionBuilder, JsonHubProtocolOptions options)
{ {
return hubConnectionBuilder.WithHubProtocol(new JsonHubProtocol(JsonSerializer.Create(serializerSettings))); return hubConnectionBuilder.WithHubProtocol(new JsonHubProtocol(Options.Create(options)));
}
public static IHubConnectionBuilder WithJsonProtocol(this IHubConnectionBuilder hubConnectionBuilder, JsonSerializer jsonSerializer)
{
return hubConnectionBuilder.WithHubProtocol(new JsonHubProtocol(jsonSerializer));
}
public static IHubConnectionBuilder WithMessagePackProtocol(this IHubConnectionBuilder hubConnectionBuilder)
{
return hubConnectionBuilder.WithHubProtocol(new MessagePackHubProtocol());
}
public static IHubConnectionBuilder WithMessagePackProtocol(this IHubConnectionBuilder hubConnectionBuilder, SerializationContext serializationContext)
{
if (serializationContext == null)
{
throw new ArgumentNullException(nameof(serializationContext));
}
return hubConnectionBuilder.WithHubProtocol(new MessagePackHubProtocol(serializationContext));
} }
public static IHubConnectionBuilder WithLoggerFactory(this IHubConnectionBuilder hubConnectionBuilder, ILoggerFactory loggerFactory) public static IHubConnectionBuilder WithLoggerFactory(this IHubConnectionBuilder hubConnectionBuilder, ILoggerFactory loggerFactory)

View File

@ -0,0 +1,19 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNetCore.SignalR.Internal.Protocol;
using Microsoft.Extensions.Options;
namespace Microsoft.AspNetCore.SignalR.Client
{
public static class MessagePackProtocolHubConnectionBuilderExtensions
{
public static IHubConnectionBuilder WithMessagePackProtocol(this IHubConnectionBuilder builder) =>
WithMessagePackProtocol(builder, new MessagePackHubProtocolOptions());
public static IHubConnectionBuilder WithMessagePackProtocol(this IHubConnectionBuilder builder, MessagePackHubProtocolOptions options)
{
return builder.WithHubProtocol(new MessagePackHubProtocol(Options.Create(options)));
}
}
}

View File

@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Description>Provides client-side support for the MsgPack protocol in ASP.NET Core SignalR</Description>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Microsoft.AspNetCore.SignalR.Client.Core\Microsoft.AspNetCore.SignalR.Client.Core.csproj" />
<ProjectReference Include="..\Microsoft.AspNetCore.SignalR.Protocols.MsgPack\Microsoft.AspNetCore.SignalR.Protocols.MsgPack.csproj" />
</ItemGroup>
</Project>

View File

@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Runtime.ExceptionServices; using System.Runtime.ExceptionServices;
using Microsoft.AspNetCore.SignalR.Internal.Formatters; using Microsoft.AspNetCore.SignalR.Internal.Formatters;
using Microsoft.Extensions.Options;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization; using Newtonsoft.Json.Serialization;
@ -23,35 +24,21 @@ namespace Microsoft.AspNetCore.SignalR.Internal.Protocol
private const string ArgumentsPropertyName = "arguments"; private const string ArgumentsPropertyName = "arguments";
private const string PayloadPropertyName = "payload"; private const string PayloadPropertyName = "payload";
public static readonly string ProtocolName = "json";
// ONLY to be used for application payloads (args, return values, etc.) // ONLY to be used for application payloads (args, return values, etc.)
private JsonSerializer _payloadSerializer; public JsonSerializer PayloadSerializer { get; }
/// <summary> public JsonHubProtocol() : this(Options.Create(new JsonHubProtocolOptions()))
/// Creates an instance of the <see cref="JsonHubProtocol"/> using the default <see cref="JsonSerializer"/>
/// to serialize application payloads (arguments, results, etc.). The serialization of the outer protocol can
/// NOT be changed using this serializer.
/// </summary>
public JsonHubProtocol()
: this(JsonSerializer.Create(CreateDefaultSerializerSettings()))
{ }
/// <summary>
/// Creates an instance of the <see cref="JsonHubProtocol"/> using the specified <see cref="JsonSerializer"/>
/// to serialize application payloads (arguments, results, etc.). The serialization of the outer protocol can
/// NOT be changed using this serializer.
/// </summary>
/// <param name="payloadSerializer">The <see cref="JsonSerializer"/> to use to serialize application payloads (arguments, results, etc.).</param>
public JsonHubProtocol(JsonSerializer payloadSerializer)
{ {
if (payloadSerializer == null)
{
throw new ArgumentNullException(nameof(payloadSerializer));
}
_payloadSerializer = payloadSerializer;
} }
public string Name => "json"; public JsonHubProtocol(IOptions<JsonHubProtocolOptions> options)
{
PayloadSerializer = JsonSerializer.Create(options.Value.PayloadSerializerSettings);
}
public string Name => ProtocolName;
public ProtocolType Type => ProtocolType.Text; public ProtocolType Type => ProtocolType.Text;
@ -167,7 +154,7 @@ namespace Microsoft.AspNetCore.SignalR.Internal.Protocol
else if (message.HasResult) else if (message.HasResult)
{ {
writer.WritePropertyName(ResultPropertyName); writer.WritePropertyName(ResultPropertyName);
_payloadSerializer.Serialize(writer, message.Result); PayloadSerializer.Serialize(writer, message.Result);
} }
writer.WriteEndObject(); writer.WriteEndObject();
} }
@ -184,7 +171,7 @@ namespace Microsoft.AspNetCore.SignalR.Internal.Protocol
writer.WriteStartObject(); writer.WriteStartObject();
WriteHubInvocationMessageCommon(message, writer, HubProtocolConstants.StreamItemMessageType); WriteHubInvocationMessageCommon(message, writer, HubProtocolConstants.StreamItemMessageType);
writer.WritePropertyName(ItemPropertyName); writer.WritePropertyName(ItemPropertyName);
_payloadSerializer.Serialize(writer, message.Item); PayloadSerializer.Serialize(writer, message.Item);
writer.WriteEndObject(); writer.WriteEndObject();
} }
@ -218,7 +205,7 @@ namespace Microsoft.AspNetCore.SignalR.Internal.Protocol
writer.WriteStartArray(); writer.WriteStartArray();
foreach (var argument in arguments) foreach (var argument in arguments)
{ {
_payloadSerializer.Serialize(writer, argument); PayloadSerializer.Serialize(writer, argument);
} }
writer.WriteEndArray(); writer.WriteEndArray();
} }
@ -299,7 +286,7 @@ namespace Microsoft.AspNetCore.SignalR.Internal.Protocol
for (var i = 0; i < paramTypes.Length; i++) for (var i = 0; i < paramTypes.Length; i++)
{ {
var paramType = paramTypes[i]; var paramType = paramTypes[i];
arguments[i] = args[i].ToObject(paramType, _payloadSerializer); arguments[i] = args[i].ToObject(paramType, PayloadSerializer);
} }
return arguments; return arguments;
@ -316,7 +303,7 @@ namespace Microsoft.AspNetCore.SignalR.Internal.Protocol
var result = JsonUtils.GetRequiredProperty<JToken>(json, ItemPropertyName); var result = JsonUtils.GetRequiredProperty<JToken>(json, ItemPropertyName);
var returnType = binder.GetReturnType(invocationId); var returnType = binder.GetReturnType(invocationId);
return new StreamItemMessage(invocationId, result?.ToObject(returnType, _payloadSerializer)); return new StreamItemMessage(invocationId, result?.ToObject(returnType, PayloadSerializer));
} }
private CompletionMessage BindCompletionMessage(JObject json, IInvocationBinder binder) private CompletionMessage BindCompletionMessage(JObject json, IInvocationBinder binder)
@ -336,7 +323,7 @@ namespace Microsoft.AspNetCore.SignalR.Internal.Protocol
} }
var returnType = binder.GetReturnType(invocationId); var returnType = binder.GetReturnType(invocationId);
var payload = resultProp.Value?.ToObject(returnType, _payloadSerializer); var payload = resultProp.Value?.ToObject(returnType, PayloadSerializer);
return new CompletionMessage(invocationId, error, result: payload, hasResult: true); return new CompletionMessage(invocationId, error, result: payload, hasResult: true);
} }
@ -346,7 +333,7 @@ namespace Microsoft.AspNetCore.SignalR.Internal.Protocol
return new CancelInvocationMessage(invocationId); return new CancelInvocationMessage(invocationId);
} }
public static JsonSerializerSettings CreateDefaultSerializerSettings() internal static JsonSerializerSettings CreateDefaultSerializerSettings()
{ {
return new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() }; return new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() };
} }

View File

@ -0,0 +1,13 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNetCore.SignalR.Internal.Protocol;
using Newtonsoft.Json;
namespace Microsoft.AspNetCore.SignalR
{
public class JsonHubProtocolOptions
{
public JsonSerializerSettings PayloadSerializerSettings { get; set; } = JsonHubProtocol.CreateDefaultSerializerSettings();
}
}

View File

@ -9,11 +9,11 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="$(NewtonsoftJsonPackageVersion)" /> <PackageReference Include="Newtonsoft.Json" Version="$(NewtonsoftJsonPackageVersion)" />
<PackageReference Include="MsgPack.Cli" Version="$(MsgPackCliPackageVersion)" />
<PackageReference Include="System.Buffers.Primitives" Version="$(SystemBuffersPrimitivesPackageVersion)" /> <PackageReference Include="System.Buffers.Primitives" Version="$(SystemBuffersPrimitivesPackageVersion)" />
<PackageReference Include="System.Memory" Version="$(SystemMemoryPackageVersion)" /> <PackageReference Include="System.Memory" Version="$(SystemMemoryPackageVersion)" />
<PackageReference Include="System.Numerics.Vectors" Version="$(SystemNumericsVectorsPackageVersion)" /> <PackageReference Include="System.Numerics.Vectors" Version="$(SystemNumericsVectorsPackageVersion)" />
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="$(SystemRuntimeCompilerServicesUnsafePackageVersion)" /> <PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="$(SystemRuntimeCompilerServicesUnsafePackageVersion)" />
<PackageReference Include="Microsoft.Extensions.Options" Version="$(MicrosoftExtensionsOptionsPackageVersion)" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -12,7 +12,6 @@ using System.Threading.Channels;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.SignalR.Core; using Microsoft.AspNetCore.SignalR.Core;
using Microsoft.AspNetCore.SignalR.Core.Internal;
using Microsoft.AspNetCore.SignalR.Internal; using Microsoft.AspNetCore.SignalR.Internal;
using Microsoft.AspNetCore.SignalR.Internal.Encoders; using Microsoft.AspNetCore.SignalR.Internal.Encoders;
using Microsoft.AspNetCore.SignalR.Internal.Protocol; using Microsoft.AspNetCore.SignalR.Internal.Protocol;

View File

@ -12,7 +12,6 @@ using System.Threading.Channels;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.SignalR.Core; using Microsoft.AspNetCore.SignalR.Core;
using Microsoft.AspNetCore.SignalR.Core.Internal;
using Microsoft.AspNetCore.SignalR.Internal; using Microsoft.AspNetCore.SignalR.Internal;
using Microsoft.AspNetCore.SignalR.Internal.Protocol; using Microsoft.AspNetCore.SignalR.Internal.Protocol;
using Microsoft.AspNetCore.Sockets; using Microsoft.AspNetCore.Sockets;

View File

@ -2,9 +2,6 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using Microsoft.AspNetCore.SignalR.Internal.Protocol;
using MsgPack.Serialization;
using Newtonsoft.Json;
namespace Microsoft.AspNetCore.SignalR namespace Microsoft.AspNetCore.SignalR
{ {
@ -16,8 +13,6 @@ namespace Microsoft.AspNetCore.SignalR
/// </summary> /// </summary>
public static readonly TimeSpan DefaultKeepAliveInterval = TimeSpan.FromSeconds(15); public static readonly TimeSpan DefaultKeepAliveInterval = TimeSpan.FromSeconds(15);
public JsonSerializerSettings JsonSerializerSettings { get; set; } = JsonHubProtocol.CreateDefaultSerializerSettings();
public SerializationContext MessagePackSerializationContext { get; set; } = MessagePackHubProtocol.CreateDefaultSerializationContext();
public TimeSpan NegotiateTimeout { get; set; } = TimeSpan.FromSeconds(5); public TimeSpan NegotiateTimeout { get; set; } = TimeSpan.FromSeconds(5);
/// <summary> /// <summary>

View File

@ -1,8 +1,12 @@
// Copyright (c) .NET Foundation. All rights reserved. // Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.SignalR.Internal.Protocol; using Microsoft.AspNetCore.SignalR.Internal.Protocol;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Newtonsoft.Json; using Newtonsoft.Json;
@ -11,23 +15,37 @@ namespace Microsoft.AspNetCore.SignalR.Internal
public class DefaultHubProtocolResolver : IHubProtocolResolver public class DefaultHubProtocolResolver : IHubProtocolResolver
{ {
private readonly IOptions<HubOptions> _options; private readonly IOptions<HubOptions> _options;
private readonly ILogger<DefaultHubProtocolResolver> _logger;
private readonly Dictionary<string, IHubProtocol> _availableProtocols;
public DefaultHubProtocolResolver(IOptions<HubOptions> options) public DefaultHubProtocolResolver(IOptions<HubOptions> options, IEnumerable<IHubProtocol> availableProtocols, ILogger<DefaultHubProtocolResolver> logger)
{ {
_options = options; _options = options ?? throw new ArgumentNullException(nameof(options));
_logger = logger ?? NullLogger<DefaultHubProtocolResolver>.Instance;
_availableProtocols = new Dictionary<string, IHubProtocol>(StringComparer.OrdinalIgnoreCase);
foreach(var protocol in availableProtocols)
{
if(_availableProtocols.ContainsKey(protocol.Name))
{
throw new InvalidOperationException($"Multiple Hub Protocols with the name '{protocol.Name}' were registered.");
}
_logger.RegisteredSignalRProtocol(protocol.Name, protocol.GetType());
_availableProtocols.Add(protocol.Name, protocol);
}
} }
public IHubProtocol GetProtocol(string protocolName, HubConnectionContext connection) public IHubProtocol GetProtocol(string protocolName, HubConnectionContext connection)
{ {
switch (protocolName?.ToLowerInvariant()) protocolName = protocolName ?? throw new ArgumentNullException(nameof(protocolName));
if (_availableProtocols.TryGetValue(protocolName, out var protocol))
{ {
case "json": _logger.FoundImplementationForProtocol(protocolName);
return new JsonHubProtocol(JsonSerializer.Create(_options.Value.JsonSerializerSettings)); return protocol;
case "messagepack":
return new MessagePackHubProtocol(_options.Value.MessagePackSerializationContext);
default:
throw new NotSupportedException($"The protocol '{protocolName ?? "(null)"}' is not supported.");
} }
throw new NotSupportedException($"The protocol '{protocolName ?? "(null)"}' is not supported.");
} }
} }
} }

View File

@ -5,7 +5,7 @@ using System;
using Microsoft.AspNetCore.SignalR.Internal.Protocol; using Microsoft.AspNetCore.SignalR.Internal.Protocol;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
namespace Microsoft.AspNetCore.SignalR.Core.Internal namespace Microsoft.AspNetCore.SignalR.Internal
{ {
internal static class SignalRCoreLoggerExtensions internal static class SignalRCoreLoggerExtensions
{ {
@ -77,6 +77,13 @@ namespace Microsoft.AspNetCore.SignalR.Core.Internal
private static readonly Action<ILogger, Exception> _transportBufferFull = private static readonly Action<ILogger, Exception> _transportBufferFull =
LoggerMessage.Define(LogLevel.Debug, new EventId(4, nameof(TransportBufferFull)), "Unable to send Ping message to client, the transport buffer is full."); LoggerMessage.Define(LogLevel.Debug, new EventId(4, nameof(TransportBufferFull)), "Unable to send Ping message to client, the transport buffer is full.");
// Category: DefaultHubProtocolResolver
private static readonly Action<ILogger, string, Type, Exception> _registeredSignalRProtocol =
LoggerMessage.Define<string, Type>(LogLevel.Debug, new EventId(0, nameof(RegisteredSignalRProtocol)), "Registered SignalR Protocol: {ProtocolName}, implemented by {ImplementationType}.");
private static readonly Action<ILogger, string, Exception> _foundImplementationForProtocol =
LoggerMessage.Define<string>(LogLevel.Debug, new EventId(1, nameof(FoundImplementationForProtocol)), "Found protocol implementation for requested protocol: {ProtocolName}.");
public static void UsingHubProtocol(this ILogger logger, string hubProtocol) public static void UsingHubProtocol(this ILogger logger, string hubProtocol)
{ {
_usingHubProtocol(logger, hubProtocol, null); _usingHubProtocol(logger, hubProtocol, null);
@ -186,5 +193,15 @@ namespace Microsoft.AspNetCore.SignalR.Core.Internal
{ {
_transportBufferFull(logger, null); _transportBufferFull(logger, null);
} }
public static void RegisteredSignalRProtocol(this ILogger logger, string protocolName, Type implementationType)
{
_registeredSignalRProtocol(logger, protocolName, implementationType, null);
}
public static void FoundImplementationForProtocol(this ILogger logger, string protocolName)
{
_foundImplementationForProtocol(logger, protocolName, null);
}
} }
} }

View File

@ -0,0 +1,37 @@
using System;
using Microsoft.AspNetCore.SignalR;
using Microsoft.AspNetCore.SignalR.Internal.Protocol;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
namespace Microsoft.Extensions.DependencyInjection
{
public static class JsonProtocolDependencyInjectionExtensions
{
/// <summary>
/// Enables the JSON protocol for SignalR.
/// </summary>
/// <remarks>
/// This has no effect if the JSON protocol has already been enabled.
/// </remarks>
/// <param name="builder">The <see cref="ISignalRBuilder"/> representing the SignalR server to add JSON protocol support to.</param>
/// <returns>The value of <paramref name="builder"/></returns>
public static ISignalRBuilder AddJsonProtocol(this ISignalRBuilder builder) => AddJsonProtocol(builder, _ => { });
/// <summary>
/// Enables the JSON protocol for SignalR and allows options for the JSON protocol to be configured.
/// </summary>
/// <remarks>
/// Any options configured here will be applied, even if the JSON protocol has already been registered with the server.
/// </remarks>
/// <param name="builder">The <see cref="ISignalRBuilder"/> representing the SignalR server to add JSON protocol support to.</param>
/// <param name="configure">A delegate that can be used to configure the <see cref="JsonHubProtocolOptions"/></param>
/// <returns>The value of <paramref name="builder"/></returns>
public static ISignalRBuilder AddJsonProtocol(this ISignalRBuilder builder, Action<JsonHubProtocolOptions> configure)
{
builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<IHubProtocol, JsonHubProtocol>());
builder.Services.Configure(configure);
return builder;
}
}
}

View File

@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation. All rights reserved. // Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNetCore.SignalR; using Microsoft.AspNetCore.SignalR;

View File

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Description>Provides server-side support for the MsgPack protocol in ASP.NET Core SignalR</Description>
<TargetFramework>netstandard2.0</TargetFramework>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Microsoft.AspNetCore.SignalR.Core\Microsoft.AspNetCore.SignalR.Core.csproj" />
<ProjectReference Include="..\Microsoft.AspNetCore.SignalR.Protocols.MsgPack\Microsoft.AspNetCore.SignalR.Protocols.MsgPack.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,37 @@
using System;
using System.Linq;
using Microsoft.AspNetCore.SignalR;
using Microsoft.AspNetCore.SignalR.Internal.Protocol;
using Microsoft.Extensions.DependencyInjection.Extensions;
namespace Microsoft.Extensions.DependencyInjection
{
public static class MsgPackProtocolDependencyInjectionExtensions
{
/// <summary>
/// Enables the MsgPack protocol for SignalR.
/// </summary>
/// <remarks>
/// This has no effect if the MsgPack protocol has already been enabled.
/// </remarks>
/// <param name="builder">The <see cref="ISignalRBuilder"/> representing the SignalR server to add MsgPack protocol support to.</param>
/// <returns>The value of <paramref name="builder"/></returns>
public static ISignalRBuilder AddMessagePackProtocol(this ISignalRBuilder builder) => AddMessagePackProtocol(builder, _ => { });
/// <summary>
/// Enables the MsgPack protocol for SignalR and allows options for the MsgPack protocol to be configured.
/// </summary>
/// <remarks>
/// Any options configured here will be applied, even if the MsgPack protocol has already been registered with the server.
/// </remarks>
/// <param name="builder">The <see cref="ISignalRBuilder"/> representing the SignalR server to add MsgPack protocol support to.</param>
/// <param name="configure">A delegate that can be used to configure the <see cref="MessagePackHubProtocolOptions"/></param>
/// <returns>The value of <paramref name="builder"/></returns>
public static ISignalRBuilder AddMessagePackProtocol(this ISignalRBuilder builder, Action<MessagePackHubProtocolOptions> configure)
{
builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<IHubProtocol, MessagePackHubProtocol>());
builder.Services.Configure(configure);
return builder;
}
}
}

View File

@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Runtime.ExceptionServices; using System.Runtime.ExceptionServices;
using Microsoft.AspNetCore.SignalR.Internal.Formatters; using Microsoft.AspNetCore.SignalR.Internal.Formatters;
using Microsoft.Extensions.Options;
using MsgPack; using MsgPack;
using MsgPack.Serialization; using MsgPack.Serialization;
@ -17,19 +18,21 @@ namespace Microsoft.AspNetCore.SignalR.Internal.Protocol
private const int VoidResult = 2; private const int VoidResult = 2;
private const int NonVoidResult = 3; private const int NonVoidResult = 3;
private readonly SerializationContext _serializationContext; public static readonly string ProtocolName = "messagepack";
public string Name => "messagepack"; public SerializationContext SerializationContext { get; }
public string Name => ProtocolName;
public ProtocolType Type => ProtocolType.Binary; public ProtocolType Type => ProtocolType.Binary;
public MessagePackHubProtocol() public MessagePackHubProtocol()
: this(CreateDefaultSerializationContext()) : this(Options.Create(new MessagePackHubProtocolOptions()))
{ } { }
public MessagePackHubProtocol(SerializationContext serializationContext) public MessagePackHubProtocol(IOptions<MessagePackHubProtocolOptions> options)
{ {
_serializationContext = serializationContext; SerializationContext = options.Value.SerializationContext;
} }
public bool TryParseMessages(ReadOnlySpan<byte> input, IInvocationBinder binder, out IList<HubMessage> messages) public bool TryParseMessages(ReadOnlySpan<byte> input, IInvocationBinder binder, out IList<HubMessage> messages)
@ -236,7 +239,7 @@ namespace Microsoft.AspNetCore.SignalR.Internal.Protocol
packer.PackString(invocationMessage.InvocationId); packer.PackString(invocationMessage.InvocationId);
} }
packer.PackString(invocationMessage.Target); packer.PackString(invocationMessage.Target);
packer.PackObject(invocationMessage.Arguments, _serializationContext); packer.PackObject(invocationMessage.Arguments, SerializationContext);
} }
private void WriteStreamInvocationMessage(StreamInvocationMessage streamInvocationMessage, Packer packer) private void WriteStreamInvocationMessage(StreamInvocationMessage streamInvocationMessage, Packer packer)
@ -245,7 +248,7 @@ namespace Microsoft.AspNetCore.SignalR.Internal.Protocol
packer.Pack(HubProtocolConstants.StreamInvocationMessageType); packer.Pack(HubProtocolConstants.StreamInvocationMessageType);
packer.PackString(streamInvocationMessage.InvocationId); packer.PackString(streamInvocationMessage.InvocationId);
packer.PackString(streamInvocationMessage.Target); packer.PackString(streamInvocationMessage.Target);
packer.PackObject(streamInvocationMessage.Arguments, _serializationContext); packer.PackObject(streamInvocationMessage.Arguments, SerializationContext);
} }
private void WriteStreamingItemMessage(StreamItemMessage streamItemMessage, Packer packer) private void WriteStreamingItemMessage(StreamItemMessage streamItemMessage, Packer packer)
@ -253,7 +256,7 @@ namespace Microsoft.AspNetCore.SignalR.Internal.Protocol
packer.PackArrayHeader(3); packer.PackArrayHeader(3);
packer.Pack(HubProtocolConstants.StreamItemMessageType); packer.Pack(HubProtocolConstants.StreamItemMessageType);
packer.PackString(streamItemMessage.InvocationId); packer.PackString(streamItemMessage.InvocationId);
packer.PackObject(streamItemMessage.Item, _serializationContext); packer.PackObject(streamItemMessage.Item, SerializationContext);
} }
private void WriteCompletionMessage(CompletionMessage completionMessage, Packer packer) private void WriteCompletionMessage(CompletionMessage completionMessage, Packer packer)
@ -274,7 +277,7 @@ namespace Microsoft.AspNetCore.SignalR.Internal.Protocol
packer.PackString(completionMessage.Error); packer.PackString(completionMessage.Error);
break; break;
case NonVoidResult: case NonVoidResult:
packer.PackObject(completionMessage.Result, _serializationContext); packer.PackObject(completionMessage.Result, SerializationContext);
break; break;
} }
} }
@ -395,7 +398,7 @@ namespace Microsoft.AspNetCore.SignalR.Internal.Protocol
throw new FormatException($"Deserializing object of the `{type.Name}` type for '{field}' failed.", msgPackException); throw new FormatException($"Deserializing object of the `{type.Name}` type for '{field}' failed.", msgPackException);
} }
public static SerializationContext CreateDefaultSerializationContext() internal static SerializationContext CreateDefaultSerializationContext()
{ {
// serializes objects (here: arguments and results) as maps so that property names are preserved // serializes objects (here: arguments and results) as maps so that property names are preserved
var serializationContext = new SerializationContext { SerializationMethod = SerializationMethod.Map }; var serializationContext = new SerializationContext { SerializationMethod = SerializationMethod.Map };

View File

@ -0,0 +1,13 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNetCore.SignalR.Internal.Protocol;
using MsgPack.Serialization;
namespace Microsoft.AspNetCore.SignalR
{
public class MessagePackHubProtocolOptions
{
public SerializationContext SerializationContext { get; set; } = MessagePackHubProtocol.CreateDefaultSerializationContext();
}
}

View File

@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Description>
Implements the SignalR Hub Protocol over MsgPack. This package provides internal infrastructure.
To use MsgPack, use the Microsoft.AspNetCore.SignalR.Client.MsgPack (for the Client) or
Microsoft.AspNetCore.SignalR.MsgPack (for the Server) packages.
</Description>
<TargetFramework>netstandard2.0</TargetFramework>
<RootNamespace>Microsoft.AspNetCore.SignalR</RootNamespace>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="MsgPack.Cli" Version="$(MsgPackCliPackageVersion)" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Microsoft.AspNetCore.SignalR.Common\Microsoft.AspNetCore.SignalR.Common.csproj" />
</ItemGroup>
</Project>

View File

@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation. All rights reserved. // Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
@ -17,7 +17,8 @@ namespace Microsoft.Extensions.DependencyInjection
{ {
services.Configure(configure); services.Configure(configure);
services.AddSockets(); services.AddSockets();
return services.AddSignalRCore(); return services.AddSignalRCore()
.AddJsonProtocol();
} }
} }
} }

View File

@ -17,6 +17,8 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.SignalR.MsgPack\Microsoft.AspNetCore.SignalR.MsgPack.csproj" />
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.SignalR.Protocols.MsgPack\Microsoft.AspNetCore.SignalR.Protocols.MsgPack.csproj" />
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.SignalR\Microsoft.AspNetCore.SignalR.csproj" /> <ProjectReference Include="..\..\src\Microsoft.AspNetCore.SignalR\Microsoft.AspNetCore.SignalR.csproj" />
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.SignalR.Client\Microsoft.AspNetCore.SignalR.Client.csproj" /> <ProjectReference Include="..\..\src\Microsoft.AspNetCore.SignalR.Client\Microsoft.AspNetCore.SignalR.Client.csproj" />
<ProjectReference Include="..\Microsoft.AspNetCore.SignalR.Tests.Utils\Microsoft.AspNetCore.SignalR.Tests.Utils.csproj" /> <ProjectReference Include="..\Microsoft.AspNetCore.SignalR.Tests.Utils\Microsoft.AspNetCore.SignalR.Tests.Utils.csproj" />

View File

@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation. All rights reserved. // Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
@ -19,7 +19,8 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
public void ConfigureServices(IServiceCollection services) public void ConfigureServices(IServiceCollection services)
{ {
services.AddSignalR(); services.AddSignalR()
.AddMessagePackProtocol();
services.AddAuthorization(options => services.AddAuthorization(options =>
{ {
options.AddPolicy(JwtBearerDefaults.AuthenticationScheme, policy => options.AddPolicy(JwtBearerDefaults.AuthenticationScheme, policy =>

View File

@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation. All rights reserved. // Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Net.Http; using System.Net.Http;

View File

@ -1,7 +1,11 @@
// Copyright (c) .NET Foundation. All rights reserved. // Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using Microsoft.AspNetCore.SignalR.Internal.Protocol;
using MsgPack.Serialization;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using Xunit; using Xunit;
namespace Microsoft.AspNetCore.SignalR.Client.Tests namespace Microsoft.AspNetCore.SignalR.Client.Tests
@ -30,5 +34,53 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
Assert.Equal("loggerFactory", Assert.Equal("loggerFactory",
Assert.Throws<ArgumentNullException>(() => new HubConnectionBuilder().WithLoggerFactory(null)).ParamName); Assert.Throws<ArgumentNullException>(() => new HubConnectionBuilder().WithLoggerFactory(null)).ParamName);
} }
[Fact]
public void WithJsonHubProtocolSetsHubProtocolToJsonWithDefaultOptions()
{
Assert.True(new HubConnectionBuilder().WithJsonProtocol().TryGetSetting<IHubProtocol>(HubConnectionBuilderDefaults.HubProtocolKey, out var hubProtocol));
var actualProtocol = Assert.IsType<JsonHubProtocol>(hubProtocol);
Assert.IsType<CamelCasePropertyNamesContractResolver>(actualProtocol.PayloadSerializer.ContractResolver);
}
[Fact]
public void WithJsonHubProtocolSetsHubProtocolToJsonWithProvidedOptions()
{
var expectedOptions = new JsonHubProtocolOptions()
{
PayloadSerializerSettings = new JsonSerializerSettings()
{
DateFormatString = "JUST A TEST"
}
};
Assert.True(new HubConnectionBuilder().WithJsonProtocol(expectedOptions).TryGetSetting<IHubProtocol>(HubConnectionBuilderDefaults.HubProtocolKey, out var hubProtocol));
var actualProtocol = Assert.IsType<JsonHubProtocol>(hubProtocol);
Assert.Equal("JUST A TEST", actualProtocol.PayloadSerializer.DateFormatString);
}
[Fact]
public void WithMessagePackHubProtocolSetsHubProtocolToMsgPackWithDefaultOptions()
{
Assert.True(new HubConnectionBuilder().WithMessagePackProtocol().TryGetSetting<IHubProtocol>(HubConnectionBuilderDefaults.HubProtocolKey, out var hubProtocol));
var actualProtocol = Assert.IsType<MessagePackHubProtocol>(hubProtocol);
Assert.Equal(SerializationMethod.Map, actualProtocol.SerializationContext.SerializationMethod);
}
[Fact]
public void WithMessagePackHubProtocolSetsHubProtocolToMsgPackWithProvidedOptions()
{
var expectedOptions = new MessagePackHubProtocolOptions()
{
SerializationContext = new SerializationContext()
{
SerializationMethod = SerializationMethod.Array
}
};
Assert.True(new HubConnectionBuilder().WithMessagePackProtocol(expectedOptions).TryGetSetting<IHubProtocol>(HubConnectionBuilderDefaults.HubProtocolKey, out var hubProtocol));
var actualProtocol = Assert.IsType<MessagePackHubProtocol>(hubProtocol);
Assert.Equal(SerializationMethod.Array, actualProtocol.SerializationContext.SerializationMethod);
}
} }
} }

View File

@ -125,7 +125,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
public async Task ConnectionNotClosedOnCallbackArgumentCountMismatch() public async Task ConnectionNotClosedOnCallbackArgumentCountMismatch()
{ {
var connection = new TestConnection(); var connection = new TestConnection();
var hubConnection = new HubConnection(connection, new JsonHubProtocol(new JsonSerializer()), new LoggerFactory()); var hubConnection = new HubConnection(connection, new JsonHubProtocol(), new LoggerFactory());
var receiveTcs = new TaskCompletionSource<int>(); var receiveTcs = new TaskCompletionSource<int>();
try try

View File

@ -141,7 +141,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
public async Task StreamCompletesWhenCompletionMessageIsReceived() public async Task StreamCompletesWhenCompletionMessageIsReceived()
{ {
var connection = new TestConnection(); var connection = new TestConnection();
var hubConnection = new HubConnection(connection, new JsonHubProtocol(new JsonSerializer()), new LoggerFactory()); var hubConnection = new HubConnection(connection, new JsonHubProtocol(), new LoggerFactory());
try try
{ {
await hubConnection.StartAsync(); await hubConnection.StartAsync();

View File

@ -11,6 +11,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.SignalR.Client.MsgPack\Microsoft.AspNetCore.SignalR.Client.MsgPack.csproj" />
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.SignalR.Client\Microsoft.AspNetCore.SignalR.Client.csproj" /> <ProjectReference Include="..\..\src\Microsoft.AspNetCore.SignalR.Client\Microsoft.AspNetCore.SignalR.Client.csproj" />
<ProjectReference Include="..\Microsoft.AspNetCore.SignalR.Tests.Utils\Microsoft.AspNetCore.SignalR.Tests.Utils.csproj" /> <ProjectReference Include="..\Microsoft.AspNetCore.SignalR.Tests.Utils\Microsoft.AspNetCore.SignalR.Tests.Utils.csproj" />
</ItemGroup> </ItemGroup>

View File

@ -7,6 +7,7 @@ using System.IO;
using System.Text; using System.Text;
using Microsoft.AspNetCore.SignalR.Internal.Formatters; using Microsoft.AspNetCore.SignalR.Internal.Formatters;
using Microsoft.AspNetCore.SignalR.Internal.Protocol; using Microsoft.AspNetCore.SignalR.Internal.Protocol;
using Microsoft.Extensions.Options;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Serialization; using Newtonsoft.Json.Serialization;
using Xunit; using Xunit;
@ -67,13 +68,16 @@ namespace Microsoft.AspNetCore.SignalR.Common.Tests.Internal.Protocol
{ {
expectedOutput = Frame(expectedOutput); expectedOutput = Frame(expectedOutput);
var jsonSerializer = new JsonSerializer var protocolOptions = new JsonHubProtocolOptions
{ {
NullValueHandling = nullValueHandling, PayloadSerializerSettings = new JsonSerializerSettings()
ContractResolver = camelCase ? new CamelCasePropertyNamesContractResolver() : new DefaultContractResolver() {
NullValueHandling = nullValueHandling,
ContractResolver = camelCase ? new CamelCasePropertyNamesContractResolver() : new DefaultContractResolver()
}
}; };
var protocol = new JsonHubProtocol(jsonSerializer); var protocol = new JsonHubProtocol(Options.Create(protocolOptions));
using (var ms = new MemoryStream()) using (var ms = new MemoryStream())
{ {
@ -90,14 +94,17 @@ namespace Microsoft.AspNetCore.SignalR.Common.Tests.Internal.Protocol
{ {
input = Frame(input); input = Frame(input);
var jsonSerializer = new JsonSerializer var protocolOptions = new JsonHubProtocolOptions
{ {
NullValueHandling = nullValueHandling, PayloadSerializerSettings = new JsonSerializerSettings
ContractResolver = camelCase ? new CamelCasePropertyNamesContractResolver() : new DefaultContractResolver() {
NullValueHandling = nullValueHandling,
ContractResolver = camelCase ? new CamelCasePropertyNamesContractResolver() : new DefaultContractResolver()
}
}; };
var binder = new TestBinder(expectedMessage); var binder = new TestBinder(expectedMessage);
var protocol = new JsonHubProtocol(jsonSerializer); var protocol = new JsonHubProtocol(Options.Create(protocolOptions));
protocol.TryParseMessages(Encoding.UTF8.GetBytes(input), binder, out var messages); protocol.TryParseMessages(Encoding.UTF8.GetBytes(input), binder, out var messages);
Assert.Equal(expectedMessage, messages[0], TestHubMessageEqualityComparer.Instance); Assert.Equal(expectedMessage, messages[0], TestHubMessageEqualityComparer.Instance);

View File

@ -12,6 +12,7 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.SignalR.Common\Microsoft.AspNetCore.SignalR.Common.csproj" /> <ProjectReference Include="..\..\src\Microsoft.AspNetCore.SignalR.Common\Microsoft.AspNetCore.SignalR.Common.csproj" />
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.SignalR.Protocols.MsgPack\Microsoft.AspNetCore.SignalR.Protocols.MsgPack.csproj" />
<ProjectReference Include="..\Microsoft.AspNetCore.SignalR.Tests.Utils\Microsoft.AspNetCore.SignalR.Tests.Utils.csproj" /> <ProjectReference Include="..\Microsoft.AspNetCore.SignalR.Tests.Utils\Microsoft.AspNetCore.SignalR.Tests.Utils.csproj" />
</ItemGroup> </ItemGroup>

View File

@ -2,10 +2,12 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using System.Collections.Concurrent;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
namespace Microsoft.AspNetCore.SignalR.Redis.Tests namespace Microsoft.AspNetCore.SignalR.Redis.Tests
{ {
@ -51,7 +53,7 @@ namespace Microsoft.AspNetCore.SignalR.Redis.Tests
return null; return null;
} }
public int Start(ILogger logger) public void Start(ILogger logger)
{ {
logger.LogInformation("Starting docker container"); logger.LogInformation("Starting docker container");
@ -59,23 +61,41 @@ namespace Microsoft.AspNetCore.SignalR.Redis.Tests
// use static name 'redisTestContainer' so if the container doesn't get removed we don't keep adding more // use static name 'redisTestContainer' so if the container doesn't get removed we don't keep adding more
// use redis base docker image // use redis base docker image
// 10 second timeout to allow redis image to be downloaded // 10 second timeout to allow redis image to be downloaded
return RunProcess(_path, $"run --rm -p 6379:6379 --name {_dockerContainerName} -d redis", logger, TimeSpan.FromSeconds(10)); RunProcessAndThrowIfFailed(_path, $"run --rm -p 6379:6379 --name {_dockerContainerName} -d redis", logger, TimeSpan.FromSeconds(10));
} }
public int Stop(ILogger logger) public void Stop(ILogger logger)
{ {
logger.LogInformation("Stopping docker container"); logger.LogInformation("Stopping docker container");
return RunProcess(_path, $"stop {_dockerContainerName}", logger, TimeSpan.FromSeconds(5)); RunProcessAndThrowIfFailed(_path, $"stop {_dockerContainerName}", logger, TimeSpan.FromSeconds(5));
} }
private static int RunProcess(string fileName, string arugments, ILogger logger, TimeSpan timeout) public int RunCommand(string commandAndArguments, out string output) =>
RunCommand(commandAndArguments, NullLogger.Instance, out output);
public int RunCommand(string commandAndArguments, ILogger logger, out string output)
{
return RunProcess(_path, commandAndArguments, logger, TimeSpan.FromSeconds(5), out output);
}
private static void RunProcessAndThrowIfFailed(string fileName, string arguments, ILogger logger, TimeSpan timeout)
{
var exitCode = RunProcess(fileName, arguments, logger, timeout, out var output);
if(exitCode != 0)
{
throw new Exception($"Command '{fileName} {arguments}' failed with exit code '{exitCode}'. Output:{Environment.NewLine}{output}");
}
}
private static int RunProcess(string fileName, string arguments, ILogger logger, TimeSpan timeout, out string output)
{ {
var process = new Process var process = new Process
{ {
StartInfo = new ProcessStartInfo StartInfo = new ProcessStartInfo
{ {
FileName = fileName, FileName = fileName,
Arguments = arugments, Arguments = arguments,
UseShellExecute = false, UseShellExecute = false,
RedirectStandardError = true, RedirectStandardError = true,
RedirectStandardOutput = true RedirectStandardOutput = true
@ -84,9 +104,18 @@ namespace Microsoft.AspNetCore.SignalR.Redis.Tests
}; };
var exitCode = 0; var exitCode = 0;
var lines = new ConcurrentQueue<string>();
process.Exited += (_, __) => exitCode = process.ExitCode; process.Exited += (_, __) => exitCode = process.ExitCode;
process.OutputDataReceived += (_, a) => LogIfNotNull(logger.LogInformation, "stdout: {0}", a.Data); process.OutputDataReceived += (_, a) =>
process.ErrorDataReceived += (_, a) => LogIfNotNull(logger.LogError, "stderr: {0}", a.Data); {
LogIfNotNull(logger.LogInformation, "stdout: {0}", a.Data);
lines.Enqueue(a.Data);
};
process.ErrorDataReceived += (_, a) =>
{
LogIfNotNull(logger.LogError, "stderr: {0}", a.Data);
lines.Enqueue(a.Data);
};
process.Start(); process.Start();
@ -95,6 +124,8 @@ namespace Microsoft.AspNetCore.SignalR.Redis.Tests
process.WaitForExit((int)timeout.TotalMilliseconds); process.WaitForExit((int)timeout.TotalMilliseconds);
output = string.Join(Environment.NewLine, lines);
return exitCode; return exitCode;
} }
@ -106,4 +137,4 @@ namespace Microsoft.AspNetCore.SignalR.Redis.Tests
} }
} }
} }
} }

View File

@ -11,6 +11,8 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.SignalR.MsgPack\Microsoft.AspNetCore.SignalR.MsgPack.csproj" />
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.SignalR.Protocols.MsgPack\Microsoft.AspNetCore.SignalR.Protocols.MsgPack.csproj" />
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.SignalR.Redis\Microsoft.AspNetCore.SignalR.Redis.csproj" /> <ProjectReference Include="..\..\src\Microsoft.AspNetCore.SignalR.Redis\Microsoft.AspNetCore.SignalR.Redis.csproj" />
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Sockets\Microsoft.AspNetCore.Sockets.csproj" /> <ProjectReference Include="..\..\src\Microsoft.AspNetCore.Sockets\Microsoft.AspNetCore.Sockets.csproj" />
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.SignalR\Microsoft.AspNetCore.SignalR.csproj" /> <ProjectReference Include="..\..\src\Microsoft.AspNetCore.SignalR\Microsoft.AspNetCore.SignalR.csproj" />

View File

@ -9,7 +9,31 @@ namespace Microsoft.AspNetCore.SignalR.Redis.Tests
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class SkipIfDockerNotPresentAttribute : Attribute, ITestCondition public class SkipIfDockerNotPresentAttribute : Attribute, ITestCondition
{ {
public bool IsMet => Docker.Default != null; public bool IsMet => CheckDocker();
public string SkipReason => "Docker is not installed on the host machine."; public string SkipReason { get; private set; } = "Docker is not available";
private bool CheckDocker()
{
if(Docker.Default != null)
{
// Docker is present, but is it working?
if (Docker.Default.RunCommand("ps", out var output) != 0)
{
SkipReason = $"Failed to invoke test command 'docker ps'. Output: {output}";
}
else
{
// We have a docker
return true;
}
}
else
{
SkipReason = "Docker is not installed on the host machine.";
}
// If we get here, we don't have a docker
return false;
}
} }
} }

View File

@ -12,6 +12,7 @@ namespace Microsoft.AspNetCore.SignalR.Redis.Tests
public void ConfigureServices(IServiceCollection services) public void ConfigureServices(IServiceCollection services)
{ {
services.AddSignalR() services.AddSignalR()
.AddMessagePackProtocol()
.AddRedis(options => .AddRedis(options =>
{ {
// We start the servers before starting redis so we want to time them out ASAP // We start the servers before starting redis so we want to time them out ASAP

View File

@ -42,6 +42,30 @@ namespace System.Threading.Tasks
return await task; return await task;
} }
public static async Task OrThrowIfOtherFails(this Task task, Task otherTask)
{
var completed = await Task.WhenAny(task, otherTask);
if(completed == otherTask && otherTask.IsFaulted)
{
// Manifest the exception
otherTask.GetAwaiter().GetResult();
throw new Exception("Unreachable code");
}
else
{
// Await the task we were asked to await. Either it's finished, or the otherTask finished successfully, and it's not our job to check that
await task;
}
}
public static async Task<T> OrThrowIfOtherFails<T>(this Task<T> task, Task otherTask)
{
await OrThrowIfOtherFails((Task)task, otherTask);
// If we get here, 'task' is finished and succeeded.
return task.GetAwaiter().GetResult();
}
private static string GetMessage(string memberName, string filePath, int? lineNumber) private static string GetMessage(string memberName, string filePath, int? lineNumber)
{ {
if (!string.IsNullOrEmpty(memberName)) if (!string.IsNullOrEmpty(memberName))

View File

@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation. All rights reserved. // Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
@ -54,8 +54,10 @@ namespace Microsoft.AspNetCore.SignalR.Tests.HubEndpointTestUtils
{ {
var services = new ServiceCollection(); var services = new ServiceCollection();
services.AddOptions() services.AddOptions()
.AddLogging() .AddLogging();
.AddSignalR();
services.AddSignalR()
.AddMessagePackProtocol();
addServices?.Invoke(services); addServices?.Invoke(services);

View File

@ -14,6 +14,7 @@ using Microsoft.AspNetCore.SignalR.Tests.HubEndpointTestUtils;
using Microsoft.AspNetCore.Sockets; using Microsoft.AspNetCore.Sockets;
using Microsoft.AspNetCore.Sockets.Features; using Microsoft.AspNetCore.Sockets.Features;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Moq; using Moq;
using MsgPack; using MsgPack;
using MsgPack.Serialization; using MsgPack.Serialization;
@ -969,7 +970,7 @@ namespace Microsoft.AspNetCore.SignalR.Tests
Assert.Equal("Second and Third", invocation.Arguments[0]); Assert.Equal("Second and Third", invocation.Arguments[0]);
// Check that first client only got the completion message // Check that first client only got the completion message
var hubMessage= await firstClient.ReadAsync().OrTimeout(); var hubMessage = await firstClient.ReadAsync().OrTimeout();
Assert.IsType<CompletionMessage>(hubMessage); Assert.IsType<CompletionMessage>(hubMessage);
Assert.Null(firstClient.TryRead()); Assert.Null(firstClient.TryRead());
@ -1338,7 +1339,8 @@ namespace Microsoft.AspNetCore.SignalR.Tests
var endPointLifetime = endPoint.OnConnectedAsync(client.Connection); var endPointLifetime = endPoint.OnConnectedAsync(client.Connection);
await client.Connected.OrTimeout(); // Wait for a connection, or for the endpoint to fail.
await client.Connected.OrThrowIfOtherFails(endPointLifetime).OrTimeout();
var messages = await client.StreamAsync(method, 4).OrTimeout(); var messages = await client.StreamAsync(method, 4).OrTimeout();
@ -1470,13 +1472,15 @@ namespace Microsoft.AspNetCore.SignalR.Tests
{ {
var serviceProvider = HubEndPointTestUtils.CreateServiceProvider(services => var serviceProvider = HubEndPointTestUtils.CreateServiceProvider(services =>
{ {
services.AddSignalR(o => services
{ .AddSignalR()
o.JsonSerializerSettings = new JsonSerializerSettings .AddJsonProtocol(o =>
{ {
ContractResolver = new DefaultContractResolver() o.PayloadSerializerSettings = new JsonSerializerSettings
}; {
}); ContractResolver = new DefaultContractResolver()
};
});
}); });
var endPoint = serviceProvider.GetService<HubEndPoint<MethodHub>>(); var endPoint = serviceProvider.GetService<HubEndPoint<MethodHub>>();
@ -1532,20 +1536,19 @@ namespace Microsoft.AspNetCore.SignalR.Tests
[Fact] [Fact]
public async Task HubOptionsCanUseCustomMessagePackSettings() public async Task HubOptionsCanUseCustomMessagePackSettings()
{ {
var serializationContext = MessagePackHubProtocol.CreateDefaultSerializationContext();
serializationContext.SerializationMethod = SerializationMethod.Array;
var serviceProvider = HubEndPointTestUtils.CreateServiceProvider(services => var serviceProvider = HubEndPointTestUtils.CreateServiceProvider(services =>
{ {
services.AddSignalR(options => services.AddSignalR()
{ .AddMessagePackProtocol(options =>
options.MessagePackSerializationContext = serializationContext; {
}); options.SerializationContext.SerializationMethod = SerializationMethod.Array;
});
}); });
var endPoint = serviceProvider.GetService<HubEndPoint<MethodHub>>(); var endPoint = serviceProvider.GetService<HubEndPoint<MethodHub>>();
using (var client = new TestClient(synchronousCallbacks: false, protocol: new MessagePackHubProtocol(serializationContext))) var msgPackOptions = serviceProvider.GetRequiredService<IOptions<MessagePackHubProtocolOptions>>();
using (var client = new TestClient(synchronousCallbacks: false, protocol: new MessagePackHubProtocol(msgPackOptions)))
{ {
var transportFeature = new Mock<IConnectionTransportFeature>(); var transportFeature = new Mock<IConnectionTransportFeature>();
transportFeature.SetupGet(f => f.TransportCapabilities).Returns(TransferMode.Binary); transportFeature.SetupGet(f => f.TransportCapabilities).Returns(TransferMode.Binary);
@ -1633,7 +1636,7 @@ namespace Microsoft.AspNetCore.SignalR.Tests
var endPointLifetime = endPoint.OnConnectedAsync(client.Connection); var endPointLifetime = endPoint.OnConnectedAsync(client.Connection);
await client.Connected.OrTimeout(); await client.Connected.OrThrowIfOtherFails(endPointLifetime).OrTimeout();
await client.SendInvocationAsync(nameof(MethodHub.SendAnonymousObject)).OrTimeout(); await client.SendInvocationAsync(nameof(MethodHub.SendAnonymousObject)).OrTimeout();

View File

@ -3,40 +3,67 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Channels;
using Microsoft.AspNetCore.SignalR.Internal; using Microsoft.AspNetCore.SignalR.Internal;
using Microsoft.AspNetCore.SignalR.Internal.Protocol; using Microsoft.AspNetCore.SignalR.Internal.Protocol;
using Microsoft.AspNetCore.Sockets; using Microsoft.AspNetCore.Sockets;
using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Moq; using Moq;
using Newtonsoft.Json;
using Xunit; using Xunit;
namespace Microsoft.AspNetCore.SignalR.Common.Protocol.Tests namespace Microsoft.AspNetCore.SignalR.Common.Protocol.Tests
{ {
public class DefaultHubProtocolResolverTests public class DefaultHubProtocolResolverTests
{ {
private static readonly IList<IHubProtocol> AllProtocols = new List<IHubProtocol>()
{
new JsonHubProtocol(),
new MessagePackHubProtocol()
};
[Theory] [Theory]
[MemberData(nameof(HubProtocols))] [MemberData(nameof(HubProtocols))]
public void DefaultHubProtocolResolverTestsCanCreateSupportedProtocols(IHubProtocol protocol) public void DefaultHubProtocolResolverTestsCanCreateSupportedProtocols(IHubProtocol protocol)
{ {
var mockConnection = new Mock<HubConnectionContext>(new Mock<ConnectionContext>().Object, TimeSpan.FromSeconds(30), NullLoggerFactory.Instance); var mockConnection = new Mock<HubConnectionContext>(new Mock<ConnectionContext>().Object, TimeSpan.FromSeconds(30), NullLoggerFactory.Instance);
var resolver = new DefaultHubProtocolResolver(Options.Create(new HubOptions()), AllProtocols, NullLogger<DefaultHubProtocolResolver>.Instance);
Assert.IsType( Assert.IsType(
protocol.GetType(), protocol.GetType(),
new DefaultHubProtocolResolver(Options.Create(new HubOptions())).GetProtocol(protocol.Name, mockConnection.Object)); resolver.GetProtocol(protocol.Name, mockConnection.Object));
} }
[Theory] [Fact]
[InlineData(null)] public void DefaultHubProtocolResolverThrowsForNullProtocol()
[InlineData("dummy")]
public void DefaultHubProtocolResolverThrowsForNotSupportedProtocol(string protocolName)
{ {
var mockConnection = new Mock<HubConnectionContext>(new Mock<ConnectionContext>().Object, TimeSpan.FromSeconds(30), NullLoggerFactory.Instance); var mockConnection = new Mock<HubConnectionContext>(new Mock<ConnectionContext>().Object, TimeSpan.FromSeconds(30), NullLoggerFactory.Instance);
var exception = Assert.Throws<NotSupportedException>( var resolver = new DefaultHubProtocolResolver(Options.Create(new HubOptions()), AllProtocols, NullLogger<DefaultHubProtocolResolver>.Instance);
() => new DefaultHubProtocolResolver(Options.Create(new HubOptions())).GetProtocol(protocolName, mockConnection.Object)); var exception = Assert.Throws<ArgumentNullException>(
() => resolver.GetProtocol(null, mockConnection.Object));
Assert.Equal($"The protocol '{protocolName ?? "(null)"}' is not supported.", exception.Message); Assert.Equal("protocolName", exception.ParamName);
}
[Fact]
public void DefaultHubProtocolResolverThrowsForNotSupportedProtocol()
{
var mockConnection = new Mock<HubConnectionContext>(new Mock<ConnectionContext>().Object, TimeSpan.FromSeconds(30), NullLoggerFactory.Instance);
var resolver = new DefaultHubProtocolResolver(Options.Create(new HubOptions()), AllProtocols, NullLogger<DefaultHubProtocolResolver>.Instance);
var exception = Assert.Throws<NotSupportedException>(
() => resolver.GetProtocol("notARealProtocol", mockConnection.Object));
Assert.Equal("The protocol 'notARealProtocol' is not supported.", exception.Message);
}
[Fact]
public void RegisteringMultipleHubProtocolsFails()
{
var mockConnection = new Mock<HubConnectionContext>(new Mock<ConnectionContext>().Object, TimeSpan.FromSeconds(30), NullLoggerFactory.Instance);
var exception = Assert.Throws<InvalidOperationException>(() => new DefaultHubProtocolResolver(Options.Create(new HubOptions()), new[] {
new JsonHubProtocol(),
new JsonHubProtocol()
}, NullLogger<DefaultHubProtocolResolver>.Instance));
Assert.Equal($"Multiple Hub Protocols with the name '{JsonHubProtocol.ProtocolName}' were registered.", exception.Message);
} }
public static IEnumerable<object[]> HubProtocols => public static IEnumerable<object[]> HubProtocols =>

View File

@ -22,6 +22,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.SignalR.MsgPack\Microsoft.AspNetCore.SignalR.MsgPack.csproj" />
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.SignalR\Microsoft.AspNetCore.SignalR.csproj" /> <ProjectReference Include="..\..\src\Microsoft.AspNetCore.SignalR\Microsoft.AspNetCore.SignalR.csproj" />
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.SignalR.Client\Microsoft.AspNetCore.SignalR.Client.csproj" /> <ProjectReference Include="..\..\src\Microsoft.AspNetCore.SignalR.Client\Microsoft.AspNetCore.SignalR.Client.csproj" />
<ProjectReference Include="..\Microsoft.AspNetCore.SignalR.Tests.Utils\Microsoft.AspNetCore.SignalR.Tests.Utils.csproj" /> <ProjectReference Include="..\Microsoft.AspNetCore.SignalR.Tests.Utils\Microsoft.AspNetCore.SignalR.Tests.Utils.csproj" />

View File

@ -1,38 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using MsgPack.Serialization;
using Xunit;
namespace Microsoft.AspNetCore.SignalR.Tests
{
public class SignalRDependencyInjectionExtensionsTests
{
[Fact]
public void JSonSerializerSettingsShouldNotBeNullInOptions()
{
var services = new ServiceCollection();
services.AddOptions();
services.AddSignalR();
var serviceProvider = services.BuildServiceProvider();
var hubOptions = serviceProvider.GetService<IOptions<HubOptions>>();
Assert.NotNull(hubOptions.Value.JsonSerializerSettings);
}
[Fact]
public void MessagePackSerializationContextInOptionsIsSetAndHasDefaultSettings()
{
var services = new ServiceCollection();
services.AddOptions();
services.AddSignalR();
var serviceProvider = services.BuildServiceProvider();
var hubOptions = serviceProvider.GetService<IOptions<HubOptions>>();
var serializationContext = hubOptions.Value.MessagePackSerializationContext;
Assert.NotNull(serializationContext);
Assert.Equal(SerializationMethod.Map, serializationContext.SerializationMethod);
Assert.True(serializationContext.CompatibilityOptions.AllowAsymmetricSerializer);
}
}
}

View File

@ -1,4 +1,4 @@
{ {
"longRunningTestSeconds": 5, "longRunningTestSeconds": 30,
"diagnosticMessages": true "diagnosticMessages": true
} }