【问题标题】:How to get base url without accessing a request如何在不访问请求的情况下获取基本 URL
【发布时间】:2017-02-13 08:13:33
【问题描述】:

如何在没有请求的情况下获取 AspNet 核心应用程序中的基本 URL?

我从请求中知道您可以获得方案和主机(即$"{Request.Scheme}://{Request.Host}" 会给出类似https://localhost:5000 的内容),但是否可以从其他任何地方获取此信息?

也就是说,如果我有一个服务类需要构建绝对 URL,那么在没有可用的 http 请求的情况下,如何获取当前 URL?

更新:也许这种情况甚至没有意义,因为托管 URL 完全在应用程序外部,这就是为什么只有从请求主机中提取它才有意义..

【问题讨论】:

  • 请注意,在 AspNetCore 中有一个服务可以注入到任何类中以从当前请求中获取基本 url(如果我们不在可以直接访问 Request 的控制器中) )。只需注入 IHttpContextAccessor contextAccessor 然后构建 var url = $"{contextAccessor.HttpContext.Request.Scheme}://{contextAccessor.HttpContext.Request.Host.ToUriComponent()}"; 但根据 github.com/aspnet/Hosting/issues/793 似乎有必要在 DI 中显式注册它:services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();

标签: asp.net-core asp.net-core-mvc base-url


【解决方案1】:

出于某种原因,我需要在 Start.cs 配置中获取基本 URL,所以我想出了这个

var URLS = app.ServerFeatures.Get<IServerAddressesFeature>().Addresses;

【讨论】:

  • 这仅在使用 VS 调试时有效。在 IIS Express 和 IIS 中,它返回随机端口号。
  • 它返回一个随机端口,还是红隼正在监听的端口? IIS 使用 ANCM 将流量路由到 kestrel Web 服务。
  • 我在 appsettings.json 中用 "Kestrel": {"Endpoints": {"Https": {"Url": "https://*:5002"... 覆盖了 URL,它并没有反映在这个设置中。很烦人。
【解决方案2】:

你是对的,托管 URL 是一个外部信息,你可以简单地将它作为配置参数传递给你的应用程序。

也许这会对您有所帮助:无需请求,您可以使用IWebHostBuilder 接口获取配置的监听地址(如http://+:5000)。它通过GetSetting 方法提供对主机设置的访问:

/// <summary>
/// Get the setting value from the configuration.
/// </summary>
/// <param name="key">The key of the setting to look up.</param>
/// <returns>The value the setting currently contains.</returns>
string GetSetting(string key);

有一个WebHostDefaults.ServerUrlsKey 设置名称,允许配置监听地址。我们在添加.UseUrls扩展方法时覆盖它:

public static IWebHostBuilder UseUrls(this IWebHostBuilder hostBuilder, params string[] urls);

或者按照the documentation中的描述定义urls配置参数(你知道,默认情况下监听配置为localhost:5000)。

因此,拥有IWebHostBuilder 的实例,您可以调用.GetSetting(WebHostDefaults.ServerUrlsKey) 并获取当前值。

【讨论】:

    【解决方案3】:

    ,ASP.NET Core 模块生成一个动态端口分配给后端进程。 CreateDefaultBuilder 调用 UseIISIntegration 方法。 UseIISIntegration 将 Kestrel 配置为侦听 localhost IP 地址 (127.0.0.1) 的动态端口。如果动态端口是 1234,Kestrel 会监听 127.0.0.1:1234。此配置替代了其他提供的 URL 配置。

    对于 IIS 集成,如果您在 WebHostBuilder.Build() 运行后获取地址,它就可以工作。

     var builder = CreateWebHostBuilder(args);
     var webHost = builder.Build();
     var addresses = webHost.ServerFeatures.Get<IServerAddressesFeature>().Addresses;
     var address = addresses.FirstOrDefault();
     AppDomain.CurrentDomain.SetData("BaseUrl", address ?? "");
     webHost.Run();
    

    并像这样在 HostedService 中获取本地 Kestrel 地址:

      string baseUrl = AppDomain.CurrentDomain.GetData("BaseUrl").ToString();
    

    但是有一个问题——这个地址是没有用的,因为你不能直接在这个地址上发出请求。 IIS 集成中间件检查是否只有 IIS 处理程序可以对该地址发出请求。它会产生类似的错误:

    <category>Microsoft.AspNetCore.Server.IISIntegration.IISMiddleware</category>
      <state>'MS-ASPNETCORE-TOKEN' does not match the expected pairing token 'ed5bc610-b7b9-4c1c-9941-954d0579edfc', request rejected.</state>
    

    在一般情况下(没有 IIS 集成),如果您使用配置为使用自定义端口(不是 5000)或动态端口 0 运行的 Kestrel,则这种获取地址的方法不起作用。在这种情况下,地址需要延迟获取,只能在应用启动后获取。

    对于这种情况,我尝试了这种方式:在 StartUp 类的 Configure 方法中,我保存在私有成员的 ServerAddressFeature 中。

      private IServerAddressesFeature _serverAddressesFeature;
    
      public void Configure(IApplicationBuilder app, IHostingEnvironment env)
      {
                _serverAddressesFeature = app.ServerFeatures.Get<IServerAddressesFeature>();
              ... not related code here ...
    

    在 ConfigureServices 方法中我添加了一个依赖项

     public void ConfigureServices(IServiceCollection services)
     {
         services.AddSingleton<IServerAddressesFeature>((sp) => _serverAddressesFeature);
      ... not related code here ...
    

    然后在托管服务中,我使用依赖注入获取此保存的功能,并使用它来获取地址。 有效,只在StartAsync方法中获取地址,在服务构造函数中不行!

        public class WarmUpService : IHostedService
        {
            private readonly ILogger _logger;
            private readonly IServerAddressesFeature _saf;
    
            public WarmUpService(ILogger<WarmUpService> logger, IServerAddressesFeature serverAddressesFeature)
            {
                _logger = logger;
                _saf = serverAddressesFeature;
            }
    
            public async Task StartAsync(CancellationToken cancellationToken)
            {
                try
                {
                    // the URL can be Got here
                    string baseUrl = _saf?.Addresses?.FirstOrDefault();
                    // await _WarmUp(baseUrl);
                }
                catch(Exception ex)
                {
                    _logger.LogCritical(ex, "WarmUp Failed");
                }
            }
    
            public Task StopAsync(CancellationToken cancellationToken)
            {
                return Task.CompletedTask;
            }
        }
    

    【讨论】:

    • 在 Asp.Net Core 3.1 的 IServerAddressesFeature 中没有地址,至少使用本地运行 IIS Express 的默认 Web 服务器构建器,即使使用 lauchSettings.json 和 IIS Express 配置文件
    • 这意味着它现在已成为历史
    • 我在 Blazor 服务器中使用此进程总是得到一个空基地址。
    猜你喜欢
    • 1970-01-01
    • 2021-01-07
    • 2020-02-29
    • 2011-09-19
    • 1970-01-01
    • 2011-09-05
    • 2017-09-08
    • 2012-10-25
    • 2011-05-15
    相关资源
    最近更新 更多