Refactor HubConnectionBuilder (#1830)

This commit is contained in:
James Newton-King 2018-04-04 21:19:13 +12:00 committed by GitHub
parent 99ae47be09
commit e7b84b753b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
44 changed files with 462 additions and 603 deletions

View File

@ -81,10 +81,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Signal
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.SignalR.Protocols.MsgPack", "src\Microsoft.AspNetCore.SignalR.Protocols.MsgPack\Microsoft.AspNetCore.SignalR.Protocols.MsgPack.csproj", "{55DB4B6F-12E5-4A27-97F4-E97E135470FF}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.SignalR.MsgPack", "src\Microsoft.AspNetCore.SignalR.MsgPack\Microsoft.AspNetCore.SignalR.MsgPack.csproj", "{FDDB4E1F-2FD2-49E8-B0FF-874B0931369A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.SignalR.Client.MsgPack", "src\Microsoft.AspNetCore.SignalR.Client.MsgPack\Microsoft.AspNetCore.SignalR.Client.MsgPack.csproj", "{4DBF918E-BD37-4309-B448-BA68C935944D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FunctionalTests", "clients\ts\FunctionalTests\FunctionalTests.csproj", "{D0C7B22E-B0B6-4D62-BF7D-79EE4AAF1981}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BenchmarkServer", "benchmarks\BenchmarkServer\BenchmarkServer.csproj", "{B5286020-C218-443C-91A9-B65751FB9B29}"
@ -195,14 +191,6 @@ Global
{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
{D0C7B22E-B0B6-4D62-BF7D-79EE4AAF1981}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D0C7B22E-B0B6-4D62-BF7D-79EE4AAF1981}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D0C7B22E-B0B6-4D62-BF7D-79EE4AAF1981}.Release|Any CPU.ActiveCfg = Release|Any CPU
@ -241,8 +229,6 @@ Global
{1A953296-E869-4DE2-A693-FD5FCDE27057} = {C4BC9889-B49F-41B6-806B-F84941B2549B}
{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}
{D0C7B22E-B0B6-4D62-BF7D-79EE4AAF1981} = {3A76C5A2-79ED-49BC-8BDC-6A3A766FFA1B}
{B5286020-C218-443C-91A9-B65751FB9B29} = {8A4582C8-DC59-4B61-BCE7-119FBAA99EFB}
EndGlobalSection

View File

@ -9,7 +9,7 @@
</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" />
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="$(MicrosoftAspNetCoreServerKestrelPackageVersion)" />

View File

@ -1,15 +1,18 @@
// 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.Buffers;
using System.IO.Pipelines;
using System.Threading.Tasks;
using BenchmarkDotNet.Attributes;
using Microsoft.AspNetCore.Connections;
using Microsoft.AspNetCore.Connections.Features;
using Microsoft.AspNetCore.SignalR.Client;
using Microsoft.AspNetCore.SignalR.Internal;
using Microsoft.AspNetCore.SignalR.Internal.Protocol;
using Microsoft.AspNetCore.SignalR.Microbenchmarks.Shared;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging.Abstractions;
namespace Microsoft.AspNetCore.SignalR.Microbenchmarks
@ -47,7 +50,12 @@ namespace Microsoft.AspNetCore.SignalR.Microbenchmarks
connection.Transport = _pipe;
var protocol = Protocol == "json" ? (IHubProtocol)new JsonHubProtocol() : new MessagePackHubProtocol();
_hubConnection = new HubConnection(() => connection, protocol, new NullLoggerFactory());
var hubConnectionBuilder = new HubConnectionBuilder();
hubConnectionBuilder.WithHubProtocol(protocol);
hubConnectionBuilder.WithConnectionFactory(() => connection);
_hubConnection = hubConnectionBuilder.Build();
_hubConnection.StartAsync().GetAwaiter().GetResult();
_arguments = new object[ArgumentCount];

View File

@ -13,6 +13,7 @@ using Microsoft.AspNetCore.SignalR.Client;
using Microsoft.AspNetCore.SignalR.Internal;
using Microsoft.AspNetCore.SignalR.Internal.Protocol;
using Microsoft.AspNetCore.SignalR.Microbenchmarks.Shared;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging.Abstractions;
namespace Microsoft.AspNetCore.SignalR.Microbenchmarks
@ -44,7 +45,11 @@ namespace Microsoft.AspNetCore.SignalR.Microbenchmarks
connection.Features.Set<IConnectionInherentKeepAliveFeature>(new TestConnectionInherentKeepAliveFeature());
connection.Transport = _pipe;
_hubConnection = new HubConnection(() => connection, new JsonHubProtocol(), new NullLoggerFactory());
var hubConnectionBuilder = new HubConnectionBuilder();
hubConnectionBuilder.WithHubProtocol(new JsonHubProtocol());
hubConnectionBuilder.WithConnectionFactory(() => connection);
_hubConnection = hubConnectionBuilder.Build();
}
private void AddHandshakeResponse()

View File

@ -19,7 +19,7 @@
</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" />
</ItemGroup>

View File

@ -1,5 +1,9 @@
using System.Net;
using System;
using System.Net;
using ClientSample;
using Microsoft.AspNetCore.Connections;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
namespace Microsoft.AspNetCore.SignalR.Client
{
@ -7,7 +11,7 @@ namespace Microsoft.AspNetCore.SignalR.Client
{
public static IHubConnectionBuilder WithEndPoint(this IHubConnectionBuilder builder, IPEndPoint endPoint)
{
builder.ConfigureConnectionFactory(() => new TcpConnection(endPoint));
builder.WithConnectionFactory(() => new TcpConnection(endPoint));
return builder;
}

View File

@ -28,13 +28,15 @@ namespace JwtClientSample
private async Task RunConnection(HttpTransportType transportType)
{
var userId = "C#" + transportType.ToString();
var userId = "C#" + transportType;
_tokens[userId] = await GetJwtToken(userId);
var hubConnection = new HubConnectionBuilder()
.WithUrl(ServerUrl + "/broadcast")
.WithTransport(transportType)
.WithAccessToken(() => _tokens[userId])
.WithUrl(ServerUrl + "/broadcast", options =>
{
options.Transport = transportType;
options.AccessTokenFactory = () => _tokens[userId];
})
.Build();
var closedTcs = new TaskCompletionSource<object>();

View File

@ -7,7 +7,7 @@
</PropertyGroup>
<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.Http.Connections\Microsoft.AspNetCore.Http.Connections.csproj" />
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.SignalR.Redis\Microsoft.AspNetCore.SignalR.Redis.csproj" />

View File

@ -391,12 +391,12 @@ namespace Microsoft.AspNetCore.Http.Connections.Client
}
httpMessageHandler = httpClientHandler;
if (_httpOptions.HttpMessageHandler != null)
if (_httpOptions.HttpMessageHandlerFactory != null)
{
httpMessageHandler = _httpOptions.HttpMessageHandler(httpClientHandler);
httpMessageHandler = _httpOptions.HttpMessageHandlerFactory(httpClientHandler);
if (httpMessageHandler == null)
{
throw new InvalidOperationException("Configured HttpMessageHandler did not return a value.");
throw new InvalidOperationException("Configured HttpMessageHandlerFactory did not return a value.");
}
}
}

View File

@ -13,10 +13,10 @@ namespace Microsoft.AspNetCore.Http.Connections.Client
public class HttpOptions
{
/// <summary>
/// Gets or sets a delegate for wrapping or replacing the <see cref="HttpMessageHandler"/>
/// Gets or sets a delegate for wrapping or replacing the <see cref="HttpMessageHandlerFactory"/>
/// that will make HTTP requests the server.
/// </summary>
public Func<HttpMessageHandler, HttpMessageHandler> HttpMessageHandler { get; set; }
public Func<HttpMessageHandler, HttpMessageHandler> HttpMessageHandlerFactory { get; set; }
public IReadOnlyCollection<KeyValuePair<string, string>> Headers { get; set; }
public Func<string> AccessTokenFactory { get; set; }

View File

@ -14,6 +14,7 @@ using Microsoft.AspNetCore.Connections;
using Microsoft.AspNetCore.Connections.Features;
using Microsoft.AspNetCore.SignalR.Internal;
using Microsoft.AspNetCore.SignalR.Internal.Protocol;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
@ -30,6 +31,7 @@ namespace Microsoft.AspNetCore.SignalR.Client
private readonly ILoggerFactory _loggerFactory;
private readonly ILogger _logger;
private readonly IHubProtocol _protocol;
private readonly IServiceProvider _serviceProvider;
private readonly Func<IConnection> _connectionFactory;
private readonly ConcurrentDictionary<string, List<InvocationHandler>> _handlers = new ConcurrentDictionary<string, List<InvocationHandler>>();
private bool _disposed;
@ -45,14 +47,11 @@ namespace Microsoft.AspNetCore.SignalR.Client
/// </summary>
public TimeSpan ServerTimeout { get; set; } = DefaultServerTimeout;
public HubConnection(Func<IConnection> connectionFactory, IHubProtocol protocol) : this(connectionFactory, protocol, NullLoggerFactory.Instance)
{
}
public HubConnection(Func<IConnection> connectionFactory, IHubProtocol protocol, ILoggerFactory loggerFactory)
public HubConnection(Func<IConnection> connectionFactory, IHubProtocol protocol, IServiceProvider serviceProvider, ILoggerFactory loggerFactory)
{
_connectionFactory = connectionFactory ?? throw new ArgumentNullException(nameof(connectionFactory));
_protocol = protocol ?? throw new ArgumentNullException(nameof(protocol));
_serviceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider));
_loggerFactory = loggerFactory ?? NullLoggerFactory.Instance;
_logger = _loggerFactory.CreateLogger<HubConnection>();
@ -185,6 +184,7 @@ namespace Microsoft.AspNetCore.SignalR.Client
if (disposing)
{
(_serviceProvider as IDisposable)?.Dispose();
_disposed = true;
}
}

View File

@ -2,72 +2,75 @@
// 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.ComponentModel;
using System.Linq;
using Microsoft.AspNetCore.Connections;
using Microsoft.AspNetCore.SignalR.Internal.Protocol;
using Newtonsoft.Json;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
namespace Microsoft.AspNetCore.SignalR.Client
{
public class HubConnectionBuilder : IHubConnectionBuilder
{
private readonly Dictionary<KeyValuePair<string, Type>, object> _settings = new Dictionary<KeyValuePair<string, Type>, object>();
private Func<IConnection> _connectionFactoryDelegate;
private bool _hubConnectionBuilt;
public void ConfigureConnectionFactory(Func<IConnection> connectionFactoryDelegate) =>
_connectionFactoryDelegate = connectionFactoryDelegate;
public IServiceCollection Services { get; }
public void AddSetting<T>(string name, T value)
public HubConnectionBuilder()
{
_settings[new KeyValuePair<string, Type>(name, typeof(T))] = value;
}
public bool TryGetSetting<T>(string name, out T value)
{
value = default;
if (!_settings.TryGetValue(new KeyValuePair<string, Type>(name, typeof(T)), out var setting))
{
return false;
}
value = (T)setting;
return true;
Services = new ServiceCollection();
Services.AddSingleton<ILoggerFactory>(NullLoggerFactory.Instance);
Services.AddSingleton<IHubProtocol, JsonHubProtocol>();
Services.AddSingleton<HubConnection>();
}
public HubConnection Build()
{
if (_connectionFactoryDelegate == null)
// Build can only be used once
if (_hubConnectionBuilt)
{
throw new InvalidOperationException("Cannot create IConnection instance. The connection factory was not configured.");
throw new InvalidOperationException("HubConnectionBuilder allows creation only of a single instance of HubConnection.");
}
IHubConnectionBuilder builder = this;
_hubConnectionBuilt = true;
var loggerFactory = builder.GetLoggerFactory();
var hubProtocol = builder.GetHubProtocol();
// The service provider is disposed by the HubConnection
var serviceProvider = Services.BuildServiceProvider();
return new HubConnection(_connectionFactoryDelegate, hubProtocol ?? new JsonHubProtocol(), loggerFactory);
var connectionFactory = serviceProvider.GetService<Func<IConnection>>();
if (connectionFactory == null)
{
throw new InvalidOperationException("Cannot create HubConnection instance. A connection was not configured.");
}
return serviceProvider.GetService<HubConnection>();
}
// Prevents from being displayed in intellisense
[EditorBrowsable(EditorBrowsableState.Never)]
public override int GetHashCode()
{
return base.GetHashCode();
}
// Prevents from being displayed in intellisense
[EditorBrowsable(EditorBrowsableState.Never)]
public override bool Equals(object obj)
{
return base.Equals(obj);
}
// Prevents from being displayed in intellisense
[EditorBrowsable(EditorBrowsableState.Never)]
public override string ToString()
{
return base.ToString();
}
// Prevents from being displayed in intellisense
[EditorBrowsable(EditorBrowsableState.Never)]
public new Type GetType()
{

View File

@ -1,11 +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.
namespace Microsoft.AspNetCore.SignalR.Client
{
public static class HubConnectionBuilderDefaults
{
public static readonly string LoggerFactoryKey = "LoggerFactory";
public static readonly string HubProtocolKey = "HubProtocol";
}
}

View File

@ -2,7 +2,9 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.AspNetCore.Connections;
using Microsoft.AspNetCore.SignalR.Internal.Protocol;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
@ -10,46 +12,34 @@ namespace Microsoft.AspNetCore.SignalR.Client
{
public static class HubConnectionBuilderExtensions
{
public static IHubConnectionBuilder WithHubProtocol(this IHubConnectionBuilder hubConnectionBuilder, IHubProtocol hubProtocol)
public static IHubConnectionBuilder WithConnectionFactory(this IHubConnectionBuilder hubConnectionBuilder, Func<IConnection> connectionFactory)
{
hubConnectionBuilder.AddSetting(HubConnectionBuilderDefaults.HubProtocolKey, hubProtocol);
hubConnectionBuilder.Services.AddSingleton(connectionFactory);
return hubConnectionBuilder;
}
public static IHubConnectionBuilder WithJsonProtocol(this IHubConnectionBuilder hubConnectionBuilder)
public static IHubConnectionBuilder WithHubProtocol(this IHubConnectionBuilder hubConnectionBuilder, IHubProtocol hubProtocol)
{
return hubConnectionBuilder.WithHubProtocol(new JsonHubProtocol());
}
public static IHubConnectionBuilder WithJsonProtocol(this IHubConnectionBuilder hubConnectionBuilder, JsonHubProtocolOptions options)
{
return hubConnectionBuilder.WithHubProtocol(new JsonHubProtocol(Options.Create(options)));
hubConnectionBuilder.Services.AddSingleton(hubProtocol);
return hubConnectionBuilder;
}
public static IHubConnectionBuilder WithLoggerFactory(this IHubConnectionBuilder hubConnectionBuilder, ILoggerFactory loggerFactory)
{
hubConnectionBuilder.AddSetting(HubConnectionBuilderDefaults.LoggerFactoryKey,
loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory)));
if (loggerFactory == null)
{
throw new ArgumentNullException(nameof(loggerFactory));
}
hubConnectionBuilder.Services.AddSingleton(loggerFactory);
return hubConnectionBuilder;
}
public static IHubConnectionBuilder WithLogger(this IHubConnectionBuilder hubConnectionBuilder, Action<ILoggerFactory> configureLogging)
{
var loggerFactory = hubConnectionBuilder.GetLoggerFactory() ?? new LoggerFactory();
var loggerFactory = new LoggerFactory();
configureLogging(loggerFactory);
return hubConnectionBuilder.WithLoggerFactory(loggerFactory);
}
public static ILoggerFactory GetLoggerFactory(this IHubConnectionBuilder hubConnectionBuilder)
{
hubConnectionBuilder.TryGetSetting<ILoggerFactory>(HubConnectionBuilderDefaults.LoggerFactoryKey, out var loggerFactory);
return loggerFactory;
}
public static IHubProtocol GetHubProtocol(this IHubConnectionBuilder hubConnectionBuilder)
{
hubConnectionBuilder.TryGetSetting<IHubProtocol>(HubConnectionBuilderDefaults.HubProtocolKey, out var hubProtocol);
return hubProtocol;
}
}
}
}

View File

@ -1,16 +1,10 @@
// 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 Microsoft.AspNetCore.Connections;
namespace Microsoft.AspNetCore.SignalR.Client
{
public interface IHubConnectionBuilder
public interface IHubConnectionBuilder : ISignalRBuilder
{
void AddSetting<T>(string name, T value);
bool TryGetSetting<T>(string name, out T value);
void ConfigureConnectionFactory(Func<IConnection> connectionFactoryDelegate);
HubConnection Build();
}
}

View File

@ -16,6 +16,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="$(MicrosoftExtensionsDependencyInjectionPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="$(MicrosoftExtensionsLoggingPackageVersion)" />
<PackageReference Include="System.Threading.Channels" Version="$(SystemThreadingChannelsPackageVersion)" />
</ItemGroup>

View File

@ -1,19 +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.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

@ -1,13 +0,0 @@
<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

@ -0,0 +1,68 @@
// 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.Net;
using System.Net.Http;
using System.Net.WebSockets;
using System.Security.Cryptography.X509Certificates;
using Microsoft.AspNetCore.Http.Connections;
namespace Microsoft.AspNetCore.SignalR.Client
{
public class HttpConnectionOptions
{
internal X509CertificateCollection _clientCertificates;
internal IDictionary<string, string> _headers;
internal CookieContainer _cookies;
public Uri Url { get; set; }
public HttpTransportType? Transport { get; set; }
public Func<HttpMessageHandler, HttpMessageHandler> MessageHandlerFactory { get; set; }
public bool? UseDefaultCredentials { get; set; }
public ICredentials Credentials { get; set; }
public IWebProxy Proxy { get; set; }
public Func<string> AccessTokenFactory { get; set; }
public Action<ClientWebSocketOptions> WebSocketOptions { get; set; }
public X509CertificateCollection ClientCertificates
{
get
{
if (_clientCertificates == null)
{
_clientCertificates = new X509CertificateCollection();
}
return _clientCertificates;
}
}
public CookieContainer Cookies
{
get
{
if (_cookies == null)
{
_cookies = new CookieContainer();
}
return _cookies;
}
}
public IDictionary<string, string> Headers
{
get
{
if (_headers == null)
{
_headers = new Dictionary<string, string>();
}
return _headers;
}
}
}
}

View File

@ -2,283 +2,101 @@
// 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.Collections.ObjectModel;
using System.Net;
using System.Net.Http;
using System.Net.WebSockets;
using System.Security.Cryptography.X509Certificates;
using Microsoft.AspNetCore.Connections;
using Microsoft.AspNetCore.Http.Connections;
using Microsoft.AspNetCore.Http.Connections.Client;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
namespace Microsoft.AspNetCore.SignalR.Client
{
public static class HubConnectionBuilderHttpExtensions
{
public static readonly string TransportTypeKey = "TransportType";
public static readonly string HttpMessageHandlerKey = "HttpMessageHandler";
public static readonly string HeadersKey = "Headers";
public static readonly string AccessTokenFactoryKey = "AccessTokenFactory";
public static readonly string WebSocketOptionsKey = "WebSocketOptions";
public static readonly string CookiesKey = "Cookies";
public static readonly string ProxyKey = "Proxy";
public static readonly string ClientCertificatesKey = "ClientCertificates";
public static readonly string CredentialsKey = "Credentials";
public static readonly string UseDefaultCredentialsKey = "UseDefaultCredentials";
public static IHubConnectionBuilder WithUrl(this IHubConnectionBuilder hubConnectionBuilder, string url)
{
if (url == null)
{
throw new ArgumentNullException(nameof(url));
}
hubConnectionBuilder.WithUrl(new Uri(url), null, _ => { });
return hubConnectionBuilder;
}
return hubConnectionBuilder.WithUrl(new Uri(url));
public static IHubConnectionBuilder WithUrl(this IHubConnectionBuilder hubConnectionBuilder, string url, Action<HttpConnectionOptions> configureHttpConnection)
{
hubConnectionBuilder.WithUrl(new Uri(url), null, configureHttpConnection);
return hubConnectionBuilder;
}
public static IHubConnectionBuilder WithUrl(this IHubConnectionBuilder hubConnectionBuilder, string url, HttpTransportType? transportType)
{
hubConnectionBuilder.WithUrl(new Uri(url), transportType, _ => { });
return hubConnectionBuilder;
}
public static IHubConnectionBuilder WithUrl(this IHubConnectionBuilder hubConnectionBuilder, string url, HttpTransportType? transportType, Action<HttpConnectionOptions> configureHttpConnection)
{
hubConnectionBuilder.WithUrl(new Uri(url), transportType, configureHttpConnection);
return hubConnectionBuilder;
}
public static IHubConnectionBuilder WithUrl(this IHubConnectionBuilder hubConnectionBuilder, Uri url)
{
if (url == null)
hubConnectionBuilder.WithUrl(url, null, _ => { });
return hubConnectionBuilder;
}
public static IHubConnectionBuilder WithUrl(this IHubConnectionBuilder hubConnectionBuilder, Uri url, Action<HttpConnectionOptions> configureHttpConnection)
{
hubConnectionBuilder.WithUrl(url, null, configureHttpConnection);
return hubConnectionBuilder;
}
public static IHubConnectionBuilder WithUrl(this IHubConnectionBuilder hubConnectionBuilder, Uri url, HttpTransportType? transportType)
{
hubConnectionBuilder.WithUrl(url, null, _ => { });
return hubConnectionBuilder;
}
public static IHubConnectionBuilder WithUrl(this IHubConnectionBuilder hubConnectionBuilder, Uri url, HttpTransportType? transportType, Action<HttpConnectionOptions> configureHttpConnection)
{
hubConnectionBuilder.Services.Configure<HttpConnectionOptions>(o =>
{
throw new ArgumentNullException(nameof(url));
o.Url = url;
o.Transport = transportType;
});
if (configureHttpConnection != null)
{
hubConnectionBuilder.Services.Configure(configureHttpConnection);
}
hubConnectionBuilder.ConfigureConnectionFactory(() =>
hubConnectionBuilder.Services.AddSingleton(services =>
{
var headers = hubConnectionBuilder.GetHeaders();
var value = services.GetService<IOptions<HttpConnectionOptions>>().Value;
var httpOptions = new HttpOptions
{
HttpMessageHandler = hubConnectionBuilder.GetMessageHandler(),
Headers = headers != null ? new ReadOnlyDictionary<string, string>(headers) : null,
AccessTokenFactory = hubConnectionBuilder.GetAccessTokenFactory(),
WebSocketOptions = hubConnectionBuilder.GetWebSocketOptions(),
Cookies = hubConnectionBuilder.GetCookies(),
Proxy = hubConnectionBuilder.GetProxy(),
UseDefaultCredentials = hubConnectionBuilder.GetUseDefaultCredentials(),
ClientCertificates = hubConnectionBuilder.GetClientCertificates(),
Credentials = hubConnectionBuilder.GetCredentials(),
HttpMessageHandlerFactory = value.MessageHandlerFactory,
Headers = value._headers != null ? new ReadOnlyDictionary<string, string>(value._headers) : null,
AccessTokenFactory = value.AccessTokenFactory,
WebSocketOptions = value.WebSocketOptions,
Cookies = value._cookies,
Proxy = value.Proxy,
UseDefaultCredentials = value.UseDefaultCredentials,
ClientCertificates = value._clientCertificates,
Credentials = value.Credentials,
};
return new HttpConnection(url,
hubConnectionBuilder.GetTransport(),
hubConnectionBuilder.GetLoggerFactory(),
Func<IConnection> createConnection = () => new HttpConnection(
value.Url,
value.Transport ?? HttpTransportType.All,
services.GetService<ILoggerFactory>(),
httpOptions);
return createConnection;
});
return hubConnectionBuilder;
}
public static IHubConnectionBuilder WithTransport(this IHubConnectionBuilder hubConnectionBuilder, HttpTransportType transportType)
{
hubConnectionBuilder.AddSetting(TransportTypeKey, transportType);
return hubConnectionBuilder;
}
/// <summary>
/// Sets a delegate for wrapping or replacing the <see cref="HttpMessageHandler"/> that will make HTTP requests the server.
/// </summary>
/// <param name="hubConnectionBuilder">The <see cref="IHubConnectionBuilder"/>.</param>
/// <param name="configurehttpMessageHandler">A delegate for wrapping or replacing the <see cref="HttpMessageHandler"/> that will make HTTP requests the server.</param>
/// <returns>The <see cref="IHubConnectionBuilder"/>.</returns>
public static IHubConnectionBuilder WithMessageHandler(this IHubConnectionBuilder hubConnectionBuilder, Func<HttpMessageHandler, HttpMessageHandler> configurehttpMessageHandler)
{
hubConnectionBuilder.AddSetting(HttpMessageHandlerKey, configurehttpMessageHandler);
return hubConnectionBuilder;
}
public static IHubConnectionBuilder WithHeader(this IHubConnectionBuilder hubConnectionBuilder, string name, string value)
{
if (string.IsNullOrEmpty(name))
{
throw new ArgumentException("Header name cannot be null or empty string.", nameof(name));
}
var headers = hubConnectionBuilder.GetHeaders();
if (headers == null)
{
headers = new Dictionary<string, string>();
hubConnectionBuilder.AddSetting(HeadersKey, headers);
}
headers.Add(name, value);
return hubConnectionBuilder;
}
public static IHubConnectionBuilder WithUseDefaultCredentials(this IHubConnectionBuilder hubConnectionBuilder, bool useDefaultCredentials)
{
hubConnectionBuilder.AddSetting<bool?>(UseDefaultCredentialsKey, useDefaultCredentials);
return hubConnectionBuilder;
}
public static IHubConnectionBuilder WithCredentials(this IHubConnectionBuilder hubConnectionBuilder, ICredentials credentials)
{
hubConnectionBuilder.AddSetting(CredentialsKey, credentials);
return hubConnectionBuilder;
}
public static IHubConnectionBuilder WithProxy(this IHubConnectionBuilder hubConnectionBuilder, IWebProxy proxy)
{
hubConnectionBuilder.AddSetting(ProxyKey, proxy);
return hubConnectionBuilder;
}
public static IHubConnectionBuilder WithCookie(this IHubConnectionBuilder hubConnectionBuilder, Cookie cookie)
{
if (cookie == null)
{
throw new ArgumentNullException(nameof(cookie));
}
var cookies = hubConnectionBuilder.GetCookies();
if (cookies == null)
{
cookies = new CookieContainer();
hubConnectionBuilder.AddSetting(CookiesKey, cookies);
}
cookies.Add(cookie);
return hubConnectionBuilder;
}
public static IHubConnectionBuilder WithClientCertificate(this IHubConnectionBuilder hubConnectionBuilder, X509Certificate clientCertificate)
{
if (clientCertificate == null)
{
throw new ArgumentNullException(nameof(clientCertificate));
}
var clientCertificates = hubConnectionBuilder.GetClientCertificates();
if (clientCertificates == null)
{
clientCertificates = new X509CertificateCollection();
hubConnectionBuilder.AddSetting(ClientCertificatesKey, clientCertificates);
}
clientCertificates.Add(clientCertificate);
return hubConnectionBuilder;
}
public static IHubConnectionBuilder WithAccessToken(this IHubConnectionBuilder hubConnectionBuilder, Func<string> accessTokenFactory)
{
if (accessTokenFactory == null)
{
throw new ArgumentNullException(nameof(accessTokenFactory));
}
hubConnectionBuilder.AddSetting(AccessTokenFactoryKey, accessTokenFactory);
return hubConnectionBuilder;
}
public static IHubConnectionBuilder WithWebSocketOptions(this IHubConnectionBuilder hubConnectionBuilder, Action<ClientWebSocketOptions> configureWebSocketOptions)
{
if (configureWebSocketOptions == null)
{
throw new ArgumentNullException(nameof(configureWebSocketOptions));
}
hubConnectionBuilder.AddSetting(WebSocketOptionsKey, configureWebSocketOptions);
return hubConnectionBuilder;
}
public static HttpTransportType GetTransport(this IHubConnectionBuilder hubConnectionBuilder)
{
if (hubConnectionBuilder.TryGetSetting<HttpTransportType>(TransportTypeKey, out var transportType))
{
return transportType;
}
return HttpTransportType.All;
}
/// <summary>
/// Gets a delegate for wrapping or replacing the <see cref="HttpMessageHandler"/> that will make HTTP requests the server.
/// </summary>
/// <param name="hubConnectionBuilder">The <see cref="IHubConnectionBuilder"/>.</param>
/// <returns>A delegate for wrapping or replacing the <see cref="HttpMessageHandler"/> that will make HTTP requests the server.</returns>
public static Func<HttpMessageHandler, HttpMessageHandler> GetMessageHandler(this IHubConnectionBuilder hubConnectionBuilder)
{
hubConnectionBuilder.TryGetSetting<Func<HttpMessageHandler, HttpMessageHandler>>(HttpMessageHandlerKey, out var messageHandler);
return messageHandler;
}
public static IDictionary<string, string> GetHeaders(this IHubConnectionBuilder hubConnectionBuilder)
{
if (hubConnectionBuilder.TryGetSetting<IDictionary<string, string>>(HeadersKey, out var headers))
{
return headers;
}
return null;
}
public static IWebProxy GetProxy(this IHubConnectionBuilder hubConnectionBuilder)
{
if (hubConnectionBuilder.TryGetSetting<IWebProxy>(ProxyKey, out var proxy))
{
return proxy;
}
return null;
}
public static bool? GetUseDefaultCredentials(this IHubConnectionBuilder hubConnectionBuilder)
{
if (hubConnectionBuilder.TryGetSetting<bool?>(UseDefaultCredentialsKey, out var useDefaultCredentials))
{
return useDefaultCredentials;
}
return null;
}
public static CookieContainer GetCookies(this IHubConnectionBuilder hubConnectionBuilder)
{
if (hubConnectionBuilder.TryGetSetting<CookieContainer>(CookiesKey, out var cookies))
{
return cookies;
}
return null;
}
public static ICredentials GetCredentials(this IHubConnectionBuilder hubConnectionBuilder)
{
if (hubConnectionBuilder.TryGetSetting<ICredentials>(CredentialsKey, out var credentials))
{
return credentials;
}
return null;
}
public static X509CertificateCollection GetClientCertificates(this IHubConnectionBuilder hubConnectionBuilder)
{
if (hubConnectionBuilder.TryGetSetting<X509CertificateCollection>(ClientCertificatesKey, out var clientCertificates))
{
return clientCertificates;
}
return null;
}
public static Func<string> GetAccessTokenFactory(this IHubConnectionBuilder hubConnectionBuilder)
{
if (hubConnectionBuilder.TryGetSetting<Func<string>>(AccessTokenFactoryKey, out var factory))
{
return factory;
}
return null;
}
public static Action<ClientWebSocketOptions> GetWebSocketOptions(this IHubConnectionBuilder hubConnectionBuilder)
{
hubConnectionBuilder.TryGetSetting<Action<ClientWebSocketOptions>>(WebSocketOptionsKey, out var webSocketOptions);
return webSocketOptions;
}
}
}

View File

@ -0,0 +1,9 @@
// 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.
namespace Microsoft.AspNetCore.SignalR
{
public interface ISignalRServerBuilder : ISignalRBuilder
{
}
}

View File

@ -16,7 +16,8 @@ namespace Microsoft.Extensions.DependencyInjection
/// </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, _ => { });
public static TBuilder AddJsonProtocol<TBuilder>(this TBuilder builder) where TBuilder : ISignalRBuilder
=> AddJsonProtocol(builder, _ => { });
/// <summary>
/// Enables the JSON protocol for SignalR and allows options for the JSON protocol to be configured.
@ -27,7 +28,7 @@ namespace Microsoft.Extensions.DependencyInjection
/// <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)
public static TBuilder AddJsonProtocol<TBuilder>(this TBuilder builder, Action<JsonHubProtocolOptions> configure) where TBuilder : ISignalRBuilder
{
builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<IHubProtocol, JsonHubProtocol>());
builder.Services.Configure(configure);

View File

@ -9,9 +9,9 @@ using Microsoft.Extensions.DependencyInjection;
namespace Microsoft.AspNetCore.SignalR
{
public class SignalRBuilder : ISignalRBuilder
public class SignalRServerBuilder : ISignalRServerBuilder
{
public SignalRBuilder(IServiceCollection services)
public SignalRServerBuilder(IServiceCollection services)
{
Services = services;
}

View File

@ -9,7 +9,7 @@ namespace Microsoft.Extensions.DependencyInjection
{
public static class SignalRDependencyInjectionExtensions
{
public static ISignalRBuilder AddSignalRCore(this IServiceCollection services)
public static ISignalRServerBuilder AddSignalRCore(this IServiceCollection services)
{
services.AddSingleton(typeof(HubLifetimeManager<>), typeof(DefaultHubLifetimeManager<>));
services.AddSingleton(typeof(IHubProtocolResolver), typeof(DefaultHubProtocolResolver));
@ -22,7 +22,7 @@ namespace Microsoft.Extensions.DependencyInjection
services.AddAuthorization();
return new SignalRBuilder(services);
return new SignalRServerBuilder(services);
}
}
}

View File

@ -1,14 +0,0 @@
<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

@ -16,7 +16,8 @@ namespace Microsoft.Extensions.DependencyInjection
/// </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, _ => { });
public static TBuilder AddMessagePackProtocol<TBuilder>(this TBuilder builder) where TBuilder : ISignalRBuilder
=> AddMessagePackProtocol(builder, _ => { });
/// <summary>
/// Enables the MsgPack protocol for SignalR and allows options for the MsgPack protocol to be configured.
@ -27,7 +28,7 @@ namespace Microsoft.Extensions.DependencyInjection
/// <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)
public static TBuilder AddMessagePackProtocol<TBuilder>(this TBuilder builder, Action<MessagePackHubProtocolOptions> configure) where TBuilder : ISignalRBuilder
{
builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<IHubProtocol, MessagePackHubProtocol>());
builder.Services.Configure(configure);

View File

@ -10,12 +10,12 @@ namespace Microsoft.Extensions.DependencyInjection
{
public static class RedisDependencyInjectionExtensions
{
public static ISignalRBuilder AddRedis(this ISignalRBuilder builder)
public static ISignalRServerBuilder AddRedis(this ISignalRServerBuilder builder)
{
return AddRedis(builder, o => { });
}
public static ISignalRBuilder AddRedis(this ISignalRBuilder builder, string redisConnectionString)
public static ISignalRServerBuilder AddRedis(this ISignalRServerBuilder builder, string redisConnectionString)
{
return AddRedis(builder, o =>
{
@ -23,7 +23,7 @@ namespace Microsoft.Extensions.DependencyInjection
});
}
public static ISignalRBuilder AddRedis(this ISignalRBuilder builder, Action<RedisOptions> configure)
public static ISignalRServerBuilder AddRedis(this ISignalRServerBuilder builder, Action<RedisOptions> configure)
{
builder.Services.Configure(configure);
builder.Services.AddSingleton(typeof(HubLifetimeManager<>), typeof(RedisHubLifetimeManager<>));

View File

@ -9,7 +9,7 @@ namespace Microsoft.Extensions.DependencyInjection
{
public static class HubOptionsDependencyInjectionExtensions
{
public static ISignalRBuilder AddHubOptions<THub>(this ISignalRBuilder signalrBuilder, Action<HubOptions<THub>> options) where THub : Hub
public static ISignalRServerBuilder AddHubOptions<THub>(this ISignalRServerBuilder signalrBuilder, Action<HubOptions<THub>> options) where THub : Hub
{
signalrBuilder.Services.AddSingleton<IConfigureOptions<HubOptions<THub>>, HubOptionsSetup<THub>>();
signalrBuilder.Services.Configure(options);

View File

@ -9,7 +9,7 @@ namespace Microsoft.Extensions.DependencyInjection
{
public static class SignalRDependencyInjectionExtensions
{
public static ISignalRBuilder AddSignalR(this IServiceCollection services)
public static ISignalRServerBuilder AddSignalR(this IServiceCollection services)
{
services.AddConnections();
services.AddSingleton<SignalRMarkerService>();
@ -18,7 +18,7 @@ namespace Microsoft.Extensions.DependencyInjection
.AddJsonProtocol();
}
public static ISignalRBuilder AddSignalR(this IServiceCollection services, Action<HubOptions> options)
public static ISignalRServerBuilder AddSignalR(this IServiceCollection services, Action<HubOptions> options)
{
return services.Configure(options)
.AddSignalR();

View File

@ -14,6 +14,7 @@ using Microsoft.AspNetCore.Http.Connections.Client;
using Microsoft.AspNetCore.SignalR.Internal.Protocol;
using Microsoft.AspNetCore.SignalR.Tests;
using Microsoft.AspNetCore.Testing.xunit;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Testing;
using Xunit;
@ -42,6 +43,25 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
_serverFixture = serverFixture;
}
private HubConnection CreateHubConnection(
string path = null,
HttpTransportType? transportType = null,
IHubProtocol protocol = null,
ILoggerFactory loggerFactory = null)
{
var hubConnectionBuilder = new HubConnectionBuilder();
hubConnectionBuilder.WithHubProtocol(protocol);
hubConnectionBuilder.WithLoggerFactory(loggerFactory);
hubConnectionBuilder.WithConnectionFactory(GetHttpConnectionFactory(loggerFactory, path, transportType ?? HttpTransportType.All));
return hubConnectionBuilder.Build();
}
private Func<IConnection> GetHttpConnectionFactory(ILoggerFactory loggerFactory, string path, HttpTransportType transportType)
{
return () => new HttpConnection(new Uri(_serverFixture.Url + path), transportType, loggerFactory);
}
[Theory]
[MemberData(nameof(HubProtocolsAndTransportsAndHubPaths))]
public async Task CheckFixedMessage(string protocolName, HttpTransportType transportType, string path)
@ -50,10 +70,9 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
using (StartLog(out var loggerFactory, $"{nameof(CheckFixedMessage)}_{protocol.Name}_{transportType}_{path.TrimStart('/')}"))
{
var connection = new HubConnectionBuilder()
.WithUrl(_serverFixture.Url + path)
.WithTransport(transportType)
.WithLoggerFactory(loggerFactory)
.WithHubProtocol(protocol)
.WithUrl(_serverFixture.Url + path, transportType)
.Build();
try
@ -84,7 +103,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
using (StartLog(out var loggerFactory, $"{nameof(CanSendAndReceiveMessage)}_{protocol.Name}_{transportType}_{path.TrimStart('/')}"))
{
const string originalMessage = "SignalR";
var connection = new HubConnection(GetHttpConnectionFactory(loggerFactory, path, transportType), protocol, loggerFactory);
var connection = CreateHubConnection(path, transportType, protocol, loggerFactory);
try
{
await connection.StartAsync().OrTimeout();
@ -113,7 +132,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
using (StartLog(out var loggerFactory, LogLevel.Trace, $"{nameof(CanStopAndStartConnection)}_{protocol.Name}_{transportType}_{path.TrimStart('/')}"))
{
const string originalMessage = "SignalR";
var connection = new HubConnection(GetHttpConnectionFactory(loggerFactory, path, transportType), protocol, loggerFactory);
var connection = CreateHubConnection(path, transportType, protocol, loggerFactory);
try
{
await connection.StartAsync().OrTimeout();
@ -146,7 +165,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
var logger = loggerFactory.CreateLogger<HubConnectionTests>();
const string originalMessage = "SignalR";
var connection = new HubConnection(GetHttpConnectionFactory(loggerFactory, "/default", transportType), new JsonHubProtocol(), loggerFactory);
var connection = CreateHubConnection(path, transportType, protocol, loggerFactory);
var restartTcs = new TaskCompletionSource<object>();
connection.Closed += async e =>
{
@ -189,11 +208,6 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
}
}
private Func<IConnection> GetHttpConnectionFactory(ILoggerFactory loggerFactory, string path, HttpTransportType transportType)
{
return () => new HttpConnection(new Uri(_serverFixture.Url + path), transportType, loggerFactory);
}
[Theory]
[MemberData(nameof(HubProtocolsAndTransportsAndHubPaths))]
public async Task MethodsAreCaseInsensitive(string protocolName, HttpTransportType transportType, string path)
@ -202,8 +216,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
using (StartLog(out var loggerFactory, $"{nameof(MethodsAreCaseInsensitive)}_{protocol.Name}_{transportType}_{path.TrimStart('/')}"))
{
const string originalMessage = "SignalR";
var uriString = "http://test/" + path;
var connection = new HubConnection(GetHttpConnectionFactory(loggerFactory, path, transportType), protocol, loggerFactory);
var connection = CreateHubConnection(path, transportType, protocol, loggerFactory);
try
{
await connection.StartAsync().OrTimeout();
@ -233,7 +246,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
{
const string originalMessage = "SignalR";
var connection = new HubConnection(GetHttpConnectionFactory(loggerFactory, path, transportType), protocol, loggerFactory);
var connection = CreateHubConnection(path, transportType, protocol, loggerFactory);
try
{
await connection.StartAsync().OrTimeout();
@ -264,7 +277,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
var protocol = HubProtocols[protocolName];
using (StartLog(out var loggerFactory, LogLevel.Trace, $"{nameof(InvokeNonExistantClientMethodFromServer)}_{protocol.Name}_{transportType}_{path.TrimStart('/')}"))
{
var connection = new HubConnection(GetHttpConnectionFactory(loggerFactory, path, transportType), protocol, loggerFactory);
var connection = CreateHubConnection(path, transportType, protocol, loggerFactory);
var closeTcs = new TaskCompletionSource<object>();
connection.Closed += e =>
{
@ -304,7 +317,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
var protocol = HubProtocols[protocolName];
using (StartLog(out var loggerFactory, LogLevel.Trace, $"{nameof(CanStreamClientMethodFromServer)}_{protocol.Name}_{transportType}_{path.TrimStart('/')}"))
{
var connection = new HubConnection(GetHttpConnectionFactory(loggerFactory, path, transportType), protocol, loggerFactory);
var connection = CreateHubConnection(path, transportType, protocol, loggerFactory);
try
{
await connection.StartAsync().OrTimeout();
@ -333,7 +346,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
var protocol = HubProtocols[protocolName];
using (StartLog(out var loggerFactory, $"{nameof(CanCloseStreamMethodEarly)}_{protocol.Name}_{transportType}_{path.TrimStart('/')}"))
{
var connection = new HubConnection(GetHttpConnectionFactory(loggerFactory, path, transportType), protocol, loggerFactory);
var connection = CreateHubConnection(path, transportType, protocol, loggerFactory);
try
{
await connection.StartAsync().OrTimeout();
@ -373,10 +386,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
var protocol = HubProtocols[protocolName];
using (StartLog(out var loggerFactory, LogLevel.Trace, $"{nameof(StreamDoesNotStartIfTokenAlreadyCanceled)}_{protocol.Name}_{transportType}_{path.TrimStart('/')}"))
{
var connection =
new HubConnection(
GetHttpConnectionFactory(loggerFactory, path, transportType), protocol,
loggerFactory);
var connection = CreateHubConnection(path, transportType, protocol, loggerFactory);
try
{
await connection.StartAsync().OrTimeout();
@ -408,7 +418,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
var protocol = HubProtocols[protocolName];
using (StartLog(out var loggerFactory, $"{nameof(ExceptionFromStreamingSentToClient)}_{protocol.Name}_{transportType}_{path.TrimStart('/')}"))
{
var connection = new HubConnection(GetHttpConnectionFactory(loggerFactory, path, transportType), protocol, loggerFactory);
var connection = CreateHubConnection(path, transportType, protocol, loggerFactory);
try
{
await connection.StartAsync().OrTimeout();
@ -436,7 +446,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
var hubProtocol = HubProtocols[hubProtocolName];
using (StartLog(out var loggerFactory, $"{nameof(ServerThrowsHubExceptionIfHubMethodCannotBeResolved)}_{hubProtocol.Name}_{transportType}_{hubPath.TrimStart('/')}"))
{
var connection = new HubConnection(GetHttpConnectionFactory(loggerFactory, hubPath, transportType), hubProtocol, loggerFactory);
var connection = CreateHubConnection(hubPath, transportType, hubProtocol, loggerFactory);
try
{
await connection.StartAsync().OrTimeout();
@ -463,7 +473,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
var hubProtocol = HubProtocols[hubProtocolName];
using (StartLog(out var loggerFactory, $"{nameof(ServerThrowsHubExceptionOnHubMethodArgumentCountMismatch)}_{hubProtocol.Name}_{transportType}_{hubPath.TrimStart('/')}"))
{
var connection = new HubConnection(GetHttpConnectionFactory(loggerFactory, hubPath, transportType), hubProtocol, loggerFactory);
var connection = CreateHubConnection(hubPath, transportType, hubProtocol, loggerFactory);
try
{
await connection.StartAsync().OrTimeout();
@ -490,7 +500,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
var hubProtocol = HubProtocols[hubProtocolName];
using (StartLog(out var loggerFactory, $"{nameof(ServerThrowsHubExceptionOnHubMethodArgumentTypeMismatch)}_{hubProtocol.Name}_{transportType}_{hubPath.TrimStart('/')}"))
{
var connection = new HubConnection(GetHttpConnectionFactory(loggerFactory, hubPath, transportType), hubProtocol, loggerFactory);
var connection = CreateHubConnection(hubPath, transportType, hubProtocol, loggerFactory);
try
{
await connection.StartAsync().OrTimeout();
@ -517,7 +527,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
var hubProtocol = HubProtocols[hubProtocolName];
using (StartLog(out var loggerFactory, $"{nameof(ServerThrowsHubExceptionIfStreamingHubMethodCannotBeResolved)}_{hubProtocol.Name}_{transportType}_{hubPath.TrimStart('/')}"))
{
var connection = new HubConnection(GetHttpConnectionFactory(loggerFactory, hubPath, transportType), hubProtocol, loggerFactory);
var connection = CreateHubConnection(hubPath, transportType, hubProtocol, loggerFactory);
try
{
await connection.StartAsync().OrTimeout();
@ -546,7 +556,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
using (StartLog(out var loggerFactory, $"{nameof(ServerThrowsHubExceptionOnStreamingHubMethodArgumentCountMismatch)}_{hubProtocol.Name}_{transportType}_{hubPath.TrimStart('/')}"))
{
loggerFactory.AddConsole(LogLevel.Trace);
var connection = new HubConnection(GetHttpConnectionFactory(loggerFactory, hubPath, transportType), hubProtocol, loggerFactory);
var connection = CreateHubConnection(hubPath, transportType, hubProtocol, loggerFactory);
try
{
await connection.StartAsync().OrTimeout();
@ -574,7 +584,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
var hubProtocol = HubProtocols[hubProtocolName];
using (StartLog(out var loggerFactory, $"{nameof(ServerThrowsHubExceptionOnStreamingHubMethodArgumentTypeMismatch)}_{hubProtocol.Name}_{transportType}_{hubPath.TrimStart('/')}"))
{
var connection = new HubConnection(GetHttpConnectionFactory(loggerFactory, hubPath, transportType), hubProtocol, loggerFactory);
var connection = CreateHubConnection(hubPath, transportType, hubProtocol, loggerFactory);
try
{
await connection.StartAsync().OrTimeout();
@ -602,7 +612,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
var hubProtocol = HubProtocols[hubProtocolName];
using (StartLog(out var loggerFactory, $"{nameof(ServerThrowsHubExceptionIfNonStreamMethodInvokedWithStreamAsync)}_{hubProtocol.Name}_{transportType}_{hubPath.TrimStart('/')}"))
{
var connection = new HubConnection(GetHttpConnectionFactory(loggerFactory, hubPath, transportType), hubProtocol, loggerFactory);
var connection = CreateHubConnection(hubPath, transportType, hubProtocol, loggerFactory);
try
{
await connection.StartAsync().OrTimeout();
@ -629,7 +639,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
var hubProtocol = HubProtocols[hubProtocolName];
using (StartLog(out var loggerFactory, $"{nameof(ServerThrowsHubExceptionIfStreamMethodInvokedWithInvoke)}_{hubProtocol.Name}_{transportType}_{hubPath.TrimStart('/')}"))
{
var connection = new HubConnection(GetHttpConnectionFactory(loggerFactory, hubPath, transportType), hubProtocol, loggerFactory);
var connection = CreateHubConnection(hubPath, transportType, hubProtocol, loggerFactory);
try
{
await connection.StartAsync().OrTimeout();
@ -656,7 +666,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
var hubProtocol = HubProtocols[hubProtocolName];
using (StartLog(out var loggerFactory, $"{nameof(ServerThrowsHubExceptionIfBuildingAsyncEnumeratorIsNotPossible)}_{hubProtocol.Name}_{transportType}_{hubPath.TrimStart('/')}"))
{
var connection = new HubConnection(GetHttpConnectionFactory(loggerFactory, hubPath, transportType), hubProtocol, loggerFactory);
var connection = CreateHubConnection(hubPath, transportType, hubProtocol, loggerFactory);
try
{
await connection.StartAsync().OrTimeout();
@ -687,10 +697,11 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
var token = await httpResponse.Content.ReadAsStringAsync();
var hubConnection = new HubConnectionBuilder()
.WithUrl(_serverFixture.Url + "/authorizedhub")
.WithTransport(transportType)
.WithLoggerFactory(loggerFactory)
.WithAccessToken(() => token)
.WithUrl(_serverFixture.Url + "/authorizedhub", transportType, options =>
{
options.AccessTokenFactory = () => token;
})
.Build();
try
{
@ -717,11 +728,12 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
using (StartLog(out var loggerFactory, $"{nameof(ClientCanSendHeaders)}_{transportType}"))
{
var hubConnection = new HubConnectionBuilder()
.WithUrl(_serverFixture.Url + "/default")
.WithTransport(transportType)
.WithLoggerFactory(loggerFactory)
.WithHeader("X-test", "42")
.WithHeader("X-42", "test")
.WithUrl(_serverFixture.Url + "/default", transportType, options =>
{
options.Headers["X-test"] = "42";
options.Headers["X-42"] = "test";
})
.Build();
try
{
@ -747,15 +759,16 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
{
using (StartLog(out var loggerFactory, $"{nameof(WebSocketOptionsAreApplied)}"))
{
// System.Net has a TransportType type which means we need to fully-qualify this rather than 'use' the namespace
// System.Net has a HttpTransportType type which means we need to fully-qualify this rather than 'use' the namespace
var cookieJar = new System.Net.CookieContainer();
cookieJar.Add(new System.Net.Cookie("Foo", "Bar", "/", new Uri(_serverFixture.Url).Host));
var hubConnection = new HubConnectionBuilder()
.WithUrl(_serverFixture.Url + "/default")
.WithTransport(HttpTransportType.WebSockets)
.WithLoggerFactory(loggerFactory)
.WithWebSocketOptions(options => options.Cookies = cookieJar)
.WithUrl(_serverFixture.Url + "/default", HttpTransportType.WebSockets, options =>
{
options.WebSocketOptions = o => o.Cookies = cookieJar;
})
.Build();
try
{
@ -782,9 +795,8 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
using (StartLog(out var loggerFactory, $"{nameof(CheckHttpConnectionFeatures)}_{transportType}"))
{
var hubConnection = new HubConnectionBuilder()
.WithUrl(_serverFixture.Url + "/default")
.WithTransport(transportType)
.WithLoggerFactory(loggerFactory)
.WithUrl(_serverFixture.Url + "/default", transportType)
.Build();
try
{
@ -819,9 +831,9 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
using (StartLog(out var loggerFactory))
{
var hubConnection = new HubConnectionBuilder()
.WithUrl(_serverFixture.Url + "/default-nowebsockets")
.WithHubProtocol(new MessagePackHubProtocol())
.WithLoggerFactory(loggerFactory)
.WithHubProtocol(new MessagePackHubProtocol())
.WithUrl(_serverFixture.Url + "/default-nowebsockets")
.Build();
try
{

View File

@ -15,7 +15,6 @@
</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.Client\Microsoft.AspNetCore.SignalR.Client.csproj" />

View File

@ -17,7 +17,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
{
var httpOptions = new HttpOptions()
{
HttpMessageHandler = (httpMessageHandler) => httpHandler ?? TestHttpMessageHandler.CreateDefault(),
HttpMessageHandlerFactory = (httpMessageHandler) => httpHandler ?? TestHttpMessageHandler.CreateDefault(),
};
return CreateConnection(httpOptions, loggerFactory, url, transport, transportFactory, transportType);

View File

@ -63,7 +63,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
HttpClientHandler httpClientHandler = null;
var httpOptions = new HttpOptions();
httpOptions.HttpMessageHandler = inner =>
httpOptions.HttpMessageHandlerFactory = inner =>
{
httpClientHandler = (HttpClientHandler)inner;
return testHttpHandler;
@ -99,7 +99,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
testHttpHandler.OnNegotiate((request, cancellationToken) => ResponseUtils.CreateResponse(HttpStatusCode.BadGateway));
var httpOptions = new HttpOptions();
httpOptions.HttpMessageHandler = inner => testHttpHandler;
httpOptions.HttpMessageHandlerFactory = inner => testHttpHandler;
const string loggerName = "Microsoft.AspNetCore.Http.Connections.Client.Internal.LoggingHttpMessageHandler";
var testSink = new TestSink();

View File

@ -2,14 +2,12 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Security.Cryptography.X509Certificates;
using Microsoft.AspNetCore.Http.Connections;
using Microsoft.AspNetCore.SignalR.Internal.Protocol;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Console;
using Microsoft.Extensions.Options;
using Moq;
using Xunit;
@ -18,114 +16,100 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
public class HubConnectionBuilderExtensionsTests
{
[Fact]
public void WithProxyRegistersGivenProxy()
public void WithHttpConnectionSetsUrl()
{
var connectionBuilder = new HubConnectionBuilder();
connectionBuilder.WithUrl("http://tempuri.org");
var serviceProvider = connectionBuilder.Services.BuildServiceProvider();
var value = serviceProvider.GetService<IOptions<HttpConnectionOptions>>().Value;
Assert.Equal(new Uri("http://tempuri.org"), value.Url);
}
[Fact]
public void WithHttpConnectionSetsTransport()
{
var connectionBuilder = new HubConnectionBuilder();
connectionBuilder.WithUrl("http://tempuri.org", HttpTransportType.LongPolling);
var serviceProvider = connectionBuilder.Services.BuildServiceProvider();
var value = serviceProvider.GetService<IOptions<HttpConnectionOptions>>().Value;
Assert.Equal(HttpTransportType.LongPolling, value.Transport);
}
[Fact]
public void WithHttpConnectionCallsConfigure()
{
var proxy = Mock.Of<IWebProxy>();
connectionBuilder.WithProxy(proxy);
Assert.Same(proxy, connectionBuilder.GetProxy());
var connectionBuilder = new HubConnectionBuilder();
connectionBuilder.WithUrl("http://tempuri.org", options => { options.Proxy = proxy; });
var serviceProvider = connectionBuilder.Services.BuildServiceProvider();
var value = serviceProvider.GetService<IOptions<HttpConnectionOptions>>().Value;
Assert.Same(proxy, value.Proxy);
}
[Fact]
public void WithCredentialsRegistersGivenCredentials()
public void WithConsoleLoggerAddsLogger()
{
var loggingFactory = Mock.Of<ILoggerFactory>();
var connectionBuilder = new HubConnectionBuilder();
var credentials = Mock.Of<ICredentials>();
connectionBuilder.WithCredentials(credentials);
Assert.Same(credentials, connectionBuilder.GetCredentials());
connectionBuilder.WithLoggerFactory(loggingFactory);
var serviceProvider = connectionBuilder.Services.BuildServiceProvider();
var resolvedLoggingFactory = serviceProvider.GetService<ILoggerFactory>();
Assert.Same(resolvedLoggingFactory, loggingFactory);
}
[Fact]
public void WithUseDefaultCredentialsRegistersGivenUseDefaultCredentials()
public void WithHubProtocolAddsProtocol()
{
var connectionBuilder = new HubConnectionBuilder();
var useDefaultCredentials = true;
connectionBuilder.WithUseDefaultCredentials(useDefaultCredentials);
Assert.Equal(useDefaultCredentials, connectionBuilder.GetUseDefaultCredentials());
}
[Fact]
public void WithClientCertificateRegistersGivenClientCertificate()
{
var connectionBuilder = new HubConnectionBuilder();
var certificate = new X509Certificate();
connectionBuilder.WithClientCertificate(certificate);
Assert.Contains(certificate, connectionBuilder.GetClientCertificates().Cast<X509Certificate>());
}
[Fact]
public void WithCookieRegistersGivenCookie()
{
var connectionBuilder = new HubConnectionBuilder();
var cookie = new Cookie("Name!", "Value!", string.Empty, "www.contoso.com");
connectionBuilder.WithCookie(cookie);
Assert.Equal(1, connectionBuilder.GetCookies().Count);
}
[Fact]
public void WithHubProtocolRegistersGivenProtocol()
{
var connectionBuilder = new HubConnectionBuilder();
var hubProtocol = Mock.Of<IHubProtocol>();
var connectionBuilder = new HubConnectionBuilder();
connectionBuilder.WithHubProtocol(hubProtocol);
Assert.Same(hubProtocol, connectionBuilder.GetHubProtocol());
var serviceProvider = connectionBuilder.Services.BuildServiceProvider();
var resolvedHubProtocol = serviceProvider.GetService<IHubProtocol>();
Assert.Same(hubProtocol, resolvedHubProtocol);
}
[Fact]
public void WithJsonProtocolRegistersJsonProtocol()
public void AddJsonProtocolAddsProtocol()
{
var connectionBuilder = new HubConnectionBuilder();
connectionBuilder.WithJsonProtocol();
Assert.IsType<JsonHubProtocol>(connectionBuilder.GetHubProtocol());
connectionBuilder.AddJsonProtocol();
var serviceProvider = connectionBuilder.Services.BuildServiceProvider();
var resolvedHubProtocol = serviceProvider.GetService<IHubProtocol>();
Assert.IsType<JsonHubProtocol>(resolvedHubProtocol);
}
[Fact]
public void WithMessagePackProtocolRegistersMessagePackProtocol()
public void AddMessagePackProtocolAddsProtocol()
{
var connectionBuilder = new HubConnectionBuilder();
connectionBuilder.WithMessagePackProtocol();
Assert.IsType<MessagePackHubProtocol>(connectionBuilder.GetHubProtocol());
}
connectionBuilder.AddMessagePackProtocol();
[Fact]
public void WithLoggerRegistersGivenLogger()
{
var connectionBuilder = new HubConnectionBuilder();
var loggerFactory = Mock.Of<ILoggerFactory>();
connectionBuilder.WithLoggerFactory(loggerFactory);
Assert.Same(loggerFactory, connectionBuilder.GetLoggerFactory());
}
var serviceProvider = connectionBuilder.Services.BuildServiceProvider();
[Fact]
public void WithConsoleLoggerRegistersConsoleLogger()
{
var connectionBuilder = new HubConnectionBuilder();
var mockLoggerFactory = new Mock<ILoggerFactory>();
connectionBuilder.WithLoggerFactory(mockLoggerFactory.Object);
connectionBuilder.WithConsoleLogger();
mockLoggerFactory.Verify(f => f.AddProvider(It.IsAny<ConsoleLoggerProvider>()), Times.Once);
}
var resolvedHubProtocol = serviceProvider.GetService<IHubProtocol>();
[Fact]
public void WithMsgHandlerRegistersGivenMessageHandler()
{
var messageHandler = new Func<HttpMessageHandler, HttpMessageHandler>(httpMessageHandler => default);
var connectionBuilder = new HubConnectionBuilder();
connectionBuilder.WithMessageHandler(messageHandler);
Assert.Same(messageHandler, connectionBuilder.GetMessageHandler());
}
[Theory]
[InlineData(HttpTransportType.All)]
[InlineData(HttpTransportType.WebSockets)]
[InlineData(HttpTransportType.ServerSentEvents)]
[InlineData(HttpTransportType.LongPolling)]
public void WithTransportRegistersGivenTransportType(HttpTransportType transportType)
{
var connectionBuilder = new HubConnectionBuilder();
connectionBuilder.WithTransport(transportType);
Assert.Equal(transportType, connectionBuilder.GetTransport());
Assert.IsType<MessagePackHubProtocol>(resolvedHubProtocol);
}
}
}
}

View File

@ -2,7 +2,10 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Linq;
using Microsoft.AspNetCore.Connections;
using Microsoft.AspNetCore.SignalR.Internal.Protocol;
using Microsoft.Extensions.DependencyInjection;
using MsgPack.Serialization;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
@ -16,16 +19,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
public void HubConnectionBuiderThrowsIfConnectionFactoryNotConfigured()
{
var ex = Assert.Throws<InvalidOperationException>(() => new HubConnectionBuilder().Build());
Assert.Equal("Cannot create IConnection instance. The connection factory was not configured.", ex.Message);
}
[Fact]
public void WithUrlThrowsForNullUrls()
{
Assert.Equal("url",
Assert.Throws<ArgumentNullException>(() => new HubConnectionBuilder().WithUrl((string)null)).ParamName);
Assert.Equal("url",
Assert.Throws<ArgumentNullException>(() => new HubConnectionBuilder().WithUrl((Uri)null)).ParamName);
Assert.Equal("Cannot create HubConnection instance. A connection was not configured.", ex.Message);
}
[Fact]
@ -36,50 +30,71 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
}
[Fact]
public void WithJsonHubProtocolSetsHubProtocolToJsonWithDefaultOptions()
public void AddJsonProtocolSetsHubProtocolToJsonWithDefaultOptions()
{
Assert.True(new HubConnectionBuilder().WithJsonProtocol().TryGetSetting<IHubProtocol>(HubConnectionBuilderDefaults.HubProtocolKey, out var hubProtocol));
var actualProtocol = Assert.IsType<JsonHubProtocol>(hubProtocol);
var serviceProvider = new HubConnectionBuilder().AddJsonProtocol().Services.BuildServiceProvider();
var actualProtocol = Assert.IsType<JsonHubProtocol>(serviceProvider.GetService<IHubProtocol>());
Assert.IsType<CamelCasePropertyNamesContractResolver>(actualProtocol.PayloadSerializer.ContractResolver);
}
[Fact]
public void WithJsonHubProtocolSetsHubProtocolToJsonWithProvidedOptions()
public void AddJsonProtocolSetsHubProtocolToJsonWithProvidedOptions()
{
var expectedOptions = new JsonHubProtocolOptions()
var serviceProvider = new HubConnectionBuilder().AddJsonProtocol(options =>
{
PayloadSerializerSettings = new JsonSerializerSettings()
options.PayloadSerializerSettings = new JsonSerializerSettings
{
DateFormatString = "JUST A TEST"
}
};
};
}).Services.BuildServiceProvider();
Assert.True(new HubConnectionBuilder().WithJsonProtocol(expectedOptions).TryGetSetting<IHubProtocol>(HubConnectionBuilderDefaults.HubProtocolKey, out var hubProtocol));
var actualProtocol = Assert.IsType<JsonHubProtocol>(hubProtocol);
var actualProtocol = Assert.IsType<JsonHubProtocol>(serviceProvider.GetService<IHubProtocol>());
Assert.Equal("JUST A TEST", actualProtocol.PayloadSerializer.DateFormatString);
}
[Fact]
public void WithMessagePackHubProtocolSetsHubProtocolToMsgPackWithDefaultOptions()
public void WithConnectionFactorySetsConnectionFactory()
{
Assert.True(new HubConnectionBuilder().WithMessagePackProtocol().TryGetSetting<IHubProtocol>(HubConnectionBuilderDefaults.HubProtocolKey, out var hubProtocol));
var actualProtocol = Assert.IsType<MessagePackHubProtocol>(hubProtocol);
Func<IConnection> connectionFactory = () => null;
var serviceProvider = new HubConnectionBuilder().WithConnectionFactory(connectionFactory).Services.BuildServiceProvider();
Assert.Equal(connectionFactory, serviceProvider.GetService<Func<IConnection>>());
}
[Fact]
public void BuildCanOnlyBeCalledOnce()
{
var builder = new HubConnectionBuilder().WithConnectionFactory(() => null);
Assert.NotNull(builder.Build());
var ex = Assert.Throws<InvalidOperationException>(() => builder.Build());
Assert.Equal("HubConnectionBuilder allows creation only of a single instance of HubConnection.", ex.Message);
}
[Fact]
public void AddMessagePackProtocolSetsHubProtocolToMsgPackWithDefaultOptions()
{
var serviceProvider = new HubConnectionBuilder().AddMessagePackProtocol().Services.BuildServiceProvider();
var actualProtocol = Assert.IsType<MessagePackHubProtocol>(serviceProvider.GetService<IHubProtocol>());
Assert.Equal(SerializationMethod.Map, actualProtocol.SerializationContext.SerializationMethod);
}
[Fact]
public void WithMessagePackHubProtocolSetsHubProtocolToMsgPackWithProvidedOptions()
public void AddMessagePackProtocolSetsHubProtocolToMsgPackWithProvidedOptions()
{
var expectedOptions = new MessagePackHubProtocolOptions()
var serviceProvider = new HubConnectionBuilder().AddMessagePackProtocol(options =>
{
SerializationContext = new SerializationContext()
options.SerializationContext = new SerializationContext
{
SerializationMethod = SerializationMethod.Array
}
};
};
}).Services.BuildServiceProvider();
Assert.True(new HubConnectionBuilder().WithMessagePackProtocol(expectedOptions).TryGetSetting<IHubProtocol>(HubConnectionBuilderDefaults.HubProtocolKey, out var hubProtocol));
var actualProtocol = Assert.IsType<MessagePackHubProtocol>(hubProtocol);
var actualProtocol = Assert.IsType<MessagePackHubProtocol>(serviceProvider.GetService<IHubProtocol>());
Assert.Equal(SerializationMethod.Array, actualProtocol.SerializationContext.SerializationMethod);
}
}

View File

@ -4,6 +4,7 @@ using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Connections;
using Microsoft.AspNetCore.SignalR.Internal.Protocol;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json.Linq;
using Xunit;
@ -23,11 +24,18 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
public static IEnumerable<object[]> MethodsNamesThatRequireActiveConnection => MethodsThatRequireActiveConnection.Keys.Select(k => new object[] { k });
private HubConnection CreateHubConnection(Func<IConnection> connectionFactory)
{
var builder = new HubConnectionBuilder();
builder.WithConnectionFactory(connectionFactory);
return builder.Build();
}
[Fact]
public async Task StartAsyncStartsTheUnderlyingConnection()
{
var testConnection = new TestConnection();
await AsyncUsing(new HubConnection(() => testConnection, new JsonHubProtocol()), async connection =>
await AsyncUsing(CreateHubConnection(() => testConnection), async connection =>
{
await connection.StartAsync();
Assert.True(testConnection.Started.IsCompleted);
@ -39,7 +47,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
{
// Set up StartAsync to wait on the syncPoint when starting
var testConnection = new TestConnection(onStart: SyncPoint.Create(out var syncPoint));
await AsyncUsing(new HubConnection(() => testConnection, new JsonHubProtocol()), async connection =>
await AsyncUsing(CreateHubConnection(() => testConnection), async connection =>
{
var firstStart = connection.StartAsync().OrTimeout();
Assert.False(firstStart.IsCompleted);
@ -71,7 +79,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
return new TestConnection();
}
await AsyncUsing(new HubConnection(ConnectionFactory, new JsonHubProtocol()), async connection =>
await AsyncUsing(CreateHubConnection(ConnectionFactory), async connection =>
{
await connection.StartAsync().OrTimeout();
Assert.Equal(1, createCount);
@ -94,7 +102,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
return new TestConnection(onDispose: createCount == 1 ? onDisposeForFirstConnection : null);
}
await AsyncUsing(new HubConnection(ConnectionFactory, new JsonHubProtocol()), async connection =>
await AsyncUsing(CreateHubConnection(ConnectionFactory), async connection =>
{
await connection.StartAsync().OrTimeout();
Assert.Equal(1, createCount);
@ -119,7 +127,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
public async Task StartAsyncWithFailedHandshakeCanBeStopped()
{
var testConnection = new TestConnection(autoHandshake: false);
await AsyncUsing(new HubConnection(() => testConnection, new JsonHubProtocol()), async connection =>
await AsyncUsing(CreateHubConnection(() => testConnection), async connection =>
{
testConnection.Transport.Input.Complete();
try
@ -141,7 +149,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
var method = MethodsThatRequireActiveConnection[name];
var testConnection = new TestConnection();
await AsyncUsing(new HubConnection(() => testConnection, new JsonHubProtocol()), async connection =>
await AsyncUsing(CreateHubConnection(() => testConnection), async connection =>
{
var ex = await Assert.ThrowsAsync<InvalidOperationException>(() => method(connection));
Assert.Equal($"The '{name}' method cannot be called if the connection is not active", ex.Message);
@ -156,7 +164,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
// Set up StartAsync to wait on the syncPoint when starting
var testConnection = new TestConnection(onStart: SyncPoint.Create(out var syncPoint));
await AsyncUsing(new HubConnection(() => testConnection, new JsonHubProtocol()), async connection =>
await AsyncUsing(CreateHubConnection(() => testConnection), async connection =>
{
// Start, and wait for the sync point to be hit
var startTask = connection.StartAsync().OrTimeout();
@ -187,7 +195,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
public async Task StopAsyncStopsConnection()
{
var testConnection = new TestConnection();
await AsyncUsing(new HubConnection(() => testConnection, new JsonHubProtocol()), async connection =>
await AsyncUsing(CreateHubConnection(() => testConnection), async connection =>
{
await connection.StartAsync().OrTimeout();
Assert.True(testConnection.Started.IsCompleted);
@ -201,7 +209,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
public async Task StopAsyncNoOpsIfConnectionNotYetStarted()
{
var testConnection = new TestConnection();
await AsyncUsing(new HubConnection(() => testConnection, new JsonHubProtocol()), async connection =>
await AsyncUsing(CreateHubConnection(() => testConnection), async connection =>
{
await connection.StopAsync().OrTimeout();
Assert.False(testConnection.Disposed.IsCompleted);
@ -212,7 +220,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
public async Task StopAsyncNoOpsIfConnectionAlreadyStopped()
{
var testConnection = new TestConnection();
await AsyncUsing(new HubConnection(() => testConnection, new JsonHubProtocol()), async connection =>
await AsyncUsing(CreateHubConnection(() => testConnection), async connection =>
{
await connection.StartAsync().OrTimeout();
Assert.True(testConnection.Started.IsCompleted);
@ -229,7 +237,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
{
var testConnection = new TestConnection();
var closed = new TaskCompletionSource<object>();
await AsyncUsing(new HubConnection(() => testConnection, new JsonHubProtocol()), async connection =>
await AsyncUsing(CreateHubConnection(() => testConnection), async connection =>
{
connection.Closed += (e) => closed.TrySetResult(null);
await connection.StartAsync().OrTimeout();
@ -251,7 +259,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
var testConnection = new TestConnection();
var testConnectionClosed = new TaskCompletionSource<object>();
var connectionClosed = new TaskCompletionSource<object>();
await AsyncUsing(new HubConnection(() => testConnection, new JsonHubProtocol()), async connection =>
await AsyncUsing(CreateHubConnection(() => testConnection), async connection =>
{
// We're hooking the TestConnection shutting down here because the HubConnection one will be blocked on the lock
testConnection.Transport.Input.OnWriterCompleted((_, __) => testConnectionClosed.TrySetResult(null), null);
@ -286,7 +294,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
{
var testConnection = new TestConnection();
var connectionClosed = new TaskCompletionSource<object>();
await AsyncUsing(new HubConnection(() => testConnection, new JsonHubProtocol()), async connection =>
await AsyncUsing(CreateHubConnection(() => testConnection), async connection =>
{
connection.Closed += (e) => connectionClosed.TrySetResult(null);
@ -319,7 +327,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
// Set up StartAsync to wait on the syncPoint when starting
var testConnection = new TestConnection(onDispose: SyncPoint.Create(out var syncPoint));
await AsyncUsing(new HubConnection(() => testConnection, new JsonHubProtocol()), async connection =>
await AsyncUsing(CreateHubConnection(() => testConnection), async connection =>
{
await connection.StartAsync().OrTimeout();

View File

@ -1,7 +1,9 @@
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.AspNetCore.Connections;
using Microsoft.AspNetCore.SignalR.Internal.Protocol;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
namespace Microsoft.AspNetCore.SignalR.Client.Tests
@ -10,7 +12,14 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
{
private static HubConnection CreateHubConnection(TestConnection connection, IHubProtocol protocol = null)
{
return new HubConnection(() => connection, protocol ?? new JsonHubProtocol(), new LoggerFactory());
var builder = new HubConnectionBuilder();
builder.WithConnectionFactory(() => connection);
if (protocol != null)
{
builder.WithHubProtocol(protocol);
}
return builder.Build();
}
}
}

View File

@ -8,6 +8,7 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.Connections;
using Microsoft.AspNetCore.SignalR.Internal;
using Microsoft.AspNetCore.SignalR.Internal.Protocol;
using Microsoft.Extensions.DependencyInjection;
using Moq;
using Xunit;
@ -42,7 +43,10 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
[Fact]
public async Task ClosedEventRaisedWhenTheClientIsStopped()
{
var hubConnection = new HubConnection(() => new TestConnection(), Mock.Of<IHubProtocol>(), null);
var builder = new HubConnectionBuilder();
builder.WithConnectionFactory(() => new TestConnection());
var hubConnection = builder.Build();
var closedEventTcs = new TaskCompletionSource<Exception>();
hubConnection.Closed += e => closedEventTcs.SetResult(e);

View File

@ -11,7 +11,6 @@
</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="..\Microsoft.AspNetCore.SignalR.Tests.Utils\Microsoft.AspNetCore.SignalR.Tests.Utils.csproj" />
</ItemGroup>

View File

@ -11,7 +11,6 @@
</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\Microsoft.AspNetCore.SignalR.csproj" />

View File

@ -92,10 +92,9 @@ namespace Microsoft.AspNetCore.SignalR.Redis.Tests
private static HubConnection CreateConnection(string url, HttpTransportType transportType, IHubProtocol protocol, ILoggerFactory loggerFactory)
{
return new HubConnectionBuilder()
.WithUrl(url)
.WithTransport(transportType)
.WithHubProtocol(protocol)
.WithLoggerFactory(loggerFactory)
.WithUrl(url, transportType)
.Build();
}

View File

@ -170,7 +170,7 @@ namespace Microsoft.AspNetCore.SignalR.Tests
.Returns<HttpRequestMessage, CancellationToken>(
(request, cancellationToken) => Task.FromException<HttpResponseMessage>(new InvalidOperationException("HTTP requests should not be sent.")));
var connection = new HttpConnection(new Uri(url), HttpTransportType.WebSockets, loggerFactory, new HttpOptions { HttpMessageHandler = (httpMessageHandler) => mockHttpHandler.Object });
var connection = new HttpConnection(new Uri(url), HttpTransportType.WebSockets, loggerFactory, new HttpOptions { HttpMessageHandlerFactory = (httpMessageHandler) => mockHttpHandler.Object });
try
{
@ -339,9 +339,8 @@ namespace Microsoft.AspNetCore.SignalR.Tests
var url = _serverFixture.Url + "/uncreatable";
var connection = new HubConnectionBuilder()
.WithUrl(new Uri(url))
.WithTransport(transportType)
.WithLoggerFactory(loggerFactory)
.WithUrl(url, transportType)
.Build();
try
{

View File

@ -26,7 +26,6 @@
</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.Client\Microsoft.AspNetCore.SignalR.Client.csproj" />
<ProjectReference Include="..\Microsoft.AspNetCore.SignalR.Tests.Utils\Microsoft.AspNetCore.SignalR.Tests.Utils.csproj" />