Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2.Http2ConnectionErrorException

I have the following exception

Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2.Http2ConnectionErrorException: HTTP/2 connection error (PROTOCOL_ERROR): Invalid HTTP/2 connection preface.

I will describe my conditions. I have very simple grpc .Net Core project and I want make HTTP endpoint.

Here is Startup.cs

public class Startup
{
    // This method gets called by the runtime. Use this method to add services to the container.
    // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc(options => options.EnableEndpointRouting = false);
        services.AddGrpc();

        services.AddHttpClient<IAnalyticApiAsker, AnalyticApiAsker>();

        // db context
        services.AddSingleton<IApplicationMongoContext, ApplicationMongoContext>();

        // repos
        services.AddTransient<IWorkspacesRepo, WorkspaceRepo>();
        services.AddTransient<IApplicationRepo, ApplicationRepo>();
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseRouting();

        app.UseEndpoints(endpoints =>
        {
            // Communication with gRPC endpoints must be made through a gRPC client.
            // To learn how to create a client, visit: https://go.microsoft.com/fwlink/?linkid=2086909
            endpoints.MapGrpcService<ApplicationsService>();
            endpoints.MapGrpcService<WorkspacesService>();
        });

        // I think I have to use this middleware for get http endpoints ability ?? Right? 
        app.UseMvc();
    }
}

And Program.cs

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
}

launchSettings.json

{
  "profiles": {
    "Dashboard": {
      "commandName": "Project",
      "launchBrowser": false,
      "applicationUrl": "http://*:50053",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Local"
      }
    }
  }
}

For the endpoint I have the following controller:

public class HealthController : Controller
{ 
    [Route("/healthcheck")]
    [HttpGet]
    public IActionResult Index()
    {
        return Ok(new
        {
            status = "ok",
            description = "works"
        });
    }
}

But when I request from a browser my application's URL http://localhost:50053/healthcheck I have this exception. it looks like Kestrel configured only for http2. If it's true, how to switch on HTTP handling?

Update

Ok, after some researching I have understood the following. It's impossible to switch on both protocol types handling: grpc (that works with HTTP 2) and ordinary http1 at the same time. Am I right?

I have modified my Startapp.cs to:

    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .ConfigureKestrel(options =>
            {
                options.ListenLocalhost(50053, listenOptions =>
                {
                    listenOptions.Protocols = HttpProtocols.Http1AndHttp2;
                });
            })
            .UseStartup<Startup>();

HttpProtocols.Http1AndHttp2 this property has variant for each HTTP type (Http1, Http, Http1AndHttp2). But it does not work for GRPC. I think it's happening because of whether to use http1 to GRPC or http2. And I don't know how to set up it.

So, listenOptions.Protocols = HttpProtocols.Http1 - works for web, listenOptions.Protocols = HttpProtocols.Http2 - works for GRPC and listenOptions.Protocols = HttpProtocols.Http1AndHttp2 - works for web.

Update 2

I'm not sure if it answers or not, but I have solved the task with the help of the following Program.cs modification:

    public static void Main(string[] args)
    {
        CreateWebHostBuilder(args).Build().Run();
    }

    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .ConfigureKestrel(options =>
            {
                options.ListenLocalhost(80, listenOptions =>
                {
                    listenOptions.Protocols = HttpProtocols.Http1;
                });

                options.ListenLocalhost(50053, listenOptions =>
                {
                    listenOptions.Protocols = HttpProtocols.Http2;
                });
            })
            .UseStartup<Startup>();
}

Now I can work with http1 and http2. But now I have a new problem, it works only on localhost.

like image 413
Aleksej_Shherbak Avatar asked Jul 02 '19 14:07

Aleksej_Shherbak


People also ask

Does Kestrel support HTTP2?

‡Kestrel has limited support for HTTP/2 on Windows Server 2012 R2 and Windows 8.1. Support is limited because the list of supported TLS cipher suites available on these operating systems is limited.

What is Microsoft Aspnetcore server Kestrel?

Kestrel is a cross-platform web server for ASP.NET Core. Kestrel is the web server that's included and enabled by default in ASP.NET Core project templates. Kestrel supports the following scenarios: HTTPS. HTTP/2 (except on macOS†)


1 Answers

Ok, I have solved it with the help of the following Program.cs modification:

public class Program
{
    public static void Main(string[] args)
    {
        CreateWebHostBuilder(args).Build().Run();
    }

    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .ConfigureKestrel(options =>
            {
                options.ListenAnyIP(80, listenOptions =>
                {
                    listenOptions.Protocols = HttpProtocols.Http1;
                });

                options.ListenAnyIP(50053, listenOptions =>
                {
                    listenOptions.Protocols = HttpProtocols.Http2;
                });
            })
            .UseStartup<Startup>();
}

Now I can work with GRPC and http1 in the same time, and connection allowed for any IP.

I hope it will useful for somebody who will add http1 to GRPC configured project.

like image 177
Aleksej_Shherbak Avatar answered Oct 19 '22 09:10

Aleksej_Shherbak