aspnetcore icon indicating copy to clipboard operation
aspnetcore copied to clipboard

Allow running two IServer implementations side by side

Open Misiu opened this issue 1 year ago • 4 comments

Is there an existing issue for this?

  • [X] I have searched the existing issues

Is your feature request related to a problem? Please describe the problem.

I need to create an API that will allow two types of communication, a standard way using HTTP requests and a second using AMQP messages. I've implemented a custom IServer and I was able to plug it into the default ASP.NET Core Web API (.NET8) project using: builder.Services.AddSingleton<IServer, RabbitMqServer>(); but this disables the default communication via HTTP.

I've tried creating a composite server using https://github.com/stop-cran/AspNetCoreExtras.Solace.Server as a reference,

public class CompositeServer(RabbitMqServer rabbitMqServer, KestrelServer kestrelServer) : IServer
{
    public IFeatureCollection Features => kestrelServer.Features;

    public async Task StartAsync<TContext>(IHttpApplication<TContext> application, CancellationToken cancellationToken) where TContext : notnull
    {
        await rabbitMqServer.StartAsync(application, cancellationToken);
        await kestrelServer.StartAsync(application, cancellationToken);
    }

    public async Task StopAsync(CancellationToken cancellationToken)
    {
        await rabbitMqServer.StopAsync(cancellationToken);
        await kestrelServer.StopAsync(cancellationToken);
    }

    public void Dispose()
    {
        rabbitMqServer.Dispose();
        kestrelServer.Dispose();
    }
}

But when I try to start project from VS I get this errors:

System.IO.IOException
  HResult=0x80131620
  Message=Failed to bind to address http://localhost:5016.
  Source=Microsoft.AspNetCore.Server.Kestrel.Core
  StackTrace:
   at Microsoft.AspNetCore.Server.Kestrel.Core.LocalhostListenOptions.<BindAsync>d__2.MoveNext() in /_/src/Servers/Kestrel/Core/src/LocalhostListenOptions.cs:line 63
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.AddressBinder.AddressesStrategy.<BindAsync>d__3.MoveNext() in /_/src/Servers/Kestrel/Core/src/Internal/AddressBinder.cs:line 247
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.AddressBinder.<BindAsync>d__0.MoveNext() in /_/src/Servers/Kestrel/Core/src/Internal/AddressBinder.cs:line 32
   at Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServerImpl.<BindAsync>d__31.MoveNext() in /_/src/Servers/Kestrel/Core/src/Internal/KestrelServerImpl.cs:line 309
   at Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServerImpl.<StartAsync>d__28`1.MoveNext() in /_/src/Servers/Kestrel/Core/src/Internal/KestrelServerImpl.cs:line 225
   at Tunnels.CompositeServer.<StartAsync>d__5`1.MoveNext() in C:\Users\tj\source\repos\Tunnels\Tunnels\CompositeServer.cs:line 15
   at Microsoft.AspNetCore.Hosting.GenericWebHostService.<StartAsync>d__40.MoveNext() in /_/src/Hosting/Hosting/src/GenericHost/GenericWebHostService.cs:line 161
   at Microsoft.Extensions.Hosting.Internal.Host.<<StartAsync>b__15_1>d.MoveNext() in /_/src/libraries/Microsoft.Extensions.Hosting/src/Internal/Host.cs:line 136
   at Microsoft.Extensions.Hosting.Internal.Host.<ForeachService>d__18`1.MoveNext() in /_/src/libraries/Microsoft.Extensions.Hosting/src/Internal/Host.cs:line 390
   at Microsoft.Extensions.Hosting.Internal.Host.<StartAsync>d__15.MoveNext() in /_/src/libraries/Microsoft.Extensions.Hosting/src/Internal/Host.cs:line 145
   at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.<RunAsync>d__4.MoveNext() in /_/src/libraries/Microsoft.Extensions.Hosting.Abstractions/src/HostingAbstractionsHostExtensions.cs:line 67
   at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.<RunAsync>d__4.MoveNext() in /_/src/libraries/Microsoft.Extensions.Hosting.Abstractions/src/HostingAbstractionsHostExtensions.cs:line 79
   at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.Run(IHost host) in /_/src/libraries/Microsoft.Extensions.Hosting.Abstractions/src/HostingAbstractionsHostExtensions.cs:line 53
   at Tunnels.Program.Main(String[] args) in C:\Users\tj\source\repos\Tunnels\Tunnels\Program.cs:line 44

  This exception was originally thrown at this call stack:
    Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure.TransportManager.BindAsync(System.Net.EndPoint, Microsoft.AspNetCore.Connections.ConnectionDelegate, Microsoft.AspNetCore.Server.Kestrel.Core.Internal.EndpointConfig, System.Threading.CancellationToken) in TransportManager.cs
    Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServerImpl.StartAsync.__OnBind|0(Microsoft.AspNetCore.Server.Kestrel.Core.ListenOptions, System.Threading.CancellationToken) in KestrelServerImpl.cs
    Microsoft.AspNetCore.Server.Kestrel.Core.Internal.AddressBinder.BindEndpointAsync(Microsoft.AspNetCore.Server.Kestrel.Core.ListenOptions, Microsoft.AspNetCore.Server.Kestrel.Core.Internal.AddressBindContext, System.Threading.CancellationToken) in AddressBinder.cs
    Microsoft.AspNetCore.Server.Kestrel.Core.LocalhostListenOptions.BindAsync(Microsoft.AspNetCore.Server.Kestrel.Core.Internal.AddressBindContext, System.Threading.CancellationToken) in LocalhostListenOptions.cs

Inner Exception 1:
AggregateException: One or more errors occurred. (No registered IConnectionListenerFactory supports endpoint IPEndPoint: 127.0.0.1:5016) (No registered IConnectionListenerFactory supports endpoint IPEndPoint: [::1]:5016)

Inner Exception 2:
InvalidOperationException: No registered IConnectionListenerFactory supports endpoint IPEndPoint: 127.0.0.1:5016

I've tried configuring Kestrel via

builder.WebHost.ConfigureKestrel(options =>
{
    options.ListenAnyIP(5000); // Change to a different port if needed
});

but this gives me this error:

System.InvalidOperationException
  HResult=0x80131509
  Message=No registered IConnectionListenerFactory supports endpoint IPEndPoint: 0.0.0.0:5000
  Source=Microsoft.AspNetCore.Server.Kestrel.Core
  StackTrace:
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure.TransportManager.<BindAsync>d__10.MoveNext() in /_/src/Servers/Kestrel/Core/src/Internal/Infrastructure/TransportManager.cs:line 62
   at Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServerImpl.<>c__DisplayClass28_0`1.<<StartAsync>g__OnBind|0>d.MoveNext() in /_/src/Servers/Kestrel/Core/src/Internal/KestrelServerImpl.cs:line 199
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.AddressBinder.<BindEndpointAsync>d__3.MoveNext() in /_/src/Servers/Kestrel/Core/src/Internal/AddressBinder.cs:line 90
   at Microsoft.AspNetCore.Server.Kestrel.Core.ListenOptions.<BindAsync>d__61.MoveNext() in /_/src/Servers/Kestrel/Core/src/ListenOptions.cs:line 224
   at Microsoft.AspNetCore.Server.Kestrel.Core.AnyIPListenOptions.<BindAsync>d__1.MoveNext() in /_/src/Servers/Kestrel/Core/src/AnyIPListenOptions.cs:line 42
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.AddressBinder.EndpointsStrategy.<BindAsync>d__2.MoveNext() in /_/src/Servers/Kestrel/Core/src/Internal/AddressBinder.cs:line 219
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.AddressBinder.<BindAsync>d__0.MoveNext() in /_/src/Servers/Kestrel/Core/src/Internal/AddressBinder.cs:line 32
   at Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServerImpl.<BindAsync>d__31.MoveNext() in /_/src/Servers/Kestrel/Core/src/Internal/KestrelServerImpl.cs:line 309
   at Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServerImpl.<StartAsync>d__28`1.MoveNext() in /_/src/Servers/Kestrel/Core/src/Internal/KestrelServerImpl.cs:line 225
   at Tunnels.CompositeServer.<StartAsync>d__5`1.MoveNext() in C:\Users\tj\source\repos\Tunnels\Tunnels\CompositeServer.cs:line 15
   at Microsoft.AspNetCore.Hosting.GenericWebHostService.<StartAsync>d__40.MoveNext() in /_/src/Hosting/Hosting/src/GenericHost/GenericWebHostService.cs:line 161
   at Microsoft.Extensions.Hosting.Internal.Host.<<StartAsync>b__15_1>d.MoveNext() in /_/src/libraries/Microsoft.Extensions.Hosting/src/Internal/Host.cs:line 136
   at Microsoft.Extensions.Hosting.Internal.Host.<ForeachService>d__18`1.MoveNext() in /_/src/libraries/Microsoft.Extensions.Hosting/src/Internal/Host.cs:line 390
   at Microsoft.Extensions.Hosting.Internal.Host.<StartAsync>d__15.MoveNext() in /_/src/libraries/Microsoft.Extensions.Hosting/src/Internal/Host.cs:line 145
   at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.<RunAsync>d__4.MoveNext() in /_/src/libraries/Microsoft.Extensions.Hosting.Abstractions/src/HostingAbstractionsHostExtensions.cs:line 67
   at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.<RunAsync>d__4.MoveNext() in /_/src/libraries/Microsoft.Extensions.Hosting.Abstractions/src/HostingAbstractionsHostExtensions.cs:line 79
   at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.Run(IHost host) in /_/src/libraries/Microsoft.Extensions.Hosting.Abstractions/src/HostingAbstractionsHostExtensions.cs:line 53
   at Tunnels.Program.Main(String[] args) in C:\Users\tj\source\repos\Tunnels\Tunnels\Program.cs:line 49

Describe the solution you'd like

Ideally, we should be able to easily add additional IServer implementations to projects, so they can work side by side.

Additional context

I want to reuse as many features as I can, my idea is to configure authorization, cache, rate limiting, etc in my app and allow invoking requests via HTTP and AMQP.

If there is an easier way to "dispatch" a request from AMQP message and catch the response please let me know.

Misiu avatar Oct 08 '24 11:10 Misiu