Dispose Hubs from ActivatorUtilities
This commit is contained in:
parent
7c8eeb11f4
commit
28e3c8331b
|
|
@ -43,6 +43,8 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "SocialWeather", "samples\So
|
||||||
EndProject
|
EndProject
|
||||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.SignalR.Test.Server", "test\Microsoft.AspNetCore.SignalR.Test.Server\Microsoft.AspNetCore.SignalR.Test.Server.xproj", "{A0BF246B-FE7D-4E12-99BF-FFDC131B85D8}"
|
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.SignalR.Test.Server", "test\Microsoft.AspNetCore.SignalR.Test.Server\Microsoft.AspNetCore.SignalR.Test.Server.xproj", "{A0BF246B-FE7D-4E12-99BF-FFDC131B85D8}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.SignalR.Tests", "test\Microsoft.AspNetCore.SignalR.Tests\Microsoft.AspNetCore.SignalR.Tests.xproj", "{1CE2B3BE-056C-41E3-A5F5-6A1EF1D288BA}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
|
@ -105,6 +107,10 @@ Global
|
||||||
{A0BF246B-FE7D-4E12-99BF-FFDC131B85D8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{A0BF246B-FE7D-4E12-99BF-FFDC131B85D8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{A0BF246B-FE7D-4E12-99BF-FFDC131B85D8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{A0BF246B-FE7D-4E12-99BF-FFDC131B85D8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{A0BF246B-FE7D-4E12-99BF-FFDC131B85D8}.Release|Any CPU.Build.0 = Release|Any CPU
|
{A0BF246B-FE7D-4E12-99BF-FFDC131B85D8}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{1CE2B3BE-056C-41E3-A5F5-6A1EF1D288BA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{1CE2B3BE-056C-41E3-A5F5-6A1EF1D288BA}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{1CE2B3BE-056C-41E3-A5F5-6A1EF1D288BA}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{1CE2B3BE-056C-41E3-A5F5-6A1EF1D288BA}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|
@ -124,5 +130,6 @@ Global
|
||||||
{300979F6-A02E-407A-B8DF-F6200806C18D} = {C4BC9889-B49F-41B6-806B-F84941B2549B}
|
{300979F6-A02E-407A-B8DF-F6200806C18D} = {C4BC9889-B49F-41B6-806B-F84941B2549B}
|
||||||
{8D789F94-CB74-45FD-ACE7-92AF6E55042E} = {C4BC9889-B49F-41B6-806B-F84941B2549B}
|
{8D789F94-CB74-45FD-ACE7-92AF6E55042E} = {C4BC9889-B49F-41B6-806B-F84941B2549B}
|
||||||
{A0BF246B-FE7D-4E12-99BF-FFDC131B85D8} = {6A35B453-52EC-48AF-89CA-D4A69800F131}
|
{A0BF246B-FE7D-4E12-99BF-FFDC131B85D8} = {6A35B453-52EC-48AF-89CA-D4A69800F131}
|
||||||
|
{1CE2B3BE-056C-41E3-A5F5-6A1EF1D288BA} = {6A35B453-52EC-48AF-89CA-D4A69800F131}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
|
|
||||||
|
|
@ -63,9 +63,15 @@ namespace Microsoft.AspNetCore.SignalR
|
||||||
|
|
||||||
using (var scope = _serviceScopeFactory.CreateScope())
|
using (var scope = _serviceScopeFactory.CreateScope())
|
||||||
{
|
{
|
||||||
var hub = scope.ServiceProvider.GetService<THub>() ?? Activator.CreateInstance<THub>();
|
bool created;
|
||||||
InitializeHub(connection, hub);
|
var hub = CreateHub(scope.ServiceProvider, connection, out created);
|
||||||
|
|
||||||
await hub.OnConnectedAsync();
|
await hub.OnConnectedAsync();
|
||||||
|
|
||||||
|
if (created)
|
||||||
|
{
|
||||||
|
hub.Dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await DispatchMessagesAsync(connection);
|
await DispatchMessagesAsync(connection);
|
||||||
|
|
@ -74,9 +80,15 @@ namespace Microsoft.AspNetCore.SignalR
|
||||||
{
|
{
|
||||||
using (var scope = _serviceScopeFactory.CreateScope())
|
using (var scope = _serviceScopeFactory.CreateScope())
|
||||||
{
|
{
|
||||||
var hub = scope.ServiceProvider.GetService<THub>() ?? Activator.CreateInstance<THub>();
|
bool created;
|
||||||
InitializeHub(connection, hub);
|
var hub = CreateHub(scope.ServiceProvider, connection, out created);
|
||||||
|
|
||||||
await hub.OnDisconnectedAsync();
|
await hub.OnDisconnectedAsync();
|
||||||
|
|
||||||
|
if (created)
|
||||||
|
{
|
||||||
|
hub.Dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await _lifetimeManager.OnDisconnectedAsync(connection);
|
await _lifetimeManager.OnDisconnectedAsync(connection);
|
||||||
|
|
@ -132,11 +144,22 @@ namespace Microsoft.AspNetCore.SignalR
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InitializeHub(Connection connection, THub hub)
|
private THub CreateHub(IServiceProvider provider, Connection connection, out bool created)
|
||||||
{
|
{
|
||||||
|
var hub = provider.GetService<THub>();
|
||||||
|
created = false;
|
||||||
|
|
||||||
|
if (hub == null)
|
||||||
|
{
|
||||||
|
hub = ActivatorUtilities.CreateInstance<THub>(provider);
|
||||||
|
created = true;
|
||||||
|
}
|
||||||
|
|
||||||
hub.Clients = _hubContext.Clients;
|
hub.Clients = _hubContext.Clients;
|
||||||
hub.Context = new HubCallerContext(connection);
|
hub.Context = new HubCallerContext(connection);
|
||||||
hub.Groups = new GroupManager<THub>(connection, _lifetimeManager);
|
hub.Groups = new GroupManager<THub>(connection, _lifetimeManager);
|
||||||
|
|
||||||
|
return hub;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DiscoverHubMethods()
|
private void DiscoverHubMethods()
|
||||||
|
|
@ -169,17 +192,8 @@ namespace Microsoft.AspNetCore.SignalR
|
||||||
|
|
||||||
using (var scope = _serviceScopeFactory.CreateScope())
|
using (var scope = _serviceScopeFactory.CreateScope())
|
||||||
{
|
{
|
||||||
var hub = scope.ServiceProvider.GetService<THub>();
|
bool created;
|
||||||
|
var hub = CreateHub(scope.ServiceProvider, connection, out created);
|
||||||
bool created = false;
|
|
||||||
|
|
||||||
if (hub == null)
|
|
||||||
{
|
|
||||||
hub = Activator.CreateInstance<THub>();
|
|
||||||
created = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
InitializeHub(connection, hub);
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
@ -212,8 +226,7 @@ namespace Microsoft.AspNetCore.SignalR
|
||||||
|
|
||||||
if (created)
|
if (created)
|
||||||
{
|
{
|
||||||
// Dispose the object if it's disposable and we created it
|
hub.Dispose();
|
||||||
(hub as IDisposable)?.Dispose();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,107 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.IO.Pipelines;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Security.Claims;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.AspNetCore.Hosting.Internal;
|
||||||
|
using Microsoft.AspNetCore.Sockets;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.SignalR.Tests
|
||||||
|
{
|
||||||
|
public class HubEndpointTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public async Task HubsAreDisposed()
|
||||||
|
{
|
||||||
|
var trackDispose = new TrackDispose();
|
||||||
|
var serviceProvider = CreateServiceProvider(s => s.AddSingleton(trackDispose));
|
||||||
|
|
||||||
|
var endPoint = serviceProvider.GetService<HubEndPoint<TestHub>>();
|
||||||
|
|
||||||
|
using (var connectionWrapper = new ConnectionWrapper())
|
||||||
|
{
|
||||||
|
var endPointTask = endPoint.OnConnectedAsync(connectionWrapper.Connection);
|
||||||
|
|
||||||
|
await connectionWrapper.HttpConnection.Input.ReadingStarted;
|
||||||
|
|
||||||
|
// kill the connection
|
||||||
|
connectionWrapper.Connection.Channel.Dispose();
|
||||||
|
|
||||||
|
await endPointTask;
|
||||||
|
|
||||||
|
Assert.Equal(2, trackDispose.DisposeCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TestHub : Hub
|
||||||
|
{
|
||||||
|
private TrackDispose _trackDispose;
|
||||||
|
|
||||||
|
public TestHub(TrackDispose trackDispose)
|
||||||
|
{
|
||||||
|
_trackDispose = trackDispose;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Dispose(bool dispose)
|
||||||
|
{
|
||||||
|
if (dispose)
|
||||||
|
{
|
||||||
|
_trackDispose.DisposeCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TrackDispose
|
||||||
|
{
|
||||||
|
public int DisposeCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IServiceProvider CreateServiceProvider(Action<ServiceCollection> addServices = null)
|
||||||
|
{
|
||||||
|
var services = new ServiceCollection();
|
||||||
|
services.AddOptions()
|
||||||
|
.AddLogging()
|
||||||
|
.AddSignalR();
|
||||||
|
|
||||||
|
addServices?.Invoke(services);
|
||||||
|
|
||||||
|
return services.BuildServiceProvider();
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ConnectionWrapper : IDisposable
|
||||||
|
{
|
||||||
|
private PipelineFactory _factory;
|
||||||
|
private HttpConnection _httpConnection;
|
||||||
|
|
||||||
|
public Connection Connection;
|
||||||
|
public HttpConnection HttpConnection => (HttpConnection)Connection.Channel;
|
||||||
|
|
||||||
|
public ConnectionWrapper(string format = "json")
|
||||||
|
{
|
||||||
|
_factory = new PipelineFactory();
|
||||||
|
_httpConnection = new HttpConnection(_factory);
|
||||||
|
|
||||||
|
var lifetime = new ApplicationLifetime(new Logger<ApplicationLifetime>(new LoggerFactory()), Enumerable.Empty<IApplicationLifetimeEvents>());
|
||||||
|
var connectionManager = new ConnectionManager(lifetime);
|
||||||
|
|
||||||
|
Connection = connectionManager.AddNewConnection(_httpConnection).Connection;
|
||||||
|
Connection.Metadata["formatType"] = format;
|
||||||
|
Connection.User = new ClaimsPrincipal(new ClaimsIdentity());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Connection.Channel.Dispose();
|
||||||
|
_httpConnection.Dispose();
|
||||||
|
_factory.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<PropertyGroup>
|
||||||
|
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
|
||||||
|
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<ProjectGuid>1ce2b3be-056c-41e3-a5f5-6a1ef1d288ba</ProjectGuid>
|
||||||
|
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath>
|
||||||
|
<OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<SchemaVersion>2.0</SchemaVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||||
|
</Project>
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
// General Information about an assembly is controlled through the following
|
||||||
|
// set of attributes. Change these attribute values to modify the information
|
||||||
|
// associated with an assembly.
|
||||||
|
[assembly: AssemblyConfiguration("")]
|
||||||
|
[assembly: AssemblyCompany("")]
|
||||||
|
[assembly: AssemblyProduct("Microsoft.AspNetCore.SignalR.Tests")]
|
||||||
|
[assembly: AssemblyTrademark("")]
|
||||||
|
|
||||||
|
// Setting ComVisible to false makes the types in this assembly not visible
|
||||||
|
// to COM components. If you need to access a type in this assembly from
|
||||||
|
// COM, set the ComVisible attribute to true on that type.
|
||||||
|
[assembly: ComVisible(false)]
|
||||||
|
|
||||||
|
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||||
|
[assembly: Guid("1ce2b3be-056c-41e3-a5f5-6a1ef1d288ba")]
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
{
|
||||||
|
"buildOptions": {
|
||||||
|
"warningsAsErrors": true
|
||||||
|
},
|
||||||
|
|
||||||
|
"dependencies": {
|
||||||
|
"dotnet-test-xunit": "2.2.0-*",
|
||||||
|
"Microsoft.AspNetCore.Hosting": "1.2.0-*",
|
||||||
|
"Microsoft.AspNetCore.Sockets": {
|
||||||
|
"target": "project"
|
||||||
|
},
|
||||||
|
"Microsoft.AspNetCore.SignalR": {
|
||||||
|
"target": "project"
|
||||||
|
},
|
||||||
|
"Microsoft.Extensions.DependencyInjection": "1.2.0-*",
|
||||||
|
"Microsoft.Extensions.Logging": "1.2.0-*",
|
||||||
|
"xunit": "2.2.0-*"
|
||||||
|
},
|
||||||
|
"frameworks": {
|
||||||
|
"netcoreapp1.1": {
|
||||||
|
"dependencies": {
|
||||||
|
"Microsoft.NETCore.App": {
|
||||||
|
"version": "1.1.0-*",
|
||||||
|
"type": "platform"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"net451": { }
|
||||||
|
},
|
||||||
|
"testRunner": "xunit"
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue