Merge pull request #1679 from aspnet/release/2.1

Release/2.1
This commit is contained in:
Andrew Stanton-Nurse 2018-03-21 10:12:42 -07:00 committed by GitHub
commit bb59bb0a12
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 122 additions and 75 deletions

View File

@ -16,7 +16,7 @@ namespace BenchmarkServer.Hubs
{ {
var t = new CancellationTokenSource(); var t = new CancellationTokenSource();
t.CancelAfter(TimeSpan.FromSeconds(duration)); t.CancelAfter(TimeSpan.FromSeconds(duration));
while (!t.IsCancellationRequested && !Context.Connection.ConnectionAbortedToken.IsCancellationRequested) while (!t.IsCancellationRequested && !Context.ConnectionAborted.IsCancellationRequested)
{ {
await Clients.All.SendAsync("echo", DateTime.UtcNow); await Clients.All.SendAsync("echo", DateTime.UtcNow);
} }

View File

@ -30,7 +30,7 @@ namespace FunctionalTests
public Task InvokeWithString(string message) public Task InvokeWithString(string message)
{ {
return Clients.Client(Context.Connection.ConnectionId).SendAsync("Message", message); return Clients.Client(Context.ConnectionId).SendAsync("Message", message);
} }
public Task SendCustomObject(CustomObject customObject) public Task SendCustomObject(CustomObject customObject)
@ -55,7 +55,7 @@ namespace FunctionalTests
public string GetActiveTransportName() public string GetActiveTransportName()
{ {
return Context.Connection.Items[ConnectionMetadataNames.Transport].ToString(); return Context.Items[ConnectionMetadataNames.Transport].ToString();
} }
public ComplexObject EchoComplexObject(ComplexObject complexObject) public ComplexObject EchoComplexObject(ComplexObject complexObject)

View File

@ -8,7 +8,7 @@ export interface HttpRequest {
method?: string; method?: string;
url?: string; url?: string;
content?: string | ArrayBuffer; content?: string | ArrayBuffer;
headers?: Map<string, string>; headers?: { [key: string]: string };
responseType?: XMLHttpRequestResponseType; responseType?: XMLHttpRequestResponseType;
abortSignal?: AbortSignal; abortSignal?: AbortSignal;
timeout?: number; timeout?: number;
@ -58,7 +58,8 @@ export class DefaultHttpClient extends HttpClient {
xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest"); xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
if (request.headers) { if (request.headers) {
request.headers.forEach((value, header) => xhr.setRequestHeader(header, value)); Object.keys(request.headers)
.forEach((header) => xhr.setRequestHeader(header, request.headers[header]));
} }
if (request.responseType) { if (request.responseType) {

View File

@ -83,8 +83,9 @@ export class HttpConnection implements IConnection {
let headers; let headers;
const token = this.options.accessTokenFactory(); const token = this.options.accessTokenFactory();
if (token) { if (token) {
headers = new Map<string, string>(); headers = {
headers.set("Authorization", `Bearer ${token}`); ["Authorization"]: `Bearer ${token}`,
};
} }
const negotiatePayload = await this.httpClient.post(this.resolveNegotiateUrl(this.baseUrl), { const negotiatePayload = await this.httpClient.post(this.resolveNegotiateUrl(this.baseUrl), {

View File

@ -25,8 +25,8 @@ export class HubConnection {
private readonly connection: IConnection; private readonly connection: IConnection;
private readonly logger: ILogger; private readonly logger: ILogger;
private protocol: IHubProtocol; private protocol: IHubProtocol;
private callbacks: Map<string, (invocationEvent: StreamItemMessage | CompletionMessage, error?: Error) => void>; private callbacks: { [invocationId: string]: (invocationEvent: StreamItemMessage | CompletionMessage, error?: Error) => void };
private methods: Map<string, Array<(...args: any[]) => void>>; private methods: { [name: string]: Array<(...args: any[]) => void> };
private id: number; private id: number;
private closedCallbacks: ConnectionClosed[]; private closedCallbacks: ConnectionClosed[];
private timeoutHandle: NodeJS.Timer; private timeoutHandle: NodeJS.Timer;
@ -53,8 +53,8 @@ export class HubConnection {
this.connection.onreceive = (data: any) => this.processIncomingData(data); this.connection.onreceive = (data: any) => this.processIncomingData(data);
this.connection.onclose = (error?: Error) => this.connectionClosed(error); this.connection.onclose = (error?: Error) => this.connectionClosed(error);
this.callbacks = new Map<string, (invocationEvent: HubMessage, error?: Error) => void>(); this.callbacks = {};
this.methods = new Map<string, Array<(...args: any[]) => void>>(); this.methods = {};
this.closedCallbacks = []; this.closedCallbacks = [];
this.id = 0; this.id = 0;
} }
@ -79,10 +79,10 @@ export class HubConnection {
break; break;
case MessageType.StreamItem: case MessageType.StreamItem:
case MessageType.Completion: case MessageType.Completion:
const callback = this.callbacks.get(message.invocationId); const callback = this.callbacks[message.invocationId];
if (callback != null) { if (callback != null) {
if (message.type === MessageType.Completion) { if (message.type === MessageType.Completion) {
this.callbacks.delete(message.invocationId); delete this.callbacks[message.invocationId];
} }
callback(message); callback(message);
} }
@ -174,7 +174,7 @@ export class HubConnection {
} }
private invokeClientMethod(invocationMessage: InvocationMessage) { private invokeClientMethod(invocationMessage: InvocationMessage) {
const methods = this.methods.get(invocationMessage.target.toLowerCase()); const methods = this.methods[invocationMessage.target.toLowerCase()];
if (methods) { if (methods) {
methods.forEach((m) => m.apply(this, invocationMessage.arguments)); methods.forEach((m) => m.apply(this, invocationMessage.arguments));
if (invocationMessage.invocationId) { if (invocationMessage.invocationId) {
@ -189,10 +189,14 @@ export class HubConnection {
} }
private connectionClosed(error?: Error) { private connectionClosed(error?: Error) {
this.callbacks.forEach((callback) => { const callbacks = this.callbacks;
callback(undefined, error ? error : new Error("Invocation canceled due to connection being closed.")); this.callbacks = {};
});
this.callbacks.clear(); Object.keys(callbacks)
.forEach((key) => {
const callback = callbacks[key];
callback(undefined, error ? error : new Error("Invocation canceled due to connection being closed."));
});
this.cleanupTimeout(); this.cleanupTimeout();
@ -228,12 +232,12 @@ export class HubConnection {
const cancelInvocation: CancelInvocationMessage = this.createCancelInvocation(invocationDescriptor.invocationId); const cancelInvocation: CancelInvocationMessage = this.createCancelInvocation(invocationDescriptor.invocationId);
const cancelMessage: any = this.protocol.writeMessage(cancelInvocation); const cancelMessage: any = this.protocol.writeMessage(cancelInvocation);
this.callbacks.delete(invocationDescriptor.invocationId); delete this.callbacks[invocationDescriptor.invocationId];
return this.connection.send(cancelMessage); return this.connection.send(cancelMessage);
}); });
this.callbacks.set(invocationDescriptor.invocationId, (invocationEvent: CompletionMessage | StreamItemMessage, error?: Error) => { this.callbacks[invocationDescriptor.invocationId] = (invocationEvent: CompletionMessage | StreamItemMessage, error?: Error) => {
if (error) { if (error) {
subject.error(error); subject.error(error);
return; return;
@ -248,14 +252,14 @@ export class HubConnection {
} else { } else {
subject.next((invocationEvent.item) as T); subject.next((invocationEvent.item) as T);
} }
}); };
const message = this.protocol.writeMessage(invocationDescriptor); const message = this.protocol.writeMessage(invocationDescriptor);
this.connection.send(message) this.connection.send(message)
.catch((e) => { .catch((e) => {
subject.error(e); subject.error(e);
this.callbacks.delete(invocationDescriptor.invocationId); delete this.callbacks[invocationDescriptor.invocationId];
}); });
return subject; return subject;
@ -273,7 +277,7 @@ export class HubConnection {
const invocationDescriptor = this.createInvocation(methodName, args, false); const invocationDescriptor = this.createInvocation(methodName, args, false);
const p = new Promise<any>((resolve, reject) => { const p = new Promise<any>((resolve, reject) => {
this.callbacks.set(invocationDescriptor.invocationId, (invocationEvent: StreamItemMessage | CompletionMessage, error?: Error) => { this.callbacks[invocationDescriptor.invocationId] = (invocationEvent: StreamItemMessage | CompletionMessage, error?: Error) => {
if (error) { if (error) {
reject(error); reject(error);
return; return;
@ -288,14 +292,14 @@ export class HubConnection {
} else { } else {
reject(new Error(`Unexpected message type: ${invocationEvent.type}`)); reject(new Error(`Unexpected message type: ${invocationEvent.type}`));
} }
}); };
const message = this.protocol.writeMessage(invocationDescriptor); const message = this.protocol.writeMessage(invocationDescriptor);
this.connection.send(message) this.connection.send(message)
.catch((e) => { .catch((e) => {
reject(e); reject(e);
this.callbacks.delete(invocationDescriptor.invocationId); delete this.callbacks[invocationDescriptor.invocationId];
}); });
}); });
@ -308,11 +312,11 @@ export class HubConnection {
} }
methodName = methodName.toLowerCase(); methodName = methodName.toLowerCase();
if (!this.methods.has(methodName)) { if (!this.methods[methodName]) {
this.methods.set(methodName, []); this.methods[methodName] = [];
} }
this.methods.get(methodName).push(method); this.methods[methodName].push(method);
} }
public off(methodName: string, method: (...args: any[]) => void) { public off(methodName: string, method: (...args: any[]) => void) {
@ -321,7 +325,7 @@ export class HubConnection {
} }
methodName = methodName.toLowerCase(); methodName = methodName.toLowerCase();
const handlers = this.methods.get(methodName); const handlers = this.methods[methodName];
if (!handlers) { if (!handlers) {
return; return;
} }
@ -329,7 +333,7 @@ export class HubConnection {
if (removeIdx !== -1) { if (removeIdx !== -1) {
handlers.splice(removeIdx, 1); handlers.splice(removeIdx, 1);
if (handlers.length === 0) { if (handlers.length === 0) {
this.methods.delete(methodName); delete this.methods[methodName];
} }
} }
} }

View File

@ -238,7 +238,7 @@ export class LongPollingTransport implements ITransport {
private async poll(url: string, transferFormat: TransferFormat): Promise<void> { private async poll(url: string, transferFormat: TransferFormat): Promise<void> {
const pollOptions: HttpRequest = { const pollOptions: HttpRequest = {
abortSignal: this.pollAbort.signal, abortSignal: this.pollAbort.signal,
headers: new Map<string, string>(), headers: {},
timeout: 90000, timeout: 90000,
}; };
@ -248,7 +248,8 @@ export class LongPollingTransport implements ITransport {
const token = this.accessTokenFactory(); const token = this.accessTokenFactory();
if (token) { if (token) {
pollOptions.headers.set("Authorization", `Bearer ${token}`); // tslint:disable-next-line:no-string-literal
pollOptions.headers["Authorization"] = `Bearer ${token}`;
} }
while (!this.pollAbort.signal.aborted) { while (!this.pollAbort.signal.aborted) {
@ -316,8 +317,9 @@ async function send(httpClient: HttpClient, url: string, accessTokenFactory: ()
let headers; let headers;
const token = accessTokenFactory(); const token = accessTokenFactory();
if (token) { if (token) {
headers = new Map<string, string>(); headers = {
headers.set("Authorization", `Bearer ${accessTokenFactory()}`); ["Authorization"]: `Bearer ${accessTokenFactory()}`,
};
} }
await httpClient.post(url, { await httpClient.post(url, {

View File

@ -13,6 +13,6 @@
"noImplicitAny": true, "noImplicitAny": true,
"suppressImplicitAnyIndexErrors": true, "suppressImplicitAnyIndexErrors": true,
"noEmitOnError": true, "noEmitOnError": true,
"lib": [ "es2016", "dom" ] "lib": [ "es5", "es2015.promise", "es2015.iterable", "dom" ]
} }
} }

View File

@ -85,7 +85,7 @@ namespace ChatSample
else else
{ {
return hub.OnUsersJoined( return hub.OnUsersJoined(
users.Where(u => u.ConnectionId != hub.Context.Connection.ConnectionId).ToArray()); users.Where(u => u.ConnectionId != hub.Context.ConnectionId).ToArray());
} }
return Task.CompletedTask; return Task.CompletedTask;
}); });
@ -112,7 +112,7 @@ namespace ChatSample
} }
hub.Clients = new HubCallerClients(_hubContext.Clients, connection.ConnectionId); hub.Clients = new HubCallerClients(_hubContext.Clients, connection.ConnectionId);
hub.Context = new HubCallerContext(connection); hub.Context = new DefaultHubCallerContext(connection);
hub.Groups = _hubContext.Groups; hub.Groups = _hubContext.Groups;
try try

View File

@ -0,0 +1,36 @@
// 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.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Security.Claims;
using System.Threading;
using Microsoft.AspNetCore.Http.Features;
namespace Microsoft.AspNetCore.SignalR
{
public class DefaultHubCallerContext : HubCallerContext
{
private readonly HubConnectionContext _connection;
public DefaultHubCallerContext(HubConnectionContext connection)
{
_connection = connection;
}
public override string ConnectionId => _connection.ConnectionId;
public override string UserIdentifier => _connection.UserIdentifier;
public override ClaimsPrincipal User => _connection.User;
public override IDictionary<object, object> Items => _connection.Items;
public override IFeatureCollection Features => _connection.Features;
public override CancellationToken ConnectionAborted => _connection.ConnectionAborted;
public override void Abort() => _connection.Abort();
}
}

View File

@ -1,21 +1,29 @@
// Copyright (c) .NET Foundation. All rights reserved. // Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Security.Claims; using System.Security.Claims;
using System.Threading;
using Microsoft.AspNetCore.Http.Features;
namespace Microsoft.AspNetCore.SignalR namespace Microsoft.AspNetCore.SignalR
{ {
public class HubCallerContext public abstract class HubCallerContext
{ {
public HubCallerContext(HubConnectionContext connection) public abstract string ConnectionId { get; }
{
Connection = connection;
}
public HubConnectionContext Connection { get; } public abstract string UserIdentifier { get; }
public ClaimsPrincipal User => Connection.User; public abstract ClaimsPrincipal User { get; }
public string ConnectionId => Connection.ConnectionId; public abstract IDictionary<object, object> Items { get; }
public abstract IFeatureCollection Features { get; }
public abstract CancellationToken ConnectionAborted { get; }
public abstract void Abort();
} }
} }

View File

@ -41,11 +41,11 @@ namespace Microsoft.AspNetCore.SignalR
{ {
_connectionContext = connectionContext; _connectionContext = connectionContext;
_logger = loggerFactory.CreateLogger<HubConnectionContext>(); _logger = loggerFactory.CreateLogger<HubConnectionContext>();
ConnectionAbortedToken = _connectionAbortedTokenSource.Token; ConnectionAborted = _connectionAbortedTokenSource.Token;
_keepAliveDuration = (int)keepAliveInterval.TotalMilliseconds * (Stopwatch.Frequency / 1000); _keepAliveDuration = (int)keepAliveInterval.TotalMilliseconds * (Stopwatch.Frequency / 1000);
} }
public virtual CancellationToken ConnectionAbortedToken { get; } public virtual CancellationToken ConnectionAborted { get; }
public virtual string ConnectionId => _connectionContext.ConnectionId; public virtual string ConnectionId => _connectionContext.ConnectionId;
@ -66,14 +66,6 @@ namespace Microsoft.AspNetCore.SignalR
// Currently used only for streaming methods // Currently used only for streaming methods
internal ConcurrentDictionary<string, CancellationTokenSource> ActiveRequestCancellationSources { get; } = new ConcurrentDictionary<string, CancellationTokenSource>(); internal ConcurrentDictionary<string, CancellationTokenSource> ActiveRequestCancellationSources { get; } = new ConcurrentDictionary<string, CancellationTokenSource>();
public IPAddress RemoteIpAddress => Features.Get<IHttpConnectionFeature>()?.RemoteIpAddress;
public IPAddress LocalIpAddress => Features.Get<IHttpConnectionFeature>()?.LocalIpAddress;
public int? RemotePort => Features.Get<IHttpConnectionFeature>()?.RemotePort;
public int? LocalPort => Features.Get<IHttpConnectionFeature>()?.LocalPort;
public virtual ValueTask WriteAsync(HubMessage message) public virtual ValueTask WriteAsync(HubMessage message)
{ {
// We were unable to get the lock so take the slow async path of waiting for the semaphore // We were unable to get the lock so take the slow async path of waiting for the semaphore

View File

@ -162,7 +162,7 @@ namespace Microsoft.AspNetCore.SignalR
{ {
while (true) while (true)
{ {
var result = await connection.Input.ReadAsync(connection.ConnectionAbortedToken); var result = await connection.Input.ReadAsync(connection.ConnectionAborted);
var buffer = result.Buffer; var buffer = result.Buffer;
var consumed = buffer.End; var consumed = buffer.End;
var examined = buffer.End; var examined = buffer.End;

View File

@ -300,7 +300,7 @@ namespace Microsoft.AspNetCore.SignalR.Internal
private void InitializeHub(THub hub, HubConnectionContext connection) private void InitializeHub(THub hub, HubConnectionContext connection)
{ {
hub.Clients = new HubCallerClients(_hubContext.Clients, connection.ConnectionId); hub.Clients = new HubCallerClients(_hubContext.Clients, connection.ConnectionId);
hub.Context = new HubCallerContext(connection); hub.Context = new DefaultHubCallerContext(connection);
hub.Groups = _hubContext.Groups; hub.Groups = _hubContext.Groups;
} }
@ -376,7 +376,7 @@ namespace Microsoft.AspNetCore.SignalR.Internal
{ {
var streamCts = new CancellationTokenSource(); var streamCts = new CancellationTokenSource();
connection.ActiveRequestCancellationSources.TryAdd(invocationId, streamCts); connection.ActiveRequestCancellationSources.TryAdd(invocationId, streamCts);
return CancellationTokenSource.CreateLinkedTokenSource(connection.ConnectionAbortedToken, streamCts.Token).Token; return CancellationTokenSource.CreateLinkedTokenSource(connection.ConnectionAborted, streamCts.Token).Token;
} }
} }

View File

@ -6,9 +6,9 @@ using Microsoft.AspNetCore.Sockets.Http.Features;
namespace Microsoft.AspNetCore.SignalR namespace Microsoft.AspNetCore.SignalR
{ {
public static class DefaultConnectionContextExtensions public static class HubCallerContextExtensions
{ {
public static HttpContext GetHttpContext(this HubConnectionContext connection) public static HttpContext GetHttpContext(this HubCallerContext connection)
{ {
return connection.Features.Get<IHttpContextFeature>()?.HttpContext; return connection.Features.Get<IHttpContextFeature>()?.HttpContext;
} }

View File

@ -9,6 +9,7 @@ using System.Threading.Channels;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Sockets; using Microsoft.AspNetCore.Sockets;
namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
@ -37,7 +38,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
public IEnumerable<string> GetHeaderValues(string[] headerNames) public IEnumerable<string> GetHeaderValues(string[] headerNames)
{ {
var context = Context.Connection.GetHttpContext(); var context = Context.GetHttpContext();
if (context == null) if (context == null)
{ {
@ -56,17 +57,19 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
public string GetCookieValue(string cookieName) public string GetCookieValue(string cookieName)
{ {
return Context.Connection.GetHttpContext().Request.Cookies[cookieName]; return Context.GetHttpContext().Request.Cookies[cookieName];
} }
public object[] GetIHttpConnectionFeatureProperties() public object[] GetIHttpConnectionFeatureProperties()
{ {
var feature = Context.Features.Get<IHttpConnectionFeature>();
object[] result = object[] result =
{ {
Context.Connection.LocalPort, feature.LocalPort,
Context.Connection.RemotePort, feature.RemotePort,
Context.Connection.LocalIpAddress.ToString(), feature.LocalIpAddress.ToString(),
Context.Connection.RemoteIpAddress.ToString() feature.RemoteIpAddress.ToString()
}; };
return result; return result;
@ -74,7 +77,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
public string GetActiveTransportName() public string GetActiveTransportName()
{ {
return Context.Connection.Items[ConnectionMetadataNames.Transport].ToString(); return Context.Items[ConnectionMetadataNames.Transport].ToString();
} }
} }

View File

@ -144,7 +144,7 @@ namespace Microsoft.AspNetCore.SignalR.Tests.HubEndpointTestUtils
public bool HasHttpContext() public bool HasHttpContext()
{ {
return Context.Connection.GetHttpContext() != null; return Context.GetHttpContext() != null;
} }
public Task SendToOthers(string message) public Task SendToOthers(string message)
@ -162,7 +162,7 @@ namespace Microsoft.AspNetCore.SignalR.Tests.HubEndpointTestUtils
{ {
public override Task OnConnectedAsync() public override Task OnConnectedAsync()
{ {
var tcs = (TaskCompletionSource<bool>)Context.Connection.Items["ConnectedTask"]; var tcs = (TaskCompletionSource<bool>)Context.Items["ConnectedTask"];
tcs?.TrySetResult(true); tcs?.TrySetResult(true);
return base.OnConnectedAsync(); return base.OnConnectedAsync();
} }
@ -172,7 +172,7 @@ namespace Microsoft.AspNetCore.SignalR.Tests.HubEndpointTestUtils
{ {
public override Task OnConnectedAsync() public override Task OnConnectedAsync()
{ {
var tcs = (TaskCompletionSource<bool>)Context.Connection.Items["ConnectedTask"]; var tcs = (TaskCompletionSource<bool>)Context.Items["ConnectedTask"];
tcs?.TrySetResult(true); tcs?.TrySetResult(true);
return base.OnConnectedAsync(); return base.OnConnectedAsync();
} }
@ -252,7 +252,7 @@ namespace Microsoft.AspNetCore.SignalR.Tests.HubEndpointTestUtils
{ {
public override Task OnConnectedAsync() public override Task OnConnectedAsync()
{ {
var tcs = (TaskCompletionSource<bool>)Context.Connection.Items["ConnectedTask"]; var tcs = (TaskCompletionSource<bool>)Context.Items["ConnectedTask"];
tcs?.TrySetResult(true); tcs?.TrySetResult(true);
return base.OnConnectedAsync(); return base.OnConnectedAsync();
} }
@ -437,7 +437,7 @@ namespace Microsoft.AspNetCore.SignalR.Tests.HubEndpointTestUtils
{ {
public void Kill() public void Kill()
{ {
Context.Connection.Abort(); Context.Abort();
} }
} }
@ -623,9 +623,9 @@ namespace Microsoft.AspNetCore.SignalR.Tests.HubEndpointTestUtils
public override Task OnConnectedAsync() public override Task OnConnectedAsync()
{ {
_state.TokenStateInConnected = Context.Connection.ConnectionAbortedToken.IsCancellationRequested; _state.TokenStateInConnected = Context.ConnectionAborted.IsCancellationRequested;
Context.Connection.ConnectionAbortedToken.Register(() => Context.ConnectionAborted.Register(() =>
{ {
_state.TokenCallbackTriggered = true; _state.TokenCallbackTriggered = true;
}); });
@ -635,7 +635,7 @@ namespace Microsoft.AspNetCore.SignalR.Tests.HubEndpointTestUtils
public override Task OnDisconnectedAsync(Exception exception) public override Task OnDisconnectedAsync(Exception exception)
{ {
_state.TokenStateInDisconnected = Context.Connection.ConnectionAbortedToken.IsCancellationRequested; _state.TokenStateInDisconnected = Context.ConnectionAborted.IsCancellationRequested;
return base.OnDisconnectedAsync(exception); return base.OnDisconnectedAsync(exception);
} }