.NET .NET Aspire 内部循环网络概述

使用 .NET.NET Aspire 进行开发的优点之一是,它使你能够在本地开发、测试和调试云原生应用。 内部循环网络是 .NET.NET Aspire 的一个关键方面,它允许应用在开发环境中相互通信。 本文将介绍 .NET.NET Aspire 如何通过代理、终结点、终结点配置和启动配置文件处理各种网络方案。

内部循环中的网络

内部循环是在将应用部署到目标环境之前在本地开发和测试应用的过程。 .NET .NET Aspire 提供了多种工具和功能来简化和增强内部循环中的网络体验,例如:

  • 启动配置文件:启动配置文件是指定如何在本地运行应用的配置文件。 可以使用启动配置文件(如 launchSettings.json 文件)来定义应用的终结点、环境变量和启动设置。
  • Kestrel 配置:Kestrel 配置使您可以指定 Kestrel Web 服务器侦听的端点。 可以在应用设置中配置 Kestrel 终结点,.NET.NET Aspire 自动使用这些设置来创建终结点。
  • 终结点/终结点配置:终结点是应用与它依赖的服务之间的连接,例如数据库、消息队列或 API。 终结点提供服务名称、主机端口、方案和环境变量等信息。 您可以通过启动配置文件隐式添加终结点,或者通过调用 WithEndpoint显式添加终结点到您的应用程序。
  • 代理:.NET.NET Aspire 会为您添加到应用的每个服务绑定自动启动一个代理,并为每个代理分配一个侦听端口。 然后,代理将请求转发到应用监听的端口,该端口可能与代理所使用的端口不同。 这样,便可以避免端口冲突,并使用一致且可预测的 URL 访问应用和服务。

终结点的工作原理

.NET .NET Aspire 中的服务绑定涉及两个集成:表示应用所需的外部资源的 服务(例如数据库、消息队列或 API),以及 绑定,用于在应用和服务之间建立连接并提供必要信息。

.NET .NET Aspire 支持两种服务绑定类型:隐式,这种类型基于在不同环境中定义应用行为的指定启动配置文件自动创建;以及 显式,这种类型需要使用 WithEndpoint手动创建。

创建绑定时,无论是隐式还是显式的,.NET.NET Aspire 在指定的端口上启动轻型反向代理,处理从应用到服务的请求的路由和负载均衡。 代理是一个 .NET.NET Aspire 实现细节,不需要任何配置或管理上的关注。

为了帮助可视化终结点的工作原理,请考虑 .NET.NET Aspire 起始模板的内部循环网络图:

.NET.NET Aspire 初学者应用程序模板内部循环网络关系图。

启动配置

调用 AddProject时,应用主机将查找 属性/launchSettings.json 以确定默认的终结点集。 应用主机使用以下规则选择特定的启动配置文件:

  1. 调用 launchProfileName时传递的显式 AddProject 参数。
  2. DOTNET_LAUNCH_PROFILE 环境变量。 有关详细信息,请参阅 .NET 环境变量
  3. launchSettings.json中定义的第一个启动配置文件。

请考虑以下 launchSettings.json 文件:

{
  "$schema": "http://json.schemastore.org/launchsettings.json",
  "profiles": {
    "http": {
      "commandName": "Project",
      "dotnetRunMessages": true,
      "launchBrowser": false,
      "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    },
    "https": {
      "commandName": "Project",
      "dotnetRunMessages": true,
      "launchBrowser": true,
      "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
      "applicationUrl": "https://localhost:7239;http://localhost:5066",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    }
  }
}

对于本文的其余部分,请设想你已使用 IDistributedApplicationBuilder API 创建了 builder,并将其分配给一个名为 CreateBuilder() 的变量。

var builder = DistributedApplication.CreateBuilder(args);

若要指定 httphttps 启动配置文件,请在 launchSettings.json 文件中配置两者 applicationUrl 值。 这些 URL 用于为此项目创建终结点。 这相当于:

builder.AddProject<Projects.Networking_Frontend>("frontend")
       .WithHttpEndpoint(port: 5066)
       .WithHttpsEndpoint(port: 7239);

重要

如果没有 launchSettings.json(或启动配置文件),则默认情况下没有绑定。

有关详细信息,请参阅 .NET.NET Aspire 和启动配置文件

Kestrel 配置的终结点

.NET .NET Aspire 支持 Kestrel 终结点配置。 例如,考虑某个定义了具有 HTTPS 方案和端口 5271 的 Kestrel 终结点的项目的 appsettings.json 文件:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "Kestrel": {
    "Endpoints": {
      "Https": {
        "Url": "https://*:5271"
      }
    }
  }
}

上述配置指定 Https 终结点。 Url 属性设置为 https://*:5271,这意味着终结点在端口 5271 上侦听所有接口。 有关详细信息,请参阅 为 ASP.NET Core Kestrel Web 服务器配置终结点。

配置 Kestrel 终结点后,项目应从 launchSettings.json 文件中删除任何配置的 applicationUrl

注意

如果 launchSettings.json 文件中存在 applicationUrl,并且配置了 Kestrel 终结点,则应用主机将引发异常。

在添加项目资源时,有一个重载允许你指定应使用 Kestrel 终结点,而不是 launchSettings.json 文件:

builder.AddProject<Projects.Networking_ApiService>(
    name: "apiservice",
    configure: static project =>
    {
        project.ExcludeLaunchProfile = true;
        project.ExcludeKestrelEndpoints = false;
    })
    .WithHttpsEndpoint();

有关详细信息,请参阅 AddProject

端口和代理

定义服务绑定时,主机端口 始终 提供给位于服务前面的代理。 这允许服务的单个或多个副本的行为类似。 此外,所有使用 WithReference API 的资源依赖项都依赖于环境变量中的代理终结点。

请考虑调用 AddProjectWithHttpEndpoint,然后 WithReplicas的以下方法链:

builder.AddProject<Projects.Networking_Frontend>("frontend")
       .WithHttpEndpoint(port: 5066)
       .WithReplicas(2);

上述代码将生成以下网络关系图:

.NET.NET Aspire 具有特定主机端口和两个副本的前端应用网络关系图。

上图描述了以下内容:

  • Web 浏览器作为应用的入口点。
  • 主机端口 5066。
  • 前端代理位于 Web 浏览器和前端服务副本之间,监听网络端口 5066。
  • frontend_0 前端服务副本在随机分配的端口 65001 上进行侦听。
  • frontend_1 前端服务副本在随机分配的端口 65002 上侦听。

如果没有调用 WithReplicas,则只有一个前端服务。 代理仍侦听端口 5066,但前端服务侦听随机端口:

builder.AddProject<Projects.Networking_Frontend>("frontend")
       .WithHttpEndpoint(port: 5066);

定义了两个端口:

  • 主机端口 5066。
  • 底层服务将绑定到的随机代理端口。

.NET.NET Aspire 具有特定主机端口和随机端口的前端应用网络关系图。

上图描述了以下内容:

  • Web 浏览器作为应用的入口点。
  • 主机端口 5066。
  • 前端代理位于 Web 浏览器和前端服务之间,侦听端口 5066。
  • 侦听 65001 随机端口的前端服务。

基础服务通过 ASPNETCORE_URLS 为项目资源提供此端口。 通过在服务绑定上指定一个环境变量来访问此端口的其他资源。

builder.AddNpmApp("frontend", "../NodeFrontend", "watch")
       .WithHttpEndpoint(port: 5067, env: "PORT");

前面的代码使随机端口在 PORT 环境变量中可用。 应用使用此端口侦听来自代理的传入连接。 请考虑下图:

.NET.NET Aspire 具有特定主机端口和环境变量端口的前端应用网络关系图。

上图描述了以下内容:

  • Web 浏览器作为应用的入口点。
  • 一个主机端口 5067。
  • 前端代理位于 Web 浏览器和前端服务之间,侦听端口 5067。
  • 侦听环境 65001 的前端服务。

提示

若要避免终结点被代理,将 IsProxied 属性设置为 false,然后调用 WithEndpoint 扩展方法。 有关详细信息,请参阅 终结点扩展:的其他注意事项。

省略主机端口

省略主机端口时,.NET.NET Aspire 为主机和服务端口生成随机端口。 如果想要避免端口冲突,并且不关心主机或服务端口,这非常有用。 请考虑以下代码:

builder.AddProject<Projects.Networking_Frontend>("frontend")
       .WithHttpEndpoint();

在此方案中,主机和服务端口都是随机的,如下图所示:

.NET.NET Aspire 前端应用的网络图,显示随机的主机端口和代理端口。

上图描述了以下内容:

  • Web 浏览器作为应用的入口点。
  • 随机主机端口 65000。
  • 前端代理位于 Web 浏览器和前端服务之间,侦听端口 65000。
  • 侦听随机端口 65001 的前端服务。

容器端口

添加容器资源时,.NET.NET Aspire 会自动向容器分配随机端口。 若要指定容器端口,请使用所需的端口配置容器资源:

builder.AddContainer("frontend", "mcr.microsoft.com/dotnet/samples", "aspnetapp")
       .WithHttpEndpoint(port: 8000, targetPort: 8080);

前面的代码:

  • frontend 映像创建名为 mcr.microsoft.com/dotnet/samples:aspnetapp的容器资源。
  • 通过将主机绑定到端口 8000 并将其映射到容器的端口 8080 来公开 http 终结点。

请考虑下图:

使用 docker 主机 .NET.NET Aspire 前端应用网络关系图。

终结点扩展方法

实现 IResourceWithEndpoints 接口的任何资源都可以使用 WithEndpoint 扩展方法。 此扩展有多个重载,允许您指定协议、容器端口、主机端口、环境变量名称以及端点是否被代理。

还有一种重载方法,允许您指定委托来配置终结点。 如果需要根据环境或其他因素配置终结点,这非常有用。 请考虑以下代码:

builder.AddProject<Projects.Networking_ApiService>("apiService")
       .WithEndpoint(
            endpointName: "admin",
            callback: static endpoint =>
       {
           endpoint.Port = 17003;
           endpoint.UriScheme = "http";
           endpoint.Transport = "http";
       });

前述代码提供用于配置终结点的回调委托。 终结点命名为 admin,配置为使用 http 方案和传输,以及 17003 主机端口。 使用者按名称引用此终结点,请考虑以下 AddHttpClient 调用:

builder.Services.AddHttpClient<WeatherApiClient>(
    client => client.BaseAddress = new Uri("http://_admin.apiservice"));

Uri 是通过在 admin 终结点名称前加上 _ 哨兵来构建的。 这是一种约定,指示 admin 段是属于 apiservice 服务的终结点名称。 有关详细信息,请参阅 .NET.NET Aspire 服务发现

其他注意事项

调用 WithEndpoint 扩展方法时,callback 重载会暴露原始 EndpointAnnotation,这允许使用者自定义端点的许多方面。

AllocatedEndpoint 属性允许获取或设置服务的终结点。 IsExternalIsProxied 属性决定了终结点的管理和公开方式:IsExternal 决定是否应公开访问终结点,而 IsProxied 确保 DCP 对其进行管理,从而允许内部端口差异和复制。

提示

如果您要托管一个运行自身代理的外部可执行文件,并且由于 DCP 已经绑定了端口而遇到端口绑定问题,请尝试将 IsProxied 属性设置为 false。 这可以防止 DCP 管理代理,从而允许可执行文件成功绑定端口。

Name 属性标识服务,而 PortTargetPort 属性分别指定所需的端口和侦听端口。

对于网络通信,Protocol 属性支持 TCPUDP,将来可能会有更多可能性,Transport 属性指示传输协议(HTTPHTTP2HTTP3)。 最后,如果服务有 URI 地址,则 UriScheme 属性提供用于构建服务 URI 的 URI 协议。

有关详细信息,请参阅 EndpointAnnotation 属性的可用属性。

端点过滤

所有 .NET.NET Aspire 项目资源端点都遵循一组默认启发式。 某些终结点在运行时包含在 ASPNETCORE_URLS 中,某些终结点作为 HTTP/HTTPS_PORTS发布,还有一些配置是从 Kestrel 配置中解析的。 无论默认行为如何,都可以使用 WithEndpointsInEnvironment 扩展方法筛选环境变量中包含的终结点:

builder.AddProject<Projects.Networking_ApiService>("apiservice")
    .WithHttpsEndpoint() // Adds a default "https" endpoint
    .WithHttpsEndpoint(port: 19227, name: "admin")
    .WithEndpointsInEnvironment(
        filter: static endpoint =>
        {
            return endpoint.Name is not "admin";
        });

上述代码在端口 19227 上添加默认 HTTPS 终结点以及 admin 终结点。 但是,admin 端点被从环境变量中排除。 如果想要公开终结点供内部使用,这非常有用。