Search code examples
c#asp.net.nethttpskestrel

UseHttps() throws System.ArgumentNullException:Value cannot be null. (Parameter 'provider') when attempting to enable QUIC/Http3


Calling the constructor of below NanoKestrel class throws

ERROR System.ArgumentNullException: Value cannot be null. (Parameter 'provider') at System.ThrowHelper.Throw(String paramName) at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider) at Microsoft.AspNetCore.Hosting.ListenOptionsHttpsExtensions.UseHttps(ListenOptions listenOptions, HttpsConnectionAdapterOptions httpsOptions) at NanoKestrel.<>c__DisplayClass16_0.<.ctor>b__2(ListenOptions listenOptions)

public class NanoKestrel
    {
        public IServer Server { get; set; }
        private HostingApplication _application { get; set; }
        private X509Certificate2 _serverCertificate { get; set; }

        public NanoKestrel(IPEndPoint endPoint, X509Certificate2 certificate = null)
        {
            _serverCertificate = certificate;
            var services = new ServiceCollection();
            services.AddLogging(b =>
            {
                b.AddFilter("Microsoft.AspNetCore.Server.Kestrel", LogLevel.Warning);
            });

            services.Configure<KestrelServerOptions>(options =>
            {
                options.Listen(endPoint, listenOptions =>
                {
                    listenOptions.Protocols = HttpProtocols.Http1AndHttp2AndHttp3;
                    if (_serverCertificate != null) listenOptions.UseHttps(new HttpsConnectionAdapterOptions() { ServerCertificate = _serverCertificate });           // <--exception thrown at this line in stacktrace
                });

            });

            services.AddSingleton<IServer, KestrelServer>();


            services.AddSingleton<IConnectionListenerFactory, SocketTransportFactory>();
            services.AddSingleton<IHostApplicationLifetime, ApplicationLifetime>();
            services.AddTransient<IHttpContextFactory, DefaultHttpContextFactory>();


            services.AddTransient<HostingApplication>();

            var serviceProvider = services.BuildServiceProvider();
            Server = serviceProvider.GetRequiredService<IServer>();
            _application = serviceProvider.GetRequiredService<HostingApplication>();
        }

        public async void StartAsync()
        {
            await Server.StartAsync(_application, default).ConfigureAwait(false);
        }
}

i tried to serve a certificate to the listenOptions.UseHttps(); but throws the same exception.

I intend to enable QUIC/Http3 on Kestrel, following guidance from https://www.meziantou.net/using-http-3-quic-in-dotnet.htm

Package References:

Microsoft.Extensions.Features 7.0.2

FrameworkReference:

Include="Microsoft.AspNetCore.App"


Solution

  • I solved the problem myself by adding a line marked as below:

     services.Configure<KestrelServerOptions>(options =>
                {
                    options.ApplicationServices ??= _serviceProvier;  //<=
        //this line above is needed to solve the issue, otherwise Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServerOptions.EnsureDefaultCert() throws the "Value cannot be null. (Parameter 'provider') " exception.
                    options.Listen(endPoint, listenOptions =>
                    {
                        listenOptions.Protocols = HttpProtocols.Http1AndHttp2AndHttp3;
                        if (_serverCertificate != null) listenOptions.UseHttps();
                    });
                });