Windows 服务中自托管 ASPNET 核心 5.0 Web API 的问题

时间:2021-07-28 17:18:31

标签: api rest asp.net-core windows-services self-hosting

我在 Windows Service Worker 中托管 asp.net core 5 rest 服务时遇到问题。 该服务正在运行,我可以通过 webbrowser 在我的控制器上调用 GET 方法。 但是,当我使用 postman 或使用 HttpClient 从 .net core 5 客户端尝试相同操作时,我总是会出错。

错误消息没有给我提供任何更详细的信息来定位问题。

我使用 Serilog 进行日志记录,并且包含了 Microsoft.AspNetCore.App

从任何网络浏览器调用:

<块引用>

好的

从 Postman 调用端点:

<块引用>

错误:读取ECONNRESET

Postman 配置了标准的 HttpHeader 变量,当在 IIS 中托管相同的服务时,它可以正常工作。但不幸的是不在自托管服务中。

从 HttpClient 调用:

<块引用>

发生了一个或多个错误。 (发送请求时发生错误。) -> 调用未到达控制器端点。

WorkerService Program.cs 如下所示:

public class Program
    {
        public static void Main(string[] args)
        {
            var logPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "std.log");

            Log.Logger = new LoggerConfiguration()
            .MinimumLevel.Information()
            .WriteTo.File(logPath, rollingInterval: RollingInterval.Month)
            .CreateLogger();

            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .UseSerilog()
                .UseWindowsService()
                .ConfigureServices((hostContext, services) =>
                {
                    services.AddHostedService<SsmWorker>();
                })
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                });
    }

Startup.cs 如下所示:

    public class Startup
    {
        public IConfiguration Configuration { get; }

        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        // 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)
        {
            try
            {
                //services.AddControllers();
                services.AddMvcCore();

                //services.AddSwaggerGen(c =>
                //{
                //    c.SwaggerDoc("v1", new OpenApiInfo { Title = "WebCommand", Version = "v1" });
                //});
            }
            catch (Exception ex)
            {
                throw new Exception("Error in ConfigureServices.", ex);
            }
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
                //app.UseSwagger();
                //app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "WebCommand v1"));
            }

            //app.UseHttpsRedirection();

            app.UseRouting();

            //app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }
    }

来自控制台客户端应用的调用如下所示:

private void HandleGetInfo()
        {
            using (var httpClientHandler = new HttpClientHandler())
            {
                httpClientHandler.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => { return true; };
                using (var client = new HttpClient(httpClientHandler))
                {
                    var httpResponseTask = client.GetAsync("https://localhost:5101/ssm/info", HttpCompletionOption.ResponseHeadersRead);
                    httpResponseTask.Wait();

                    var httpResponse = httpResponseTask.Result;

                    var contentTask = httpResponse.Content.ReadAsStringAsync();
                    contentTask.Wait();

                    var content = contentTask.Result;

                    Console.WriteLine("");
                    ConsoleHelper.WriteLineColored("Response: ", ConsoleColor.Green);
                    Console.WriteLine("");
                    Console.WriteLine(content);
                    Console.WriteLine("");
                }
            }
        }

当我通过 IIS 托管服务时,相同的配置在所有情况下都可以正常工作。

任何想法可能是什么原因?

1 个答案:

答案 0 :(得分:0)

问题解决了!

问题是,如果服务器配置为仅通过 TLS 连接 http2,则 kestrel 无法处理 Postman 调用或来自 HttpClient 的调用。

我在 appsettings.json 中的第一个方法是:

  "AllowedHosts": "*",
  "Kestrel": {
    "EndpointDefaults": {
      "Protocols": "http2"
    },
    "Endpoints": {
      "Http": {
        "Url": "http://localhost:5100"
      },
      "Https": {
        "Url": "https://localhost:5101"
      }
    },
    "Certificates": {
      "Default": {
        "Subject": "mycert.de",
        "Store": "My",
        "Location": "LocalMachine",
        "AllowInvalid": true
      }
    }
  }

将协议更改为“Http1AndHttp2”后,一切正常。

但即使我也不知道为什么在 IIS 中托管时相同的配置会起作用。