【问题标题】:ASP.NET Core (HttpSys) Routing works locally but not when deployedASP.NET Core (HttpSys) 路由在本地工作,但在部署时不工作
【发布时间】:2019-12-15 14:17:28
【问题描述】:

由于某种原因,当我在 Windows 服务器(通过服务结构)上使用 HttpSys 运行我的 ASP.NET Core API 时,路由不起作用,而在本地一切正常。问题是中间件工作正常,所以我知道请求正在处理,但它永远无法命中任何控制器,它只是默认为我的 app.run("Some 404 response") 404 中间件。我的一些代码:

Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    #region IOC
    //ommitted
    #endregion 

    services.AddAutoMapper(typeof(SomeModel));

    services.AddCors(c => 
    {
        c.AddPolicy("AllowOrigin", options => options.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod());
    });

    services.AddDbContext<SomeContext>(options => options.UseSqlServer(_configuration.GetConnectionString("Dev")));

    services.AddMvc().AddFluentValidation();
}        

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
        IdentityModelEventSource.ShowPII = true;
    }

    //Eliminating that auth is the problem
    //app.UseAuthentication(); 

    if (env.IsProduction())
    {
        app.UseHsts();
        app.UseHttpsRedirection();
    }

    app.UseCors("AllowOrigin");
    app.UseMvcWithDefaultRoute(); //tried this instead of below. No luck

    //app.UseMvc();

    app.Use((context, next) =>
    {
        if (context.Request.Path.Value == "" || context.Request.Path.Value == "/")
        {
            context.Response.ContentType = "text/plain";
            return context.Response.WriteAsync("We're running!");
        }

        return next.Invoke();
    });

    app.Run(context =>
    {
        context.Response.StatusCode = 404;
        context.Response.ContentType = "application/json";

        return context.Response.WriteAsync("{ \"message\": \"Not found\" }");
        });
    }
}

Program.cs:

public static void Main(string[] args)
{
    using (var scope = host.Services.CreateScope())
    {
        var services = scope.ServiceProvider;
        try
        {
            var context = services.GetRequiredService<SomeContext>();
            DbInitializer.Initialize(context);
        }
        catch (Exception ex)
        {
            logger.Error(ex, "An error occured while seeding the database");
        }
    }

    host.Run();
}
public static IWebHost CreateWebHostBuilder(string[] args)
{
    IHostingEnvironment env = null;

    var builder = 
        WebHost.CreateDefaultBuilder(args)
        .UseStartup<Startup>()
        .ConfigureAppConfiguration((hostingContext, config) =>
        {
           env = hostingContext.HostingEnvironment;
        })
        .UseHttpSys(options =>
        {
            if (!env.IsDevelopment())
            {
                options.UrlPrefixes.Add("https://*:30010/BasePathOfAPI/");
            }
            else
            {
                options.UrlPrefixes.Add("http://localhost:5000/BasePathOfAPI/");
            }
        })
        .ConfigureLogging(b =>
        {
            b.AddApplicationInsights("id here");
        })
        .UseNLog()
        .Build();

    return builder;
}

因此,除了 UrlPrefixes 之外,设置几乎相似。我可以通过网关和在 Windows 服务器上调用 https://somehost/BasePathOfAPI/ 并在浏览器中显示消息 We're running!,这一事实告诉我 API 已启动并正在运行,但它根本无法访问任何控制器,如果我试试。控制器示例:

[Route("api/{someNumber:int}/Home")]
[ApiController]
public class HomeController: ControllerBase
{
    //ctor and props ommitted

    [HttpGet("GetSomeData")
    [ProducesResponseType(StatusCodes.200OK)]
    public async Task<IActionResult> GetSomeData()
    {
        //implemenetation
    }
}

现在,我用来尝试访问上述控制器的 url 是:

https://somehost/BasePathOfAPI/api/1234/Home/GetSomeData

返回 404 消息:未找到,但是如果我在本地运行:

http://localhost:5000/BasePathOfAPI/api/1234/Home/GetSomeData

效果很好。

不确定我哪里出错了,可能是 UrlPrefixes 的问题,但如果不正确,我应该能够访问中间件吗? 也许与路由有关,但为什么它在本地工作?

【问题讨论】:

  • https://*:30010/BasePathOfAPI/ 您的生产 URL 中的端口号 (30010) 在哪里?
  • 网关将使用该端口。如果我使用端口号在服务器上本地执行此操作,则结果完全相同。我正在调用我的应用程序,因为我看到了我的硬编码 404 消息,而且如果没有给出路径,我会看到我的“我们正在运行!”留言
  • 你能检查一下这个“只有 HTTP URL 前缀是有效的。Kestrel 在使用 UseUrls 配置 URL 绑定时不支持 HTTPS”docs.microsoft.com/en-us/aspnet/core/fundamentals/servers/…
  • 我没有使用 Kestrel,我使用的是 Http.sys,据我所知,它允许在 UrlPrefix 中有 https

标签: c# asp.net-core asp.net-mvc-routing


【解决方案1】:

已解决 - 必须将完整路径基础添加到 UrlPrefix 和 urlacl 注册所以

netsh http add urlacl url=https://*:30010/BasePathOfAPI/ user="NT AUTHORITY\NETWORK SERVICE" 

此外,由于控制器位于另一个 dll 中,因此必须在 ConfigureServices 方法中引用程序集:

services.AddMvc().AddApplicationPart(typeof(SystemController).Assembly)

这两个修复让它工作了

【讨论】:

    【解决方案2】:

    这可能是 UrlPrefix 中弱通配符的问题。

    试试这个用于生产绑定:-

    options.UrlPrefixes.Add("https://somehost:30010/BasePathOfAPI/");
    

    somehost 是机器的 FQDN。

    【讨论】:

    • 主机在网关后面是动态的,因为它是运行应用程序的节点的 IP。但是,如果主机是问题,那么我应该无法首先访问我的应用程序,对吧?
    • 或许可以试试强通配符...options.UrlPrefixes.Add("https://+:30010/BasePathOfAPI/");。我之前也遇到过类似的问题,它与弱通配符的路由不匹配;可能与 URL 保留有关。
    • 我刚才试了一下,还是跳到404中间件。好像根本没有路由,但还是设法把请求拿到应用程序中。
    • 您有多确定它是在命中 your 404 中间件而不是其他进程?这让我之前......我认为这是我的应用程序响应,它是别的东西。另外,为了清楚起见,在您的问题中,您说您正在尝试访问 https://somehost/BasePathOfAPI/api/1234/Home/GetSomeData,但您的 UrlPrefix 位于端口 30010 上……这只是一个错字吗?
    • 我 100% 确定,因为我试图改变它并观察到“我们正在运行!”的文本都发生了变化。和未找到的也是如此。它肯定会击中我的应用程序。该端口被忽略,因为网关将使用端口号转发它。但是,如果您登录到运行应用程序的 VM 并执行 https://localhost:30010/BasePathOfApi/api/1234/Home/GetSomeData,则可以观察到完全相同的行为
    猜你喜欢
    • 2018-03-30
    • 1970-01-01
    • 2021-05-22
    • 2020-09-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-20
    • 1970-01-01
    相关资源
    最近更新 更多