-
Notifications
You must be signed in to change notification settings - Fork 10.5k
Description
Is there an existing issue for this?
- I have searched the existing issues
Is your feature request related to a problem? Please describe the problem.
Kestrel supports being extended to support new transports. This is done by registering IConnectionListenerFactory or IMultiplexedConnectionListenerFactory in DI.
When starting up, for each factory type, Kestrel then gets all registered factories. It then uses the last one for any registered listeners. IConnectionListenerFactory is used for HTTP/1.1 and HTTP/2 endpoints, and IMultiplexedConnectionListenerFactory is used for HTTP/3.
The problem with this is it isn't easily possible to mix transports together. Someone might want to support TCP endpoints using options.ListenLocalhost(80) and a custom transport using options.Listen(new MyCustomEndPoint("address")). Both endpoints are sent to the last factory type.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddGrpc();
builder.Services.AddSingleton<IConnectionListenerFactory, NamedPipeTransportFactory>();
builder.WebHost.ConfigureKestrel(options =>
{
options.ListenLocalhost(80); // TCP!
options.Listen(new NamedPipeEndPoint("Pipe-1")); // Named pipes!
});
var app = builder.Build();Describe the solution you'd like
I think default interface implementation methods should be added to IConnectionListenerFactory and IMultiplexedConnectionListenerFactory which can be used to test if a factory supports binding a given endpoint.
public interface IConnectionListenerFactory
{
Task<IConnectionListener> BindAsync(EndPoint endpoint, CancellationToken cancellationToken)
+ public bool CanBind(EndPoint endpoint) => true;
}public interface IMultiplexedConnectionListenerFactory
{
Task<IMultiplexedConnectionListener> BindAsync(EndPoint endpoint, CancellationToken cancellationToken)
+ public bool CanBind(EndPoint endpoint) => true;
}Kestrel continues to get all registered instances of IConnectionListenerFactory and IMultiplexedConnectionListenerFactory from DI, but instead of using the last one registered, Kestrel now keeps all instances, and then when binding a new listener, Kestrel tests each factory with CanBind to see whether it supports binding a given endpoint, then falls back to the next listener.
The new CanBind default implementation returns true, which follows current behavior, and existing factories can override the CanBind method to only allow currently supported addresses. If no factories support an endpoint then Kestrel throws an error saying the endpoint isn't supported.
Additional context
IConnectionListenerFactory and IMultiplexedConnectionListenerFactory are in the Microsoft.AspNetCore.Connections.Abstractions project. It targets netstandard2.0 and .NET Framework. The new DIM would only be available in .NET 8+. Is there precedence for doing this?