RickStrahl / Westwind.AspnetCore.LiveReload

ASP.NET Core Live Reload Middleware that monitors file changes in your project and automatically reloads the browser's active page
Other
473 stars 42 forks source link

HTTP2 issue #4

Closed dotnetshadow closed 5 years ago

dotnetshadow commented 5 years ago

Firstly what a great library, keep up the good work!

I found an issue when trying to specify http support in kestrel. With your reload library enabled, an error is thrown and the the application keeps reloading itself

fail: Microsoft.AspNetCore.Server.Kestrel[0]
      HTTP/2 over TLS was not negotiated on an HTTP/2-only endpoint.

The error is caused by using the following configuration in program.cs

 public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
    WebHost.CreateDefaultBuilder(args)
        .ConfigureKestrel((context, options) =>
        {
            options.AddServerHeader = false; // removes the server header
            options.ConfigureHttpsDefaults(_ => _.SslProtocols = SslProtocols.Tls12);
            options.ConfigureEndpointDefaults(c => c.Protocols = HttpProtocols.Http2);
        })
        .UseStartup<Startup>();

I enabled this in your sample application and got the same result

RickStrahl commented 5 years ago

How do you get this to work? I get errors just trying to launch the server with HTTPS2.

image

Is there anything else that needs to be set?

If I remove the Http2 endpoint then it works with https/tls12. The failure is prior to startup before anything in startup is fired.

dotnetshadow commented 5 years ago

Hi Rick,

I just stepped out of the office, i will have check what else needs to be added to get the test case working.

If you disable livereload through the config you will see that it should work. As soon as you enable reliad https errors appear

Basically in my site i use https2 for kestrel. So my views (documents) will have the h2 protocol when viewing in chrome. https://dotnetthoughts.net/enable-http2-on-kestrel/

RickStrahl commented 5 years ago

No worries - just asking to see if I can duplicate, but not having any luck since http2 is not even starting the server (not firing even into Startup at all.

I'm also not sure why the LiveReload would interfere at the protocol level since it only looks at the body content. I'd just like to be able to duplicate so I can try to see what might be happening, but can't get http2 to work even with.

I saw the post but I think that shouldn't be necessary if the site is working with TLS1.2 which means the cert is working. I'm using the same code you showed - you're not doing the extra bit of registering the certificate in your setup are you?

dotnetshadow commented 5 years ago

I'll have to check what's different.i writing be interested to know if you home/index comes up as http1.1 or http2 if you don't specify the configuration like I did

dotnetshadow commented 5 years ago

This is how I got the https2 to be working but it will cause an error

Program.cs

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Options;

namespace Westwind.AspnetCore.LiveReload.Web
{
    public class Program
    {
        public static void Main(string[] args)
        {
            CreateWebHostBuilder(args).Build().Run();
        }

        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .ConfigureKestrel((context, options) =>
                {
                    options.AddServerHeader = false; // removes the server header
                    options.ConfigureHttpsDefaults(_ => _.SslProtocols = SslProtocols.Tls12);
                    options.ConfigureEndpointDefaults(c => c.Protocols = HttpProtocols.Http2);
                })
                .UseStartup<Startup>();
    }
}

image

image

dotnetshadow commented 5 years ago

Quick demo version (hopefully it runs on your end) Westwind.AspnetCore.LiveReload-masterHttps2.zip

I'm using .net core 2.2, I removed the .net core 3.0 example. Using visual studio 2019 sdk for .net core 2.2

I run it, using https://localhost:5001 in chrome Setting "LiveReloadEnabled": true, ERROR Setting "LiveReloadEnabled": false, NO ERROR

RickStrahl commented 5 years ago

Hmmm... I get the same error as you do with the HTTP2 only above - during startup. That's showing that it's not binding and from what I understand you have to useHttp1andHttp2 to get the negotation to work. However, in my case even that doesn't work - with LiveReload enabled or not. So there's something else happening on my end, but I don't know what. Tried your project and same issue it won't come with Http2 enabled live reload or not.

RickStrahl commented 5 years ago

Ok managed to get this to work. I guess this is a known issue if you have Windows 1903 update and a certificate that predates it.

To fix you have to recreate the dev certificate:

dotnet dev-certs https --clean
dotnet dev-certs https --trust

This fixes the certificate and now I can run with Http2 as well.

I also see the refresh issue - looks like the connection is closing - I think that might be a bug with Kestrel. Going to take a look.

RickStrahl commented 5 years ago

So it looks like WebSockets are not supported over http2 at this point.

image

So this approach won't work and you'd have to downgrade to http1 during development. Apparently there's no way to upgrade the http2 connection to a Websocket connection in the currently supported browser implementations.

dotnetshadow commented 5 years ago

Great work Rick, , that makes sense why the issue is happening. I learn something everyday, even the certificate thing was handy to know

I also had a slight problem when I was modifying a css, I use webpack and it generated the css etc, but the changes weren't refreshing. I managed to get it working eventually by fluking it. I did read your comment about this: Sometime you may have to refresh once to get the cache to reset for CSS changes to show, but subsequent refreshes should show immediately.

For some reason I had to directly load up the css file then subsequent changes were detected. Even though I have the tagehelper asp-append-version.

Like now that I know the issue I can work around it, just wonder if people might trip up on this?

RickStrahl commented 5 years ago

Actually I got this to work after all.

Try changing to this:

options.ConfigureEndpointDefaults(c => c.Protocols = HttpProtocols.Http1AndHttp2);

This is working for me now.

The page loads in Http2 and the socket request is handled on http1.

image

RickStrahl commented 5 years ago

I also added an explicit WebSocketHost property to the config you can explicitly specify a host URL for the socket to the be use:

config.WebSocketHost = "ws://localhost:5000";

So if you want to run in all Http2 mode you can point at separate URL (in the same site) that is not.

dotnetshadow commented 5 years ago

That's awesome I'll give both those a go. I learnt something about websockets :) Appreciate all your help