Re-layer the .NET Client into Http and non-Http (#544)

* Re-layer the .NET Client into Http and non-Http
- Moved IConnection to Sockets.Abstractions and removed
HttpConnection and TransportType dependency.
- Renamed Sockets.Client to Sockets.Client.Http
- Renamed Sockets.Common to Sockets.Common.Http
- Renamed Connection to HttpConnection
- Removed HTTP dependency from HubConnection
- Removed tests that were testing connection logic in HubConnection

#518
This commit is contained in:
David Fowler 2017-06-09 08:58:54 -10:00 committed by GitHub
parent bdea0f07ef
commit 12917ef0e9
33 changed files with 389 additions and 590 deletions

View File

@ -16,41 +16,37 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{C4BC9889-B49F-41B6-806B-F84941B2549B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SocketsSample", "samples\SocketsSample\SocketsSample.csproj", "{C4AEAB04-F341-4539-B6C0-52368FB4BF9E}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SocketsSample", "samples\SocketsSample\SocketsSample.csproj", "{C4AEAB04-F341-4539-B6C0-52368FB4BF9E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNetCore.Sockets", "src\Microsoft.AspNetCore.Sockets\Microsoft.AspNetCore.Sockets.csproj", "{1715EA8D-8E13-4ACF-8BCA-57D048E55ED8}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Sockets", "src\Microsoft.AspNetCore.Sockets\Microsoft.AspNetCore.Sockets.csproj", "{1715EA8D-8E13-4ACF-8BCA-57D048E55ED8}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{6A35B453-52EC-48AF-89CA-D4A69800F131}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNetCore.Sockets.Tests", "test\Microsoft.AspNetCore.Sockets.Tests\Microsoft.AspNetCore.Sockets.Tests.csproj", "{AAD719D5-5E31-4ED1-A60F-6EB92EFA66D9}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Sockets.Tests", "test\Microsoft.AspNetCore.Sockets.Tests\Microsoft.AspNetCore.Sockets.Tests.csproj", "{AAD719D5-5E31-4ED1-A60F-6EB92EFA66D9}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNetCore.SignalR", "src\Microsoft.AspNetCore.SignalR\Microsoft.AspNetCore.SignalR.csproj", "{42E76F87-92B6-45AB-BF07-6B811C0F2CAC}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.SignalR", "src\Microsoft.AspNetCore.SignalR\Microsoft.AspNetCore.SignalR.csproj", "{42E76F87-92B6-45AB-BF07-6B811C0F2CAC}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNetCore.SignalR.Redis", "src\Microsoft.AspNetCore.SignalR.Redis\Microsoft.AspNetCore.SignalR.Redis.csproj", "{59319B72-38BE-4041-8E5C-FF6938874CE8}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.SignalR.Redis", "src\Microsoft.AspNetCore.SignalR.Redis\Microsoft.AspNetCore.SignalR.Redis.csproj", "{59319B72-38BE-4041-8E5C-FF6938874CE8}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ChatSample", "samples\ChatSample\ChatSample.csproj", "{300979F6-A02E-407A-B8DF-F6200806C18D}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ChatSample", "samples\ChatSample\ChatSample.csproj", "{300979F6-A02E-407A-B8DF-F6200806C18D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SocialWeather", "samples\SocialWeather\SocialWeather.csproj", "{8D789F94-CB74-45FD-ACE7-92AF6E55042E}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SocialWeather", "samples\SocialWeather\SocialWeather.csproj", "{8D789F94-CB74-45FD-ACE7-92AF6E55042E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNetCore.SignalR.Test.Server", "client-ts\Microsoft.AspNetCore.SignalR.Test.Server\Microsoft.AspNetCore.SignalR.Test.Server.csproj", "{A0BF246B-FE7D-4E12-99BF-FFDC131B85D8}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.SignalR.Test.Server", "client-ts\Microsoft.AspNetCore.SignalR.Test.Server\Microsoft.AspNetCore.SignalR.Test.Server.csproj", "{A0BF246B-FE7D-4E12-99BF-FFDC131B85D8}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNetCore.SignalR.Tests", "test\Microsoft.AspNetCore.SignalR.Tests\Microsoft.AspNetCore.SignalR.Tests.csproj", "{1CE2B3BE-056C-41E3-A5F5-6A1EF1D288BA}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.SignalR.Tests", "test\Microsoft.AspNetCore.SignalR.Tests\Microsoft.AspNetCore.SignalR.Tests.csproj", "{1CE2B3BE-056C-41E3-A5F5-6A1EF1D288BA}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ClientSample", "samples\ClientSample\ClientSample.csproj", "{BA99C2A1-48F9-4FA5-B95A-9687A73B7CC9}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ClientSample", "samples\ClientSample\ClientSample.csproj", "{BA99C2A1-48F9-4FA5-B95A-9687A73B7CC9}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebSocketSample", "samples\WebSocketSample\WebSocketSample.csproj", "{EE790D50-C632-46B9-A430-06FA2F2FDCD7}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebSocketSample", "samples\WebSocketSample\WebSocketSample.csproj", "{EE790D50-C632-46B9-A430-06FA2F2FDCD7}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNetCore.Sockets.Client", "src\Microsoft.AspNetCore.Sockets.Client\Microsoft.AspNetCore.Sockets.Client.csproj", "{623FD372-36DE-41A9-A564-F6040D570DBD}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.SignalR.Client.Tests", "test\Microsoft.AspNetCore.SignalR.Client.Tests\Microsoft.AspNetCore.SignalR.Client.Tests.csproj", "{B19C15A5-F5EA-4CA7-936B-1166ABEE35C4}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNetCore.SignalR.Client.Tests", "test\Microsoft.AspNetCore.SignalR.Client.Tests\Microsoft.AspNetCore.SignalR.Client.Tests.csproj", "{B19C15A5-F5EA-4CA7-936B-1166ABEE35C4}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.SignalR.Common", "src\Microsoft.AspNetCore.SignalR.Common\Microsoft.AspNetCore.SignalR.Common.csproj", "{E37324FF-6BAF-4243-BA80-7C024CF5F29D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNetCore.SignalR.Common", "src\Microsoft.AspNetCore.SignalR.Common\Microsoft.AspNetCore.SignalR.Common.csproj", "{E37324FF-6BAF-4243-BA80-7C024CF5F29D}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.SignalR.Client", "src\Microsoft.AspNetCore.SignalR.Client\Microsoft.AspNetCore.SignalR.Client.csproj", "{354335AB-CEE9-4434-A641-78058F6EFE56}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNetCore.SignalR.Client", "src\Microsoft.AspNetCore.SignalR.Client\Microsoft.AspNetCore.SignalR.Client.csproj", "{354335AB-CEE9-4434-A641-78058F6EFE56}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNetCore.SignalR.Client.FunctionalTests", "test\Microsoft.AspNetCore.SignalR.Client.FunctionalTests\Microsoft.AspNetCore.SignalR.Client.FunctionalTests.csproj", "{455B68D2-C5B6-4BF4-A685-964B07AFAAF8}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNetCore.Sockets.Common", "src\Microsoft.AspNetCore.Sockets.Common\Microsoft.AspNetCore.Sockets.Common.csproj", "{F3EFFD9F-DD85-48A2-9B11-83A133ECC099}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.SignalR.Client.FunctionalTests", "test\Microsoft.AspNetCore.SignalR.Client.FunctionalTests\Microsoft.AspNetCore.SignalR.Client.FunctionalTests.csproj", "{455B68D2-C5B6-4BF4-A685-964B07AFAAF8}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.SignalR.Client.TS", "client-ts\Microsoft.AspNetCore.SignalR.Client.TS\Microsoft.AspNetCore.SignalR.Client.TS.csproj", "{333526A4-633B-491A-AC45-CC62A0012D1C}"
EndProject
@ -67,7 +63,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "client-ts", "client-ts", "{
client-ts\package.json = client-ts\package.json
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNetCore.SignalR.Microbenchmarks", "test\Microsoft.AspNetCore.SignalR.Microbenchmarks\Microsoft.AspNetCore.SignalR.Microbenchmarks.csproj", "{96771B3F-4D18-41A7-A75B-FF38E76AAC89}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.SignalR.Microbenchmarks", "test\Microsoft.AspNetCore.SignalR.Microbenchmarks\Microsoft.AspNetCore.SignalR.Microbenchmarks.csproj", "{96771B3F-4D18-41A7-A75B-FF38E76AAC89}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.SignalR.Common.Tests", "test\Microsoft.AspNetCore.SignalR.Common.Tests\Microsoft.AspNetCore.SignalR.Common.Tests.csproj", "{75E342F6-5445-4E7E-9143-6D9AE62C2B1E}"
EndProject
@ -77,6 +73,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Signal
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Sockets.Http", "src\Microsoft.AspNetCore.Sockets.Http\Microsoft.AspNetCore.Sockets.Http.csproj", "{9E403E93-3284-486F-9A5F-1E15FCE426A5}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Sockets.Client.Http", "src\Microsoft.AspNetCore.Sockets.Client.Http\Microsoft.AspNetCore.Sockets.Client.Http.csproj", "{B0243F99-2D3F-4CC6-AD71-E3F891B64724}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Sockets.Common.Http", "src\Microsoft.AspNetCore.Sockets.Common.Http\Microsoft.AspNetCore.Sockets.Common.Http.csproj", "{E081EE41-D95F-4AD2-BC0B-4B562C0A2A47}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -127,10 +127,6 @@ Global
{EE790D50-C632-46B9-A430-06FA2F2FDCD7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EE790D50-C632-46B9-A430-06FA2F2FDCD7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EE790D50-C632-46B9-A430-06FA2F2FDCD7}.Release|Any CPU.Build.0 = Release|Any CPU
{623FD372-36DE-41A9-A564-F6040D570DBD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{623FD372-36DE-41A9-A564-F6040D570DBD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{623FD372-36DE-41A9-A564-F6040D570DBD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{623FD372-36DE-41A9-A564-F6040D570DBD}.Release|Any CPU.Build.0 = Release|Any CPU
{B19C15A5-F5EA-4CA7-936B-1166ABEE35C4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B19C15A5-F5EA-4CA7-936B-1166ABEE35C4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B19C15A5-F5EA-4CA7-936B-1166ABEE35C4}.Release|Any CPU.ActiveCfg = Release|Any CPU
@ -147,10 +143,6 @@ Global
{455B68D2-C5B6-4BF4-A685-964B07AFAAF8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{455B68D2-C5B6-4BF4-A685-964B07AFAAF8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{455B68D2-C5B6-4BF4-A685-964B07AFAAF8}.Release|Any CPU.Build.0 = Release|Any CPU
{F3EFFD9F-DD85-48A2-9B11-83A133ECC099}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F3EFFD9F-DD85-48A2-9B11-83A133ECC099}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F3EFFD9F-DD85-48A2-9B11-83A133ECC099}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F3EFFD9F-DD85-48A2-9B11-83A133ECC099}.Release|Any CPU.Build.0 = Release|Any CPU
{333526A4-633B-491A-AC45-CC62A0012D1C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{333526A4-633B-491A-AC45-CC62A0012D1C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{333526A4-633B-491A-AC45-CC62A0012D1C}.Release|Any CPU.ActiveCfg = Release|Any CPU
@ -175,6 +167,14 @@ Global
{9E403E93-3284-486F-9A5F-1E15FCE426A5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9E403E93-3284-486F-9A5F-1E15FCE426A5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9E403E93-3284-486F-9A5F-1E15FCE426A5}.Release|Any CPU.Build.0 = Release|Any CPU
{B0243F99-2D3F-4CC6-AD71-E3F891B64724}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B0243F99-2D3F-4CC6-AD71-E3F891B64724}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B0243F99-2D3F-4CC6-AD71-E3F891B64724}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B0243F99-2D3F-4CC6-AD71-E3F891B64724}.Release|Any CPU.Build.0 = Release|Any CPU
{E081EE41-D95F-4AD2-BC0B-4B562C0A2A47}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E081EE41-D95F-4AD2-BC0B-4B562C0A2A47}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E081EE41-D95F-4AD2-BC0B-4B562C0A2A47}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E081EE41-D95F-4AD2-BC0B-4B562C0A2A47}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -191,12 +191,10 @@ Global
{1CE2B3BE-056C-41E3-A5F5-6A1EF1D288BA} = {6A35B453-52EC-48AF-89CA-D4A69800F131}
{BA99C2A1-48F9-4FA5-B95A-9687A73B7CC9} = {C4BC9889-B49F-41B6-806B-F84941B2549B}
{EE790D50-C632-46B9-A430-06FA2F2FDCD7} = {C4BC9889-B49F-41B6-806B-F84941B2549B}
{623FD372-36DE-41A9-A564-F6040D570DBD} = {DA69F624-5398-4884-87E4-B816698CDE65}
{B19C15A5-F5EA-4CA7-936B-1166ABEE35C4} = {6A35B453-52EC-48AF-89CA-D4A69800F131}
{E37324FF-6BAF-4243-BA80-7C024CF5F29D} = {DA69F624-5398-4884-87E4-B816698CDE65}
{354335AB-CEE9-4434-A641-78058F6EFE56} = {DA69F624-5398-4884-87E4-B816698CDE65}
{455B68D2-C5B6-4BF4-A685-964B07AFAAF8} = {6A35B453-52EC-48AF-89CA-D4A69800F131}
{F3EFFD9F-DD85-48A2-9B11-83A133ECC099} = {DA69F624-5398-4884-87E4-B816698CDE65}
{333526A4-633B-491A-AC45-CC62A0012D1C} = {3A76C5A2-79ED-49BC-8BDC-6A3A766FFA1B}
{6CEC3DC2-5B01-45A8-8F0D-8531315DA90B} = {6A35B453-52EC-48AF-89CA-D4A69800F131}
{96771B3F-4D18-41A7-A75B-FF38E76AAC89} = {6A35B453-52EC-48AF-89CA-D4A69800F131}
@ -204,5 +202,7 @@ Global
{F2E4FBD6-9AEA-4A82-BAC9-3FAACA677DF8} = {DA69F624-5398-4884-87E4-B816698CDE65}
{FD80BB0F-0876-4F11-8D84-6657C8EF84CA} = {DA69F624-5398-4884-87E4-B816698CDE65}
{9E403E93-3284-486F-9A5F-1E15FCE426A5} = {DA69F624-5398-4884-87E4-B816698CDE65}
{B0243F99-2D3F-4CC6-AD71-E3F891B64724} = {DA69F624-5398-4884-87E4-B816698CDE65}
{E081EE41-D95F-4AD2-BC0B-4B562C0A2A47} = {DA69F624-5398-4884-87E4-B816698CDE65}
EndGlobalSection
EndGlobal

View File

@ -15,6 +15,7 @@
<ItemGroup>
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.SignalR.Client\Microsoft.AspNetCore.SignalR.Client.csproj" />
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Sockets.Client.Http\Microsoft.AspNetCore.Sockets.Client.Http.csproj" />
</ItemGroup>
<ItemGroup>

View File

@ -6,6 +6,7 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.SignalR.Client;
using Microsoft.AspNetCore.Sockets.Client;
using Microsoft.Extensions.CommandLineUtils;
using Microsoft.Extensions.Logging;
@ -32,7 +33,8 @@ namespace ClientSample
var loggerFactory = new LoggerFactory();
Console.WriteLine("Connecting to {0}", baseUrl);
var connection = new HubConnection(new Uri(baseUrl), loggerFactory);
var httpConnection = new HttpConnection(new Uri(baseUrl));
var connection = new HubConnection(httpConnection, loggerFactory);
try
{
await connection.StartAsync();

View File

@ -8,7 +8,6 @@ using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Sockets;
using Microsoft.AspNetCore.Sockets.Client;
using Microsoft.Extensions.CommandLineUtils;
using Microsoft.Extensions.Logging;
@ -37,7 +36,7 @@ namespace ClientSample
var logger = loggerFactory.CreateLogger<Program>();
Console.WriteLine($"Connecting to {baseUrl}...");
var connection = new Connection(new Uri(baseUrl), loggerFactory);
var connection = new HttpConnection(new Uri(baseUrl), loggerFactory);
try
{
var cts = new CancellationTokenSource();

View File

@ -5,13 +5,11 @@ using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using System.Threading.Tasks.Channels;
using Microsoft.AspNetCore.SignalR.Internal;
using Microsoft.AspNetCore.SignalR.Internal.Protocol;
using Microsoft.AspNetCore.Sockets;
using Microsoft.AspNetCore.Sockets.Client;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
@ -27,8 +25,6 @@ namespace Microsoft.AspNetCore.SignalR.Client
private readonly IHubProtocol _protocol;
private readonly HubBinder _binder;
private HttpClient _httpClient;
private readonly object _pendingCallsLock = new object();
private readonly CancellationTokenSource _connectionActive = new CancellationTokenSource();
private readonly Dictionary<string, InvocationRequest> _pendingCalls = new Dictionary<string, InvocationRequest>();
@ -48,12 +44,8 @@ namespace Microsoft.AspNetCore.SignalR.Client
remove { _connection.Closed -= value; }
}
public HubConnection(Uri url)
: this(new Connection(url), new JsonHubProtocol(new JsonSerializer()), null)
{ }
public HubConnection(Uri url, ILoggerFactory loggerFactory)
: this(new Connection(url), new JsonHubProtocol(new JsonSerializer()), loggerFactory)
public HubConnection(IConnection connection)
: this(connection, new JsonHubProtocol(new JsonSerializer()), null)
{ }
// These are only really needed for tests now...
@ -82,31 +74,14 @@ namespace Microsoft.AspNetCore.SignalR.Client
_connection.Closed += Shutdown;
}
public Task StartAsync() => StartAsync(TransportType.All, httpClient: null);
public Task StartAsync(HttpClient httpClient) => StartAsync(TransportType.All, httpClient: httpClient);
public Task StartAsync(TransportType transportType) => StartAsync(transportType, httpClient: null);
public async Task StartAsync(TransportType transportType, HttpClient httpClient)
public async Task StartAsync()
{
if (httpClient == null)
{
// We are creating the client so store it to be able to dispose
_httpClient = httpClient = new HttpClient();
}
await _connection.StartAsync(new DefaultTransportFactory(transportType, _loggerFactory, httpClient), httpClient);
}
public async Task StartAsync(ITransportFactory transportFactory, HttpClient httpClient)
{
await _connection.StartAsync(transportFactory, httpClient);
await _connection.StartAsync();
}
public async Task DisposeAsync()
{
await _connection.DisposeAsync();
_httpClient?.Dispose();
}
// TODO: Client return values/tasks?

View File

@ -13,7 +13,8 @@
<ItemGroup>
<ProjectReference Include="..\Microsoft.AspNetCore.SignalR.Common\Microsoft.AspNetCore.SignalR.Common.csproj" />
<ProjectReference Include="..\Microsoft.AspNetCore.Sockets.Client\Microsoft.AspNetCore.Sockets.Client.csproj" />
<ProjectReference Include="..\Microsoft.AspNetCore.Sockets.Abstractions\Microsoft.AspNetCore.Sockets.Abstractions.csproj" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="$(AspNetCoreVersion)" />
</ItemGroup>
</Project>

View File

@ -21,8 +21,4 @@
<PackageReference Include="System.IO.Pipelines.Text.Primitives" Version="$(CoreFxLabsVersion)" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Microsoft.AspNetCore.Sockets.Common\Microsoft.AspNetCore.Sockets.Common.csproj" />
</ItemGroup>
</Project>

View File

@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
@ -10,7 +9,7 @@ namespace Microsoft.AspNetCore.Sockets.Client
{
public interface IConnection
{
Task StartAsync(ITransportFactory transportFactory, HttpClient httpClient);
Task StartAsync();
Task SendAsync(byte[] data, CancellationToken cancellationToken);
Task DisposeAsync();

View File

@ -15,18 +15,19 @@ using Newtonsoft.Json;
namespace Microsoft.AspNetCore.Sockets.Client
{
public class Connection : IConnection
public class HttpConnection : IConnection
{
private readonly ILoggerFactory _loggerFactory;
private readonly ILogger _logger;
private volatile int _connectionState = ConnectionState.Initial;
private volatile IChannelConnection<byte[], SendMessage> _transportChannel;
private HttpClient _httpClient;
private readonly HttpClient _httpClient;
private volatile ITransport _transport;
private volatile Task _receiveLoopTask;
private TaskCompletionSource<object> _startTcs = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);
private TaskQueue _eventQueue = new TaskQueue();
private readonly ITransportFactory _transportFactory;
private ReadableChannel<byte[]> Input => _transportChannel.Input;
private WritableChannel<SendMessage> Output => _transportChannel.Output;
@ -37,34 +38,45 @@ namespace Microsoft.AspNetCore.Sockets.Client
public event Action<byte[]> Received;
public event Action<Exception> Closed;
public Connection(Uri url)
: this(url, null)
public HttpConnection(Uri url)
: this(url, TransportType.WebSockets)
{ }
public Connection(Uri url, ILoggerFactory loggerFactory)
public HttpConnection(Uri url, TransportType transportType)
: this(url, transportType, loggerFactory: null)
{
}
public HttpConnection(Uri url, ILoggerFactory loggerFactory)
: this(url, TransportType.WebSockets, loggerFactory, httpMessageHandler: null)
{
}
public HttpConnection(Uri url, TransportType transportType, ILoggerFactory loggerFactory)
: this(url, transportType, loggerFactory, httpMessageHandler: null)
{
}
public HttpConnection(Uri url, TransportType transportType, ILoggerFactory loggerFactory, HttpMessageHandler httpMessageHandler)
{
Url = url ?? throw new ArgumentNullException(nameof(url));
_loggerFactory = loggerFactory ?? NullLoggerFactory.Instance;
_logger = _loggerFactory.CreateLogger<Connection>();
_logger = _loggerFactory.CreateLogger<HttpConnection>();
_httpClient = httpMessageHandler == null ? new HttpClient() : new HttpClient(httpMessageHandler);
_transportFactory = new DefaultTransportFactory(transportType, _loggerFactory, _httpClient);
}
public Task StartAsync() => StartAsync(transportFactory: null, httpClient: null);
public Task StartAsync(HttpClient httpClient) => StartAsync(transportFactory: null, httpClient: httpClient);
public Task StartAsync(ITransportFactory transportFactory) => StartAsync(transportFactory, httpClient: null);
public Task StartAsync(TransportType transportType) => StartAsync(transportType, httpClient: null);
public Task StartAsync(TransportType transportType, HttpClient httpClient)
public HttpConnection(Uri url, ITransportFactory transportFactory, ILoggerFactory loggerFactory, HttpMessageHandler httpMessageHandler)
{
if (httpClient == null)
{
// We are creating the client so store it to be able to dispose
_httpClient = httpClient = new HttpClient();
}
return StartAsync(new DefaultTransportFactory(transportType, _loggerFactory, httpClient), httpClient);
Url = url ?? throw new ArgumentNullException(nameof(url));
_loggerFactory = loggerFactory ?? NullLoggerFactory.Instance;
_logger = _loggerFactory.CreateLogger<HttpConnection>();
_httpClient = httpMessageHandler == null ? new HttpClient() : new HttpClient(httpMessageHandler);
_transportFactory = transportFactory ?? throw new ArgumentNullException(nameof(transportFactory));
}
public Task StartAsync(ITransportFactory transportFactory, HttpClient httpClient)
public Task StartAsync()
{
if (Interlocked.CompareExchange(ref _connectionState, ConnectionState.Connecting, ConnectionState.Initial)
!= ConnectionState.Initial)
@ -73,13 +85,7 @@ namespace Microsoft.AspNetCore.Sockets.Client
new InvalidOperationException("Cannot start a connection that is not in the Initial state."));
}
if (httpClient == null)
{
// We are creating the client so store it to be able to dispose
_httpClient = httpClient = new HttpClient();
}
StartAsyncInternal(transportFactory ?? new DefaultTransportFactory(TransportType.All, _loggerFactory, httpClient), httpClient)
StartAsyncInternal()
.ContinueWith(t =>
{
if (t.IsFaulted)
@ -99,13 +105,13 @@ namespace Microsoft.AspNetCore.Sockets.Client
return _startTcs.Task;
}
private async Task StartAsyncInternal(ITransportFactory transportFactory, HttpClient httpClient)
private async Task StartAsyncInternal()
{
_logger.LogDebug("Starting connection.");
try
{
var negotiationResponse = await Negotiate(Url, httpClient, _logger);
var negotiationResponse = await Negotiate(Url, _httpClient, _logger);
// Connection is being stopped while start was in progress
if (_connectionState == ConnectionState.Disconnected)
@ -114,7 +120,7 @@ namespace Microsoft.AspNetCore.Sockets.Client
return;
}
_transport = transportFactory.CreateTransport(GetAvailableServerTransports(negotiationResponse));
_transport = _transportFactory.CreateTransport(GetAvailableServerTransports(negotiationResponse));
var connectUrl = CreateConnectUrl(Url, negotiationResponse);
_logger.LogDebug("Starting transport '{0}' with Url: {1}", _transport.GetType().Name, connectUrl);
@ -161,7 +167,7 @@ namespace Microsoft.AspNetCore.Sockets.Client
_logger.LogDebug("Draining event queue");
await _eventQueue.Drain();
_httpClient?.Dispose();
_httpClient.Dispose();
_logger.LogDebug("Raising Closed event");
@ -387,7 +393,7 @@ namespace Microsoft.AspNetCore.Sockets.Client
await _receiveLoopTask;
}
_httpClient?.Dispose();
_httpClient.Dispose();
}
private class ConnectionState

View File

@ -13,7 +13,7 @@
<ItemGroup>
<ProjectReference Include="..\Microsoft.AspNetCore.Sockets.Abstractions\Microsoft.AspNetCore.Sockets.Abstractions.csproj" />
<ProjectReference Include="..\Microsoft.AspNetCore.Sockets.Common\Microsoft.AspNetCore.Sockets.Common.csproj" />
<ProjectReference Include="..\Microsoft.AspNetCore.Sockets.Common.Http\Microsoft.AspNetCore.Sockets.Common.Http.csproj" />
</ItemGroup>
<ItemGroup>

View File

@ -17,7 +17,7 @@
<ItemGroup>
<ProjectReference Include="..\Microsoft.AspNetCore.Sockets\Microsoft.AspNetCore.Sockets.csproj" />
<ProjectReference Include="..\Microsoft.AspNetCore.Sockets.Common\Microsoft.AspNetCore.Sockets.Common.csproj" />
<ProjectReference Include="..\Microsoft.AspNetCore.Sockets.Common.Http\Microsoft.AspNetCore.Sockets.Common.Http.csproj" />
<PackageReference Include="Microsoft.AspNetCore.Authorization.Policy" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Hosting.Abstractions" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Routing" Version="$(AspNetCoreVersion)" />

View File

@ -9,6 +9,7 @@ using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.SignalR.Tests.Common;
using Microsoft.AspNetCore.Sockets;
using Microsoft.AspNetCore.Sockets.Client;
using Microsoft.AspNetCore.TestHost;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
@ -51,21 +52,19 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
{
var loggerFactory = CreateLogger();
using (var httpClient = _testServer.CreateClient())
var httpConnection = new HttpConnection(new Uri("http://test/hubs"), TransportType.LongPolling, loggerFactory, _testServer.CreateHandler());
var connection = new HubConnection(httpConnection, loggerFactory);
try
{
var connection = new HubConnection(new Uri("http://test/hubs"), loggerFactory);
try
{
await connection.StartAsync(TransportType.LongPolling, httpClient);
await connection.StartAsync();
var result = await connection.Invoke<string>(nameof(TestHub.HelloWorld));
var result = await connection.Invoke<string>(nameof(TestHub.HelloWorld));
Assert.Equal("Hello World!", result);
}
finally
{
await connection.DisposeAsync();
}
Assert.Equal("Hello World!", result);
}
finally
{
await connection.DisposeAsync();
}
}
@ -75,21 +74,19 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
var loggerFactory = CreateLogger();
const string originalMessage = "SignalR";
using (var httpClient = _testServer.CreateClient())
var httpConnection = new HttpConnection(new Uri("http://test/hubs"), TransportType.LongPolling, loggerFactory, _testServer.CreateHandler());
var connection = new HubConnection(httpConnection, loggerFactory);
try
{
var connection = new HubConnection(new Uri("http://test/hubs"), loggerFactory);
try
{
await connection.StartAsync(TransportType.LongPolling, httpClient);
await connection.StartAsync();
var result = await connection.Invoke<string>(nameof(TestHub.Echo), originalMessage);
var result = await connection.Invoke<string>(nameof(TestHub.Echo), originalMessage);
Assert.Equal(originalMessage, result);
}
finally
{
await connection.DisposeAsync();
}
Assert.Equal(originalMessage, result);
}
finally
{
await connection.DisposeAsync();
}
}
@ -99,21 +96,19 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
var loggerFactory = CreateLogger();
const string originalMessage = "SignalR";
using (var httpClient = _testServer.CreateClient())
var httpConnection = new HttpConnection(new Uri("http://test/hubs"), TransportType.LongPolling, loggerFactory, _testServer.CreateHandler());
var connection = new HubConnection(httpConnection, loggerFactory);
try
{
var connection = new HubConnection(new Uri("http://test/hubs"), loggerFactory);
try
{
await connection.StartAsync(TransportType.LongPolling, httpClient);
await connection.StartAsync();
var result = await connection.Invoke<string>(nameof(TestHub.Echo).ToLowerInvariant(), originalMessage);
var result = await connection.Invoke<string>(nameof(TestHub.Echo).ToLowerInvariant(), originalMessage);
Assert.Equal(originalMessage, result);
}
finally
{
await connection.DisposeAsync();
}
Assert.Equal(originalMessage, result);
}
finally
{
await connection.DisposeAsync();
}
}
@ -123,24 +118,22 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
var loggerFactory = CreateLogger();
const string originalMessage = "SignalR";
using (var httpClient = _testServer.CreateClient())
var httpConnection = new HttpConnection(new Uri("http://test/hubs"), TransportType.LongPolling, loggerFactory, _testServer.CreateHandler());
var connection = new HubConnection(httpConnection, loggerFactory);
try
{
var connection = new HubConnection(new Uri("http://test/hubs"), loggerFactory);
try
{
await connection.StartAsync(TransportType.LongPolling, httpClient);
await connection.StartAsync();
var tcs = new TaskCompletionSource<string>();
connection.On<string>("Echo", tcs.SetResult);
var tcs = new TaskCompletionSource<string>();
connection.On<string>("Echo", tcs.SetResult);
await connection.Invoke(nameof(TestHub.CallEcho), originalMessage).OrTimeout();
await connection.Invoke(nameof(TestHub.CallEcho), originalMessage).OrTimeout();
Assert.Equal(originalMessage, await tcs.Task.OrTimeout());
}
finally
{
await connection.DisposeAsync().OrTimeout();
}
Assert.Equal(originalMessage, await tcs.Task.OrTimeout());
}
finally
{
await connection.DisposeAsync().OrTimeout();
}
}
@ -149,23 +142,21 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
{
var loggerFactory = CreateLogger();
using (var httpClient = _testServer.CreateClient())
var httpConnection = new HttpConnection(new Uri("http://test/hubs"), TransportType.LongPolling, loggerFactory, _testServer.CreateHandler());
var connection = new HubConnection(httpConnection, loggerFactory);
try
{
var connection = new HubConnection(new Uri("http://test/hubs"), loggerFactory);
try
{
await connection.StartAsync(TransportType.LongPolling, httpClient);
await connection.StartAsync();
var tcs = new TaskCompletionSource<string>();
var tcs = new TaskCompletionSource<string>();
var results = await connection.Stream<string>(nameof(TestHub.Stream)).ReadAllAsync().OrTimeout();
var results = await connection.Stream<string>(nameof(TestHub.Stream)).ReadAllAsync().OrTimeout();
Assert.Equal(new[] { "a", "b", "c" }, results.ToArray());
}
finally
{
await connection.DisposeAsync().OrTimeout();
}
Assert.Equal(new[] { "a", "b", "c" }, results.ToArray());
}
finally
{
await connection.DisposeAsync().OrTimeout();
}
}
@ -174,22 +165,20 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
{
var loggerFactory = CreateLogger();
using (var httpClient = _testServer.CreateClient())
var httpConnection = new HttpConnection(new Uri("http://test/hubs"), TransportType.LongPolling, loggerFactory, _testServer.CreateHandler());
var connection = new HubConnection(httpConnection, loggerFactory);
try
{
var connection = new HubConnection(new Uri("http://test/hubs"), loggerFactory);
try
{
await connection.StartAsync(TransportType.LongPolling, httpClient);
await connection.StartAsync();
var ex = await Assert.ThrowsAnyAsync<Exception>(
async () => await connection.Invoke("!@#$%"));
var ex = await Assert.ThrowsAnyAsync<Exception>(
async () => await connection.Invoke("!@#$%"));
Assert.Equal("Unknown hub method '!@#$%'", ex.Message);
}
finally
{
await connection.DisposeAsync();
}
Assert.Equal("Unknown hub method '!@#$%'", ex.Message);
}
finally
{
await connection.DisposeAsync();
}
}

View File

@ -15,6 +15,7 @@
<ItemGroup>
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.SignalR.Http\Microsoft.AspNetCore.SignalR.Http.csproj" />
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.SignalR.Client\Microsoft.AspNetCore.SignalR.Client.csproj" />
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Sockets.Client.Http\Microsoft.AspNetCore.Sockets.Client.Http.csproj" />
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Sockets\Microsoft.AspNetCore.Sockets.csproj" />
<PackageReference Include="Microsoft.AspNetCore.Diagnostics" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Hosting" Version="$(AspNetCoreVersion)" />

View File

@ -21,7 +21,7 @@ namespace Microsoft.AspNetCore.Sockets.Client.Tests
[Fact]
public void CannotCreateConnectionWithNullUrl()
{
var exception = Assert.Throws<ArgumentNullException>(() => new Connection(null));
var exception = Assert.Throws<ArgumentNullException>(() => new HttpConnection(null));
Assert.Equal("url", exception.ParamName);
}
@ -29,17 +29,16 @@ namespace Microsoft.AspNetCore.Sockets.Client.Tests
public void ConnectionReturnsUrlUsedToStartTheConnection()
{
var connectionUrl = new Uri("http://fakeuri.org/");
Assert.Equal(connectionUrl, new Connection(connectionUrl).Url);
Assert.Equal(connectionUrl, new HttpConnection(connectionUrl).Url);
}
[Theory]
[InlineData((TransportType)0)]
[InlineData(TransportType.All + 1)]
public async Task CannotStartConnectionWithInvalidTransportType(TransportType requestedTransportType)
public void CannotStartConnectionWithInvalidTransportType(TransportType requestedTransportType)
{
var connection = new Connection(new Uri("http://fakeuri.org/"));
await Assert.ThrowsAsync<ArgumentOutOfRangeException>(
() => connection.StartAsync(requestedTransportType));
Assert.Throws<ArgumentOutOfRangeException>(
() => new HttpConnection(new Uri("http://fakeuri.org/"), requestedTransportType));
}
[Fact]
@ -57,21 +56,18 @@ namespace Microsoft.AspNetCore.Sockets.Client.Tests
: ResponseUtils.CreateResponse(HttpStatusCode.OK);
});
using (var httpClient = new HttpClient(mockHttpHandler.Object))
var connection = new HttpConnection(new Uri("http://fakeuri.org/"), TransportType.LongPolling, loggerFactory: null, httpMessageHandler: mockHttpHandler.Object);
try
{
var connection = new Connection(new Uri("http://fakeuri.org/"));
try
{
await connection.StartAsync(TransportType.LongPolling, httpClient);
var exception =
await Assert.ThrowsAsync<InvalidOperationException>(
async () => await connection.StartAsync());
Assert.Equal("Cannot start a connection that is not in the Initial state.", exception.Message);
}
finally
{
await connection.DisposeAsync();
}
await connection.StartAsync();
var exception =
await Assert.ThrowsAsync<InvalidOperationException>(
async () => await connection.StartAsync());
Assert.Equal("Cannot start a connection that is not in the Initial state.", exception.Message);
}
finally
{
await connection.DisposeAsync();
}
}
@ -89,18 +85,15 @@ namespace Microsoft.AspNetCore.Sockets.Client.Tests
: ResponseUtils.CreateResponse(HttpStatusCode.OK);
});
using (var httpClient = new HttpClient(mockHttpHandler.Object))
{
var connection = new Connection(new Uri("http://fakeuri.org/"));
var connection = new HttpConnection(new Uri("http://fakeuri.org/"), TransportType.LongPolling, loggerFactory: null, httpMessageHandler: mockHttpHandler.Object);
await connection.StartAsync(TransportType.LongPolling, httpClient);
await connection.DisposeAsync();
var exception =
await Assert.ThrowsAsync<InvalidOperationException>(
async () => await connection.StartAsync());
await connection.StartAsync();
await connection.DisposeAsync();
var exception =
await Assert.ThrowsAsync<InvalidOperationException>(
async () => await connection.StartAsync());
Assert.Equal("Cannot start a connection that is not in the Initial state.", exception.Message);
}
Assert.Equal("Cannot start a connection that is not in the Initial state.", exception.Message);
}
[Fact]
@ -108,7 +101,7 @@ namespace Microsoft.AspNetCore.Sockets.Client.Tests
{
using (var httpClient = new HttpClient())
{
var connection = new Connection(new Uri("http://fakeuri.org/"));
var connection = new HttpConnection(new Uri("http://fakeuri.org/"));
await connection.DisposeAsync();
var exception =
await Assert.ThrowsAsync<InvalidOperationException>(
@ -142,31 +135,29 @@ namespace Microsoft.AspNetCore.Sockets.Client.Tests
: ResponseUtils.CreateResponse(HttpStatusCode.OK);
});
using (var httpClient = new HttpClient(mockHttpHandler.Object))
{
var transport = new Mock<ITransport>();
transport.Setup(t => t.StopAsync()).Returns(async () => { await releaseDisposeTcs.Task; });
var connection = new Connection(new Uri("http://fakeuri.org/"));
var startTask = connection.StartAsync(new TestTransportFactory(transport.Object), httpClient);
await allowDisposeTcs.Task;
var disposeTask = connection.DisposeAsync();
// allow StartAsync to continue once DisposeAsync has started
releaseNegotiateTcs.SetResult(null);
var transport = new Mock<ITransport>();
transport.Setup(t => t.StopAsync()).Returns(async () => { await releaseDisposeTcs.Task; });
var connection = new HttpConnection(new Uri("http://fakeuri.org/"), new TestTransportFactory(transport.Object), loggerFactory: null, httpMessageHandler: mockHttpHandler.Object);
// unblock DisposeAsync only after StartAsync completed
await startTask.OrTimeout();
releaseDisposeTcs.SetResult(null);
await disposeTask.OrTimeout();
var startTask = connection.StartAsync();
await allowDisposeTcs.Task;
var disposeTask = connection.DisposeAsync();
// allow StartAsync to continue once DisposeAsync has started
releaseNegotiateTcs.SetResult(null);
transport.Verify(t => t.StartAsync(It.IsAny<Uri>(), It.IsAny<IChannelConnection<SendMessage, byte[]>>()), Times.Never);
}
// unblock DisposeAsync only after StartAsync completed
await startTask.OrTimeout();
releaseDisposeTcs.SetResult(null);
await disposeTask.OrTimeout();
transport.Verify(t => t.StartAsync(It.IsAny<Uri>(), It.IsAny<IChannelConnection<SendMessage, byte[]>>()), Times.Never);
}
[Fact]
public async Task SendThrowsIfConnectionIsNotStarted()
{
var connection = new Connection(new Uri("http://fakeuri.org/"));
var connection = new HttpConnection(new Uri("http://fakeuri.org/"));
var exception = await Assert.ThrowsAsync<InvalidOperationException>(
async () => await connection.SendAsync(new byte[0]));
Assert.Equal("Cannot send messages when the connection is not in the Connected state.", exception.Message);
@ -186,17 +177,15 @@ namespace Microsoft.AspNetCore.Sockets.Client.Tests
: ResponseUtils.CreateResponse(HttpStatusCode.OK);
});
using (var httpClient = new HttpClient(mockHttpHandler.Object))
{
var connection = new Connection(new Uri("http://fakeuri.org/"));
await connection.StartAsync(TransportType.LongPolling, httpClient);
await connection.DisposeAsync();
var connection = new HttpConnection(new Uri("http://fakeuri.org/"), TransportType.LongPolling, loggerFactory: null, httpMessageHandler: mockHttpHandler.Object);
var exception = await Assert.ThrowsAsync<InvalidOperationException>(
async () => await connection.SendAsync(new byte[0]));
Assert.Equal("Cannot send messages when the connection is not in the Connected state.", exception.Message);
}
await connection.StartAsync();
await connection.DisposeAsync();
var exception = await Assert.ThrowsAsync<InvalidOperationException>(
async () => await connection.SendAsync(new byte[0]));
Assert.Equal("Cannot send messages when the connection is not in the Connected state.", exception.Message);
}
[Fact]
@ -213,22 +202,20 @@ namespace Microsoft.AspNetCore.Sockets.Client.Tests
: ResponseUtils.CreateResponse(HttpStatusCode.OK);
});
using (var httpClient = new HttpClient(mockHttpHandler.Object))
var connection = new HttpConnection(new Uri("http://fakeuri.org/"), TransportType.LongPolling, loggerFactory: null, httpMessageHandler: mockHttpHandler.Object);
try
{
var connection = new Connection(new Uri("http://fakeuri.org/"));
try
{
var connectedEventRaisedTcs = new TaskCompletionSource<object>();
connection.Connected += () => connectedEventRaisedTcs.SetResult(null);
var connectedEventRaisedTcs = new TaskCompletionSource<object>();
connection.Connected += () => connectedEventRaisedTcs.SetResult(null);
await connection.StartAsync(TransportType.LongPolling, httpClient);
await connection.StartAsync();
await connectedEventRaisedTcs.Task.OrTimeout();
}
finally
{
await connection.DisposeAsync();
}
await connectedEventRaisedTcs.Task.OrTimeout();
}
finally
{
await connection.DisposeAsync();
}
}
@ -250,25 +237,23 @@ namespace Microsoft.AspNetCore.Sockets.Client.Tests
mockTransport.Setup(t => t.StartAsync(It.IsAny<Uri>(), It.IsAny<IChannelConnection<SendMessage, byte[]>>()))
.Returns(Task.FromException(new InvalidOperationException("Transport failed to start")));
using (var httpClient = new HttpClient(mockHttpHandler.Object))
var connection = new HttpConnection(new Uri("http://fakeuri.org/"), new TestTransportFactory(mockTransport.Object), loggerFactory: null, httpMessageHandler: mockHttpHandler.Object);
var connectedEventRaised = false;
try
{
var connection = new Connection(new Uri("http://fakeuri.org/"));
var connectedEventRaised = false;
connection.Connected += () => connectedEventRaised = true;
try
{
connection.Connected += () => connectedEventRaised = true;
await Assert.ThrowsAsync<InvalidOperationException>(
async () => await connection.StartAsync(new TestTransportFactory(mockTransport.Object), httpClient));
}
finally
{
await connection.DisposeAsync();
}
Assert.False(connectedEventRaised);
await Assert.ThrowsAsync<InvalidOperationException>(
async () => await connection.StartAsync());
}
finally
{
await connection.DisposeAsync();
}
Assert.False(connectedEventRaised);
}
[Fact]
@ -285,19 +270,17 @@ namespace Microsoft.AspNetCore.Sockets.Client.Tests
: ResponseUtils.CreateResponse(HttpStatusCode.OK);
});
using (var httpClient = new HttpClient(mockHttpHandler.Object))
{
var connection = new Connection(new Uri("http://fakeuri.org/"));
var closedEventTcs = new TaskCompletionSource<Exception>();
connection.Closed += e => closedEventTcs.SetResult(e);
var connection = new HttpConnection(new Uri("http://fakeuri.org/"), TransportType.LongPolling, loggerFactory: null, httpMessageHandler: mockHttpHandler.Object);
await connection.StartAsync(TransportType.LongPolling, httpClient);
await connection.DisposeAsync();
var closedEventTcs = new TaskCompletionSource<Exception>();
connection.Closed += e => closedEventTcs.SetResult(e);
// in case of clean disconnect error should be null
Assert.Null(await closedEventTcs.Task.OrTimeout());
}
await connection.StartAsync();
await connection.DisposeAsync();
// in case of clean disconnect error should be null
Assert.Null(await closedEventTcs.Task.OrTimeout());
}
[Fact]
@ -317,21 +300,18 @@ namespace Microsoft.AspNetCore.Sockets.Client.Tests
: ResponseUtils.CreateResponse(HttpStatusCode.OK);
});
using (var httpClient = new HttpClient(mockHttpHandler.Object))
{
var connection = new Connection(new Uri("http://fakeuri.org/"));
var closedEventTcs = new TaskCompletionSource<Exception>();
connection.Closed += e => closedEventTcs.TrySetResult(e);
var connection = new HttpConnection(new Uri("http://fakeuri.org/"), TransportType.LongPolling, loggerFactory: null, httpMessageHandler: mockHttpHandler.Object);
var closedEventTcs = new TaskCompletionSource<Exception>();
connection.Closed += e => closedEventTcs.TrySetResult(e);
try
{
await connection.StartAsync(TransportType.LongPolling, httpClient);
Assert.IsType<HttpRequestException>(await closedEventTcs.Task.OrTimeout());
}
finally
{
await connection.DisposeAsync();
}
try
{
await connection.StartAsync();
Assert.IsType<HttpRequestException>(await closedEventTcs.Task.OrTimeout());
}
finally
{
await connection.DisposeAsync();
}
}
@ -367,16 +347,14 @@ namespace Microsoft.AspNetCore.Sockets.Client.Tests
return Task.CompletedTask;
});
using (var httpClient = new HttpClient(mockHttpHandler.Object))
{
var connection = new Connection(new Uri("http://fakeuri.org/"));
var receivedInvoked = false;
connection.Received += (m) => receivedInvoked = true;
await connection.StartAsync(new TestTransportFactory(mockTransport.Object), httpClient);
await connection.DisposeAsync();
Assert.False(receivedInvoked);
}
var connection = new HttpConnection(new Uri("http://fakeuri.org/"), new TestTransportFactory(mockTransport.Object), loggerFactory: null, httpMessageHandler: mockHttpHandler.Object);
var receivedInvoked = false;
connection.Received += (m) => receivedInvoked = true;
await connection.StartAsync();
await connection.DisposeAsync();
Assert.False(receivedInvoked);
}
[Fact]
@ -408,39 +386,37 @@ namespace Microsoft.AspNetCore.Sockets.Client.Tests
return Task.CompletedTask;
});
using (var httpClient = new HttpClient(mockHttpHandler.Object))
{
var closedTcs = new TaskCompletionSource<object>();
var allowDisposeTcs = new TaskCompletionSource<object>();
int receivedInvocationCount = 0;
var connection = new Connection(new Uri("http://fakeuri.org/"));
connection.Received +=
async (m) =>
var closedTcs = new TaskCompletionSource<object>();
var allowDisposeTcs = new TaskCompletionSource<object>();
int receivedInvocationCount = 0;
var connection = new HttpConnection(new Uri("http://fakeuri.org/"), new TestTransportFactory(mockTransport.Object), loggerFactory: null, httpMessageHandler: mockHttpHandler.Object);
connection.Received +=
async (m) =>
{
if (Interlocked.Increment(ref receivedInvocationCount) == 2)
{
if (Interlocked.Increment(ref receivedInvocationCount) == 2)
{
allowDisposeTcs.TrySetResult(null);
}
await closedTcs.Task;
};
connection.Closed += e => closedTcs.SetResult(null);
allowDisposeTcs.TrySetResult(null);
}
await closedTcs.Task;
};
connection.Closed += e => closedTcs.SetResult(null);
await connection.StartAsync(new TestTransportFactory(mockTransport.Object), httpClient);
channel.Output.TryWrite(Array.Empty<byte>());
channel.Output.TryWrite(Array.Empty<byte>());
await allowDisposeTcs.Task.OrTimeout();
await connection.DisposeAsync();
Assert.Equal(2, receivedInvocationCount);
// if the events were running on the main loop they would deadlock
await closedTcs.Task.OrTimeout();
}
await connection.StartAsync();
channel.Output.TryWrite(Array.Empty<byte>());
channel.Output.TryWrite(Array.Empty<byte>());
await allowDisposeTcs.Task.OrTimeout();
await connection.DisposeAsync();
Assert.Equal(2, receivedInvocationCount);
// if the events were running on the main loop they would deadlock
await closedTcs.Task.OrTimeout();
}
[Fact]
public async Task ClosedEventNotRaisedWhenTheClientIsStoppedButWasNeverStarted()
{
var connection = new Connection(new Uri("http://fakeuri.org/"));
var connection = new HttpConnection(new Uri("http://fakeuri.org/"));
bool closedEventRaised = false;
connection.Closed += e => closedEventRaised = true;
@ -467,11 +443,11 @@ namespace Microsoft.AspNetCore.Sockets.Client.Tests
using (var httpClient = new HttpClient(mockHttpHandler.Object))
{
var longPollingTransport = new LongPollingTransport(httpClient, new LoggerFactory());
var connection = new Connection(new Uri("http://fakeuri.org/"));
var connection = new HttpConnection(new Uri("http://fakeuri.org/"), new TestTransportFactory(longPollingTransport), loggerFactory: null, httpMessageHandler: mockHttpHandler.Object);
try
{
await connection.StartAsync(new TestTransportFactory(longPollingTransport), httpClient);
await connection.StartAsync();
Assert.False(longPollingTransport.Running.IsCompleted);
}
@ -506,28 +482,25 @@ namespace Microsoft.AspNetCore.Sockets.Client.Tests
: ResponseUtils.CreateResponse(HttpStatusCode.OK);
});
using (var httpClient = new HttpClient(mockHttpHandler.Object))
var connection = new HttpConnection(new Uri("http://fakeuri.org/"), TransportType.LongPolling, loggerFactory: null, httpMessageHandler: mockHttpHandler.Object);
try
{
var connection = new Connection(new Uri("http://fakeuri.org/"));
try
{
await connection.StartAsync(TransportType.LongPolling, httpClient);
await connection.StartAsync();
await connection.SendAsync(data);
await connection.SendAsync(data);
Assert.Equal(data, await sendTcs.Task.OrTimeout());
}
finally
{
await connection.DisposeAsync();
}
Assert.Equal(data, await sendTcs.Task.OrTimeout());
}
finally
{
await connection.DisposeAsync();
}
}
[Fact]
public async Task SendAsyncThrowsIfConnectionIsNotStarted()
{
var connection = new Connection(new Uri("http://fakeuri.org/"));
var connection = new HttpConnection(new Uri("http://fakeuri.org/"));
var exception = await Assert.ThrowsAsync<InvalidOperationException>(
async () => await connection.SendAsync(new byte[0]));
@ -555,18 +528,15 @@ namespace Microsoft.AspNetCore.Sockets.Client.Tests
: ResponseUtils.CreateResponse(HttpStatusCode.OK, content);
});
using (var httpClient = new HttpClient(mockHttpHandler.Object))
{
var connection = new Connection(new Uri("http://fakeuri.org/"));
var connection = new HttpConnection(new Uri("http://fakeuri.org/"), TransportType.LongPolling, loggerFactory: null, httpMessageHandler: mockHttpHandler.Object);
await connection.StartAsync(TransportType.LongPolling, httpClient);
await connection.DisposeAsync();
await connection.StartAsync();
await connection.DisposeAsync();
var exception = await Assert.ThrowsAsync<InvalidOperationException>(
async () => await connection.SendAsync(new byte[0]));
var exception = await Assert.ThrowsAsync<InvalidOperationException>(
async () => await connection.SendAsync(new byte[0]));
Assert.Equal("Cannot send messages when the connection is not in the Connected state.", exception.Message);
}
Assert.Equal("Cannot send messages when the connection is not in the Connected state.", exception.Message);
}
[Fact]
@ -586,17 +556,14 @@ namespace Microsoft.AspNetCore.Sockets.Client.Tests
: ResponseUtils.CreateResponse(HttpStatusCode.OK);
});
using (var httpClient = new HttpClient(mockHttpHandler.Object))
{
var connection = new Connection(new Uri("http://fakeuri.org/"));
var connection = new HttpConnection(new Uri("http://fakeuri.org/"), TransportType.LongPolling, loggerFactory: null, httpMessageHandler: mockHttpHandler.Object);
await connection.StartAsync(TransportType.LongPolling, httpClient);
await connection.StartAsync();
var exception = await Assert.ThrowsAsync<HttpRequestException>(
async () => await connection.SendAsync(new byte[0]));
var exception = await Assert.ThrowsAsync<HttpRequestException>(
async () => await connection.SendAsync(new byte[0]));
await connection.DisposeAsync();
}
await connection.DisposeAsync();
}
[Fact]
@ -621,33 +588,30 @@ namespace Microsoft.AspNetCore.Sockets.Client.Tests
: ResponseUtils.CreateResponse(HttpStatusCode.OK, content);
});
using (var httpClient = new HttpClient(mockHttpHandler.Object))
var connection = new HttpConnection(new Uri("http://fakeuri.org/"), TransportType.LongPolling, loggerFactory: null, httpMessageHandler: mockHttpHandler.Object);
try
{
var connection = new Connection(new Uri("http://fakeuri.org/"));
try
{
var receiveTcs = new TaskCompletionSource<string>();
connection.Received += (data) => receiveTcs.TrySetResult(Encoding.UTF8.GetString(data));
connection.Closed += e =>
var receiveTcs = new TaskCompletionSource<string>();
connection.Received += (data) => receiveTcs.TrySetResult(Encoding.UTF8.GetString(data));
connection.Closed += e =>
{
if (e != null)
{
if (e != null)
{
receiveTcs.TrySetException(e);
}
else
{
receiveTcs.TrySetCanceled();
}
};
receiveTcs.TrySetException(e);
}
else
{
receiveTcs.TrySetCanceled();
}
};
await connection.StartAsync(TransportType.LongPolling, httpClient);
await connection.StartAsync();
Assert.Equal("42", await receiveTcs.Task.OrTimeout());
}
finally
{
await connection.DisposeAsync();
}
Assert.Equal("42", await receiveTcs.Task.OrTimeout());
}
finally
{
await connection.DisposeAsync();
}
}
@ -668,28 +632,25 @@ namespace Microsoft.AspNetCore.Sockets.Client.Tests
: ResponseUtils.CreateResponse(HttpStatusCode.OK);
});
using (var httpClient = new HttpClient(mockHttpHandler.Object))
var connection = new HttpConnection(new Uri("http://fakeuri.org/"), TransportType.LongPolling, loggerFactory: null, httpMessageHandler: mockHttpHandler.Object);
try
{
var connection = new Connection(new Uri("http://fakeuri.org/"));
try
{
var closeTcs = new TaskCompletionSource<Exception>();
connection.Closed += e => closeTcs.TrySetResult(e);
var closeTcs = new TaskCompletionSource<Exception>();
connection.Closed += e => closeTcs.TrySetResult(e);
await connection.StartAsync(TransportType.LongPolling, httpClient);
await connection.StartAsync();
// Exception in send should shutdown the connection
await closeTcs.Task.OrTimeout();
// Exception in send should shutdown the connection
await closeTcs.Task.OrTimeout();
var exception = await Assert.ThrowsAsync<InvalidOperationException>(
async () => await connection.SendAsync(new byte[0]));
var exception = await Assert.ThrowsAsync<InvalidOperationException>(
async () => await connection.SendAsync(new byte[0]));
Assert.Equal("Cannot send messages when the connection is not in the Connected state.", exception.Message);
}
finally
{
await connection.DisposeAsync();
}
Assert.Equal("Cannot send messages when the connection is not in the Connected state.", exception.Message);
}
finally
{
await connection.DisposeAsync();
}
}
@ -707,14 +668,11 @@ namespace Microsoft.AspNetCore.Sockets.Client.Tests
return ResponseUtils.CreateResponse(HttpStatusCode.OK, negotiatePayload);
});
using (var httpClient = new HttpClient(mockHttpHandler.Object))
{
var connection = new Connection(new Uri("http://fakeuri.org/"));
var exception = await Assert.ThrowsAsync<FormatException>(
() => connection.StartAsync(TransportType.LongPolling, httpClient));
var connection = new HttpConnection(new Uri("http://fakeuri.org/"), TransportType.LongPolling, loggerFactory: null, httpMessageHandler: mockHttpHandler.Object);
var exception = await Assert.ThrowsAsync<FormatException>(
() => connection.StartAsync());
Assert.Equal("Invalid negotiation response received.", exception.Message);
}
Assert.Equal("Invalid negotiation response received.", exception.Message);
}
[Fact]
@ -730,14 +688,11 @@ namespace Microsoft.AspNetCore.Sockets.Client.Tests
ResponseUtils.CreateNegotiationResponse(connectionId: null));
});
using (var httpClient = new HttpClient(mockHttpHandler.Object))
{
var connection = new Connection(new Uri("http://fakeuri.org/"));
var exception = await Assert.ThrowsAsync<FormatException>(
() => connection.StartAsync(TransportType.LongPolling, httpClient));
var connection = new HttpConnection(new Uri("http://fakeuri.org/"), TransportType.LongPolling, loggerFactory: null, httpMessageHandler: mockHttpHandler.Object);
var exception = await Assert.ThrowsAsync<FormatException>(
() => connection.StartAsync());
Assert.Equal("Invalid connection id returned in negotiation response.", exception.Message);
}
Assert.Equal("Invalid connection id returned in negotiation response.", exception.Message);
}
[Fact]
@ -753,14 +708,11 @@ namespace Microsoft.AspNetCore.Sockets.Client.Tests
ResponseUtils.CreateNegotiationResponse(transportTypes: null));
});
using (var httpClient = new HttpClient(mockHttpHandler.Object))
{
var connection = new Connection(new Uri("http://fakeuri.org/"));
var exception = await Assert.ThrowsAsync<FormatException>(
() => connection.StartAsync(TransportType.LongPolling, httpClient));
var connection = new HttpConnection(new Uri("http://fakeuri.org/"), TransportType.LongPolling, loggerFactory: null, httpMessageHandler: mockHttpHandler.Object);
var exception = await Assert.ThrowsAsync<FormatException>(
() => connection.StartAsync());
Assert.Equal("No transports returned in negotiation response.", exception.Message);
}
Assert.Equal("No transports returned in negotiation response.", exception.Message);
}
[Theory]
@ -778,14 +730,11 @@ namespace Microsoft.AspNetCore.Sockets.Client.Tests
ResponseUtils.CreateNegotiationResponse(transportTypes: serverTransports));
});
using (var httpClient = new HttpClient(mockHttpHandler.Object))
{
var connection = new Connection(new Uri("http://fakeuri.org/"));
var exception = await Assert.ThrowsAsync<InvalidOperationException>(
() => connection.StartAsync(TransportType.LongPolling, httpClient));
var connection = new HttpConnection(new Uri("http://fakeuri.org/"), TransportType.LongPolling, loggerFactory: null, httpMessageHandler: mockHttpHandler.Object);
var exception = await Assert.ThrowsAsync<InvalidOperationException>(
() => connection.StartAsync());
Assert.Equal("No requested transports available on the server.", exception.Message);
}
Assert.Equal("No requested transports available on the server.", exception.Message);
}
}
}

View File

@ -4,19 +4,13 @@
using System;
using System.Buffers;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Client.Tests;
using Microsoft.AspNetCore.SignalR.Internal;
using Microsoft.AspNetCore.SignalR.Internal.Protocol;
using Microsoft.AspNetCore.SignalR.Tests.Common;
using Microsoft.AspNetCore.Sockets;
using Microsoft.AspNetCore.Sockets.Client;
using Microsoft.AspNetCore.Sockets.Client.Tests;
using Microsoft.Extensions.Logging;
using Moq;
using Moq.Protected;
using Xunit;
namespace Microsoft.AspNetCore.SignalR.Client.Tests
@ -24,110 +18,34 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
public class HubConnectionTests
{
[Fact]
public void CannotCreateHubConnectionWithNullUrl()
public async Task StartAsyncCallsConnectionStart()
{
var exception = Assert.Throws<ArgumentNullException>(
() => new HubConnection((Uri)null, Mock.Of<ILoggerFactory>()));
Assert.Equal("url", exception.ParamName);
var connection = new Mock<IConnection>();
connection.Setup(m => m.StartAsync()).Returns(Task.CompletedTask).Verifiable();
var hubConnection = new HubConnection(connection.Object);
await hubConnection.StartAsync();
connection.Verify(c => c.StartAsync(), Times.Once());
}
[Fact]
public async Task CanDisposeNotStartedHubConnection()
public async Task DisposeAsyncCallsConnectionStart()
{
await new HubConnection(new Uri("http://fakeuri.org"), new LoggerFactory())
.DisposeAsync();
}
[Fact]
public async Task CannotStartRunningHubConnection()
{
var mockHttpHandler = new Mock<HttpMessageHandler>();
mockHttpHandler.Protected()
.Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>())
.Returns<HttpRequestMessage, CancellationToken>(async (request, cancellationToken) =>
{
await Task.Yield();
return request.Method == HttpMethod.Options
? ResponseUtils.CreateResponse(System.Net.HttpStatusCode.OK, ResponseUtils.CreateNegotiationResponse())
: ResponseUtils.CreateResponse(System.Net.HttpStatusCode.OK);
});
using (var httpClient = new HttpClient(mockHttpHandler.Object))
{
var hubConnection = new HubConnection(new Uri("http://fakeuri.org/"), new LoggerFactory());
try
{
await hubConnection.StartAsync(TransportType.LongPolling, httpClient);
var exception =
await Assert.ThrowsAsync<InvalidOperationException>(
async () => await hubConnection.StartAsync());
Assert.Equal("Cannot start a connection that is not in the Initial state.", exception.Message);
}
finally
{
await hubConnection.DisposeAsync();
}
}
}
[Fact]
public async Task CannotStartStoppedHubConnection()
{
var mockHttpHandler = new Mock<HttpMessageHandler>();
mockHttpHandler.Protected()
.Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>())
.Returns<HttpRequestMessage, CancellationToken>(async (request, cancellationToken) =>
{
await Task.Yield();
return request.Method == HttpMethod.Options
? ResponseUtils.CreateResponse(System.Net.HttpStatusCode.OK, ResponseUtils.CreateNegotiationResponse())
: ResponseUtils.CreateResponse(System.Net.HttpStatusCode.OK);
});
using (var httpClient = new HttpClient(mockHttpHandler.Object))
{
var hubConnection = new HubConnection(new Uri("http://fakeuri.org/"), new LoggerFactory());
await hubConnection.StartAsync(TransportType.LongPolling, httpClient);
await hubConnection.DisposeAsync();
var exception =
await Assert.ThrowsAsync<InvalidOperationException>(
async () => await hubConnection.StartAsync());
Assert.Equal("Cannot start a connection that is not in the Initial state.", exception.Message);
}
}
[Fact]
public async Task InvokeThrowsIfHubConnectionNotStarted()
{
var hubConnection = new HubConnection(new Uri("http://fakeuri.org"));
var exception =
await Assert.ThrowsAsync<InvalidOperationException>(async () => await hubConnection.Invoke<int>("test"));
Assert.Equal("Cannot send messages when the connection is not in the Connected state.", exception.Message);
}
[Fact]
public async Task InvokeThrowsIfHubConnectionDisposed()
{
var hubConnection = new HubConnection(new Uri("http://fakeuri.org"));
var connection = new Mock<IConnection>();
connection.Setup(m => m.StartAsync()).Verifiable();
var hubConnection = new HubConnection(connection.Object);
await hubConnection.DisposeAsync();
var exception =
await Assert.ThrowsAsync<InvalidOperationException>(async () => await hubConnection.Invoke<int>("test"));
Assert.Equal("Cannot send messages when the connection is not in the Connected state.", exception.Message);
connection.Verify(c => c.DisposeAsync(), Times.Once());
}
[Fact]
public async Task InvokeThrowsIfSerializingMessageFails()
{
var mockConnection = new Mock<IConnection>();
var exception = new InvalidOperationException();
var mockProtocol = MockHubProtocol.Throw(exception);
var hubConnection = new HubConnection(mockConnection.Object, mockProtocol, null);
await hubConnection.StartAsync(TransportType.All, httpClient: null);
var hubConnection = new HubConnection(new TestConnection(), mockProtocol, null);
await hubConnection.StartAsync();
var actualException =
await Assert.ThrowsAsync<InvalidOperationException>(async () => await hubConnection.Invoke<int>("test"));
@ -137,75 +55,43 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
[Fact]
public async Task HubConnectionConnectedEventRaisedWhenTheClientIsConnected()
{
var mockHttpHandler = new Mock<HttpMessageHandler>();
mockHttpHandler.Protected()
.Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>())
.Returns<HttpRequestMessage, CancellationToken>(async (request, cancellationToken) =>
{
await Task.Yield();
return request.Method == HttpMethod.Options
? ResponseUtils.CreateResponse(System.Net.HttpStatusCode.OK, ResponseUtils.CreateNegotiationResponse())
: ResponseUtils.CreateResponse(System.Net.HttpStatusCode.OK);
});
using (var httpClient = new HttpClient(mockHttpHandler.Object))
var connection = new TestConnection();
var hubConnection = new HubConnection(connection);
try
{
var hubConnection = new HubConnection(new Uri("http://fakeuri.org"), new LoggerFactory());
try
{
var connectedEventRaisedTcs = new TaskCompletionSource<object>();
hubConnection.Connected += () => connectedEventRaisedTcs.SetResult(null);
var connectedEventRaisedTcs = new TaskCompletionSource<object>();
hubConnection.Connected += () => connectedEventRaisedTcs.SetResult(null);
await hubConnection.StartAsync(TransportType.LongPolling, httpClient);
await hubConnection.StartAsync();
await connectedEventRaisedTcs.Task.OrTimeout();
}
finally
{
await hubConnection.DisposeAsync();
}
await connectedEventRaisedTcs.Task.OrTimeout();
}
finally
{
await hubConnection.DisposeAsync();
}
}
[Fact]
public async Task ClosedEventRaisedWhenTheClientIsStopped()
{
var mockHttpHandler = new Mock<HttpMessageHandler>();
mockHttpHandler.Protected()
.Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>())
.Returns<HttpRequestMessage, CancellationToken>(async (request, cancellationToken) =>
{
await Task.Yield();
return request.Method == HttpMethod.Options
? ResponseUtils.CreateResponse(System.Net.HttpStatusCode.OK, ResponseUtils.CreateNegotiationResponse())
: ResponseUtils.CreateResponse(System.Net.HttpStatusCode.OK);
});
var hubConnection = new HubConnection(new TestConnection());
var closedEventTcs = new TaskCompletionSource<Exception>();
hubConnection.Closed += e => closedEventTcs.SetResult(e);
using (var httpClient = new HttpClient(mockHttpHandler.Object))
{
var hubConnection = new HubConnection(new Uri("http://fakeuri.org"), new LoggerFactory());
var closedEventTcs = new TaskCompletionSource<Exception>();
hubConnection.Closed += e => closedEventTcs.SetResult(e);
await hubConnection.StartAsync();
await hubConnection.DisposeAsync();
await hubConnection.StartAsync(TransportType.LongPolling, httpClient);
await hubConnection.DisposeAsync();
Assert.Null(await closedEventTcs.Task.OrTimeout());
}
Assert.Null(await closedEventTcs.Task.OrTimeout());
}
[Fact]
public async Task CannotCallInvokeOnClosedHubConnection()
{
var mockConnection = new Mock<IConnection>();
mockConnection
.Setup(m => m.DisposeAsync())
.Callback(() => mockConnection.Raise(c => c.Closed += null, (Exception)null))
.Returns(Task.FromResult<object>(null));
var connection = new TestConnection();
var hubConnection = new HubConnection(connection, new LoggerFactory());
var hubConnection = new HubConnection(mockConnection.Object, new LoggerFactory());
await hubConnection.StartAsync(new TestTransportFactory(Mock.Of<ITransport>()), httpClient: null);
await hubConnection.StartAsync();
await hubConnection.DisposeAsync();
var exception = await Assert.ThrowsAsync<InvalidOperationException>(
async () => await hubConnection.Invoke<int>("test"));
@ -216,15 +102,10 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
[Fact]
public async Task PendingInvocationsAreCancelledWhenConnectionClosesCleanly()
{
var mockConnection = new Mock<IConnection>();
mockConnection
.Setup(m => m.DisposeAsync())
.Callback(() => mockConnection.Raise(c => c.Closed += null, (Exception)null))
.Returns(Task.FromResult<object>(null));
var connection = new TestConnection();
var hubConnection = new HubConnection(connection, new LoggerFactory());
var hubConnection = new HubConnection(mockConnection.Object, new LoggerFactory());
await hubConnection.StartAsync(new TestTransportFactory(Mock.Of<ITransport>()), httpClient: null);
await hubConnection.StartAsync();
var invokeTask = hubConnection.Invoke<int>("testMethod");
await hubConnection.DisposeAsync();
@ -243,7 +124,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
var hubConnection = new HubConnection(mockConnection.Object, new LoggerFactory());
await hubConnection.StartAsync(new TestTransportFactory(Mock.Of<ITransport>()), httpClient: null);
await hubConnection.StartAsync();
var invokeTask = hubConnection.Invoke<int>("testMethod");
await hubConnection.DisposeAsync();
@ -261,7 +142,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
var mockProtocol = MockHubProtocol.ReturnOnParse(invocation);
var hubConnection = new HubConnection(mockConnection.Object, mockProtocol, null);
await hubConnection.StartAsync(new TestTransportFactory(Mock.Of<ITransport>()), httpClient: null);
await hubConnection.StartAsync();
mockConnection.Raise(c => c.Received += null, new object[] { new byte[] { } });
Assert.Equal(1, mockProtocol.ParseCalls);

View File

@ -15,7 +15,7 @@
<ItemGroup>
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.SignalR.Client\Microsoft.AspNetCore.SignalR.Client.csproj" />
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Sockets.Client\Microsoft.AspNetCore.Sockets.Client.csproj" />
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Sockets.Client.Http\Microsoft.AspNetCore.Sockets.Client.Http.csproj" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.Extensions.Logging.Testing" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="$(TestSdkVersion)" />

View File

@ -65,7 +65,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
throw new ObjectDisposedException("Unable to send message, underlying channel was closed");
}
public Task StartAsync(ITransportFactory transportFactory, HttpClient httpClient)
public Task StartAsync()
{
_started.TrySetResult(null);
Connected?.Invoke();

View File

@ -14,7 +14,6 @@
<ItemGroup>
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.SignalR.Common\Microsoft.AspNetCore.SignalR.Common.csproj" />
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Sockets.Common\Microsoft.AspNetCore.Sockets.Common.csproj" />
<PackageReference Include="BenchmarkDotNet" Version="0.10.3" />
</ItemGroup>

View File

@ -17,7 +17,6 @@ using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Testing;
using Xunit;
using Xunit.Abstractions;
using ClientConnection = Microsoft.AspNetCore.Sockets.Client.Connection;
namespace Microsoft.AspNetCore.SignalR.Tests
{
@ -88,7 +87,7 @@ namespace Microsoft.AspNetCore.SignalR.Tests
const string message = "Major Key";
var url = _serverFixture.BaseUrl + "/echo";
var connection = new ClientConnection(new Uri(url), loggerFactory);
var connection = new HttpConnection(new Uri(url), transportType, loggerFactory);
try
{
var receiveTcs = new TaskCompletionSource<string>();
@ -114,7 +113,7 @@ namespace Microsoft.AspNetCore.SignalR.Tests
};
logger.LogInformation("Starting connection to {url}", url);
await connection.StartAsync(transportType).OrTimeout();
await connection.StartAsync().OrTimeout();
logger.LogInformation("Started connection to {url}", url);
var bytes = Encoding.UTF8.GetBytes(message);
@ -156,7 +155,7 @@ namespace Microsoft.AspNetCore.SignalR.Tests
var logger = loggerFactory.CreateLogger<EndToEndTests>();
var url = _serverFixture.BaseUrl + "/echo";
var connection = new ClientConnection(new Uri(url), loggerFactory);
var connection = new HttpConnection(new Uri(url), loggerFactory);
try
{
var receiveTcs = new TaskCompletionSource<byte[]>();
@ -167,7 +166,7 @@ namespace Microsoft.AspNetCore.SignalR.Tests
};
logger.LogInformation("Starting connection to {url}", url);
await connection.StartAsync(TransportType.WebSockets).OrTimeout();
await connection.StartAsync().OrTimeout();
logger.LogInformation("Started connection to {url}", url);
var bytes = Encoding.UTF8.GetBytes(message);
@ -213,7 +212,8 @@ namespace Microsoft.AspNetCore.SignalR.Tests
var logger = loggerFactory.CreateLogger<EndToEndTests>();
var url = _serverFixture.BaseUrl + "/uncreatable";
var connection = new HubConnection(new Uri(url), loggerFactory);
var connection = new HubConnection(new HttpConnection(new Uri(url), transportType, loggerFactory), loggerFactory);
try
{
var closeTcs = new TaskCompletionSource<object>();
@ -232,7 +232,7 @@ namespace Microsoft.AspNetCore.SignalR.Tests
};
logger.LogInformation("Starting connection to {url}", url);
await connection.StartAsync(transportType).OrTimeout();
await connection.StartAsync().OrTimeout();
await closeTcs.Task.OrTimeout();
}

View File

@ -21,6 +21,7 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Sockets.Client.Http\Microsoft.AspNetCore.Sockets.Client.Http.csproj" />
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Sockets.Http\Microsoft.AspNetCore.Sockets.Http.csproj" />
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.SignalR.Http\Microsoft.AspNetCore.SignalR.Http.csproj" />
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.SignalR.Client\Microsoft.AspNetCore.SignalR.Client.csproj" />