Adding support for JWT in the C# client

Fixes: #1018

(Bonus: also enabling passing headers)
This commit is contained in:
Pawel Kadluczka 2017-11-07 22:08:34 -08:00 committed by Pawel Kadluczka
parent fadd6f89fd
commit 0bafb304c2
20 changed files with 363 additions and 81 deletions

View File

@ -9,6 +9,7 @@
<InternalAspNetCoreSdkPackageVersion>2.1.0-preview1-15549</InternalAspNetCoreSdkPackageVersion>
<MicrosoftAspNetCoreAuthenticationCookiesPackageVersion>2.1.0-preview1-27579</MicrosoftAspNetCoreAuthenticationCookiesPackageVersion>
<MicrosoftAspNetCoreAuthenticationCorePackageVersion>2.1.0-preview1-27579</MicrosoftAspNetCoreAuthenticationCorePackageVersion>
<MicrosoftAspNetCoreAuthenticationJwtBearerPackageVersion>2.1.0-preview1-27475</MicrosoftAspNetCoreAuthenticationJwtBearerPackageVersion>
<MicrosoftAspNetCoreAuthorizationPackageVersion>2.1.0-preview1-27579</MicrosoftAspNetCoreAuthorizationPackageVersion>
<MicrosoftAspNetCoreAuthorizationPolicyPackageVersion>2.1.0-preview1-27579</MicrosoftAspNetCoreAuthorizationPolicyPackageVersion>
<MicrosoftAspNetCoreCorsPackageVersion>2.1.0-preview1-27579</MicrosoftAspNetCoreCorsPackageVersion>

View File

@ -6,7 +6,6 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.SignalR.Client;
using Microsoft.AspNetCore.Sockets.Client;
using Microsoft.Extensions.CommandLineUtils;
using Microsoft.Extensions.Logging;

View File

@ -42,9 +42,11 @@ namespace Microsoft.AspNetCore.SignalR.Client
throw new InvalidOperationException("Cannot create IConnection instance. The connection factory was not configured.");
}
IHubConnectionBuilder builder = this;
var connection = _connectionFactoryDelegate();
var loggerFactory = ((IHubConnectionBuilder)this).GetLoggerFactory();
var hubProtocol = ((IHubConnectionBuilder)this).GetHubProtocol();
var loggerFactory = builder.GetLoggerFactory();
var hubProtocol = builder.GetHubProtocol();
return new HubConnection(connection, hubProtocol ?? new JsonHubProtocol(), loggerFactory);
}

View File

@ -2,9 +2,12 @@
// 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.Http;
using Microsoft.AspNetCore.Sockets;
using Microsoft.AspNetCore.Sockets.Client;
using Microsoft.AspNetCore.Sockets.Client.Http;
namespace Microsoft.AspNetCore.SignalR.Client
{
@ -12,6 +15,8 @@ namespace Microsoft.AspNetCore.SignalR.Client
{
public static readonly string TransportTypeKey = "TransportType";
public static readonly string HttpMessageHandlerKey = "HttpMessageHandler";
public static readonly string HeadersKey = "Headers";
public static readonly string JwtBearerTokenFactoryKey = "JwtBearerTokenFactory";
public static IHubConnectionBuilder WithUrl(this IHubConnectionBuilder hubConnectionBuilder, string url)
{
@ -32,10 +37,18 @@ namespace Microsoft.AspNetCore.SignalR.Client
hubConnectionBuilder.ConfigureConnectionFactory(() =>
{
var headers = hubConnectionBuilder.GetHeaders();
var httpOptions = new HttpOptions
{
HttpMessageHandler = hubConnectionBuilder.GetMessageHandler(),
Headers = headers != null ? new ReadOnlyDictionary<string, string>(headers) : null,
JwtBearerTokenFactory = hubConnectionBuilder.GetJwtBearerTokenFactory()
};
return new HttpConnection(url,
hubConnectionBuilder.GetTransport(),
hubConnectionBuilder.GetLoggerFactory(),
hubConnectionBuilder.GetMessageHandler());
httpOptions);
});
return hubConnectionBuilder;
}
@ -52,6 +65,37 @@ namespace Microsoft.AspNetCore.SignalR.Client
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 WithJwtBearer(this IHubConnectionBuilder hubConnectionBuilder, Func<string> jwtBearerTokenFactory)
{
if (jwtBearerTokenFactory == null)
{
throw new ArgumentNullException(nameof(jwtBearerTokenFactory));
}
hubConnectionBuilder.AddSetting(JwtBearerTokenFactoryKey, jwtBearerTokenFactory);
return hubConnectionBuilder;
}
public static TransportType GetTransport(this IHubConnectionBuilder hubConnectionBuilder)
{
if (hubConnectionBuilder.TryGetSetting<TransportType>(TransportTypeKey, out var transportType))
@ -67,5 +111,25 @@ namespace Microsoft.AspNetCore.SignalR.Client
hubConnectionBuilder.TryGetSetting<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 Func<string> GetJwtBearerTokenFactory(this IHubConnectionBuilder hubConnectionBuilder)
{
if (hubConnectionBuilder.TryGetSetting<Func<string>>(JwtBearerTokenFactoryKey, out var factory))
{
return factory;
}
return null;
}
}
}

View File

@ -3,6 +3,7 @@
using System;
using System.Net.Http;
using Microsoft.AspNetCore.Sockets.Client.Http;
using Microsoft.Extensions.Logging;
namespace Microsoft.AspNetCore.Sockets.Client
@ -10,11 +11,12 @@ namespace Microsoft.AspNetCore.Sockets.Client
public class DefaultTransportFactory : ITransportFactory
{
private readonly HttpClient _httpClient;
private readonly HttpOptions _httpOptions;
private readonly TransportType _requestedTransportType;
private readonly ILoggerFactory _loggerFactory;
private static volatile bool _websocketsSupported = true;
public DefaultTransportFactory(TransportType requestedTransportType, ILoggerFactory loggerFactory, HttpClient httpClient)
public DefaultTransportFactory(TransportType requestedTransportType, ILoggerFactory loggerFactory, HttpClient httpClient, HttpOptions httpOptions)
{
if (requestedTransportType <= 0 || requestedTransportType > TransportType.All)
{
@ -29,6 +31,7 @@ namespace Microsoft.AspNetCore.Sockets.Client
_requestedTransportType = requestedTransportType;
_loggerFactory = loggerFactory;
_httpClient = httpClient;
_httpOptions = httpOptions;
}
public ITransport CreateTransport(TransportType availableServerTransports)
@ -37,7 +40,7 @@ namespace Microsoft.AspNetCore.Sockets.Client
{
try
{
return new WebSocketsTransport(_loggerFactory);
return new WebSocketsTransport(_httpOptions, _loggerFactory);
}
catch (PlatformNotSupportedException)
{
@ -47,12 +50,12 @@ namespace Microsoft.AspNetCore.Sockets.Client
if ((availableServerTransports & TransportType.ServerSentEvents & _requestedTransportType) == TransportType.ServerSentEvents)
{
return new ServerSentEventsTransport(_httpClient, _loggerFactory);
return new ServerSentEventsTransport(_httpClient, _httpOptions, _loggerFactory);
}
if ((availableServerTransports & TransportType.LongPolling & _requestedTransportType) == TransportType.LongPolling)
{
return new LongPollingTransport(_httpClient, _loggerFactory);
return new LongPollingTransport(_httpClient, _httpOptions, _loggerFactory);
}
throw new InvalidOperationException("No requested transports available on the server.");

View File

@ -31,6 +31,7 @@ namespace Microsoft.AspNetCore.Sockets.Client
private volatile int _connectionState = ConnectionState.Initial;
private volatile ChannelConnection<byte[], SendMessage> _transportChannel;
private readonly HttpClient _httpClient;
private readonly HttpOptions _httpOptions;
private volatile ITransport _transport;
private volatile Task _receiveLoopTask;
private TaskCompletionSource<object> _startTcs = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);
@ -54,49 +55,47 @@ namespace Microsoft.AspNetCore.Sockets.Client
: this(url, TransportType.All)
{ }
public HttpConnection(Uri url, HttpMessageHandler httpMessageHandler)
: this(url, TransportType.All, loggerFactory: null, httpMessageHandler: httpMessageHandler)
{ }
public HttpConnection(Uri url, TransportType transportType)
: this(url, transportType, loggerFactory: null)
{
}
public HttpConnection(Uri url, ILoggerFactory loggerFactory)
: this(url, TransportType.All, loggerFactory, httpMessageHandler: null)
: this(url, TransportType.All, loggerFactory, httpOptions: null)
{
}
public HttpConnection(Uri url, TransportType transportType, ILoggerFactory loggerFactory)
: this(url, transportType, loggerFactory, httpMessageHandler: null)
: this(url, transportType, loggerFactory, httpOptions: null)
{
}
public HttpConnection(Uri url, TransportType transportType, ILoggerFactory loggerFactory, HttpMessageHandler httpMessageHandler)
public HttpConnection(Uri url, TransportType transportType, ILoggerFactory loggerFactory, HttpOptions httpOptions)
{
Url = url ?? throw new ArgumentNullException(nameof(url));
_loggerFactory = loggerFactory ?? NullLoggerFactory.Instance;
_logger = _loggerFactory.CreateLogger<HttpConnection>();
_httpOptions = httpOptions;
_requestedTransportType = transportType;
if (_requestedTransportType != TransportType.WebSockets)
{
_httpClient = httpMessageHandler == null ? new HttpClient() : new HttpClient(httpMessageHandler);
_httpClient = httpOptions?.HttpMessageHandler == null ? new HttpClient() : new HttpClient(httpOptions.HttpMessageHandler);
_httpClient.Timeout = HttpClientTimeout;
}
_transportFactory = new DefaultTransportFactory(transportType, _loggerFactory, _httpClient);
_transportFactory = new DefaultTransportFactory(transportType, _loggerFactory, _httpClient, httpOptions);
}
public HttpConnection(Uri url, ITransportFactory transportFactory, ILoggerFactory loggerFactory, HttpMessageHandler httpMessageHandler)
public HttpConnection(Uri url, ITransportFactory transportFactory, ILoggerFactory loggerFactory, HttpOptions httpOptions)
{
Url = url ?? throw new ArgumentNullException(nameof(url));
_loggerFactory = loggerFactory ?? NullLoggerFactory.Instance;
_logger = _loggerFactory.CreateLogger<HttpConnection>();
_httpClient = httpMessageHandler == null ? new HttpClient() : new HttpClient(httpMessageHandler);
_httpClient.Timeout = HttpClientTimeout;
_httpOptions = httpOptions;
_httpClient = _httpOptions?.HttpMessageHandler == null ? new HttpClient() : new HttpClient(_httpOptions?.HttpMessageHandler);
_httpClient.Timeout = HttpClientTimeout;
_transportFactory = transportFactory ?? throw new ArgumentNullException(nameof(transportFactory));
}
@ -214,7 +213,7 @@ namespace Microsoft.AspNetCore.Sockets.Client
}
}
private async static Task<NegotiationResponse> Negotiate(Uri url, HttpClient httpClient, ILogger logger)
private async Task<NegotiationResponse> Negotiate(Uri url, HttpClient httpClient, ILogger logger)
{
try
{
@ -229,7 +228,8 @@ namespace Microsoft.AspNetCore.Sockets.Client
using (var request = new HttpRequestMessage(HttpMethod.Post, urlBuilder.Uri))
{
request.Headers.UserAgent.Add(Constants.UserAgentHeader);
SendUtils.PrepareHttpRequest(request, _httpOptions);
using (var response = await httpClient.SendAsync(request))
{
response.EnsureSuccessStatusCode();

View File

@ -0,0 +1,16 @@
// 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.Http;
namespace Microsoft.AspNetCore.Sockets.Client.Http
{
public class HttpOptions
{
public HttpMessageHandler HttpMessageHandler { get; set; }
public IReadOnlyCollection<KeyValuePair<string, string>> Headers { get; set; }
public Func<string> JwtBearerTokenFactory { get; set; }
}
}

View File

@ -2,6 +2,7 @@
// 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.Threading;
@ -17,6 +18,7 @@ namespace Microsoft.AspNetCore.Sockets.Client
public class LongPollingTransport : ITransport
{
private readonly HttpClient _httpClient;
private readonly HttpOptions _httpOptions;
private readonly ILogger _logger;
private Channel<byte[], SendMessage> _application;
private Task _sender;
@ -30,12 +32,13 @@ namespace Microsoft.AspNetCore.Sockets.Client
public TransferMode? Mode { get; private set; }
public LongPollingTransport(HttpClient httpClient)
: this(httpClient, null)
: this(httpClient, null, null)
{ }
public LongPollingTransport(HttpClient httpClient, ILoggerFactory loggerFactory)
public LongPollingTransport(HttpClient httpClient, HttpOptions httpOptions, ILoggerFactory loggerFactory)
{
_httpClient = httpClient;
_httpOptions = httpOptions;
_logger = (loggerFactory ?? NullLoggerFactory.Instance).CreateLogger<LongPollingTransport>();
}
@ -54,7 +57,7 @@ namespace Microsoft.AspNetCore.Sockets.Client
// Start sending and polling (ask for binary if the server supports it)
_poller = Poll(url, _transportCts.Token);
_sender = SendUtils.SendMessages(url, _application, _httpClient, _transportCts, _logger, _connectionId);
_sender = SendUtils.SendMessages(url, _application, _httpClient, _httpOptions, _transportCts, _logger, _connectionId);
Running = Task.WhenAll(_sender, _poller).ContinueWith(t =>
{
@ -90,7 +93,7 @@ namespace Microsoft.AspNetCore.Sockets.Client
while (!cancellationToken.IsCancellationRequested)
{
var request = new HttpRequestMessage(HttpMethod.Get, pollUrl);
request.Headers.UserAgent.Add(Constants.UserAgentHeader);
SendUtils.PrepareHttpRequest(request, _httpOptions);
HttpResponseMessage response;

View File

@ -17,7 +17,7 @@ namespace Microsoft.AspNetCore.Sockets.Client
internal static class SendUtils
{
public static async Task SendMessages(Uri sendUrl, Channel<byte[], SendMessage> application, HttpClient httpClient,
CancellationTokenSource transportCts, ILogger logger, string connectionId)
HttpOptions httpOptions, CancellationTokenSource transportCts, ILogger logger, string connectionId)
{
logger.SendStarted(connectionId);
IList<SendMessage> messages = null;
@ -39,7 +39,7 @@ namespace Microsoft.AspNetCore.Sockets.Client
// Send them in a single post
var request = new HttpRequestMessage(HttpMethod.Post, sendUrl);
request.Headers.UserAgent.Add(Constants.UserAgentHeader);
PrepareHttpRequest(request, httpOptions);
// TODO: We can probably use a pipeline here or some kind of pooled memory.
// But where do we get the pool from? ArrayBufferPool.Instance?
@ -107,5 +107,22 @@ namespace Microsoft.AspNetCore.Sockets.Client
logger.SendStopped(connectionId);
}
public static void PrepareHttpRequest(HttpRequestMessage request, HttpOptions httpOptions)
{
if (httpOptions?.Headers != null)
{
foreach (var header in httpOptions.Headers)
{
request.Headers.Add(header.Key, header.Value);
}
}
request.Headers.UserAgent.Add(Constants.UserAgentHeader);
if (httpOptions?.JwtBearerTokenFactory != null)
{
request.Headers.Add("Authorization", $"Bearer {httpOptions.JwtBearerTokenFactory()}");
}
}
}
}

View File

@ -9,6 +9,7 @@ using System.Net.Http.Headers;
using System.Threading;
using System.Threading.Tasks;
using System.Threading.Channels;
using Microsoft.AspNetCore.Sockets.Client.Http;
using Microsoft.AspNetCore.Sockets.Client.Internal;
using Microsoft.AspNetCore.Sockets.Internal.Formatters;
using Microsoft.Extensions.Logging;
@ -20,6 +21,7 @@ namespace Microsoft.AspNetCore.Sockets.Client
{
private static readonly MemoryPool _memoryPool = new MemoryPool();
private readonly HttpClient _httpClient;
private readonly HttpOptions _httpOptions;
private readonly ILogger _logger;
private readonly CancellationTokenSource _transportCts = new CancellationTokenSource();
private readonly ServerSentEventsMessageParser _parser = new ServerSentEventsMessageParser();
@ -32,10 +34,10 @@ namespace Microsoft.AspNetCore.Sockets.Client
public TransferMode? Mode { get; private set; }
public ServerSentEventsTransport(HttpClient httpClient)
: this(httpClient, null)
: this(httpClient, null, null)
{ }
public ServerSentEventsTransport(HttpClient httpClient, ILoggerFactory loggerFactory)
public ServerSentEventsTransport(HttpClient httpClient, HttpOptions httpOptions, ILoggerFactory loggerFactory)
{
if (httpClient == null)
{
@ -43,6 +45,7 @@ namespace Microsoft.AspNetCore.Sockets.Client
}
_httpClient = httpClient;
_httpOptions = httpOptions;
_logger = (loggerFactory ?? NullLoggerFactory.Instance).CreateLogger<ServerSentEventsTransport>();
}
@ -59,7 +62,7 @@ namespace Microsoft.AspNetCore.Sockets.Client
_logger.StartTransport(_connectionId, Mode.Value);
var sendTask = SendUtils.SendMessages(url, _application, _httpClient, _transportCts, _logger, _connectionId);
var sendTask = SendUtils.SendMessages(url, _application, _httpClient, _httpOptions, _transportCts, _logger, _connectionId);
var receiveTask = OpenConnection(_application, url, _transportCts.Token);
Running = Task.WhenAll(sendTask, receiveTask).ContinueWith(t =>
@ -78,6 +81,7 @@ namespace Microsoft.AspNetCore.Sockets.Client
_logger.StartReceive(_connectionId);
var request = new HttpRequestMessage(HttpMethod.Get, url);
SendUtils.PrepareHttpRequest(request, _httpOptions);
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("text/event-stream"));
var response = await _httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken);

View File

@ -6,8 +6,9 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Net.WebSockets;
using System.Threading;
using System.Threading.Tasks;
using System.Threading.Channels;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Sockets.Client.Http;
using Microsoft.AspNetCore.Sockets.Client.Internal;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
@ -16,7 +17,7 @@ namespace Microsoft.AspNetCore.Sockets.Client
{
public class WebSocketsTransport : ITransport
{
private readonly ClientWebSocket _webSocket = new ClientWebSocket();
private readonly ClientWebSocket _webSocket;
private Channel<byte[], SendMessage> _application;
private readonly CancellationTokenSource _transportCts = new CancellationTokenSource();
private readonly CancellationTokenSource _receiveCts = new CancellationTokenSource();
@ -28,12 +29,26 @@ namespace Microsoft.AspNetCore.Sockets.Client
public TransferMode? Mode { get; private set; }
public WebSocketsTransport()
: this(null)
: this(null, null)
{
}
public WebSocketsTransport(ILoggerFactory loggerFactory)
public WebSocketsTransport(HttpOptions httpOptions, ILoggerFactory loggerFactory)
{
_webSocket = new ClientWebSocket();
if (httpOptions?.Headers != null)
{
foreach (var header in httpOptions.Headers)
{
_webSocket.Options.SetRequestHeader(header.Key, header.Value);
}
}
if (httpOptions?.JwtBearerTokenFactory != null)
{
_webSocket.Options.SetRequestHeader("Authorization", $"Bearer {httpOptions.JwtBearerTokenFactory()}");
}
_logger = (loggerFactory ?? NullLoggerFactory.Instance).CreateLogger<WebSocketsTransport>();
}

View File

@ -6,8 +6,8 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Net.WebSockets;
using System.Threading;
using System.Threading.Tasks;
using System.Threading.Channels;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;

View File

@ -3,6 +3,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using System.Threading.Channels;
@ -555,6 +557,70 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
}
}
[Theory]
[MemberData(nameof(TransportTypes))]
public async Task ClientCanUseJwtBearerTokenForAuthentication(TransportType transportType)
{
using (StartLog(out var loggerFactory))
{
var httpResponse = await new HttpClient().GetAsync(_serverFixture.Url + "/generateJwtToken");
httpResponse.EnsureSuccessStatusCode();
var token = await httpResponse.Content.ReadAsStringAsync();
var hubConnection = new HubConnectionBuilder()
.WithUrl(_serverFixture.Url + "/authorizedhub")
.WithTransport(transportType)
.WithLoggerFactory(loggerFactory)
.WithJwtBearer(() => token)
.Build();
try
{
await hubConnection.StartAsync().OrTimeout();
var message = await hubConnection.InvokeAsync<string>("Echo", "Hello, World!").OrTimeout();
Assert.Equal("Hello, World!", message);
}
catch (Exception ex)
{
loggerFactory.CreateLogger<HubConnectionTests>().LogError(ex, "Exception from test");
throw;
}
finally
{
await hubConnection.DisposeAsync().OrTimeout();
}
}
}
[Theory]
[MemberData(nameof(TransportTypes))]
public async Task ClientCanSendHeaders(TransportType transportType)
{
using (StartLog(out var loggerFactory))
{
var hubConnection = new HubConnectionBuilder()
.WithUrl(_serverFixture.Url + "/default")
.WithTransport(transportType)
.WithLoggerFactory(loggerFactory)
.WithHeader("X-test", "42")
.WithHeader("X-42", "test")
.Build();
try
{
await hubConnection.StartAsync().OrTimeout();
var headerValues = await hubConnection.InvokeAsync<string[]>("GetHeaderValues", new object[] { new[] { "X-test", "X-42" } }).OrTimeout();
Assert.Equal(new[] { "42", "test" }, headerValues);
}
catch (Exception ex)
{
loggerFactory.CreateLogger<HubConnectionTests>().LogError(ex, "Exception from test");
throw;
}
finally
{
await hubConnection.DisposeAsync().OrTimeout();
}
}
}
public static IEnumerable<object[]> HubProtocolsAndTransportsAndHubPaths
{
@ -562,7 +628,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
{
foreach (var protocol in HubProtocols)
{
foreach (var transport in TransportTypes())
foreach (var transport in TransportTypes().SelectMany(t => t))
{
foreach (var hubPath in HubPaths)
{
@ -582,14 +648,14 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
new MessagePackHubProtocol(),
};
public static IEnumerable<TransportType> TransportTypes()
public static IEnumerable<object[]> TransportTypes()
{
if (TestHelpers.IsWebSocketsSupported())
{
yield return TransportType.WebSockets;
yield return new object[] { TransportType.WebSockets };
}
yield return TransportType.ServerSentEvents;
yield return TransportType.LongPolling;
yield return new object[] { TransportType.ServerSentEvents };
yield return new object[] { TransportType.LongPolling };
}
}
}

View File

@ -2,10 +2,13 @@
// 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.Reactive.Linq;
using System.Threading.Tasks;
using System.Threading.Channels;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
{
@ -30,6 +33,12 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
{
await Clients.Client(Context.ConnectionId).InvokeAsync("NoClientHandler");
}
public IEnumerable<string> GetHeaderValues(string[] headerNames)
{
var headers = Context.Connection.GetHttpContext().Request.Headers;
return headerNames.Select(h => (string)headers[h]);
}
}
public class DynamicTestHub : DynamicHub
@ -111,4 +120,10 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
Task Send(string message);
Task NoClientHandler();
}
[Authorize(JwtBearerDefaults.AuthenticationScheme)]
public class HubWithAuthorization : Hub
{
public string Echo(string message) => TestHubMethodsImpl.Echo(message);
}
}

View File

@ -23,6 +23,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="$(MicrosoftAspNetCoreAuthenticationJwtBearerPackageVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Diagnostics" Version="$(MicrosoftAspNetCoreDiagnosticsPackageVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Hosting" Version="$(MicrosoftAspNetCoreHostingPackageVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Http" Version="$(MicrosoftAspNetCoreHttpPackageVersion)" />

View File

@ -1,26 +1,77 @@
// 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.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;
namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
{
public class Startup
{
private readonly SymmetricSecurityKey SecurityKey = new SymmetricSecurityKey(Guid.NewGuid().ToByteArray());
private readonly JwtSecurityTokenHandler JwtTokenHandler = new JwtSecurityTokenHandler();
public void ConfigureServices(IServiceCollection services)
{
services.AddSignalR();
services.AddAuthorization(options =>
{
options.AddPolicy(JwtBearerDefaults.AuthenticationScheme, policy =>
{
policy.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme);
policy.RequireClaim(ClaimTypes.NameIdentifier);
});
});
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters =
new TokenValidationParameters
{
ValidateAudience = false,
ValidateIssuer = false,
ValidateActor = false,
ValidateLifetime = true,
IssuerSigningKey = SecurityKey
};
});
}
public void Configure(IApplicationBuilder app)
{
app.UseAuthentication();
app.UseSignalR(routes =>
{
routes.MapHub<TestHub>("default");
routes.MapHub<DynamicTestHub>("dynamic");
routes.MapHub<TestHubT>("hubT");
routes.MapHub<HubWithAuthorization>("authorizedhub");
});
app.Run(async (context) =>
{
if (context.Request.Path.StartsWithSegments("/generateJwtToken"))
{
await context.Response.WriteAsync(GenerateJwtToken());
return;
}
});
}
private string GenerateJwtToken()
{
var claims = new[] { new Claim(ClaimTypes.NameIdentifier, "testuser") };
var credentials = new SigningCredentials(SecurityKey, SecurityAlgorithms.HmacSha256);
var token = new JwtSecurityToken("SignalRTestServer", "SignalRTests", claims, expires: DateTime.Now.AddSeconds(5), signingCredentials: credentials);
return JwtTokenHandler.WriteToken(token);
}
}
}

View File

@ -10,6 +10,7 @@ using System.Threading.Tasks;
using System.Threading.Channels;
using Microsoft.AspNetCore.Client.Tests;
using Microsoft.AspNetCore.SignalR.Tests.Common;
using Microsoft.AspNetCore.Sockets.Client.Http;
using Microsoft.AspNetCore.Sockets.Features;
using Microsoft.Extensions.Logging;
using Moq;
@ -58,7 +59,8 @@ namespace Microsoft.AspNetCore.Sockets.Client.Tests
: ResponseUtils.CreateResponse(HttpStatusCode.OK);
});
var connection = new HttpConnection(new Uri("http://fakeuri.org/"), TransportType.LongPolling, loggerFactory: null, httpMessageHandler: mockHttpHandler.Object);
var connection = new HttpConnection(new Uri("http://fakeuri.org/"), TransportType.LongPolling, loggerFactory: null,
httpOptions: new HttpOptions { HttpMessageHandler = mockHttpHandler.Object });
try
{
await connection.StartAsync();
@ -87,7 +89,8 @@ namespace Microsoft.AspNetCore.Sockets.Client.Tests
: ResponseUtils.CreateResponse(HttpStatusCode.OK);
});
var connection = new HttpConnection(new Uri("http://fakeuri.org/"), TransportType.LongPolling, loggerFactory: null, httpMessageHandler: mockHttpHandler.Object);
var connection = new HttpConnection(new Uri("http://fakeuri.org/"), TransportType.LongPolling, loggerFactory: null,
httpOptions: new HttpOptions { HttpMessageHandler = mockHttpHandler.Object });
await connection.StartAsync();
await connection.DisposeAsync();
@ -139,7 +142,8 @@ namespace Microsoft.AspNetCore.Sockets.Client.Tests
var transport = new Mock<ITransport>();
transport.Setup(t => t.StopAsync()).Returns(async () => { await releaseDisposeTcs.Task; });
var connection = new HttpConnection(new Uri("http://fakeuri.org/"), new TestTransportFactory(transport.Object), loggerFactory: null, httpMessageHandler: mockHttpHandler.Object);
var connection = new HttpConnection(new Uri("http://fakeuri.org/"), new TestTransportFactory(transport.Object), loggerFactory: null,
httpOptions: new HttpOptions { HttpMessageHandler = mockHttpHandler.Object });
var startTask = connection.StartAsync();
await allowDisposeTcs.Task;
@ -178,7 +182,8 @@ namespace Microsoft.AspNetCore.Sockets.Client.Tests
: ResponseUtils.CreateResponse(HttpStatusCode.OK);
});
var connection = new HttpConnection(new Uri("http://fakeuri.org/"), TransportType.LongPolling, loggerFactory: null, httpMessageHandler: mockHttpHandler.Object);
var connection = new HttpConnection(new Uri("http://fakeuri.org/"), TransportType.LongPolling, loggerFactory: null,
httpOptions: new HttpOptions { HttpMessageHandler = mockHttpHandler.Object });
await connection.StartAsync();
await connection.DisposeAsync();
@ -202,7 +207,8 @@ namespace Microsoft.AspNetCore.Sockets.Client.Tests
: ResponseUtils.CreateResponse(HttpStatusCode.OK);
});
var connection = new HttpConnection(new Uri("http://fakeuri.org/"), TransportType.LongPolling, loggerFactory: null, httpMessageHandler: mockHttpHandler.Object);
var connection = new HttpConnection(new Uri("http://fakeuri.org/"), TransportType.LongPolling, loggerFactory: null,
httpOptions: new HttpOptions { HttpMessageHandler = mockHttpHandler.Object });
await connection.StartAsync().OrTimeout();
@ -228,7 +234,8 @@ namespace Microsoft.AspNetCore.Sockets.Client.Tests
: ResponseUtils.CreateResponse(HttpStatusCode.OK);
});
var connection = new HttpConnection(new Uri("http://fakeuri.org/"), TransportType.LongPolling, loggerFactory: null, httpMessageHandler: mockHttpHandler.Object);
var connection = new HttpConnection(new Uri("http://fakeuri.org/"), TransportType.LongPolling, loggerFactory: null,
httpOptions: new HttpOptions { HttpMessageHandler = mockHttpHandler.Object });
try
{
@ -274,7 +281,8 @@ namespace Microsoft.AspNetCore.Sockets.Client.Tests
});
mockTransport.SetupGet(t => t.Mode).Returns(TransferMode.Text);
var connection = new HttpConnection(new Uri("http://fakeuri.org/"), new TestTransportFactory(mockTransport.Object), loggerFactory: null, httpMessageHandler: mockHttpHandler.Object);
var connection = new HttpConnection(new Uri("http://fakeuri.org/"), new TestTransportFactory(mockTransport.Object), loggerFactory: null,
httpOptions: new HttpOptions { HttpMessageHandler = mockHttpHandler.Object });
var onReceivedInvoked = false;
connection.OnReceived( _ =>
@ -321,7 +329,8 @@ namespace Microsoft.AspNetCore.Sockets.Client.Tests
var callbackInvokedTcs = new TaskCompletionSource<object>();
var closedTcs = new TaskCompletionSource<object>();
var connection = new HttpConnection(new Uri("http://fakeuri.org/"), new TestTransportFactory(mockTransport.Object), loggerFactory: null, httpMessageHandler: mockHttpHandler.Object);
var connection = new HttpConnection(new Uri("http://fakeuri.org/"), new TestTransportFactory(mockTransport.Object), loggerFactory: null,
httpOptions: new HttpOptions { HttpMessageHandler = mockHttpHandler.Object });
connection.OnReceived(_ =>
{
@ -376,7 +385,8 @@ namespace Microsoft.AspNetCore.Sockets.Client.Tests
var blockReceiveCallbackTcs = new TaskCompletionSource<object>();
var connection = new HttpConnection(new Uri("http://fakeuri.org/"), new TestTransportFactory(mockTransport.Object), loggerFactory: null, httpMessageHandler: mockHttpHandler.Object);
var connection = new HttpConnection(new Uri("http://fakeuri.org/"), new TestTransportFactory(mockTransport.Object), loggerFactory: null,
httpOptions: new HttpOptions { HttpMessageHandler = mockHttpHandler.Object });
connection.OnReceived(_ => blockReceiveCallbackTcs.Task);
await connection.StartAsync();
@ -420,7 +430,8 @@ namespace Microsoft.AspNetCore.Sockets.Client.Tests
var callbackInvokedTcs = new TaskCompletionSource<object>();
var connection = new HttpConnection(new Uri("http://fakeuri.org/"), new TestTransportFactory(mockTransport.Object), loggerFactory: null, httpMessageHandler: mockHttpHandler.Object);
var connection = new HttpConnection(new Uri("http://fakeuri.org/"), new TestTransportFactory(mockTransport.Object), loggerFactory: null,
httpOptions: new HttpOptions { HttpMessageHandler = mockHttpHandler.Object });
connection.OnReceived( _ =>
{
throw new OperationCanceledException();
@ -461,8 +472,9 @@ namespace Microsoft.AspNetCore.Sockets.Client.Tests
using (var httpClient = new HttpClient(mockHttpHandler.Object))
{
var longPollingTransport = new LongPollingTransport(httpClient, new LoggerFactory());
var connection = new HttpConnection(new Uri("http://fakeuri.org/"), new TestTransportFactory(longPollingTransport), loggerFactory: null, httpMessageHandler: mockHttpHandler.Object);
var longPollingTransport = new LongPollingTransport(httpClient, null, new LoggerFactory());
var connection = new HttpConnection(new Uri("http://fakeuri.org/"), new TestTransportFactory(longPollingTransport), loggerFactory: null,
httpOptions: new HttpOptions { HttpMessageHandler = mockHttpHandler.Object });
try
{
@ -504,7 +516,8 @@ namespace Microsoft.AspNetCore.Sockets.Client.Tests
return ResponseUtils.CreateResponse(HttpStatusCode.OK);
});
var connection = new HttpConnection(new Uri("http://fakeuri.org/"), TransportType.LongPolling, loggerFactory: null, httpMessageHandler: mockHttpHandler.Object);
var connection = new HttpConnection(new Uri("http://fakeuri.org/"), TransportType.LongPolling, loggerFactory: null,
httpOptions: new HttpOptions { HttpMessageHandler = mockHttpHandler.Object });
try
{
await connection.StartAsync();
@ -550,7 +563,8 @@ namespace Microsoft.AspNetCore.Sockets.Client.Tests
: ResponseUtils.CreateResponse(HttpStatusCode.OK, content);
});
var connection = new HttpConnection(new Uri("http://fakeuri.org/"), TransportType.LongPolling, loggerFactory: null, httpMessageHandler: mockHttpHandler.Object);
var connection = new HttpConnection(new Uri("http://fakeuri.org/"), TransportType.LongPolling, loggerFactory: null,
httpOptions: new HttpOptions { HttpMessageHandler = mockHttpHandler.Object });
await connection.StartAsync();
await connection.DisposeAsync();
@ -578,7 +592,8 @@ namespace Microsoft.AspNetCore.Sockets.Client.Tests
: ResponseUtils.CreateResponse(HttpStatusCode.OK);
});
var connection = new HttpConnection(new Uri("http://fakeuri.org/"), TransportType.LongPolling, loggerFactory: null, httpMessageHandler: mockHttpHandler.Object);
var connection = new HttpConnection(new Uri("http://fakeuri.org/"), TransportType.LongPolling, loggerFactory: null,
httpOptions: new HttpOptions { HttpMessageHandler = mockHttpHandler.Object });
await connection.StartAsync();
var exception = await Assert.ThrowsAsync<HttpRequestException>(
@ -609,7 +624,8 @@ namespace Microsoft.AspNetCore.Sockets.Client.Tests
: ResponseUtils.CreateResponse(HttpStatusCode.OK, content);
});
var connection = new HttpConnection(new Uri("http://fakeuri.org/"), TransportType.LongPolling, loggerFactory: null, httpMessageHandler: mockHttpHandler.Object);
var connection = new HttpConnection(new Uri("http://fakeuri.org/"), TransportType.LongPolling, loggerFactory: null,
httpOptions: new HttpOptions { HttpMessageHandler = mockHttpHandler.Object });
try
{
var receiveTcs = new TaskCompletionSource<string>();
@ -664,7 +680,8 @@ namespace Microsoft.AspNetCore.Sockets.Client.Tests
: ResponseUtils.CreateResponse(HttpStatusCode.OK, content);
});
var connection = new HttpConnection(new Uri("http://fakeuri.org/"), TransportType.LongPolling, loggerFactory: null, httpMessageHandler: mockHttpHandler.Object);
var connection = new HttpConnection(new Uri("http://fakeuri.org/"), TransportType.LongPolling, loggerFactory: null,
httpOptions: new HttpOptions { HttpMessageHandler = mockHttpHandler.Object });
try
{
var receiveTcs = new TaskCompletionSource<string>();
@ -727,7 +744,8 @@ namespace Microsoft.AspNetCore.Sockets.Client.Tests
: ResponseUtils.CreateResponse(HttpStatusCode.OK, content);
});
var connection = new HttpConnection(new Uri("http://fakeuri.org/"), TransportType.LongPolling, loggerFactory: null, httpMessageHandler: mockHttpHandler.Object);
var connection = new HttpConnection(new Uri("http://fakeuri.org/"), TransportType.LongPolling, loggerFactory: null,
httpOptions: new HttpOptions { HttpMessageHandler = mockHttpHandler.Object });
try
{
var receiveTcs = new TaskCompletionSource<string>();
@ -785,7 +803,8 @@ namespace Microsoft.AspNetCore.Sockets.Client.Tests
: ResponseUtils.CreateResponse(HttpStatusCode.OK);
});
var connection = new HttpConnection(new Uri("http://fakeuri.org/"), TransportType.LongPolling, loggerFactory: null, httpMessageHandler: mockHttpHandler.Object);
var connection = new HttpConnection(new Uri("http://fakeuri.org/"), TransportType.LongPolling, loggerFactory: null,
httpOptions: new HttpOptions { HttpMessageHandler = mockHttpHandler.Object });
try
{
@ -818,7 +837,8 @@ namespace Microsoft.AspNetCore.Sockets.Client.Tests
return ResponseUtils.CreateResponse(HttpStatusCode.OK, negotiatePayload);
});
var connection = new HttpConnection(new Uri("http://fakeuri.org/"), TransportType.LongPolling, loggerFactory: null, httpMessageHandler: mockHttpHandler.Object);
var connection = new HttpConnection(new Uri("http://fakeuri.org/"), TransportType.LongPolling, loggerFactory: null,
httpOptions: new HttpOptions { HttpMessageHandler = mockHttpHandler.Object });
var exception = await Assert.ThrowsAsync<FormatException>(
() => connection.StartAsync());
@ -838,7 +858,8 @@ namespace Microsoft.AspNetCore.Sockets.Client.Tests
ResponseUtils.CreateNegotiationResponse(connectionId: null));
});
var connection = new HttpConnection(new Uri("http://fakeuri.org/"), TransportType.LongPolling, loggerFactory: null, httpMessageHandler: mockHttpHandler.Object);
var connection = new HttpConnection(new Uri("http://fakeuri.org/"), TransportType.LongPolling, loggerFactory: null,
httpOptions: new HttpOptions { HttpMessageHandler = mockHttpHandler.Object });
var exception = await Assert.ThrowsAsync<FormatException>(
() => connection.StartAsync());
@ -858,7 +879,8 @@ namespace Microsoft.AspNetCore.Sockets.Client.Tests
ResponseUtils.CreateNegotiationResponse(transportTypes: null));
});
var connection = new HttpConnection(new Uri("http://fakeuri.org/"), TransportType.LongPolling, loggerFactory: null, httpMessageHandler: mockHttpHandler.Object);
var connection = new HttpConnection(new Uri("http://fakeuri.org/"), TransportType.LongPolling, loggerFactory: null,
httpOptions: new HttpOptions { HttpMessageHandler = mockHttpHandler.Object });
var exception = await Assert.ThrowsAsync<FormatException>(
() => connection.StartAsync());
@ -880,7 +902,8 @@ namespace Microsoft.AspNetCore.Sockets.Client.Tests
ResponseUtils.CreateNegotiationResponse(transportTypes: serverTransports));
});
var connection = new HttpConnection(new Uri("http://fakeuri.org/"), TransportType.LongPolling, loggerFactory: null, httpMessageHandler: mockHttpHandler.Object);
var connection = new HttpConnection(new Uri("http://fakeuri.org/"), TransportType.LongPolling, loggerFactory: null,
httpOptions: new HttpOptions { HttpMessageHandler = mockHttpHandler.Object });
var exception = await Assert.ThrowsAsync<InvalidOperationException>(
() => connection.StartAsync());
@ -918,7 +941,7 @@ namespace Microsoft.AspNetCore.Sockets.Client.Tests
mockTransport.SetupGet(t => t.Mode).Returns(TransferMode.Binary);
var connection = new HttpConnection(new Uri("http://fakeuri.org/"), new TestTransportFactory(mockTransport.Object),
loggerFactory: null, httpMessageHandler: mockHttpHandler.Object);
loggerFactory: null, httpOptions: new HttpOptions { HttpMessageHandler = mockHttpHandler.Object });
await connection.StartAsync().OrTimeout();
var transferModeFeature = connection.Features.Get<ITransferModeFeature>();
@ -950,7 +973,8 @@ namespace Microsoft.AspNetCore.Sockets.Client.Tests
ResponseUtils.CreateNegotiationResponse());
});
var connection = new HttpConnection(new Uri(requested), TransportType.LongPolling, loggerFactory: null, httpMessageHandler: mockHttpHandler.Object);
var connection = new HttpConnection(new Uri(requested), TransportType.LongPolling, loggerFactory: null,
httpOptions: new HttpOptions { HttpMessageHandler = mockHttpHandler.Object });
await connection.StartAsync().OrTimeout();
await connection.DisposeAsync().OrTimeout();
}

View File

@ -20,7 +20,7 @@ namespace Microsoft.AspNetCore.SignalR.Tests
public void DefaultTransportFactoryCannotBeCreatedWithInvalidTransportType(TransportType transportType)
{
Assert.Throws<ArgumentOutOfRangeException>(
() => new DefaultTransportFactory(transportType, new LoggerFactory(), new HttpClient()));
() => new DefaultTransportFactory(transportType, new LoggerFactory(), new HttpClient(), httpOptions: null));
}
[Theory]
@ -32,7 +32,7 @@ namespace Microsoft.AspNetCore.SignalR.Tests
public void DefaultTransportFactoryCannotBeCreatedWithoutHttpClient(TransportType transportType)
{
var exception = Assert.Throws<ArgumentNullException>(
() => new DefaultTransportFactory(transportType, new LoggerFactory(), httpClient: null));
() => new DefaultTransportFactory(transportType, new LoggerFactory(), httpClient: null, httpOptions: null));
Assert.Equal("httpClient", exception.ParamName);
}
@ -40,7 +40,7 @@ namespace Microsoft.AspNetCore.SignalR.Tests
[Fact]
public void DefaultTransportFactoryCanBeCreatedWithoutHttpClientIfWebSocketsTransportRequestedExplicitly()
{
new DefaultTransportFactory(TransportType.WebSockets, new LoggerFactory(), httpClient: null);
new DefaultTransportFactory(TransportType.WebSockets, new LoggerFactory(), httpClient: null, httpOptions: null);
}
[ConditionalTheory]
@ -50,7 +50,7 @@ namespace Microsoft.AspNetCore.SignalR.Tests
[OSSkipCondition(OperatingSystems.Windows, WindowsVersions.Win7, WindowsVersions.Win2008R2, SkipReason = "No WebSockets Client for this platform")]
public void DefaultTransportFactoryCreatesRequestedTransportIfAvailable(TransportType requestedTransport, Type expectedTransportType)
{
var transportFactory = new DefaultTransportFactory(requestedTransport, loggerFactory: null, httpClient: new HttpClient());
var transportFactory = new DefaultTransportFactory(requestedTransport, loggerFactory: null, httpClient: new HttpClient(), httpOptions: null);
Assert.IsType(expectedTransportType,
transportFactory.CreateTransport(TransportType.All));
}
@ -63,7 +63,7 @@ namespace Microsoft.AspNetCore.SignalR.Tests
public void DefaultTransportFactoryThrowsIfItCannotCreateRequestedTransport(TransportType requestedTransport)
{
var transportFactory =
new DefaultTransportFactory(requestedTransport, loggerFactory: null, httpClient: new HttpClient());
new DefaultTransportFactory(requestedTransport, loggerFactory: null, httpClient: new HttpClient(), httpOptions: null);
var ex = Assert.Throws<InvalidOperationException>(
() => transportFactory.CreateTransport(~requestedTransport));
@ -75,7 +75,7 @@ namespace Microsoft.AspNetCore.SignalR.Tests
public void DefaultTransportFactoryCreatesWebSocketsTransportIfAvailable()
{
Assert.IsType<WebSocketsTransport>(
new DefaultTransportFactory(TransportType.All, loggerFactory: null, httpClient: new HttpClient())
new DefaultTransportFactory(TransportType.All, loggerFactory: null, httpClient: new HttpClient(), httpOptions: null)
.CreateTransport(TransportType.All));
}
@ -87,7 +87,7 @@ namespace Microsoft.AspNetCore.SignalR.Tests
{
if (!TestHelpers.IsWebSocketsSupported())
{
var transportFactory = new DefaultTransportFactory(requestedTransport, loggerFactory: null, httpClient: new HttpClient());
var transportFactory = new DefaultTransportFactory(requestedTransport, loggerFactory: null, httpClient: new HttpClient(), httpOptions: null);
Assert.IsType(expectedTransportType,
transportFactory.CreateTransport(TransportType.All));
}
@ -100,7 +100,7 @@ namespace Microsoft.AspNetCore.SignalR.Tests
if (!TestHelpers.IsWebSocketsSupported())
{
var transportFactory =
new DefaultTransportFactory(requestedTransport, loggerFactory: null, httpClient: new HttpClient());
new DefaultTransportFactory(requestedTransport, loggerFactory: null, httpClient: new HttpClient(), httpOptions: null);
var ex = Assert.Throws<InvalidOperationException>(
() => transportFactory.CreateTransport(TransportType.All));

View File

@ -12,6 +12,7 @@ using Microsoft.AspNetCore.SignalR.Client;
using Microsoft.AspNetCore.SignalR.Tests.Common;
using Microsoft.AspNetCore.Sockets;
using Microsoft.AspNetCore.Sockets.Client;
using Microsoft.AspNetCore.Sockets.Client.Http;
using Microsoft.AspNetCore.Sockets.Features;
using Microsoft.AspNetCore.Testing.xunit;
using Microsoft.Extensions.Logging;
@ -114,7 +115,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), TransportType.WebSockets, loggerFactory, mockHttpHandler.Object);
var connection = new HttpConnection(new Uri(url), TransportType.WebSockets, loggerFactory, new HttpOptions { HttpMessageHandler = mockHttpHandler.Object});
try
{

View File

@ -40,7 +40,7 @@ namespace Microsoft.AspNetCore.SignalR.Tests
var transportToConnection = Channel.CreateUnbounded<byte[]>();
var channelConnection = new ChannelConnection<SendMessage, byte[]>(connectionToTransport, transportToConnection);
var webSocketsTransport = new WebSocketsTransport(loggerFactory);
var webSocketsTransport = new WebSocketsTransport(httpOptions: null, loggerFactory: loggerFactory);
await webSocketsTransport.StartAsync(new Uri(_serverFixture.WebSocketsUrl + "/echo"), channelConnection,
TransferMode.Binary, connectionId: string.Empty).OrTimeout();
await webSocketsTransport.StopAsync().OrTimeout();
@ -58,7 +58,7 @@ namespace Microsoft.AspNetCore.SignalR.Tests
var transportToConnection = Channel.CreateUnbounded<byte[]>();
var channelConnection = new ChannelConnection<SendMessage, byte[]>(connectionToTransport, transportToConnection);
var webSocketsTransport = new WebSocketsTransport(loggerFactory);
var webSocketsTransport = new WebSocketsTransport(httpOptions: null, loggerFactory: loggerFactory);
await webSocketsTransport.StartAsync(new Uri(_serverFixture.WebSocketsUrl + "/echo"), channelConnection,
TransferMode.Binary, connectionId: string.Empty);
connectionToTransport.Writer.TryComplete();
@ -78,7 +78,7 @@ namespace Microsoft.AspNetCore.SignalR.Tests
var transportToConnection = Channel.CreateUnbounded<byte[]>();
var channelConnection = new ChannelConnection<SendMessage, byte[]>(connectionToTransport, transportToConnection);
var webSocketsTransport = new WebSocketsTransport(loggerFactory);
var webSocketsTransport = new WebSocketsTransport(httpOptions: null, loggerFactory: loggerFactory);
await webSocketsTransport.StartAsync(new Uri(_serverFixture.WebSocketsUrl + "/echo"), channelConnection, transferMode, connectionId: string.Empty);
var sendTcs = new TaskCompletionSource<object>();
@ -116,7 +116,7 @@ namespace Microsoft.AspNetCore.SignalR.Tests
var transportToConnection = Channel.CreateUnbounded<byte[]>();
var channelConnection = new ChannelConnection<SendMessage, byte[]>(connectionToTransport, transportToConnection);
var webSocketsTransport = new WebSocketsTransport(loggerFactory);
var webSocketsTransport = new WebSocketsTransport(httpOptions: null, loggerFactory: loggerFactory);
Assert.Null(webSocketsTransport.Mode);
await webSocketsTransport.StartAsync(new Uri(_serverFixture.WebSocketsUrl + "/echo"), channelConnection,
@ -138,7 +138,7 @@ namespace Microsoft.AspNetCore.SignalR.Tests
var transportToConnection = Channel.CreateUnbounded<byte[]>();
var channelConnection = new ChannelConnection<SendMessage, byte[]>(connectionToTransport, transportToConnection);
var webSocketsTransport = new WebSocketsTransport(loggerFactory);
var webSocketsTransport = new WebSocketsTransport(httpOptions: null, loggerFactory: loggerFactory);
var exception = await Assert.ThrowsAsync<ArgumentException>(() =>
webSocketsTransport.StartAsync(new Uri("http://fakeuri.org"), channelConnection, TransferMode.Text | TransferMode.Binary, connectionId: string.Empty));