简体   繁体   English

.NET Core 3.1 IHostBuilder Apache 使用 Kestrel Program.cs 设置托管

[英].NET Core 3.1 IHostBuilder Apache Hosting With Kestrel Program.cs Setup

I have a web application running on CentOS 7 with an Apache server used as a proxy for Kestrel.我有一个 web 应用程序在 CentOS 7 上运行,Apache 服务器用作 Kestrel 的代理。 In my Program.cs file I'm using the below, which seems to work fine:在我的 Program.cs 文件中,我正在使用以下内容,这似乎工作正常:

    public static void Main(string[] args)
    {
        var config = new ConfigurationBuilder()
            .SetBasePath(Directory.GetCurrentDirectory())
            .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
            .Build();

        var host = new WebHostBuilder()
            .UseKestrel()
            .UseConfiguration(config)
            .UseContentRoot(Directory.GetCurrentDirectory())
            .UseStartup<Startup>()
            .UseUrls("http://localhost:5555")
            .Build();

        host.Run();
    }

But it looks like things with .NET Core have been updated recently, and I'm trying to use the IHostBuilder in the same way as below, which seems to work fine locally, but on the production server I'm getting the error "Proxy Error 502: The proxy server received an invalid response from an upstream server".但看起来 .NET Core 的东西最近已经更新,我正在尝试以与下面相同的方式使用 IHostBuilder,这似乎在本地工作正常,但在生产服务器上我收到错误“代理错误502:代理服务器收到上游服务器的无效响应”。

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

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)            
            .ConfigureWebHostDefaults(webBuilder =>
            {                    
                webBuilder.UseKestrel();
                webBuilder.UseContentRoot(Directory.GetCurrentDirectory());
                webBuilder.UseConfiguration(new ConfigurationBuilder()
                    .SetBasePath(Directory.GetCurrentDirectory())
                    .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
                    .AddCommandLine(args).Build());
                webBuilder.UseUrls("https://localhost:5555");
                webBuilder.UseStartup<Startup>();
            });

I'm not sure if this has anything to do with the configuration of the domain on my server - which again works fine using the first example above - or if there's something else I need to do in either the Program.cs or Startup.cs that would fix this problem using IHostBuilder.我不确定这是否与我的服务器上的域配置有关 - 使用上面的第一个示例再次正常工作 - 或者我需要在 Program.cs 或 Startup.cs 中做其他事情这将使用 IHostBuilder 解决此问题。

In the meantime I'm going to keep using what I have since it's working fine that way.与此同时,我将继续使用我拥有的东西,因为它工作得很好。

Thanks in advance to anyone who can help shed some light on this.提前感谢任何可以帮助阐明这一点的人。 And please let me know if there's any other information I can provide to help.如果有任何其他信息可以提供帮助,请告诉我。

It may be the localhost binding or the SSL security that is causing the issue.可能是 localhost 绑定或 SSL 安全导致问题。
Make sure that the HTTPS cert you are using in your project can be trusted by the proxy, or disable checking in apache.确保您在项目中使用的 HTTPS 证书可以被代理信任,或者禁用 apache 中的检查。

From a.Net point of view, try adding the following to your project从 a.Net 的角度来看,尝试将以下内容添加到您的项目中

public class ConfigHelper
{
    /// <summary>
    /// This method is used in the service startup to read hosting configuration options from the applications settings
    /// The following section can be included in your appsettings.json file to specify the binding, ports and certificate information.
    /// The certificate should be self-signed in .pfx format
    /// 
    ///   "Hosting": {
    ///       "HTTPBinding": "DISABLED",
    ///       "HTTPPort": 0,
    ///       "HTTPSBinding": "ANY",
    ///       "HTTPSPort": 5555,
    ///       "SSLCert": "PathToCert"
    ///       }
    /// </summary>
    /// <param name="configuration">The configuration option loaded from a local config file</param>
    /// <param name="options">The KestrelServerOptions from WebHost.CreateDefaultBuilder(args).UseKestrel(options => ConfigHelper.SetupHostingOptions(configuration, options);)</param>
    public static void SetupHostingOptions(IConfigurationRoot configuration, KestrelServerOptions options)
    {
        IPAddress httpBinding = ConfigHelper.GetAddressFromSetting(configuration.GetValue<string>("Hosting:HTTPBinding"));
        IPAddress httpsBinding = ConfigHelper.GetAddressFromSetting(configuration.GetValue<string>("Hosting:HTTPSBinding"));
        if (httpBinding != null && httpBinding != IPAddress.None)
        {
            if (configuration.GetValue<int?>("Hosting:HTTPPort") != null)
                options.Listen(httpBinding, configuration.GetValue<int>("Hosting:HTTPPort"));
        }
        if (httpsBinding != null && httpsBinding != IPAddress.None)
        {
            int httpsPort = configuration.GetValue<int?>("Hosting:HTTPSPort") ?? 443;
            string sslCert = configuration.GetValue<string>("Hosting:SSLCert");
            string sslCertPassword = configuration.GetValue<string>("Hosting:SSLCertPassword");
            if (sslCert != null)
            {
                if (sslCertPassword != null)
                    options.Listen(httpsBinding, httpsPort, listenOptions => { listenOptions.UseHttps(sslCert, sslCertPassword); });
                else
                    options.Listen(httpsBinding, httpsPort, listenOptions => { listenOptions.UseHttps(sslCert); });
            }
        }
    }
    /// <summary>
    /// Gets the IP address from the configuration setting
    /// </summary>
    /// <param name="httpBinding"></param>
    /// <returns></returns>
    public static IPAddress GetAddressFromSetting(string httpBinding)
    {
        if (string.IsNullOrWhiteSpace(httpBinding) || httpBinding.ToUpper() == "DISABLED")
            return null;
        else
            httpBinding = httpBinding.ToUpper();
        IPAddress bindingIp = null;
        switch (httpBinding.ToUpper())
        {
            case "DISABLED":
                bindingIp = null;
                break;
            case "ANY":
                bindingIp = IPAddress.Any;
                break;
            case "IPV6ANY":
                bindingIp = IPAddress.IPv6Any;
                break;
            case "IPV6LOOPBACK":
                bindingIp = IPAddress.IPv6Loopback;
                break;
            case "IPV6NONE":
                bindingIp = IPAddress.IPv6None;
                break;
            case "LOOPBACK":
                bindingIp = IPAddress.Loopback;
                break;
            case "NONE":
                bindingIp = IPAddress.None;
                break;
            default:
                bool ipParsed = false;
                try
                {
                    bindingIp = IPAddress.Parse(httpBinding);
                    ipParsed = true;
                }
                catch(System.Exception)
                {

                }
                if(!ipParsed)
                {
                    IPHostEntry hostEntry = Dns.GetHostEntry(httpBinding);
                    if (hostEntry.AddressList.Length > 0)
                    {
                        bindingIp = hostEntry.AddressList[0];
                        ipParsed = true;
                    }
                }
                if (!ipParsed)
                {
                    throw new System.Exception("Failed to parse IP address from '" + httpBinding + "'");
                }
                break;
        }
        return bindingIp;
    }
}

Then in your main然后在你的主要

    public static void Main(string[] args)
    {
        // Start the application
        CreateHostBuilder(args).Build().Run();
    }
    /// <summary>
    /// Create the service objects
    /// </summary>
    /// <param name="args">Command line arguments</param>
    /// <returns>The configured host builder object</returns>
    public static IHostBuilder CreateHostBuilder(string[] args)
    {
        // Load the configuration object
        var configuration = new ConfigurationBuilder()
            .AddCommandLine(args)
            .SetBasePath(Environment.CurrentDirectory)
            .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
            .AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")}.json", optional: true)
            .AddEnvironmentVariables()
            .Build();
        // Create the host builder object
        return Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder
                    .UseStartup<Startup>()
                    .UseConfiguration(configuration)
                    .UseKestrel(options => { ConfigHelper.SetupHostingOptions(configuration, options); });
            });
    }

Then you appsettings.json should have a section like然后你 appsettings.json 应该有一个像

 "Hosting": {
    "HTTPBinding": "DISABLED",
    "HTTPPort": 0,
    "HTTPSBinding": "ANY",
    "HTTPSPort": 5555,
    "SSLCert": "sslcert.pfx",
    "SSLCertPassword": "sslcertpasswordhere"
  }

If you are proxying from apache to the kestrel service on the same centos instance, then you might consider running apache in HTTPS for the external world and using http on between the two (or just skip using the proxy all together) If you are proxying from apache to the kestrel service on the same centos instance, then you might consider running apache in HTTPS for the external world and using http on between the two (or just skip using the proxy all together)

Wow... it was because the service running my web app is running on http but forces redirect to https.哇...这是因为运行我的 web 应用程序的服务正在 http 上运行,但强制重定向到 https。 The issue was this line:问题是这一行:

webBuilder.UseUrls("https://localhost:5555"); webBuilder.UseUrls("https://localhost:5555");

Needs to be this:需要是这样的:

webBuilder.UseUrls("http://localhost:5555"); webBuilder.UseUrls("http://localhost:5555");

I also tested Xavier's solution, which also works.我还测试了 Xavier 的解决方案,它也有效。 So thanks for offering up a solution.因此,感谢您提供解决方案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM