parent
868b012cda
commit
9579a6fe17
|
|
@ -100,6 +100,10 @@ namespace Microsoft.AspNetCore.Connections
|
||||||
}
|
}
|
||||||
namespace Microsoft.AspNetCore.Connections.Features
|
namespace Microsoft.AspNetCore.Connections.Features
|
||||||
{
|
{
|
||||||
|
public partial interface IConnectionCompleteFeature
|
||||||
|
{
|
||||||
|
void OnCompleted(System.Func<object, System.Threading.Tasks.Task> callback, object state);
|
||||||
|
}
|
||||||
public partial interface IConnectionHeartbeatFeature
|
public partial interface IConnectionHeartbeatFeature
|
||||||
{
|
{
|
||||||
void OnHeartbeat(System.Action<object> action, object state);
|
void OnHeartbeat(System.Action<object> action, object state);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
// 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.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Connections.Features
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the completion action for a connection.
|
||||||
|
/// </summary>
|
||||||
|
public interface IConnectionCompleteFeature
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Registers a callback to be invoked after a connection has fully completed processing. This is
|
||||||
|
/// intended for resource cleanup.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="callback">The callback to invoke after the connection has completed processing.</param>
|
||||||
|
/// <param name="state">The state to pass into the callback.</param>
|
||||||
|
void OnCompleted(Func<object, Task> callback, object state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -82,6 +82,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
await connectionContext.CompleteAsync();
|
||||||
|
|
||||||
Log.ConnectionStop(connectionContext.ConnectionId);
|
Log.ConnectionStop(connectionContext.ConnectionId);
|
||||||
KestrelEventSource.Log.ConnectionStop(connectionContext);
|
KestrelEventSource.Log.ConnectionStop(connectionContext);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,11 @@ using System.IO.Pipelines;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Connections.Features;
|
||||||
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal;
|
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal;
|
||||||
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal;
|
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal;
|
||||||
using Microsoft.AspNetCore.Testing;
|
using Microsoft.AspNetCore.Testing;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
using Moq;
|
using Moq;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
|
|
@ -69,5 +71,50 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
mockPipeWriter.Verify(m => m.Complete(It.IsAny<Exception>()), Times.Once());
|
mockPipeWriter.Verify(m => m.Complete(It.IsAny<Exception>()), Times.Once());
|
||||||
mockPipeReader.Verify(m => m.Complete(It.IsAny<Exception>()), Times.Once());
|
mockPipeReader.Verify(m => m.Complete(It.IsAny<Exception>()), Times.Once());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task OnConnectionFiresOnCompleted()
|
||||||
|
{
|
||||||
|
var serviceContext = new TestServiceContext();
|
||||||
|
var dispatcher = new ConnectionDispatcher(serviceContext, _ => Task.CompletedTask);
|
||||||
|
|
||||||
|
var connection = new Mock<TransportConnection> { CallBase = true }.Object;
|
||||||
|
connection.ConnectionClosed = new CancellationToken(canceled: true);
|
||||||
|
var completeFeature = connection.Features.Get<IConnectionCompleteFeature>();
|
||||||
|
|
||||||
|
Assert.NotNull(completeFeature);
|
||||||
|
object stateObject = new object();
|
||||||
|
object callbackState = null;
|
||||||
|
completeFeature.OnCompleted(state => { callbackState = state; return Task.CompletedTask; }, stateObject);
|
||||||
|
|
||||||
|
await dispatcher.OnConnection(connection);
|
||||||
|
|
||||||
|
Assert.Equal(stateObject, callbackState);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task OnConnectionOnCompletedExceptionCaught()
|
||||||
|
{
|
||||||
|
var serviceContext = new TestServiceContext();
|
||||||
|
var dispatcher = new ConnectionDispatcher(serviceContext, _ => Task.CompletedTask);
|
||||||
|
|
||||||
|
var connection = new Mock<TransportConnection> { CallBase = true }.Object;
|
||||||
|
connection.ConnectionClosed = new CancellationToken(canceled: true);
|
||||||
|
var completeFeature = connection.Features.Get<IConnectionCompleteFeature>();
|
||||||
|
var mockLogger = new Mock<ILogger>();
|
||||||
|
connection.Logger = mockLogger.Object;
|
||||||
|
|
||||||
|
Assert.NotNull(completeFeature);
|
||||||
|
object stateObject = new object();
|
||||||
|
object callbackState = null;
|
||||||
|
completeFeature.OnCompleted(state => { callbackState = state; throw new InvalidTimeZoneException(); }, stateObject);
|
||||||
|
|
||||||
|
await dispatcher.OnConnection(connection);
|
||||||
|
|
||||||
|
Assert.Equal(stateObject, callbackState);
|
||||||
|
var log = mockLogger.Invocations.First();
|
||||||
|
Assert.Equal("An error occured running an IConnectionCompleteFeature.OnCompleted callback.", log.Arguments[2].ToString());
|
||||||
|
Assert.IsType<InvalidTimeZoneException>(log.Arguments[3]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,5 +6,6 @@
|
||||||
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.0'">
|
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.0'">
|
||||||
<Compile Include="Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.netcoreapp3.0.cs" />
|
<Compile Include="Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.netcoreapp3.0.cs" />
|
||||||
<Reference Include="Microsoft.AspNetCore.Connections.Abstractions" />
|
<Reference Include="Microsoft.AspNetCore.Connections.Abstractions" />
|
||||||
|
<Reference Include="Microsoft.Extensions.Logging.Abstractions" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal
|
||||||
ThreadPool = 1,
|
ThreadPool = 1,
|
||||||
Inline = 2,
|
Inline = 2,
|
||||||
}
|
}
|
||||||
public abstract partial class TransportConnection : Microsoft.AspNetCore.Connections.ConnectionContext, Microsoft.AspNetCore.Connections.Features.IConnectionHeartbeatFeature, Microsoft.AspNetCore.Connections.Features.IConnectionIdFeature, Microsoft.AspNetCore.Connections.Features.IConnectionItemsFeature, Microsoft.AspNetCore.Connections.Features.IConnectionLifetimeFeature, Microsoft.AspNetCore.Connections.Features.IConnectionLifetimeNotificationFeature, Microsoft.AspNetCore.Connections.Features.IConnectionTransportFeature, Microsoft.AspNetCore.Connections.Features.IMemoryPoolFeature, Microsoft.AspNetCore.Http.Features.IFeatureCollection, Microsoft.AspNetCore.Http.Features.IHttpConnectionFeature, Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal.IApplicationTransportFeature, Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal.ITransportSchedulerFeature, System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<System.Type, object>>, System.Collections.IEnumerable
|
public abstract partial class TransportConnection : Microsoft.AspNetCore.Connections.ConnectionContext, Microsoft.AspNetCore.Connections.Features.IConnectionCompleteFeature, Microsoft.AspNetCore.Connections.Features.IConnectionHeartbeatFeature, Microsoft.AspNetCore.Connections.Features.IConnectionIdFeature, Microsoft.AspNetCore.Connections.Features.IConnectionItemsFeature, Microsoft.AspNetCore.Connections.Features.IConnectionLifetimeFeature, Microsoft.AspNetCore.Connections.Features.IConnectionLifetimeNotificationFeature, Microsoft.AspNetCore.Connections.Features.IConnectionTransportFeature, Microsoft.AspNetCore.Connections.Features.IMemoryPoolFeature, Microsoft.AspNetCore.Http.Features.IFeatureCollection, Microsoft.AspNetCore.Http.Features.IHttpConnectionFeature, Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal.IApplicationTransportFeature, Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal.ITransportSchedulerFeature, System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<System.Type, object>>, System.Collections.IEnumerable
|
||||||
{
|
{
|
||||||
protected readonly System.Threading.CancellationTokenSource _connectionClosingCts;
|
protected readonly System.Threading.CancellationTokenSource _connectionClosingCts;
|
||||||
public TransportConnection() { }
|
public TransportConnection() { }
|
||||||
|
|
@ -73,6 +73,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal
|
||||||
public override System.Collections.Generic.IDictionary<object, object> Items { get { throw null; } set { } }
|
public override System.Collections.Generic.IDictionary<object, object> Items { get { throw null; } set { } }
|
||||||
public System.Net.IPAddress LocalAddress { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
public System.Net.IPAddress LocalAddress { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||||
public int LocalPort { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
public int LocalPort { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||||
|
protected internal virtual Microsoft.Extensions.Logging.ILogger Logger { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||||
public virtual System.Buffers.MemoryPool<byte> MemoryPool { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
|
public virtual System.Buffers.MemoryPool<byte> MemoryPool { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
|
||||||
System.Collections.Generic.IDictionary<object, object> Microsoft.AspNetCore.Connections.Features.IConnectionItemsFeature.Items { get { throw null; } set { } }
|
System.Collections.Generic.IDictionary<object, object> Microsoft.AspNetCore.Connections.Features.IConnectionItemsFeature.Items { get { throw null; } set { } }
|
||||||
System.Threading.CancellationToken Microsoft.AspNetCore.Connections.Features.IConnectionLifetimeFeature.ConnectionClosed { get { throw null; } set { } }
|
System.Threading.CancellationToken Microsoft.AspNetCore.Connections.Features.IConnectionLifetimeFeature.ConnectionClosed { get { throw null; } set { } }
|
||||||
|
|
@ -96,6 +97,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal
|
||||||
public int RemotePort { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
public int RemotePort { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||||
public override System.IO.Pipelines.IDuplexPipe Transport { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
public override System.IO.Pipelines.IDuplexPipe Transport { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||||
public override void Abort(Microsoft.AspNetCore.Connections.ConnectionAbortedException abortReason) { }
|
public override void Abort(Microsoft.AspNetCore.Connections.ConnectionAbortedException abortReason) { }
|
||||||
|
public System.Threading.Tasks.Task CompleteAsync() { throw null; }
|
||||||
|
void Microsoft.AspNetCore.Connections.Features.IConnectionCompleteFeature.OnCompleted(System.Func<object, System.Threading.Tasks.Task> callback, object state) { }
|
||||||
void Microsoft.AspNetCore.Connections.Features.IConnectionHeartbeatFeature.OnHeartbeat(System.Action<object> action, object state) { }
|
void Microsoft.AspNetCore.Connections.Features.IConnectionHeartbeatFeature.OnHeartbeat(System.Action<object> action, object state) { }
|
||||||
void Microsoft.AspNetCore.Connections.Features.IConnectionLifetimeFeature.Abort() { }
|
void Microsoft.AspNetCore.Connections.Features.IConnectionLifetimeFeature.Abort() { }
|
||||||
void Microsoft.AspNetCore.Connections.Features.IConnectionLifetimeNotificationFeature.RequestClose() { }
|
void Microsoft.AspNetCore.Connections.Features.IConnectionLifetimeNotificationFeature.RequestClose() { }
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,17 @@
|
||||||
// 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;
|
||||||
using System.Buffers;
|
using System.Buffers;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO.Pipelines;
|
using System.IO.Pipelines;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Connections;
|
using Microsoft.AspNetCore.Connections;
|
||||||
using Microsoft.AspNetCore.Connections.Features;
|
using Microsoft.AspNetCore.Connections.Features;
|
||||||
using Microsoft.AspNetCore.Http.Features;
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal
|
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal
|
||||||
{
|
{
|
||||||
|
|
@ -21,12 +24,16 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal
|
||||||
ITransportSchedulerFeature,
|
ITransportSchedulerFeature,
|
||||||
IConnectionLifetimeFeature,
|
IConnectionLifetimeFeature,
|
||||||
IConnectionHeartbeatFeature,
|
IConnectionHeartbeatFeature,
|
||||||
IConnectionLifetimeNotificationFeature
|
IConnectionLifetimeNotificationFeature,
|
||||||
|
IConnectionCompleteFeature
|
||||||
{
|
{
|
||||||
// NOTE: When feature interfaces are added to or removed from this TransportConnection class implementation,
|
// NOTE: When feature interfaces are added to or removed from this TransportConnection class implementation,
|
||||||
// then the list of `features` in the generated code project MUST also be updated.
|
// then the list of `features` in the generated code project MUST also be updated.
|
||||||
// See also: tools/CodeGenerator/TransportConnectionFeatureCollection.cs
|
// See also: tools/CodeGenerator/TransportConnectionFeatureCollection.cs
|
||||||
|
|
||||||
|
private Stack<KeyValuePair<Func<object, Task>, object>> _onCompleted;
|
||||||
|
private bool _completed;
|
||||||
|
|
||||||
string IHttpConnectionFeature.ConnectionId
|
string IHttpConnectionFeature.ConnectionId
|
||||||
{
|
{
|
||||||
get => ConnectionId;
|
get => ConnectionId;
|
||||||
|
|
@ -100,5 +107,82 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal
|
||||||
{
|
{
|
||||||
OnHeartbeat(action, state);
|
OnHeartbeat(action, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void IConnectionCompleteFeature.OnCompleted(Func<object, Task> callback, object state)
|
||||||
|
{
|
||||||
|
if (_completed)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("The connection is already complete.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_onCompleted == null)
|
||||||
|
{
|
||||||
|
_onCompleted = new Stack<KeyValuePair<Func<object, Task>, object>>();
|
||||||
|
}
|
||||||
|
_onCompleted.Push(new KeyValuePair<Func<object, Task>, object>(callback, state));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task CompleteAsync()
|
||||||
|
{
|
||||||
|
if (_completed)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("The connection is already complete.");
|
||||||
|
}
|
||||||
|
|
||||||
|
_completed = true;
|
||||||
|
var onCompleted = _onCompleted;
|
||||||
|
|
||||||
|
if (onCompleted == null || onCompleted.Count == 0)
|
||||||
|
{
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
return CompleteAsyncMayAwait(onCompleted);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task CompleteAsyncMayAwait(Stack<KeyValuePair<Func<object, Task>, object>> onCompleted)
|
||||||
|
{
|
||||||
|
while (onCompleted.TryPop(out var entry))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var task = entry.Key.Invoke(entry.Value);
|
||||||
|
if (!ReferenceEquals(task, Task.CompletedTask))
|
||||||
|
{
|
||||||
|
return CompleteAsyncAwaited(task, onCompleted);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger?.LogError(ex, "An error occured running an IConnectionCompleteFeature.OnCompleted callback.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task CompleteAsyncAwaited(Task currentTask, Stack<KeyValuePair<Func<object, Task>, object>> onCompleted)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await currentTask;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger?.LogError(ex, "An error occured running an IConnectionCompleteFeature.OnCompleted callback.");
|
||||||
|
}
|
||||||
|
|
||||||
|
while (onCompleted.TryPop(out var entry))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await entry.Key.Invoke(entry.Value);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger?.LogError(ex, "An error occured running an IConnectionCompleteFeature.OnCompleted callback.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal
|
||||||
private static readonly Type IConnectionLifetimeFeatureType = typeof(IConnectionLifetimeFeature);
|
private static readonly Type IConnectionLifetimeFeatureType = typeof(IConnectionLifetimeFeature);
|
||||||
private static readonly Type IConnectionHeartbeatFeatureType = typeof(IConnectionHeartbeatFeature);
|
private static readonly Type IConnectionHeartbeatFeatureType = typeof(IConnectionHeartbeatFeature);
|
||||||
private static readonly Type IConnectionLifetimeNotificationFeatureType = typeof(IConnectionLifetimeNotificationFeature);
|
private static readonly Type IConnectionLifetimeNotificationFeatureType = typeof(IConnectionLifetimeNotificationFeature);
|
||||||
|
private static readonly Type IConnectionCompleteFeatureType = typeof(IConnectionCompleteFeature);
|
||||||
|
|
||||||
private object _currentIHttpConnectionFeature;
|
private object _currentIHttpConnectionFeature;
|
||||||
private object _currentIConnectionIdFeature;
|
private object _currentIConnectionIdFeature;
|
||||||
|
|
@ -33,6 +34,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal
|
||||||
private object _currentIConnectionLifetimeFeature;
|
private object _currentIConnectionLifetimeFeature;
|
||||||
private object _currentIConnectionHeartbeatFeature;
|
private object _currentIConnectionHeartbeatFeature;
|
||||||
private object _currentIConnectionLifetimeNotificationFeature;
|
private object _currentIConnectionLifetimeNotificationFeature;
|
||||||
|
private object _currentIConnectionCompleteFeature;
|
||||||
|
|
||||||
private int _featureRevision;
|
private int _featureRevision;
|
||||||
|
|
||||||
|
|
@ -50,6 +52,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal
|
||||||
_currentIConnectionLifetimeFeature = this;
|
_currentIConnectionLifetimeFeature = this;
|
||||||
_currentIConnectionHeartbeatFeature = this;
|
_currentIConnectionHeartbeatFeature = this;
|
||||||
_currentIConnectionLifetimeNotificationFeature = this;
|
_currentIConnectionLifetimeNotificationFeature = this;
|
||||||
|
_currentIConnectionCompleteFeature = this;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -145,6 +148,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal
|
||||||
{
|
{
|
||||||
feature = _currentIConnectionLifetimeNotificationFeature;
|
feature = _currentIConnectionLifetimeNotificationFeature;
|
||||||
}
|
}
|
||||||
|
else if (key == IConnectionCompleteFeatureType)
|
||||||
|
{
|
||||||
|
feature = _currentIConnectionCompleteFeature;
|
||||||
|
}
|
||||||
else if (MaybeExtra != null)
|
else if (MaybeExtra != null)
|
||||||
{
|
{
|
||||||
feature = ExtraFeatureGet(key);
|
feature = ExtraFeatureGet(key);
|
||||||
|
|
@ -197,6 +204,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal
|
||||||
{
|
{
|
||||||
_currentIConnectionLifetimeNotificationFeature = value;
|
_currentIConnectionLifetimeNotificationFeature = value;
|
||||||
}
|
}
|
||||||
|
else if (key == IConnectionCompleteFeatureType)
|
||||||
|
{
|
||||||
|
_currentIConnectionCompleteFeature = value;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ExtraFeatureSet(key, value);
|
ExtraFeatureSet(key, value);
|
||||||
|
|
@ -247,6 +258,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal
|
||||||
{
|
{
|
||||||
feature = (TFeature)_currentIConnectionLifetimeNotificationFeature;
|
feature = (TFeature)_currentIConnectionLifetimeNotificationFeature;
|
||||||
}
|
}
|
||||||
|
else if (typeof(TFeature) == typeof(IConnectionCompleteFeature))
|
||||||
|
{
|
||||||
|
feature = (TFeature)_currentIConnectionCompleteFeature;
|
||||||
|
}
|
||||||
else if (MaybeExtra != null)
|
else if (MaybeExtra != null)
|
||||||
{
|
{
|
||||||
feature = (TFeature)(ExtraFeatureGet(typeof(TFeature)));
|
feature = (TFeature)(ExtraFeatureGet(typeof(TFeature)));
|
||||||
|
|
@ -298,6 +313,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal
|
||||||
{
|
{
|
||||||
_currentIConnectionLifetimeNotificationFeature = feature;
|
_currentIConnectionLifetimeNotificationFeature = feature;
|
||||||
}
|
}
|
||||||
|
else if (typeof(TFeature) == typeof(IConnectionCompleteFeature))
|
||||||
|
{
|
||||||
|
_currentIConnectionCompleteFeature = feature;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ExtraFeatureSet(typeof(TFeature), feature);
|
ExtraFeatureSet(typeof(TFeature), feature);
|
||||||
|
|
@ -346,6 +365,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal
|
||||||
{
|
{
|
||||||
yield return new KeyValuePair<Type, object>(IConnectionLifetimeNotificationFeatureType, _currentIConnectionLifetimeNotificationFeature);
|
yield return new KeyValuePair<Type, object>(IConnectionLifetimeNotificationFeatureType, _currentIConnectionLifetimeNotificationFeature);
|
||||||
}
|
}
|
||||||
|
if (_currentIConnectionCompleteFeature != null)
|
||||||
|
{
|
||||||
|
yield return new KeyValuePair<Type, object>(IConnectionCompleteFeatureType, _currentIConnectionCompleteFeature);
|
||||||
|
}
|
||||||
|
|
||||||
if (MaybeExtra != null)
|
if (MaybeExtra != null)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// 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;
|
using System;
|
||||||
|
|
@ -9,6 +9,7 @@ using System.Net;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using Microsoft.AspNetCore.Connections;
|
using Microsoft.AspNetCore.Connections;
|
||||||
using Microsoft.AspNetCore.Http.Features;
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal
|
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal
|
||||||
{
|
{
|
||||||
|
|
@ -35,6 +36,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal
|
||||||
|
|
||||||
public override IFeatureCollection Features => this;
|
public override IFeatureCollection Features => this;
|
||||||
|
|
||||||
|
protected internal virtual ILogger Logger { get; set; }
|
||||||
|
|
||||||
public virtual MemoryPool<byte> MemoryPool { get; }
|
public virtual MemoryPool<byte> MemoryPool { get; }
|
||||||
public virtual PipeScheduler InputWriterScheduler { get; }
|
public virtual PipeScheduler InputWriterScheduler { get; }
|
||||||
public virtual PipeScheduler OutputReaderScheduler { get; }
|
public virtual PipeScheduler OutputReaderScheduler { get; }
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="Microsoft.AspNetCore.Connections.Abstractions" />
|
<Reference Include="Microsoft.AspNetCore.Connections.Abstractions" />
|
||||||
|
<Reference Include="Microsoft.Extensions.Logging.Abstractions" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal
|
||||||
LocalPort = localEndPoint?.Port ?? 0;
|
LocalPort = localEndPoint?.Port ?? 0;
|
||||||
|
|
||||||
ConnectionClosed = _connectionClosedTokenSource.Token;
|
ConnectionClosed = _connectionClosedTokenSource.Token;
|
||||||
|
Logger = log;
|
||||||
Log = log;
|
Log = log;
|
||||||
Thread = thread;
|
Thread = thread;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal
|
||||||
_socket = socket;
|
_socket = socket;
|
||||||
MemoryPool = memoryPool;
|
MemoryPool = memoryPool;
|
||||||
_scheduler = scheduler;
|
_scheduler = scheduler;
|
||||||
|
Logger = trace;
|
||||||
_trace = trace;
|
_trace = trace;
|
||||||
|
|
||||||
var localEndPoint = (IPEndPoint)_socket.LocalEndPoint;
|
var localEndPoint = (IPEndPoint)_socket.LocalEndPoint;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// 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.
|
||||||
|
|
||||||
namespace CodeGenerator
|
namespace CodeGenerator
|
||||||
|
|
@ -20,7 +20,8 @@ namespace CodeGenerator
|
||||||
"ITransportSchedulerFeature",
|
"ITransportSchedulerFeature",
|
||||||
"IConnectionLifetimeFeature",
|
"IConnectionLifetimeFeature",
|
||||||
"IConnectionHeartbeatFeature",
|
"IConnectionHeartbeatFeature",
|
||||||
"IConnectionLifetimeNotificationFeature"
|
"IConnectionLifetimeNotificationFeature",
|
||||||
|
"IConnectionCompleteFeature"
|
||||||
};
|
};
|
||||||
|
|
||||||
var usings = $@"
|
var usings = $@"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue