Adopt Bedrock client abstractions in SignalR client (#11484)
This commit is contained in:
parent
82149f92ed
commit
30fe3a2288
|
|
@ -109,6 +109,10 @@ namespace Microsoft.AspNetCore.Connections
|
|||
Microsoft.AspNetCore.Connections.ConnectionDelegate Build();
|
||||
Microsoft.AspNetCore.Connections.IConnectionBuilder Use(System.Func<Microsoft.AspNetCore.Connections.ConnectionDelegate, Microsoft.AspNetCore.Connections.ConnectionDelegate> middleware);
|
||||
}
|
||||
public partial interface IConnectionFactory
|
||||
{
|
||||
System.Threading.Tasks.ValueTask<Microsoft.AspNetCore.Connections.ConnectionContext> ConnectAsync(System.Net.EndPoint endPoint, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken));
|
||||
}
|
||||
public partial interface IConnectionListener : System.IAsyncDisposable
|
||||
{
|
||||
System.Net.EndPoint EndPoint { get; }
|
||||
|
|
@ -125,6 +129,11 @@ namespace Microsoft.AspNetCore.Connections
|
|||
Binary = 1,
|
||||
Text = 2,
|
||||
}
|
||||
public partial class UriEndPoint : System.Net.EndPoint
|
||||
{
|
||||
public UriEndPoint(System.Uri uri) { }
|
||||
public System.Uri Uri { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
|
||||
}
|
||||
}
|
||||
namespace Microsoft.AspNetCore.Connections.Features
|
||||
{
|
||||
|
|
|
|||
|
|
@ -109,6 +109,10 @@ namespace Microsoft.AspNetCore.Connections
|
|||
Microsoft.AspNetCore.Connections.ConnectionDelegate Build();
|
||||
Microsoft.AspNetCore.Connections.IConnectionBuilder Use(System.Func<Microsoft.AspNetCore.Connections.ConnectionDelegate, Microsoft.AspNetCore.Connections.ConnectionDelegate> middleware);
|
||||
}
|
||||
public partial interface IConnectionFactory
|
||||
{
|
||||
System.Threading.Tasks.ValueTask<Microsoft.AspNetCore.Connections.ConnectionContext> ConnectAsync(System.Net.EndPoint endPoint, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken));
|
||||
}
|
||||
public partial interface IConnectionListener : System.IAsyncDisposable
|
||||
{
|
||||
System.Net.EndPoint EndPoint { get; }
|
||||
|
|
@ -125,6 +129,11 @@ namespace Microsoft.AspNetCore.Connections
|
|||
Binary = 1,
|
||||
Text = 2,
|
||||
}
|
||||
public partial class UriEndPoint : System.Net.EndPoint
|
||||
{
|
||||
public UriEndPoint(System.Uri uri) { }
|
||||
public System.Uri Uri { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
|
||||
}
|
||||
}
|
||||
namespace Microsoft.AspNetCore.Connections.Features
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,25 @@
|
|||
// 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.Net;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.AspNetCore.Connections
|
||||
{
|
||||
/// <summary>
|
||||
/// A factory abstraction for creating connections to an endpoint.
|
||||
/// </summary>
|
||||
public interface IConnectionFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new connection to an endpoint.
|
||||
/// </summary>
|
||||
/// <param name="endPoint">The <see cref="EndPoint"/> to connect to.</param>
|
||||
/// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is <see cref="CancellationToken.None" />.</param>
|
||||
/// <returns>
|
||||
/// A <see cref="ValueTask{TResult}" /> that represents the asynchronous connect, yielding the <see cref="ConnectionContext" /> for the new connection when completed.
|
||||
/// </returns>
|
||||
ValueTask<ConnectionContext> ConnectAsync(EndPoint endPoint, CancellationToken cancellationToken = default);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +1,7 @@
|
|||
// 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.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
// 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.Net;
|
||||
|
||||
namespace Microsoft.AspNetCore.Connections
|
||||
{
|
||||
/// <summary>
|
||||
/// An <see cref="EndPoint"/> defined by a <see cref="System.Uri"/>.
|
||||
/// </summary>
|
||||
public class UriEndPoint : EndPoint
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="UriEndPoint"/> class.
|
||||
/// </summary>
|
||||
/// <param name="uri">The <see cref="System.Uri"/> defining the <see cref="EndPoint"/>.</param>
|
||||
public UriEndPoint(Uri uri)
|
||||
{
|
||||
Uri = uri ?? throw new ArgumentNullException(nameof(uri));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="System.Uri"/> defining the <see cref="EndPoint"/>.
|
||||
/// </summary>
|
||||
public Uri Uri { get; }
|
||||
}
|
||||
}
|
||||
|
|
@ -8,9 +8,8 @@ namespace Microsoft.AspNetCore.SignalR.Client
|
|||
public static readonly System.TimeSpan DefaultHandshakeTimeout;
|
||||
public static readonly System.TimeSpan DefaultKeepAliveInterval;
|
||||
public static readonly System.TimeSpan DefaultServerTimeout;
|
||||
public HubConnection(Microsoft.AspNetCore.SignalR.Client.IConnectionFactory connectionFactory, Microsoft.AspNetCore.SignalR.Protocol.IHubProtocol protocol, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) { }
|
||||
public HubConnection(Microsoft.AspNetCore.SignalR.Client.IConnectionFactory connectionFactory, Microsoft.AspNetCore.SignalR.Protocol.IHubProtocol protocol, System.IServiceProvider serviceProvider, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) { }
|
||||
public HubConnection(Microsoft.AspNetCore.SignalR.Client.IConnectionFactory connectionFactory, Microsoft.AspNetCore.SignalR.Protocol.IHubProtocol protocol, System.IServiceProvider serviceProvider, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory, Microsoft.AspNetCore.SignalR.Client.IRetryPolicy reconnectPolicy) { }
|
||||
public HubConnection(Microsoft.AspNetCore.Connections.IConnectionFactory connectionFactory, Microsoft.AspNetCore.SignalR.Protocol.IHubProtocol protocol, System.Net.EndPoint endPoint, System.IServiceProvider serviceProvider, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) { }
|
||||
public HubConnection(Microsoft.AspNetCore.Connections.IConnectionFactory connectionFactory, Microsoft.AspNetCore.SignalR.Protocol.IHubProtocol protocol, System.Net.EndPoint endPoint, System.IServiceProvider serviceProvider, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory, Microsoft.AspNetCore.SignalR.Client.IRetryPolicy reconnectPolicy) { }
|
||||
public string ConnectionId { get { throw null; } }
|
||||
public System.TimeSpan HandshakeTimeout { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||
public System.TimeSpan KeepAliveInterval { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||
|
|
@ -145,11 +144,6 @@ namespace Microsoft.AspNetCore.SignalR.Client
|
|||
Connecting = 2,
|
||||
Reconnecting = 3,
|
||||
}
|
||||
public partial interface IConnectionFactory
|
||||
{
|
||||
System.Threading.Tasks.Task<Microsoft.AspNetCore.Connections.ConnectionContext> ConnectAsync(Microsoft.AspNetCore.Connections.TransferFormat transferFormat, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken));
|
||||
System.Threading.Tasks.Task DisposeAsync(Microsoft.AspNetCore.Connections.ConnectionContext connection);
|
||||
}
|
||||
public partial interface IHubConnectionBuilder : Microsoft.AspNetCore.SignalR.ISignalRBuilder
|
||||
{
|
||||
Microsoft.AspNetCore.SignalR.Client.HubConnection Build();
|
||||
|
|
|
|||
|
|
@ -8,9 +8,8 @@ namespace Microsoft.AspNetCore.SignalR.Client
|
|||
public static readonly System.TimeSpan DefaultHandshakeTimeout;
|
||||
public static readonly System.TimeSpan DefaultKeepAliveInterval;
|
||||
public static readonly System.TimeSpan DefaultServerTimeout;
|
||||
public HubConnection(Microsoft.AspNetCore.SignalR.Client.IConnectionFactory connectionFactory, Microsoft.AspNetCore.SignalR.Protocol.IHubProtocol protocol, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) { }
|
||||
public HubConnection(Microsoft.AspNetCore.SignalR.Client.IConnectionFactory connectionFactory, Microsoft.AspNetCore.SignalR.Protocol.IHubProtocol protocol, System.IServiceProvider serviceProvider, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) { }
|
||||
public HubConnection(Microsoft.AspNetCore.SignalR.Client.IConnectionFactory connectionFactory, Microsoft.AspNetCore.SignalR.Protocol.IHubProtocol protocol, System.IServiceProvider serviceProvider, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory, Microsoft.AspNetCore.SignalR.Client.IRetryPolicy reconnectPolicy) { }
|
||||
public HubConnection(Microsoft.AspNetCore.Connections.IConnectionFactory connectionFactory, Microsoft.AspNetCore.SignalR.Protocol.IHubProtocol protocol, System.Net.EndPoint endPoint, System.IServiceProvider serviceProvider, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) { }
|
||||
public HubConnection(Microsoft.AspNetCore.Connections.IConnectionFactory connectionFactory, Microsoft.AspNetCore.SignalR.Protocol.IHubProtocol protocol, System.Net.EndPoint endPoint, System.IServiceProvider serviceProvider, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory, Microsoft.AspNetCore.SignalR.Client.IRetryPolicy reconnectPolicy) { }
|
||||
public string ConnectionId { get { throw null; } }
|
||||
public System.TimeSpan HandshakeTimeout { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||
public System.TimeSpan KeepAliveInterval { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||
|
|
@ -145,11 +144,6 @@ namespace Microsoft.AspNetCore.SignalR.Client
|
|||
Connecting = 2,
|
||||
Reconnecting = 3,
|
||||
}
|
||||
public partial interface IConnectionFactory
|
||||
{
|
||||
System.Threading.Tasks.Task<Microsoft.AspNetCore.Connections.ConnectionContext> ConnectAsync(Microsoft.AspNetCore.Connections.TransferFormat transferFormat, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken));
|
||||
System.Threading.Tasks.Task DisposeAsync(Microsoft.AspNetCore.Connections.ConnectionContext connection);
|
||||
}
|
||||
public partial interface IHubConnectionBuilder : Microsoft.AspNetCore.SignalR.ISignalRBuilder
|
||||
{
|
||||
Microsoft.AspNetCore.SignalR.Client.HubConnection Build();
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ using System.Diagnostics;
|
|||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
|
|
@ -21,6 +22,7 @@ using Microsoft.AspNetCore.SignalR.Internal;
|
|||
using Microsoft.AspNetCore.SignalR.Protocol;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Microsoft.AspNetCore.SignalR.Client
|
||||
{
|
||||
|
|
@ -59,6 +61,7 @@ namespace Microsoft.AspNetCore.SignalR.Client
|
|||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly IConnectionFactory _connectionFactory;
|
||||
private readonly IRetryPolicy _reconnectPolicy;
|
||||
private readonly EndPoint _endPoint;
|
||||
private readonly ConcurrentDictionary<string, InvocationHandlerList> _handlers = new ConcurrentDictionary<string, InvocationHandlerList>(StringComparer.Ordinal);
|
||||
|
||||
// Holds all mutable state other than user-defined handlers and settable properties.
|
||||
|
|
@ -172,6 +175,7 @@ namespace Microsoft.AspNetCore.SignalR.Client
|
|||
/// </summary>
|
||||
/// <param name="connectionFactory">The <see cref="IConnectionFactory" /> used to create a connection each time <see cref="StartAsync" /> is called.</param>
|
||||
/// <param name="protocol">The <see cref="IHubProtocol" /> used by the connection.</param>
|
||||
/// <param name="endPoint">The <see cref="EndPoint"/> to connect to.</param>
|
||||
/// <param name="serviceProvider">An <see cref="IServiceProvider"/> containing the services provided to this <see cref="HubConnection"/> instance.</param>
|
||||
/// <param name="loggerFactory">The logger factory.</param>
|
||||
/// <param name="reconnectPolicy">
|
||||
|
|
@ -181,8 +185,8 @@ namespace Microsoft.AspNetCore.SignalR.Client
|
|||
/// <remarks>
|
||||
/// The <see cref="IServiceProvider"/> used to initialize the connection will be disposed when the connection is disposed.
|
||||
/// </remarks>
|
||||
public HubConnection(IConnectionFactory connectionFactory, IHubProtocol protocol, IServiceProvider serviceProvider, ILoggerFactory loggerFactory, IRetryPolicy reconnectPolicy)
|
||||
: this(connectionFactory, protocol, serviceProvider, loggerFactory)
|
||||
public HubConnection(IConnectionFactory connectionFactory, IHubProtocol protocol, EndPoint endPoint, IServiceProvider serviceProvider, ILoggerFactory loggerFactory, IRetryPolicy reconnectPolicy)
|
||||
: this(connectionFactory, protocol, endPoint, serviceProvider, loggerFactory)
|
||||
{
|
||||
_reconnectPolicy = reconnectPolicy;
|
||||
}
|
||||
|
|
@ -192,27 +196,22 @@ namespace Microsoft.AspNetCore.SignalR.Client
|
|||
/// </summary>
|
||||
/// <param name="connectionFactory">The <see cref="IConnectionFactory" /> used to create a connection each time <see cref="StartAsync" /> is called.</param>
|
||||
/// <param name="protocol">The <see cref="IHubProtocol" /> used by the connection.</param>
|
||||
/// <param name="endPoint">The <see cref="EndPoint"/> to connect to.</param>
|
||||
/// <param name="serviceProvider">An <see cref="IServiceProvider"/> containing the services provided to this <see cref="HubConnection"/> instance.</param>
|
||||
/// <param name="loggerFactory">The logger factory.</param>
|
||||
/// <remarks>
|
||||
/// The <see cref="IServiceProvider"/> used to initialize the connection will be disposed when the connection is disposed.
|
||||
/// </remarks>
|
||||
public HubConnection(IConnectionFactory connectionFactory, IHubProtocol protocol, IServiceProvider serviceProvider, ILoggerFactory loggerFactory)
|
||||
: this(connectionFactory, protocol, loggerFactory)
|
||||
{
|
||||
_serviceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="HubConnection"/> class.
|
||||
/// </summary>
|
||||
/// <param name="connectionFactory">The <see cref="IConnectionFactory" /> used to create a connection each time <see cref="StartAsync" /> is called.</param>
|
||||
/// <param name="protocol">The <see cref="IHubProtocol" /> used by the connection.</param>
|
||||
/// <param name="loggerFactory">The logger factory.</param>
|
||||
public HubConnection(IConnectionFactory connectionFactory, IHubProtocol protocol, ILoggerFactory loggerFactory)
|
||||
public HubConnection(IConnectionFactory connectionFactory,
|
||||
IHubProtocol protocol,
|
||||
EndPoint endPoint,
|
||||
IServiceProvider serviceProvider,
|
||||
ILoggerFactory loggerFactory)
|
||||
{
|
||||
_connectionFactory = connectionFactory ?? throw new ArgumentNullException(nameof(connectionFactory));
|
||||
_protocol = protocol ?? throw new ArgumentNullException(nameof(protocol));
|
||||
_endPoint = endPoint ?? throw new ArgumentException(nameof(endPoint));
|
||||
_serviceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider));
|
||||
|
||||
_loggerFactory = loggerFactory ?? NullLoggerFactory.Instance;
|
||||
_logger = _loggerFactory.CreateLogger<HubConnection>();
|
||||
|
|
@ -424,7 +423,7 @@ namespace Microsoft.AspNetCore.SignalR.Client
|
|||
Log.Starting(_logger);
|
||||
|
||||
// Start the connection
|
||||
var connection = await _connectionFactory.ConnectAsync(_protocol.TransferFormat, cancellationToken);
|
||||
var connection = await _connectionFactory.ConnectAsync(_endPoint, cancellationToken);
|
||||
var startingConnectionState = new ConnectionState(connection, this);
|
||||
|
||||
// From here on, if an error occurs we need to shut down the connection because
|
||||
|
|
@ -450,9 +449,9 @@ namespace Microsoft.AspNetCore.SignalR.Client
|
|||
Log.Started(_logger);
|
||||
}
|
||||
|
||||
private Task CloseAsync(ConnectionContext connection)
|
||||
private ValueTask CloseAsync(ConnectionContext connection)
|
||||
{
|
||||
return _connectionFactory.DisposeAsync(connection);
|
||||
return connection.DisposeAsync();
|
||||
}
|
||||
|
||||
// This method does both Dispose and Start, the 'disposing' flag indicates which.
|
||||
|
|
|
|||
|
|
@ -3,7 +3,11 @@
|
|||
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using Microsoft.AspNetCore.Connections;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Microsoft.AspNetCore.SignalR.Client
|
||||
{
|
||||
|
|
@ -42,11 +46,11 @@ namespace Microsoft.AspNetCore.SignalR.Client
|
|||
// The service provider is disposed by the HubConnection
|
||||
var serviceProvider = Services.BuildServiceProvider();
|
||||
|
||||
var connectionFactory = serviceProvider.GetService<IConnectionFactory>();
|
||||
if (connectionFactory == null)
|
||||
{
|
||||
var connectionFactory = serviceProvider.GetService<IConnectionFactory>() ??
|
||||
throw new InvalidOperationException($"Cannot create {nameof(HubConnection)} instance. An {nameof(IConnectionFactory)} was not configured.");
|
||||
}
|
||||
|
||||
var endPoint = serviceProvider.GetService<EndPoint>() ??
|
||||
throw new InvalidOperationException($"Cannot create {nameof(HubConnection)} instance. An {nameof(EndPoint)} was not configured.");
|
||||
|
||||
return serviceProvider.GetService<HubConnection>();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,35 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Connections;
|
||||
|
||||
namespace Microsoft.AspNetCore.SignalR.Client
|
||||
{
|
||||
/// <summary>
|
||||
/// A factory abstraction for creating connections to a SignalR server.
|
||||
/// </summary>
|
||||
public interface IConnectionFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new connection to a SignalR server using the specified <see cref="TransferFormat"/>.
|
||||
/// </summary>
|
||||
/// <param name="transferFormat">The transfer format the connection should use.</param>
|
||||
/// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is <see cref="CancellationToken.None" />.</param>
|
||||
/// <returns>
|
||||
/// A <see cref="Task{TResult}"/> that represents the asynchronous connect.
|
||||
/// The <see cref="Task{TResult}.Result"/> property returns a <see cref="ConnectionContext"/> for the new connection.
|
||||
/// </returns>
|
||||
Task<ConnectionContext> ConnectAsync(TransferFormat transferFormat, CancellationToken cancellationToken = default);
|
||||
|
||||
// Current plan for IAsyncDisposable is that DisposeAsync will NOT take a CancellationToken
|
||||
// https://github.com/dotnet/csharplang/blob/195efa07806284d7b57550e7447dc8bd39c156bf/proposals/async-streams.md#iasyncdisposable
|
||||
/// <summary>
|
||||
/// Disposes the specified <see cref="ConnectionContext"/>.
|
||||
/// </summary>
|
||||
/// <param name="connection">The connection to dispose.</param>
|
||||
/// <returns>A <see cref="Task"/> that represents the asynchronous dispose.</returns>
|
||||
Task DisposeAsync(ConnectionContext connection);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<Description>Client for ASP.NET Core SignalR</Description>
|
||||
|
|
|
|||
|
|
@ -3,13 +3,6 @@
|
|||
|
||||
namespace Microsoft.AspNetCore.SignalR.Client
|
||||
{
|
||||
public partial class HttpConnectionFactory : Microsoft.AspNetCore.SignalR.Client.IConnectionFactory
|
||||
{
|
||||
public HttpConnectionFactory(Microsoft.Extensions.Options.IOptions<Microsoft.AspNetCore.Http.Connections.Client.HttpConnectionOptions> options, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) { }
|
||||
[System.Diagnostics.DebuggerStepThroughAttribute]
|
||||
public System.Threading.Tasks.Task<Microsoft.AspNetCore.Connections.ConnectionContext> ConnectAsync(Microsoft.AspNetCore.Connections.TransferFormat transferFormat, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
|
||||
public System.Threading.Tasks.Task DisposeAsync(Microsoft.AspNetCore.Connections.ConnectionContext connection) { throw null; }
|
||||
}
|
||||
public static partial class HubConnectionBuilderHttpExtensions
|
||||
{
|
||||
public static Microsoft.AspNetCore.SignalR.Client.IHubConnectionBuilder WithUrl(this Microsoft.AspNetCore.SignalR.Client.IHubConnectionBuilder hubConnectionBuilder, string url) { throw null; }
|
||||
|
|
|
|||
|
|
@ -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.Net;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Connections;
|
||||
|
|
@ -14,7 +15,7 @@ namespace Microsoft.AspNetCore.SignalR.Client
|
|||
/// <summary>
|
||||
/// A factory for creating <see cref="HttpConnection"/> instances.
|
||||
/// </summary>
|
||||
public class HttpConnectionFactory : IConnectionFactory
|
||||
internal class HttpConnectionFactory : IConnectionFactory
|
||||
{
|
||||
private readonly HttpConnectionOptions _httpConnectionOptions;
|
||||
private readonly ILoggerFactory _loggerFactory;
|
||||
|
|
@ -31,22 +32,44 @@ namespace Microsoft.AspNetCore.SignalR.Client
|
|||
throw new ArgumentNullException(nameof(options));
|
||||
}
|
||||
|
||||
if (loggerFactory == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(loggerFactory));
|
||||
}
|
||||
|
||||
_httpConnectionOptions = options.Value;
|
||||
_loggerFactory = loggerFactory;
|
||||
_loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<ConnectionContext> ConnectAsync(TransferFormat transferFormat, CancellationToken cancellationToken = default)
|
||||
/// <summary>
|
||||
/// Creates a new connection to an <see cref="UriEndPoint"/>.
|
||||
/// </summary>
|
||||
/// <param name="endPoint">The <see cref="UriEndPoint"/> to connect to.</param>
|
||||
/// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is <see cref="CancellationToken.None" />.</param>
|
||||
/// <returns>
|
||||
/// A <see cref="ValueTask{TResult}" /> that represents the asynchronous connect, yielding the <see cref="ConnectionContext" /> for the new connection when completed.
|
||||
/// </returns>
|
||||
public async ValueTask<ConnectionContext> ConnectAsync(EndPoint endPoint, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var connection = new HttpConnection(_httpConnectionOptions, _loggerFactory);
|
||||
if (endPoint == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(endPoint));
|
||||
}
|
||||
|
||||
if (!(endPoint is UriEndPoint uriEndPoint))
|
||||
{
|
||||
throw new NotSupportedException($"The provided {nameof(EndPoint)} must be of type {nameof(UriEndPoint)}.");
|
||||
}
|
||||
|
||||
if (_httpConnectionOptions.Url != null && _httpConnectionOptions.Url != uriEndPoint.Uri)
|
||||
{
|
||||
throw new InvalidOperationException($"If {nameof(HttpConnectionOptions)}.{nameof(HttpConnectionOptions.Url)} was set, it must match the {nameof(UriEndPoint)}.{nameof(UriEndPoint.Uri)} passed to {nameof(ConnectAsync)}.");
|
||||
}
|
||||
|
||||
// Shallow copy before setting the Url property so we don't mutate the user-defined options object.
|
||||
var shallowCopiedOptions = ShallowCopyHttpConnectionOptions(_httpConnectionOptions);
|
||||
shallowCopiedOptions.Url = uriEndPoint.Uri;
|
||||
|
||||
var connection = new HttpConnection(shallowCopiedOptions, _loggerFactory);
|
||||
|
||||
try
|
||||
{
|
||||
await connection.StartAsync(transferFormat, cancellationToken);
|
||||
await connection.StartAsync(cancellationToken);
|
||||
return connection;
|
||||
}
|
||||
catch
|
||||
|
|
@ -57,10 +80,26 @@ namespace Microsoft.AspNetCore.SignalR.Client
|
|||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task DisposeAsync(ConnectionContext connection)
|
||||
// Internal for testing
|
||||
internal static HttpConnectionOptions ShallowCopyHttpConnectionOptions(HttpConnectionOptions options)
|
||||
{
|
||||
return connection.DisposeAsync().AsTask();
|
||||
return new HttpConnectionOptions
|
||||
{
|
||||
HttpMessageHandlerFactory = options.HttpMessageHandlerFactory,
|
||||
Headers = options.Headers,
|
||||
ClientCertificates = options.ClientCertificates,
|
||||
Cookies = options.Cookies,
|
||||
Url = options.Url,
|
||||
Transports = options.Transports,
|
||||
SkipNegotiation = options.SkipNegotiation,
|
||||
AccessTokenProvider = options.AccessTokenProvider,
|
||||
CloseTimeout = options.CloseTimeout,
|
||||
Credentials = options.Credentials,
|
||||
Proxy = options.Proxy,
|
||||
UseDefaultCredentials = options.UseDefaultCredentials,
|
||||
DefaultTransferFormat = options.DefaultTransferFormat,
|
||||
WebSocketConfiguration = options.WebSocketConfiguration,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,9 +2,13 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Net;
|
||||
using Microsoft.AspNetCore.Connections;
|
||||
using Microsoft.AspNetCore.Http.Connections;
|
||||
using Microsoft.AspNetCore.Http.Connections.Client;
|
||||
using Microsoft.AspNetCore.SignalR.Protocol;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Microsoft.AspNetCore.SignalR.Client
|
||||
{
|
||||
|
|
@ -138,8 +142,44 @@ namespace Microsoft.AspNetCore.SignalR.Client
|
|||
hubConnectionBuilder.Services.Configure(configureHttpConnection);
|
||||
}
|
||||
|
||||
// Add HttpConnectionOptionsDerivedHttpEndPoint so HubConnection can read the Url from HttpConnectionOptions
|
||||
// without the Signal.Client.Core project taking a new dependency on Http.Connections.Client.
|
||||
hubConnectionBuilder.Services.AddSingleton<EndPoint, HttpConnectionOptionsDerivedHttpEndPoint>();
|
||||
|
||||
// Configure the HttpConnection so that it uses the correct transfer format for the configured IHubProtocol.
|
||||
hubConnectionBuilder.Services.AddSingleton<IConfigureOptions<HttpConnectionOptions>, HubProtocolDerivedHttpOptionsConfigurer>();
|
||||
|
||||
// If and when HttpConnectionFactory is made public, it can be moved out of this assembly and into Http.Connections.Client.
|
||||
hubConnectionBuilder.Services.AddSingleton<IConnectionFactory, HttpConnectionFactory>();
|
||||
return hubConnectionBuilder;
|
||||
}
|
||||
|
||||
private class HttpConnectionOptionsDerivedHttpEndPoint : UriEndPoint
|
||||
{
|
||||
public HttpConnectionOptionsDerivedHttpEndPoint(IOptions<HttpConnectionOptions> httpConnectionOptions)
|
||||
: base(httpConnectionOptions.Value.Url)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private class HubProtocolDerivedHttpOptionsConfigurer : IConfigureNamedOptions<HttpConnectionOptions>
|
||||
{
|
||||
private readonly TransferFormat _defaultTransferFormat;
|
||||
|
||||
public HubProtocolDerivedHttpOptionsConfigurer(IHubProtocol hubProtocol)
|
||||
{
|
||||
_defaultTransferFormat = hubProtocol.TransferFormat;
|
||||
}
|
||||
|
||||
public void Configure(string name, HttpConnectionOptions options)
|
||||
{
|
||||
Configure(options);
|
||||
}
|
||||
|
||||
public void Configure(HttpConnectionOptions options)
|
||||
{
|
||||
options.DefaultTransferFormat = _defaultTransferFormat;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,4 +11,8 @@
|
|||
<Reference Include="Microsoft.AspNetCore.Http.Connections.Client" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<InternalsVisibleTo Include="Microsoft.AspNetCore.SignalR.Client.Tests" />
|
||||
<InternalsVisibleTo Include="Microsoft.AspNetCore.SignalR.Client.FunctionalTests" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Channels;
|
||||
|
|
@ -13,7 +14,6 @@ using Microsoft.AspNetCore.Http.Connections;
|
|||
using Microsoft.AspNetCore.Http.Connections.Client;
|
||||
using Microsoft.AspNetCore.SignalR.Protocol;
|
||||
using Microsoft.AspNetCore.SignalR.Tests;
|
||||
using Microsoft.AspNetCore.Testing;
|
||||
using Microsoft.AspNetCore.Testing.xunit;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
|
@ -42,10 +42,10 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
|
|||
{
|
||||
var hubConnectionBuilder = new HubConnectionBuilder();
|
||||
|
||||
if (protocol != null)
|
||||
{
|
||||
hubConnectionBuilder.Services.AddSingleton(protocol);
|
||||
}
|
||||
hubConnectionBuilder.WithUrl(url + path);
|
||||
|
||||
protocol ??= new JsonHubProtocol();
|
||||
hubConnectionBuilder.Services.AddSingleton(protocol);
|
||||
|
||||
if (loggerFactory != null)
|
||||
{
|
||||
|
|
@ -57,20 +57,25 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
|
|||
hubConnectionBuilder.WithAutomaticReconnect();
|
||||
}
|
||||
|
||||
transportType ??= HttpTransportType.LongPolling | HttpTransportType.WebSockets | HttpTransportType.ServerSentEvents;
|
||||
|
||||
var delegateConnectionFactory = new DelegateConnectionFactory(
|
||||
GetHttpConnectionFactory(url, loggerFactory, path, transportType ?? HttpTransportType.LongPolling | HttpTransportType.WebSockets | HttpTransportType.ServerSentEvents),
|
||||
connection => ((HttpConnection)connection).DisposeAsync().AsTask());
|
||||
GetHttpConnectionFactory(url, loggerFactory, path, transportType.Value, protocol.TransferFormat));
|
||||
hubConnectionBuilder.Services.AddSingleton<IConnectionFactory>(delegateConnectionFactory);
|
||||
|
||||
return hubConnectionBuilder.Build();
|
||||
}
|
||||
|
||||
private Func<TransferFormat, Task<ConnectionContext>> GetHttpConnectionFactory(string url, ILoggerFactory loggerFactory, string path, HttpTransportType transportType)
|
||||
private Func<EndPoint, ValueTask<ConnectionContext>> GetHttpConnectionFactory(string url, ILoggerFactory loggerFactory, string path, HttpTransportType transportType, TransferFormat transferFormat)
|
||||
{
|
||||
return async format =>
|
||||
return async endPoint =>
|
||||
{
|
||||
var connection = new HttpConnection(new Uri(url + path), transportType, loggerFactory);
|
||||
await connection.StartAsync(format);
|
||||
var httpEndpoint = (UriEndPoint)endPoint;
|
||||
var options = new HttpConnectionOptions { Url = httpEndpoint.Uri, Transports = transportType, DefaultTransferFormat = transferFormat };
|
||||
var connection = new HttpConnection(options, loggerFactory);
|
||||
|
||||
await connection.StartAsync();
|
||||
|
||||
return connection;
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
using System;
|
||||
using System.Buffers;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
|
@ -101,16 +102,19 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
|
|||
{
|
||||
using (StartServer<VersionStartup>(out var server))
|
||||
{
|
||||
var httpConnectionFactory = new HttpConnectionFactory(Options.Create(new HttpConnectionOptions
|
||||
{
|
||||
Url = new Uri(server.Url + "/version"),
|
||||
Transports = transportType
|
||||
}), LoggerFactory);
|
||||
var httpConnectionFactory = new HttpConnectionFactory(
|
||||
Options.Create(new HttpConnectionOptions
|
||||
{
|
||||
Transports = transportType,
|
||||
DefaultTransferFormat = TransferFormat.Text
|
||||
}),
|
||||
LoggerFactory);
|
||||
var tcs = new TaskCompletionSource<object>();
|
||||
|
||||
var proxyConnectionFactory = new ProxyConnectionFactory(httpConnectionFactory);
|
||||
|
||||
var connectionBuilder = new HubConnectionBuilder()
|
||||
.WithUrl(new Uri(server.Url + "/version"))
|
||||
.WithLoggerFactory(LoggerFactory);
|
||||
connectionBuilder.Services.AddSingleton<IHubProtocol>(new VersionedJsonHubProtocol(1000));
|
||||
connectionBuilder.Services.AddSingleton<IConnectionFactory>(proxyConnectionFactory);
|
||||
|
|
@ -192,23 +196,18 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
|
|||
private class ProxyConnectionFactory : IConnectionFactory
|
||||
{
|
||||
private readonly IConnectionFactory _innerFactory;
|
||||
public Task<ConnectionContext> ConnectTask { get; private set; }
|
||||
public ValueTask<ConnectionContext> ConnectTask { get; private set; }
|
||||
|
||||
public ProxyConnectionFactory(IConnectionFactory innerFactory)
|
||||
{
|
||||
_innerFactory = innerFactory;
|
||||
}
|
||||
|
||||
public Task<ConnectionContext> ConnectAsync(TransferFormat transferFormat, CancellationToken cancellationToken = default)
|
||||
public ValueTask<ConnectionContext> ConnectAsync(EndPoint endPoint, CancellationToken cancellationToken = default)
|
||||
{
|
||||
ConnectTask = _innerFactory.ConnectAsync(transferFormat, cancellationToken);
|
||||
ConnectTask = _innerFactory.ConnectAsync(endPoint, cancellationToken);
|
||||
return ConnectTask;
|
||||
}
|
||||
|
||||
public Task DisposeAsync(ConnectionContext connection)
|
||||
{
|
||||
return _innerFactory.DisposeAsync(connection);
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<object[]> TransportTypes()
|
||||
|
|
|
|||
|
|
@ -1,10 +1,20 @@
|
|||
// 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.Reflection;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Connections;
|
||||
using Microsoft.AspNetCore.Http.Connections;
|
||||
using Microsoft.AspNetCore.Http.Connections.Client;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
||||
|
|
@ -17,16 +27,94 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
|||
var testHandler = new TestHttpMessageHandler(autoNegotiate: false, handleFirstPoll: false);
|
||||
testHandler.OnRequest((req, next, ct) => Task.FromException<HttpResponseMessage>(new Exception("BOOM")));
|
||||
|
||||
var factory = new HttpConnectionFactory(Options.Create(new HttpConnectionOptions() {
|
||||
Url = new Uri("http://example.com"),
|
||||
HttpMessageHandlerFactory = _ => testHandler
|
||||
}), NullLoggerFactory.Instance);
|
||||
var factory = new HttpConnectionFactory(
|
||||
Options.Create(new HttpConnectionOptions
|
||||
{
|
||||
DefaultTransferFormat = TransferFormat.Text,
|
||||
HttpMessageHandlerFactory = _ => testHandler,
|
||||
}),
|
||||
NullLoggerFactory.Instance);
|
||||
|
||||
// We don't care about the specific exception
|
||||
await Assert.ThrowsAnyAsync<Exception>(() => factory.ConnectAsync(TransferFormat.Text));
|
||||
await Assert.ThrowsAnyAsync<Exception>(async () => await factory.ConnectAsync(new UriEndPoint(new Uri("http://example.com"))));
|
||||
|
||||
// We care that the handler (and by extension the client) was disposed
|
||||
Assert.True(testHandler.Disposed);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task DoesNotSupportNonUriEndPoints()
|
||||
{
|
||||
var factory = new HttpConnectionFactory(
|
||||
Options.Create(new HttpConnectionOptions { DefaultTransferFormat = TransferFormat.Text }),
|
||||
NullLoggerFactory.Instance);
|
||||
|
||||
var ex = await Assert.ThrowsAsync<NotSupportedException>(async () => await factory.ConnectAsync(new IPEndPoint(IPAddress.Loopback, 0)));
|
||||
|
||||
Assert.Equal("The provided EndPoint must be of type UriEndPoint.", ex.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task OptionsUrlMustMatchEndPointIfSet()
|
||||
{
|
||||
var url1 = new Uri("http://example.com/1");
|
||||
var url2 = new Uri("http://example.com/2");
|
||||
|
||||
var factory = new HttpConnectionFactory(
|
||||
Options.Create(new HttpConnectionOptions
|
||||
{
|
||||
Url = url1,
|
||||
DefaultTransferFormat = TransferFormat.Text
|
||||
}),
|
||||
NullLoggerFactory.Instance);
|
||||
|
||||
var ex = await Assert.ThrowsAsync<InvalidOperationException>(async () => await factory.ConnectAsync(new UriEndPoint(url2)));
|
||||
Assert.Equal("If HttpConnectionOptions.Url was set, it must match the UriEndPoint.Uri passed to ConnectAsync.", ex.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ShallowCopyHttpConnectionOptionsCopiesAllPublicProperties()
|
||||
{
|
||||
Func<HttpMessageHandler, HttpMessageHandler> handlerFactory = handler => handler;
|
||||
Func<Task<string>> tokenProvider = () => Task.FromResult("");
|
||||
Action<ClientWebSocketOptions> webSocketConfig = options => { };
|
||||
|
||||
var testValues = new Dictionary<string, object>
|
||||
{
|
||||
{ $"{nameof(HttpConnectionOptions.HttpMessageHandlerFactory)}", handlerFactory },
|
||||
{ $"{nameof(HttpConnectionOptions.Headers)}", new Dictionary<string, string>() },
|
||||
{ $"{nameof(HttpConnectionOptions.ClientCertificates)}", new X509CertificateCollection() },
|
||||
{ $"{nameof(HttpConnectionOptions.Cookies)}", new CookieContainer() },
|
||||
{ $"{nameof(HttpConnectionOptions.Url)}", new Uri("https://example.com") },
|
||||
{ $"{nameof(HttpConnectionOptions.Transports)}", HttpTransportType.ServerSentEvents },
|
||||
{ $"{nameof(HttpConnectionOptions.SkipNegotiation)}", true },
|
||||
{ $"{nameof(HttpConnectionOptions.AccessTokenProvider)}", tokenProvider },
|
||||
{ $"{nameof(HttpConnectionOptions.CloseTimeout)}", TimeSpan.FromDays(1) },
|
||||
{ $"{nameof(HttpConnectionOptions.Credentials)}", Mock.Of<ICredentials>() },
|
||||
{ $"{nameof(HttpConnectionOptions.Proxy)}", Mock.Of<IWebProxy>() },
|
||||
{ $"{nameof(HttpConnectionOptions.UseDefaultCredentials)}", true },
|
||||
{ $"{nameof(HttpConnectionOptions.DefaultTransferFormat)}", TransferFormat.Text },
|
||||
{ $"{nameof(HttpConnectionOptions.WebSocketConfiguration)}", webSocketConfig },
|
||||
};
|
||||
|
||||
var options = new HttpConnectionOptions();
|
||||
var properties = typeof(HttpConnectionOptions)
|
||||
.GetProperties(BindingFlags.Public | BindingFlags.Instance);
|
||||
|
||||
foreach (var property in properties)
|
||||
{
|
||||
property.SetValue(options, testValues[property.Name]);
|
||||
}
|
||||
|
||||
var shallowCopiedOptions = HttpConnectionFactory.ShallowCopyHttpConnectionOptions(options);
|
||||
|
||||
foreach (var property in properties)
|
||||
{
|
||||
Assert.Equal(testValues[property.Name], property.GetValue(shallowCopiedOptions));
|
||||
testValues.Remove(property.Name);
|
||||
}
|
||||
|
||||
Assert.Empty(testValues);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,8 +30,8 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
|||
{
|
||||
await WithConnectionAsync(CreateConnection(loggerFactory: LoggerFactory), async (connection) =>
|
||||
{
|
||||
await connection.StartAsync(TransferFormat.Text).OrTimeout();
|
||||
await connection.StartAsync(TransferFormat.Text).OrTimeout();
|
||||
await connection.StartAsync().OrTimeout();
|
||||
await connection.StartAsync().OrTimeout();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -45,9 +45,9 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
|||
CreateConnection(loggerFactory: LoggerFactory, transport: new TestTransport(onTransportStart: SyncPoint.Create(out var syncPoint))),
|
||||
async (connection) =>
|
||||
{
|
||||
var firstStart = connection.StartAsync(TransferFormat.Text);
|
||||
var firstStart = connection.StartAsync();
|
||||
await syncPoint.WaitForSyncPoint().OrTimeout();
|
||||
var secondStart = connection.StartAsync(TransferFormat.Text);
|
||||
var secondStart = connection.StartAsync();
|
||||
syncPoint.Continue();
|
||||
|
||||
await firstStart.OrTimeout();
|
||||
|
|
@ -65,11 +65,11 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
|||
CreateConnection(loggerFactory: LoggerFactory),
|
||||
async (connection) =>
|
||||
{
|
||||
await connection.StartAsync(TransferFormat.Text).OrTimeout();
|
||||
await connection.StartAsync().OrTimeout();
|
||||
await connection.DisposeAsync().OrTimeout();
|
||||
var exception =
|
||||
await Assert.ThrowsAsync<ObjectDisposedException>(
|
||||
async () => await connection.StartAsync(TransferFormat.Text)).OrTimeout();
|
||||
async () => await connection.StartAsync()).OrTimeout();
|
||||
|
||||
Assert.Equal(nameof(HttpConnection), exception.ObjectName);
|
||||
});
|
||||
|
|
@ -123,7 +123,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
|||
async (connection) =>
|
||||
{
|
||||
Assert.Equal(0, startCounter);
|
||||
await connection.StartAsync(TransferFormat.Text).OrTimeout();
|
||||
await connection.StartAsync().OrTimeout();
|
||||
Assert.Equal(passThreshold, startCounter);
|
||||
});
|
||||
}
|
||||
|
|
@ -156,7 +156,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
|||
transport: new TestTransport(onTransportStart: OnTransportStart)),
|
||||
async (connection) =>
|
||||
{
|
||||
var ex = await Assert.ThrowsAsync<AggregateException>(() => connection.StartAsync(TransferFormat.Text)).OrTimeout();
|
||||
var ex = await Assert.ThrowsAsync<AggregateException>(() => connection.StartAsync()).OrTimeout();
|
||||
Assert.Equal("Unable to connect to the server with any of the available transports. " +
|
||||
"(WebSockets failed: Transport failed to start) (ServerSentEvents failed: Transport failed to start) (LongPolling failed: Transport failed to start)",
|
||||
ex.Message);
|
||||
|
|
@ -200,7 +200,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
|||
async (connection) =>
|
||||
{
|
||||
// Start the connection and wait for the transport to start up.
|
||||
var startTask = connection.StartAsync(TransferFormat.Text);
|
||||
var startTask = connection.StartAsync();
|
||||
await transportStart.WaitForSyncPoint().OrTimeout();
|
||||
|
||||
// While the transport is starting, dispose the connection
|
||||
|
|
@ -232,7 +232,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
|||
async (connection) =>
|
||||
{
|
||||
// Start the connection
|
||||
await connection.StartAsync(TransferFormat.Text).OrTimeout();
|
||||
await connection.StartAsync().OrTimeout();
|
||||
|
||||
// Dispose the connection
|
||||
var stopTask = connection.DisposeAsync();
|
||||
|
|
@ -268,7 +268,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
|||
async (connection) =>
|
||||
{
|
||||
// Start the transport
|
||||
await connection.StartAsync(TransferFormat.Text).OrTimeout();
|
||||
await connection.StartAsync().OrTimeout();
|
||||
Assert.NotNull(testTransport.Receiving);
|
||||
Assert.False(testTransport.Receiving.IsCompleted);
|
||||
|
||||
|
|
@ -313,7 +313,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
|||
CreateConnection(httpHandler, LoggerFactory),
|
||||
async (connection) =>
|
||||
{
|
||||
await connection.StartAsync(TransferFormat.Text).OrTimeout();
|
||||
await connection.StartAsync().OrTimeout();
|
||||
await connection.Transport.Output.WriteAsync(new byte[] { 0x42 }).OrTimeout();
|
||||
|
||||
// We should get the exception in the transport input completion.
|
||||
|
|
@ -347,7 +347,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
|||
async (connection) =>
|
||||
{
|
||||
await Assert.ThrowsAsync<AggregateException>(
|
||||
() => connection.StartAsync(TransferFormat.Text).OrTimeout());
|
||||
() => connection.StartAsync().OrTimeout());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -372,7 +372,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
|||
CreateConnection(httpHandler, loggerFactory: LoggerFactory, transport: sse),
|
||||
async (connection) =>
|
||||
{
|
||||
var startTask = connection.StartAsync(TransferFormat.Text);
|
||||
var startTask = connection.StartAsync();
|
||||
Assert.False(connectResponseTcs.Task.IsCompleted);
|
||||
Assert.False(startTask.IsCompleted);
|
||||
connectResponseTcs.TrySetResult(null);
|
||||
|
|
@ -430,7 +430,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
|||
private static async Task AssertDisposedAsync(HttpConnection connection)
|
||||
{
|
||||
var exception =
|
||||
await Assert.ThrowsAsync<ObjectDisposedException>(() => connection.StartAsync(TransferFormat.Text));
|
||||
await Assert.ThrowsAsync<ObjectDisposedException>(() => connection.StartAsync());
|
||||
Assert.Equal(nameof(HttpConnection), exception.ObjectName);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
|||
ITransport transport = null,
|
||||
ITransportFactory transportFactory = null,
|
||||
HttpTransportType? transportType = null,
|
||||
TransferFormat transferFormat = TransferFormat.Text,
|
||||
Func<Task<string>> accessTokenProvider = null)
|
||||
{
|
||||
var httpOptions = new HttpConnectionOptions
|
||||
|
|
@ -35,24 +36,32 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
|||
httpOptions.Url = new Uri(url);
|
||||
}
|
||||
|
||||
return CreateConnection(httpOptions, loggerFactory, transport, transportFactory);
|
||||
return CreateConnection(httpOptions, loggerFactory, transport, transportFactory, transferFormat);
|
||||
}
|
||||
|
||||
private static HttpConnection CreateConnection(HttpConnectionOptions httpConnectionOptions, ILoggerFactory loggerFactory = null, ITransport transport = null, ITransportFactory transportFactory = null)
|
||||
private static HttpConnection CreateConnection(
|
||||
HttpConnectionOptions httpConnectionOptions,
|
||||
ILoggerFactory loggerFactory = null,
|
||||
ITransport transport = null,
|
||||
ITransportFactory transportFactory = null,
|
||||
TransferFormat transferFormat = TransferFormat.Text)
|
||||
{
|
||||
loggerFactory = loggerFactory ?? NullLoggerFactory.Instance;
|
||||
httpConnectionOptions.Url = httpConnectionOptions.Url ?? new Uri("http://fakeuri.org/");
|
||||
httpConnectionOptions.Url ??= new Uri("http://fakeuri.org/");
|
||||
httpConnectionOptions.DefaultTransferFormat = transferFormat;
|
||||
|
||||
if (transportFactory == null && transport != null)
|
||||
{
|
||||
transportFactory = new TestTransportFactory(transport);
|
||||
}
|
||||
|
||||
if (transportFactory != null)
|
||||
{
|
||||
return new HttpConnection(httpConnectionOptions, loggerFactory, transportFactory);
|
||||
}
|
||||
else if (transport != null)
|
||||
{
|
||||
return new HttpConnection(httpConnectionOptions, loggerFactory, new TestTransportFactory(transport));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use the public constructor to get the default transport factory.
|
||||
return new HttpConnection(httpConnectionOptions, loggerFactory);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
|||
CreateConnection(testHttpHandler, url: requestedUrl, loggerFactory: noErrorScope.LoggerFactory),
|
||||
async (connection) =>
|
||||
{
|
||||
await connection.StartAsync(TransferFormat.Text).OrTimeout();
|
||||
await connection.StartAsync().OrTimeout();
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -111,7 +111,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
|||
CreateConnection(testHttpHandler, loggerFactory: noErrorScope.LoggerFactory),
|
||||
async (connection) =>
|
||||
{
|
||||
await connection.StartAsync(TransferFormat.Text).OrTimeout();
|
||||
await connection.StartAsync().OrTimeout();
|
||||
connectionId = connection.ConnectionId;
|
||||
});
|
||||
}
|
||||
|
|
@ -168,7 +168,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
|||
CreateConnection(testHttpHandler, loggerFactory: noErrorScope.LoggerFactory),
|
||||
async (connection) =>
|
||||
{
|
||||
await connection.StartAsync(TransferFormat.Text).OrTimeout();
|
||||
await connection.StartAsync().OrTimeout();
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -198,7 +198,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
|||
CreateConnection(testHttpHandler, loggerFactory: noErrorScope.LoggerFactory),
|
||||
async (connection) =>
|
||||
{
|
||||
var exception = await Assert.ThrowsAsync<InvalidOperationException>(() => connection.StartAsync(TransferFormat.Text).OrTimeout());
|
||||
var exception = await Assert.ThrowsAsync<InvalidOperationException>(() => connection.StartAsync().OrTimeout());
|
||||
Assert.Equal("Negotiate redirection limit exceeded.", exception.Message);
|
||||
});
|
||||
}
|
||||
|
|
@ -274,7 +274,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
|||
CreateConnection(testHttpHandler, loggerFactory: noErrorScope.LoggerFactory, accessTokenProvider: AccessTokenProvider),
|
||||
async (connection) =>
|
||||
{
|
||||
await connection.StartAsync(TransferFormat.Text).OrTimeout();
|
||||
await connection.StartAsync().OrTimeout();
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -327,10 +327,10 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
|||
using (var noErrorScope = new VerifyNoErrorsScope())
|
||||
{
|
||||
await WithConnectionAsync(
|
||||
CreateConnection(testHttpHandler, transportFactory: transportFactory.Object, loggerFactory: noErrorScope.LoggerFactory),
|
||||
CreateConnection(testHttpHandler, transportFactory: transportFactory.Object, loggerFactory: noErrorScope.LoggerFactory, transferFormat: TransferFormat.Binary),
|
||||
async (connection) =>
|
||||
{
|
||||
await connection.StartAsync(TransferFormat.Binary).OrTimeout();
|
||||
await connection.StartAsync().OrTimeout();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -374,10 +374,10 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
|||
.Returns(new TestTransport(transferFormat: TransferFormat.Text | TransferFormat.Binary));
|
||||
|
||||
await WithConnectionAsync(
|
||||
CreateConnection(testHttpHandler, transportFactory: transportFactory.Object),
|
||||
CreateConnection(testHttpHandler, transportFactory: transportFactory.Object, transferFormat: TransferFormat.Binary),
|
||||
async (connection) =>
|
||||
{
|
||||
await connection.StartAsync(TransferFormat.Binary).OrTimeout();
|
||||
await connection.StartAsync().OrTimeout();
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -406,7 +406,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
|||
CreateConnection(testHttpHandler, loggerFactory: noErrorScope.LoggerFactory),
|
||||
async (connection) =>
|
||||
{
|
||||
var exception = await Assert.ThrowsAsync<Exception>(() => connection.StartAsync(TransferFormat.Text).OrTimeout());
|
||||
var exception = await Assert.ThrowsAsync<Exception>(() => connection.StartAsync().OrTimeout());
|
||||
Assert.Equal("Test error.", exception.Message);
|
||||
});
|
||||
}
|
||||
|
|
@ -423,7 +423,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
|||
async (connection) =>
|
||||
{
|
||||
var exception = await Assert.ThrowsAsync<TException>(
|
||||
() => connection.StartAsync(TransferFormat.Text).OrTimeout());
|
||||
() => connection.StartAsync().OrTimeout());
|
||||
|
||||
Assert.Equal(expectedExceptionMessage, exception.Message);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
|||
CreateConnection(testHttpHandler, transportType: transportType, accessTokenProvider: AccessTokenProvider),
|
||||
async (connection) =>
|
||||
{
|
||||
await connection.StartAsync(TransferFormat.Text).OrTimeout();
|
||||
await connection.StartAsync().OrTimeout();
|
||||
await connection.Transport.Output.WriteAsync(Encoding.UTF8.GetBytes("Hello world 1"));
|
||||
await connection.Transport.Output.WriteAsync(Encoding.UTF8.GetBytes("Hello world 2"));
|
||||
});
|
||||
|
|
@ -88,7 +88,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
|||
CreateConnection(testHttpHandler, transportType: transportType, loggerFactory: LoggerFactory),
|
||||
async (connection) =>
|
||||
{
|
||||
await connection.StartAsync(TransferFormat.Text).OrTimeout();
|
||||
await connection.StartAsync().OrTimeout();
|
||||
|
||||
var feature = connection.Features.Get<IConnectionInherentKeepAliveFeature>();
|
||||
Assert.NotNull(feature);
|
||||
|
|
@ -138,7 +138,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
|||
CreateConnection(testHttpHandler, transportType: transportType),
|
||||
async (connection) =>
|
||||
{
|
||||
await connection.StartAsync(TransferFormat.Text).OrTimeout();
|
||||
await connection.StartAsync().OrTimeout();
|
||||
await connection.Transport.Output.WriteAsync(Encoding.UTF8.GetBytes("Hello World"));
|
||||
});
|
||||
// Fail safe in case the code is modified and some requests don't execute as a result
|
||||
|
|
@ -178,7 +178,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
|||
CreateConnection(testHttpHandler, transportType: transportType),
|
||||
async (connection) =>
|
||||
{
|
||||
await connection.StartAsync(TransferFormat.Text).OrTimeout();
|
||||
await connection.StartAsync().OrTimeout();
|
||||
await connection.Transport.Output.WriteAsync(Encoding.UTF8.GetBytes("Hello World"));
|
||||
});
|
||||
// Fail safe in case the code is modified and some requests don't execute as a result
|
||||
|
|
@ -210,7 +210,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
|||
CreateConnection(testHttpHandler),
|
||||
async (connection) =>
|
||||
{
|
||||
await connection.StartAsync(TransferFormat.Text).OrTimeout();
|
||||
await connection.StartAsync().OrTimeout();
|
||||
Assert.Contains("This is a test", Encoding.UTF8.GetString(await connection.Transport.Input.ReadAllAsync()));
|
||||
});
|
||||
}
|
||||
|
|
@ -237,7 +237,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
|||
CreateConnection(testHttpHandler),
|
||||
async (connection) =>
|
||||
{
|
||||
await connection.StartAsync(TransferFormat.Text).OrTimeout();
|
||||
await connection.StartAsync().OrTimeout();
|
||||
|
||||
await connection.Transport.Output.WriteAsync(data).OrTimeout();
|
||||
|
||||
|
|
@ -267,7 +267,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
|||
CreateConnection(),
|
||||
async (connection) =>
|
||||
{
|
||||
await connection.StartAsync(TransferFormat.Text).OrTimeout();
|
||||
await connection.StartAsync().OrTimeout();
|
||||
await connection.DisposeAsync().OrTimeout();
|
||||
|
||||
var exception = await Assert.ThrowsAsync<ObjectDisposedException>(
|
||||
|
|
@ -284,7 +284,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
|||
CreateConnection(transport: transport),
|
||||
async (connection) =>
|
||||
{
|
||||
await connection.StartAsync(TransferFormat.Text).OrTimeout();
|
||||
await connection.StartAsync().OrTimeout();
|
||||
await connection.DisposeAsync().OrTimeout();
|
||||
|
||||
// This will throw OperationCanceledException if it's forcibly terminated
|
||||
|
|
@ -292,6 +292,21 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
|||
await transport.Receiving.OrTimeout();
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public Task StartAsyncTransferFormatOverridesOptions()
|
||||
{
|
||||
var transport = new TestTransport();
|
||||
|
||||
return WithConnectionAsync(
|
||||
CreateConnection(transport: transport, transferFormat: TransferFormat.Binary),
|
||||
async (connection) =>
|
||||
{
|
||||
await connection.StartAsync(TransferFormat.Text).OrTimeout();
|
||||
|
||||
Assert.Equal(TransferFormat.Text, transport.Format);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
|||
CreateConnection(httpOptions),
|
||||
async (connection) =>
|
||||
{
|
||||
await connection.StartAsync(TransferFormat.Text).OrTimeout();
|
||||
await connection.StartAsync().OrTimeout();
|
||||
});
|
||||
|
||||
Assert.NotNull(httpClientHandler);
|
||||
|
|
@ -115,7 +115,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
|||
CreateConnection(httpOptions, loggerFactory: mockLoggerFactory.Object),
|
||||
async (connection) =>
|
||||
{
|
||||
await connection.StartAsync(TransferFormat.Text).OrTimeout();
|
||||
await connection.StartAsync().OrTimeout();
|
||||
});
|
||||
}
|
||||
catch
|
||||
|
|
|
|||
|
|
@ -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 Microsoft.AspNetCore.Connections;
|
||||
using Microsoft.AspNetCore.Http.Connections.Client;
|
||||
using Microsoft.AspNetCore.SignalR.Protocol;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
|
@ -22,6 +23,16 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
|||
Assert.Equal("Cannot create HubConnection instance. An IConnectionFactory was not configured.", ex.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CannotCreateConnectionWithNoEndPoint()
|
||||
{
|
||||
var builder = new HubConnectionBuilder();
|
||||
builder.Services.AddSingleton<IConnectionFactory>(new HttpConnectionFactory(Options.Create(new HttpConnectionOptions()), NullLoggerFactory.Instance));
|
||||
|
||||
var ex = Assert.Throws<InvalidOperationException>(() => builder.Build());
|
||||
Assert.Equal("Cannot create HubConnection instance. An EndPoint was not configured.", ex.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddJsonProtocolSetsHubProtocolToJsonWithDefaultOptions()
|
||||
{
|
||||
|
|
@ -51,6 +62,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
|||
{
|
||||
var builder = new HubConnectionBuilder();
|
||||
builder.Services.AddSingleton<IConnectionFactory>(new HttpConnectionFactory(Options.Create(new HttpConnectionOptions()), NullLoggerFactory.Instance));
|
||||
builder.WithUrl("http://example.com");
|
||||
|
||||
Assert.NotNull(builder.Build());
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
|
@ -78,19 +79,13 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
|||
{
|
||||
// Set up StartAsync to wait on the syncPoint when starting
|
||||
var createCount = 0;
|
||||
Task<ConnectionContext> ConnectionFactory(TransferFormat format)
|
||||
ValueTask<ConnectionContext> ConnectionFactory(EndPoint endPoint)
|
||||
{
|
||||
createCount += 1;
|
||||
return new TestConnection().StartAsync(format);
|
||||
return new TestConnection().StartAsync();
|
||||
}
|
||||
|
||||
Task DisposeAsync(ConnectionContext connection)
|
||||
{
|
||||
return connection.DisposeAsync().AsTask();
|
||||
}
|
||||
|
||||
var builder = new HubConnectionBuilder();
|
||||
var delegateConnectionFactory = new DelegateConnectionFactory(ConnectionFactory, DisposeAsync);
|
||||
var builder = new HubConnectionBuilder().WithUrl("http://example.com");
|
||||
var delegateConnectionFactory = new DelegateConnectionFactory(ConnectionFactory);
|
||||
builder.Services.AddSingleton<IConnectionFactory>(delegateConnectionFactory);
|
||||
|
||||
await AsyncUsing(builder.Build(), async connection =>
|
||||
|
|
@ -116,16 +111,14 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
|||
// Set up StartAsync to wait on the syncPoint when starting
|
||||
var createCount = 0;
|
||||
var onDisposeForFirstConnection = SyncPoint.Create(out var syncPoint);
|
||||
Task<ConnectionContext> ConnectionFactory(TransferFormat format)
|
||||
ValueTask<ConnectionContext> ConnectionFactory(EndPoint endPoint)
|
||||
{
|
||||
createCount += 1;
|
||||
return new TestConnection(onDispose: createCount == 1 ? onDisposeForFirstConnection : null).StartAsync(format);
|
||||
return new TestConnection(onDispose: createCount == 1 ? onDisposeForFirstConnection : null).StartAsync();
|
||||
}
|
||||
|
||||
Task DisposeAsync(ConnectionContext connection) => connection.DisposeAsync().AsTask();
|
||||
|
||||
var builder = new HubConnectionBuilder();
|
||||
var delegateConnectionFactory = new DelegateConnectionFactory(ConnectionFactory, DisposeAsync);
|
||||
var builder = new HubConnectionBuilder().WithUrl("http://example.com");
|
||||
var delegateConnectionFactory = new DelegateConnectionFactory(ConnectionFactory);
|
||||
builder.Services.AddSingleton<IConnectionFactory>(delegateConnectionFactory);
|
||||
|
||||
await AsyncUsing(builder.Build(), async connection =>
|
||||
|
|
@ -596,12 +589,11 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
|||
[Fact]
|
||||
public async Task HubConnectionClosesWithErrorIfTerminatedWithPartialMessage()
|
||||
{
|
||||
var builder = new HubConnectionBuilder();
|
||||
var builder = new HubConnectionBuilder().WithUrl("http://example.com");
|
||||
var innerConnection = new TestConnection();
|
||||
|
||||
var delegateConnectionFactory = new DelegateConnectionFactory(
|
||||
format => innerConnection.StartAsync(format),
|
||||
connection => connection.DisposeAsync().AsTask());
|
||||
endPoint => innerConnection.StartAsync());
|
||||
builder.Services.AddSingleton<IConnectionFactory>(delegateConnectionFactory);
|
||||
|
||||
var hubConnection = builder.Build();
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
// 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.Connections;
|
||||
using Microsoft.AspNetCore.SignalR.Protocol;
|
||||
using Microsoft.AspNetCore.SignalR.Tests;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
|
@ -12,11 +13,10 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
|||
{
|
||||
private static HubConnection CreateHubConnection(TestConnection connection, IHubProtocol protocol = null, ILoggerFactory loggerFactory = null)
|
||||
{
|
||||
var builder = new HubConnectionBuilder();
|
||||
var builder = new HubConnectionBuilder().WithUrl("http://example.com");
|
||||
|
||||
var delegateConnectionFactory = new DelegateConnectionFactory(
|
||||
connection.StartAsync,
|
||||
c => c.DisposeAsync().AsTask());
|
||||
endPoint => connection.StartAsync());
|
||||
|
||||
builder.Services.AddSingleton<IConnectionFactory>(delegateConnectionFactory);
|
||||
|
||||
|
|
|
|||
|
|
@ -3,9 +3,12 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO.Pipelines;
|
||||
using System.Net;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Connections;
|
||||
using Microsoft.AspNetCore.Http.Features;
|
||||
using Microsoft.AspNetCore.Internal;
|
||||
using Microsoft.AspNetCore.SignalR.Protocol;
|
||||
using Microsoft.AspNetCore.SignalR.Tests;
|
||||
|
|
@ -75,7 +78,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
|||
|
||||
using (StartVerifiableLog(ExpectedErrors))
|
||||
{
|
||||
var builder = new HubConnectionBuilder().WithLoggerFactory(LoggerFactory);
|
||||
var builder = new HubConnectionBuilder().WithLoggerFactory(LoggerFactory).WithUrl("http://example.com");
|
||||
var testConnectionFactory = default(ReconnectingConnectionFactory);
|
||||
var startCallCount = 0;
|
||||
var originalConnectionId = "originalConnectionId";
|
||||
|
|
@ -189,7 +192,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
|||
|
||||
using (StartVerifiableLog(ExpectedErrors))
|
||||
{
|
||||
var builder = new HubConnectionBuilder().WithLoggerFactory(LoggerFactory);
|
||||
var builder = new HubConnectionBuilder().WithLoggerFactory(LoggerFactory).WithUrl("http://example.com");
|
||||
var startCallCount = 0;
|
||||
|
||||
Task OnTestConnectionStart()
|
||||
|
|
@ -281,7 +284,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
|||
|
||||
using (StartVerifiableLog(ExpectedErrors))
|
||||
{
|
||||
var builder = new HubConnectionBuilder().WithLoggerFactory(LoggerFactory);
|
||||
var builder = new HubConnectionBuilder().WithLoggerFactory(LoggerFactory).WithUrl("http://example.com");
|
||||
var testConnectionFactory = new ReconnectingConnectionFactory();
|
||||
builder.Services.AddSingleton<IConnectionFactory>(testConnectionFactory);
|
||||
|
||||
|
|
@ -376,7 +379,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
|||
|
||||
using (StartVerifiableLog(ExpectedErrors))
|
||||
{
|
||||
var builder = new HubConnectionBuilder().WithLoggerFactory(LoggerFactory);
|
||||
var builder = new HubConnectionBuilder().WithLoggerFactory(LoggerFactory).WithUrl("http://example.com");
|
||||
var testConnectionFactory = new ReconnectingConnectionFactory();
|
||||
builder.Services.AddSingleton<IConnectionFactory>(testConnectionFactory);
|
||||
|
||||
|
|
@ -431,7 +434,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
|||
|
||||
using (StartVerifiableLog(ExpectedErrors))
|
||||
{
|
||||
var builder = new HubConnectionBuilder().WithLoggerFactory(LoggerFactory);
|
||||
var builder = new HubConnectionBuilder().WithLoggerFactory(LoggerFactory).WithUrl("http://example.com");
|
||||
var testConnectionFactory = new ReconnectingConnectionFactory(() => new TestConnection(autoHandshake: false));
|
||||
builder.Services.AddSingleton<IConnectionFactory>(testConnectionFactory);
|
||||
|
||||
|
|
@ -489,7 +492,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
|||
|
||||
using (StartVerifiableLog(ExpectedErrors))
|
||||
{
|
||||
var builder = new HubConnectionBuilder().WithLoggerFactory(LoggerFactory);
|
||||
var builder = new HubConnectionBuilder().WithLoggerFactory(LoggerFactory).WithUrl("http://example.com");
|
||||
var testConnectionFactory = new ReconnectingConnectionFactory(() => new TestConnection(autoHandshake: false));
|
||||
builder.Services.AddSingleton<IConnectionFactory>(testConnectionFactory);
|
||||
|
||||
|
|
@ -596,7 +599,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
|||
|
||||
using (StartVerifiableLog(ExpectedErrors))
|
||||
{
|
||||
var builder = new HubConnectionBuilder().WithLoggerFactory(LoggerFactory);
|
||||
var builder = new HubConnectionBuilder().WithLoggerFactory(LoggerFactory).WithUrl("http://example.com");
|
||||
var testConnectionFactory = new ReconnectingConnectionFactory(() => new TestConnection(autoHandshake: false));
|
||||
builder.Services.AddSingleton<IConnectionFactory>(testConnectionFactory);
|
||||
|
||||
|
|
@ -715,7 +718,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
|||
|
||||
using (StartVerifiableLog(ExpectedErrors))
|
||||
{
|
||||
var builder = new HubConnectionBuilder().WithLoggerFactory(LoggerFactory);
|
||||
var builder = new HubConnectionBuilder().WithLoggerFactory(LoggerFactory).WithUrl("http://example.com");
|
||||
var connectionStartTcs = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
|
||||
async Task OnTestConnectionStart()
|
||||
|
|
@ -806,7 +809,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
|||
|
||||
using (StartVerifiableLog(ExpectedErrors))
|
||||
{
|
||||
var builder = new HubConnectionBuilder().WithLoggerFactory(LoggerFactory);
|
||||
var builder = new HubConnectionBuilder().WithLoggerFactory(LoggerFactory).WithUrl("http://example.com");
|
||||
var testConnectionFactory = new ReconnectingConnectionFactory();
|
||||
builder.Services.AddSingleton<IConnectionFactory>(testConnectionFactory);
|
||||
|
||||
|
|
@ -886,7 +889,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
|||
return _testConnectionTcs.Task;
|
||||
}
|
||||
|
||||
public async Task<ConnectionContext> ConnectAsync(TransferFormat transferFormat, CancellationToken cancellationToken = default)
|
||||
public async ValueTask<ConnectionContext> ConnectAsync(EndPoint endPoint, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var testConnection = _testConnectionFactory();
|
||||
|
||||
|
|
@ -894,7 +897,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
|||
|
||||
try
|
||||
{
|
||||
return await testConnection.StartAsync(transferFormat);
|
||||
return new DisposeInterceptingConnectionContextDecorator(await testConnection.StartAsync(), this);
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
|
@ -912,6 +915,31 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
|||
await disposingTestConnection.DisposeAsync();
|
||||
}
|
||||
}
|
||||
|
||||
private class DisposeInterceptingConnectionContextDecorator : ConnectionContext
|
||||
{
|
||||
private readonly ConnectionContext _inner;
|
||||
private readonly ReconnectingConnectionFactory _reconnectingConnectionFactory;
|
||||
|
||||
public DisposeInterceptingConnectionContextDecorator(ConnectionContext inner, ReconnectingConnectionFactory reconnectingConnectionFactory)
|
||||
{
|
||||
_inner = inner;
|
||||
_reconnectingConnectionFactory = reconnectingConnectionFactory;
|
||||
}
|
||||
|
||||
public override string ConnectionId { get => _inner.ConnectionId; set => _inner.ConnectionId = value; }
|
||||
public override IFeatureCollection Features => _inner.Features;
|
||||
public override IDictionary<object, object> Items { get => _inner.Items; set => _inner.Items = value; }
|
||||
public override IDuplexPipe Transport { get => _inner.Transport; set => _inner.Transport = value; }
|
||||
public override CancellationToken ConnectionClosed { get => _inner.ConnectionClosed; set => _inner.ConnectionClosed = value; }
|
||||
public override EndPoint LocalEndPoint { get => _inner.LocalEndPoint; set => _inner.LocalEndPoint = value; }
|
||||
public override EndPoint RemoteEndPoint { get => _inner.RemoteEndPoint; set => _inner.RemoteEndPoint = value; }
|
||||
|
||||
public override void Abort(ConnectionAbortedException abortReason) => _inner.Abort(abortReason);
|
||||
public override void Abort() => _inner.Abort();
|
||||
|
||||
public override ValueTask DisposeAsync() => new ValueTask(_reconnectingConnectionFactory.DisposeAsync(_inner));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,11 +59,10 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
|||
[Fact]
|
||||
public async Task ClosedEventRaisedWhenTheClientIsStopped()
|
||||
{
|
||||
var builder = new HubConnectionBuilder();
|
||||
var builder = new HubConnectionBuilder().WithUrl("http://example.com");
|
||||
|
||||
var delegateConnectionFactory = new DelegateConnectionFactory(
|
||||
format => new TestConnection().StartAsync(format),
|
||||
connection => ((TestConnection)connection).DisposeAsync().AsTask());
|
||||
endPoint => new TestConnection().StartAsync());
|
||||
builder.Services.AddSingleton<IConnectionFactory>(delegateConnectionFactory);
|
||||
|
||||
var hubConnection = builder.Build();
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
|||
|
||||
public override ValueTask DisposeAsync() => DisposeCoreAsync();
|
||||
|
||||
public async Task<ConnectionContext> StartAsync(TransferFormat transferFormat = TransferFormat.Binary)
|
||||
public async ValueTask<ConnectionContext> StartAsync()
|
||||
{
|
||||
_started.TrySetResult(null);
|
||||
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ namespace Microsoft.AspNetCore.Http.Connections.Client
|
|||
public System.TimeSpan CloseTimeout { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||
public System.Net.CookieContainer Cookies { get { throw null; } set { } }
|
||||
public System.Net.ICredentials Credentials { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||
public Microsoft.AspNetCore.Connections.TransferFormat DefaultTransferFormat { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||
public System.Collections.Generic.IDictionary<string, string> Headers { get { throw null; } set { } }
|
||||
public System.Func<System.Net.Http.HttpMessageHandler, System.Net.Http.HttpMessageHandler> HttpMessageHandlerFactory { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||
public System.Net.IWebProxy Proxy { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ namespace Microsoft.AspNetCore.Http.Connections.Client
|
|||
public System.TimeSpan CloseTimeout { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||
public System.Net.CookieContainer Cookies { get { throw null; } set { } }
|
||||
public System.Net.ICredentials Credentials { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||
public Microsoft.AspNetCore.Connections.TransferFormat DefaultTransferFormat { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||
public System.Collections.Generic.IDictionary<string, string> Headers { get { throw null; } set { } }
|
||||
public System.Func<System.Net.Http.HttpMessageHandler, System.Net.Http.HttpMessageHandler> HttpMessageHandlerFactory { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||
public System.Net.IWebProxy Proxy { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||
|
|
|
|||
|
|
@ -129,6 +129,11 @@ namespace Microsoft.AspNetCore.Http.Connections.Client
|
|||
/// <param name="loggerFactory">The logger factory.</param>
|
||||
public HttpConnection(HttpConnectionOptions httpConnectionOptions, ILoggerFactory loggerFactory)
|
||||
{
|
||||
if (httpConnectionOptions == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(httpConnectionOptions));
|
||||
}
|
||||
|
||||
if (httpConnectionOptions.Url == null)
|
||||
{
|
||||
throw new ArgumentException("Options does not have a URL specified.", nameof(httpConnectionOptions));
|
||||
|
|
@ -168,7 +173,7 @@ namespace Microsoft.AspNetCore.Http.Connections.Client
|
|||
/// </remarks>
|
||||
public Task StartAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return StartAsync(TransferFormat.Binary, cancellationToken);
|
||||
return StartAsync(_httpConnectionOptions.DefaultTransferFormat, cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -7,7 +7,9 @@ using System.Net;
|
|||
using System.Net.Http;
|
||||
using System.Net.WebSockets;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Connections;
|
||||
|
||||
namespace Microsoft.AspNetCore.Http.Connections.Client
|
||||
{
|
||||
|
|
@ -108,6 +110,12 @@ namespace Microsoft.AspNetCore.Http.Connections.Client
|
|||
/// </summary>
|
||||
public bool? UseDefaultCredentials { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the default <see cref="TransferFormat" /> to use if <see cref="HttpConnection.StartAsync(CancellationToken)"/>
|
||||
/// is called instead of <see cref="HttpConnection.StartAsync(TransferFormat, CancellationToken)"/>.
|
||||
/// </summary>
|
||||
public TransferFormat DefaultTransferFormat { get; set; } = TransferFormat.Binary;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a delegate that will be invoked with the <see cref="ClientWebSocketOptions"/> object used
|
||||
/// to configure the WebSocket when using the WebSockets transport.
|
||||
|
|
|
|||
|
|
@ -2,33 +2,26 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Connections;
|
||||
using Microsoft.AspNetCore.SignalR.Client;
|
||||
|
||||
namespace Microsoft.AspNetCore.SignalR.Tests
|
||||
{
|
||||
public class DelegateConnectionFactory : IConnectionFactory
|
||||
{
|
||||
private readonly Func<TransferFormat, Task<ConnectionContext>> _connectDelegate;
|
||||
private readonly Func<ConnectionContext, Task> _disposeDelegate;
|
||||
private readonly Func<EndPoint, ValueTask<ConnectionContext>> _connectDelegate;
|
||||
|
||||
// We have no tests that use the CancellationToken. When we do, we can add it to the delegate. This is test code.
|
||||
public DelegateConnectionFactory(Func<TransferFormat, Task<ConnectionContext>> connectDelegate, Func<ConnectionContext, Task> disposeDelegate)
|
||||
public DelegateConnectionFactory(Func<EndPoint, ValueTask<ConnectionContext>> connectDelegate)
|
||||
{
|
||||
_connectDelegate = connectDelegate;
|
||||
_disposeDelegate = disposeDelegate;
|
||||
}
|
||||
|
||||
public Task<ConnectionContext> ConnectAsync(TransferFormat transferFormat, CancellationToken cancellationToken)
|
||||
public ValueTask<ConnectionContext> ConnectAsync(EndPoint endPoint, CancellationToken cancellationToken)
|
||||
{
|
||||
return _connectDelegate(transferFormat);
|
||||
}
|
||||
|
||||
public Task DisposeAsync(ConnectionContext connection)
|
||||
{
|
||||
return _disposeDelegate(connection);
|
||||
return _connectDelegate(endPoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -77,21 +77,14 @@ namespace Microsoft.AspNetCore.SignalR.Microbenchmarks
|
|||
|
||||
_invocationMessageBytes = hubProtocol.GetMessageBytes(new InvocationMessage(MethodName, arguments));
|
||||
|
||||
var delegateConnectionFactory = new DelegateConnectionFactory(
|
||||
format =>
|
||||
{
|
||||
var connection = new DefaultConnectionContext();
|
||||
// prevents keep alive time being activated
|
||||
connection.Features.Set<IConnectionInherentKeepAliveFeature>(new TestConnectionInherentKeepAliveFeature());
|
||||
connection.Transport = _pipe;
|
||||
return Task.FromResult<ConnectionContext>(connection);
|
||||
},
|
||||
connection =>
|
||||
{
|
||||
connection.Transport.Output.Complete();
|
||||
connection.Transport.Input.Complete();
|
||||
return Task.CompletedTask;
|
||||
});
|
||||
var delegateConnectionFactory = new DelegateConnectionFactory(endPoint =>
|
||||
{
|
||||
var connection = new DefaultConnectionContext();
|
||||
// prevents keep alive time being activated
|
||||
connection.Features.Set<IConnectionInherentKeepAliveFeature>(new TestConnectionInherentKeepAliveFeature());
|
||||
connection.Transport = _pipe;
|
||||
return new ValueTask<ConnectionContext>(connection);
|
||||
});
|
||||
hubConnectionBuilder.Services.AddSingleton<IConnectionFactory>(delegateConnectionFactory);
|
||||
|
||||
_hubConnection = hubConnectionBuilder.Build();
|
||||
|
|
|
|||
|
|
@ -55,19 +55,13 @@ namespace Microsoft.AspNetCore.SignalR.Microbenchmarks
|
|||
hubConnectionBuilder.AddMessagePackProtocol();
|
||||
}
|
||||
|
||||
var delegateConnectionFactory = new DelegateConnectionFactory(format =>
|
||||
var delegateConnectionFactory = new DelegateConnectionFactory(endPoint =>
|
||||
{
|
||||
var connection = new DefaultConnectionContext();
|
||||
// prevents keep alive time being activated
|
||||
connection.Features.Set<IConnectionInherentKeepAliveFeature>(new TestConnectionInherentKeepAliveFeature());
|
||||
connection.Transport = _pipe;
|
||||
return Task.FromResult<ConnectionContext>(connection);
|
||||
},
|
||||
connection =>
|
||||
{
|
||||
connection.Transport.Output.Complete();
|
||||
connection.Transport.Input.Complete();
|
||||
return Task.CompletedTask;
|
||||
return new ValueTask<ConnectionContext>(connection);
|
||||
});
|
||||
hubConnectionBuilder.Services.AddSingleton<IConnectionFactory>(delegateConnectionFactory);
|
||||
|
||||
|
|
|
|||
|
|
@ -40,19 +40,13 @@ namespace Microsoft.AspNetCore.SignalR.Microbenchmarks
|
|||
_pipe = new TestDuplexPipe();
|
||||
|
||||
var hubConnectionBuilder = new HubConnectionBuilder();
|
||||
var delegateConnectionFactory = new DelegateConnectionFactory(format =>
|
||||
var delegateConnectionFactory = new DelegateConnectionFactory(endPoint =>
|
||||
{
|
||||
var connection = new DefaultConnectionContext();
|
||||
// prevents keep alive time being activated
|
||||
connection.Features.Set<IConnectionInherentKeepAliveFeature>(new TestConnectionInherentKeepAliveFeature());
|
||||
connection.Transport = _pipe;
|
||||
return Task.FromResult<ConnectionContext>(connection);
|
||||
},
|
||||
connection =>
|
||||
{
|
||||
connection.Transport.Output.Complete();
|
||||
connection.Transport.Input.Complete();
|
||||
return Task.CompletedTask;
|
||||
return new ValueTask<ConnectionContext>(connection);
|
||||
});
|
||||
hubConnectionBuilder.Services.AddSingleton<IConnectionFactory>(delegateConnectionFactory);
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ using System.Threading.Tasks;
|
|||
using Microsoft.AspNetCore.Connections;
|
||||
using Microsoft.AspNetCore.Http.Connections.Client;
|
||||
using Microsoft.Extensions.CommandLineUtils;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace ClientSample
|
||||
{
|
||||
|
|
@ -34,10 +33,18 @@ namespace ClientSample
|
|||
baseUrl = string.IsNullOrEmpty(baseUrl) ? "http://localhost:5000/chat" : baseUrl;
|
||||
|
||||
Console.WriteLine($"Connecting to {baseUrl}...");
|
||||
var connection = new HttpConnection(new Uri(baseUrl));
|
||||
|
||||
var connectionOptions = new HttpConnectionOptions
|
||||
{
|
||||
Url = new Uri(baseUrl),
|
||||
DefaultTransferFormat = TransferFormat.Text,
|
||||
};
|
||||
|
||||
var connection = new HttpConnection(connectionOptions, loggerFactory: null);
|
||||
|
||||
try
|
||||
{
|
||||
await connection.StartAsync(TransferFormat.Text);
|
||||
await connection.StartAsync();
|
||||
|
||||
Console.WriteLine($"Connected to {baseUrl}");
|
||||
var shutdown = new TaskCompletionSource<object>();
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ namespace ClientSample
|
|||
return default;
|
||||
}
|
||||
|
||||
public async Task<ConnectionContext> StartAsync()
|
||||
public async ValueTask<ConnectionContext> StartAsync()
|
||||
{
|
||||
await _socket.ConnectAsync(_endPoint);
|
||||
|
||||
|
|
@ -245,11 +245,5 @@ namespace ClientSample
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Task StartAsync(TransferFormat transferFormat)
|
||||
{
|
||||
// Transfer format is irrelevant
|
||||
return StartAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Net;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using ClientSample;
|
||||
using Microsoft.AspNetCore.Connections;
|
||||
using Microsoft.AspNetCore.Http.Connections.Client;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
|
||||
namespace Microsoft.AspNetCore.SignalR.Client
|
||||
{
|
||||
|
|
@ -33,28 +34,17 @@ namespace Microsoft.AspNetCore.SignalR.Client
|
|||
|
||||
public static IHubConnectionBuilder WithEndPoint(this IHubConnectionBuilder builder, EndPoint endPoint)
|
||||
{
|
||||
builder.Services.AddSingleton<IConnectionFactory>(new TcpConnectionFactory(endPoint));
|
||||
builder.Services.AddSingleton<IConnectionFactory, TcpConnectionFactory>();
|
||||
builder.Services.AddSingleton(endPoint);
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
private class TcpConnectionFactory : IConnectionFactory
|
||||
{
|
||||
private readonly EndPoint _endPoint;
|
||||
|
||||
public TcpConnectionFactory(EndPoint endPoint)
|
||||
public ValueTask<ConnectionContext> ConnectAsync(EndPoint endPoint, CancellationToken cancellationToken = default)
|
||||
{
|
||||
_endPoint = endPoint;
|
||||
}
|
||||
|
||||
public Task<ConnectionContext> ConnectAsync(TransferFormat transferFormat, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new TcpConnection(_endPoint).StartAsync();
|
||||
}
|
||||
|
||||
public Task DisposeAsync(ConnectionContext connection)
|
||||
{
|
||||
return connection.DisposeAsync().AsTask();
|
||||
return new TcpConnection(endPoint).StartAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ namespace Microsoft.AspNetCore.SignalR.Tests
|
|||
// The test should connect to the server using WebSockets transport on Windows 8 and newer.
|
||||
// On Windows 7/2008R2 it should use ServerSentEvents transport to connect to the server.
|
||||
var connection = new HttpConnection(new Uri(url), HttpTransports.All, LoggerFactory);
|
||||
await connection.StartAsync(TransferFormat.Binary).OrTimeout();
|
||||
await connection.StartAsync().OrTimeout();
|
||||
await connection.DisposeAsync().OrTimeout();
|
||||
}
|
||||
}
|
||||
|
|
@ -64,8 +64,8 @@ namespace Microsoft.AspNetCore.SignalR.Tests
|
|||
// On Windows 7/2008R2 it should use ServerSentEvents transport to connect to the server.
|
||||
|
||||
// The test logic lives in the TestTransportFactory and FakeTransport.
|
||||
var connection = new HttpConnection(new HttpConnectionOptions { Url = new Uri(url) }, LoggerFactory, new TestTransportFactory());
|
||||
await connection.StartAsync(TransferFormat.Text).OrTimeout();
|
||||
var connection = new HttpConnection(new HttpConnectionOptions { Url = new Uri(url), DefaultTransferFormat = TransferFormat.Text }, LoggerFactory, new TestTransportFactory());
|
||||
await connection.StartAsync().OrTimeout();
|
||||
await connection.DisposeAsync().OrTimeout();
|
||||
}
|
||||
}
|
||||
|
|
@ -78,8 +78,8 @@ namespace Microsoft.AspNetCore.SignalR.Tests
|
|||
using (StartServer<Startup>(out var server))
|
||||
{
|
||||
var url = server.Url + "/echo";
|
||||
var connection = new HttpConnection(new Uri(url), transportType, LoggerFactory);
|
||||
await connection.StartAsync(TransferFormat.Text).OrTimeout();
|
||||
var connection = new HttpConnection(new HttpConnectionOptions { Url = new Uri(url), Transports = transportType, DefaultTransferFormat = TransferFormat.Text }, LoggerFactory);
|
||||
await connection.StartAsync().OrTimeout();
|
||||
await connection.DisposeAsync().OrTimeout();
|
||||
}
|
||||
}
|
||||
|
|
@ -189,7 +189,7 @@ namespace Microsoft.AspNetCore.SignalR.Tests
|
|||
try
|
||||
{
|
||||
var message = new byte[] { 42 };
|
||||
await connection.StartAsync(TransferFormat.Binary).OrTimeout();
|
||||
await connection.StartAsync().OrTimeout();
|
||||
|
||||
await connection.Transport.Output.WriteAsync(message).OrTimeout();
|
||||
|
||||
|
|
@ -238,7 +238,7 @@ namespace Microsoft.AspNetCore.SignalR.Tests
|
|||
|
||||
try
|
||||
{
|
||||
var exception = await Assert.ThrowsAsync<InvalidOperationException>(() => connection.StartAsync(TransferFormat.Binary).OrTimeout());
|
||||
var exception = await Assert.ThrowsAsync<InvalidOperationException>(() => connection.StartAsync().OrTimeout());
|
||||
Assert.Equal("Negotiation can only be skipped when using the WebSocket transport directly.", exception.Message);
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
|
@ -265,11 +265,11 @@ namespace Microsoft.AspNetCore.SignalR.Tests
|
|||
const string message = "Major Key";
|
||||
|
||||
var url = server.Url + "/echo";
|
||||
var connection = new HttpConnection(new Uri(url), transportType, LoggerFactory);
|
||||
var connection = new HttpConnection(new HttpConnectionOptions { Url = new Uri(url), Transports = transportType, DefaultTransferFormat = requestedTransferFormat }, LoggerFactory);
|
||||
try
|
||||
{
|
||||
logger.LogInformation("Starting connection to {url}", url);
|
||||
await connection.StartAsync(requestedTransferFormat).OrTimeout();
|
||||
await connection.StartAsync().OrTimeout();
|
||||
logger.LogInformation("Started connection to {url}", url);
|
||||
|
||||
var bytes = Encoding.UTF8.GetBytes(message);
|
||||
|
|
@ -327,7 +327,7 @@ namespace Microsoft.AspNetCore.SignalR.Tests
|
|||
try
|
||||
{
|
||||
logger.LogInformation("Starting connection to {url}", url);
|
||||
await connection.StartAsync(TransferFormat.Binary).OrTimeout();
|
||||
await connection.StartAsync().OrTimeout();
|
||||
logger.LogInformation("Started connection to {url}", url);
|
||||
|
||||
var bytes = Encoding.UTF8.GetBytes(message);
|
||||
|
|
@ -373,7 +373,7 @@ namespace Microsoft.AspNetCore.SignalR.Tests
|
|||
var url = server.Url + "/auth";
|
||||
var connection = new HttpConnection(new Uri(url), HttpTransportType.WebSockets, LoggerFactory);
|
||||
|
||||
var exception = await Assert.ThrowsAsync<HttpRequestException>(() => connection.StartAsync(TransferFormat.Binary).OrTimeout());
|
||||
var exception = await Assert.ThrowsAsync<HttpRequestException>(() => connection.StartAsync().OrTimeout());
|
||||
|
||||
Assert.Contains("401", exception.Message);
|
||||
}
|
||||
|
|
@ -404,7 +404,7 @@ namespace Microsoft.AspNetCore.SignalR.Tests
|
|||
|
||||
var connection = new HttpConnection(options, LoggerFactory);
|
||||
|
||||
await Assert.ThrowsAsync<WebSocketException>(() => connection.StartAsync(TransferFormat.Binary).OrTimeout());
|
||||
await Assert.ThrowsAsync<WebSocketException>(() => connection.StartAsync().OrTimeout());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -430,7 +430,7 @@ namespace Microsoft.AspNetCore.SignalR.Tests
|
|||
try
|
||||
{
|
||||
logger.LogInformation("Starting connection to {url}", url);
|
||||
await connection.StartAsync(TransferFormat.Binary).OrTimeout();
|
||||
await connection.StartAsync().OrTimeout();
|
||||
Assert.True(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
|
@ -470,17 +470,20 @@ namespace Microsoft.AspNetCore.SignalR.Tests
|
|||
}
|
||||
|
||||
var url = server.Url + "/auth";
|
||||
var connection = new HttpConnection(new HttpConnectionOptions()
|
||||
{
|
||||
AccessTokenProvider = () => Task.FromResult(token),
|
||||
Url = new Uri(url),
|
||||
Transports = HttpTransportType.ServerSentEvents
|
||||
}, LoggerFactory);
|
||||
var connection = new HttpConnection(
|
||||
new HttpConnectionOptions()
|
||||
{
|
||||
Url = new Uri(url),
|
||||
AccessTokenProvider = () => Task.FromResult(token),
|
||||
Transports = HttpTransportType.ServerSentEvents,
|
||||
DefaultTransferFormat = TransferFormat.Text,
|
||||
},
|
||||
LoggerFactory);
|
||||
|
||||
try
|
||||
{
|
||||
logger.LogInformation("Starting connection to {url}", url);
|
||||
await connection.StartAsync(TransferFormat.Text).OrTimeout();
|
||||
await connection.StartAsync().OrTimeout();
|
||||
logger.LogInformation("Connected to {url}", url);
|
||||
}
|
||||
finally
|
||||
|
|
|
|||
Loading…
Reference in New Issue