远程应用设置

重要

框架和核心应用程序必须使用相同的虚拟目录布局。

虚拟目录设置用于系统中的路由生成、授权和其他服务。 此时,由于 ASP.NET Framework 的工作原理,找不到任何可靠的方法来启用不同的虚拟目录。

在某些增量升级方案中,新的 ASP.NET Core 应用能够与原始 ASP.NET 应用通信非常有用。

这可实现以下常见方案:

配置值

若要使 ASP.NET Core 应用能够与 ASP.NET 应用通信,必须对每个应用进行少量更改。

需要在两个应用程序中配置两个配置值:

  • RemoteAppApiKey:在两个应用程序之间共享的密钥(需要解析为 GUID)。 这应该是一个类似于 12345678-1234-1234-1234-123456789012 的 GUID 值。
  • RemoteAppUri:远程 ASP.NET 框架应用程序的 URI(仅在 ASP.NET 核心应用程序配置中是必需的)。 这应该是托管 ASP.NET 框架应用的完整 URL,例如 https://localhost:44300https://myapp.example.com

配置 ASP.NET Framework 应用程序

重要

应启用 SSL 托管 ASP.NET 框架应用程序。 在用于增量迁移的远程应用设置中,无需在外部直接访问。 建议仅允许客户端应用程序通过代理进行访问。

对于 ASP.NET Framework 应用程序,将这些值添加到 <appSettings> 部分中的 web.config 中:

重要

ASP.NET Framework 将其 appSettings 存储在 web.config 中。 但是,可以使用 配置生成器从其他源(如环境变量)检索它们。 这使得在此设置中的本地应用程序与远程应用程序之间共享配置值要容易得多。

<appSettings>
  <add key="RemoteAppApiKey" value="..." />
</appSettings>

若要将应用程序配置为可用于处理来自 ASP.NET Core 客户端的请求,请设置以下内容:

  1. 安装 NuGet 包 Microsoft.AspNetCore.SystemWebAdapters.FrameworkServices

  2. 将配置代码添加到您的 Global.asax.cs 文件中的 Application_Start 方法内:

    protected void Application_Start()
    {
        SystemWebAdapterConfiguration.AddSystemWebAdapters(this)
            .AddRemoteAppServer(options =>
            {
                // ApiKey is a string representing a GUID
                options.ApiKey = ConfigurationManager.AppSettings["RemoteAppApiKey"];
            });
    
        // ...existing code...
    }
    
  3. ** 如果尚未由 NuGet 添加,则将 SystemWebAdapterModule 模块添加到 web.config。 IIS 托管方案需要此模块配置。 使用用于 ASP.NET Core 的 SDK 样式项目时,不会自动添加该 SystemWebAdapterModule 模块。

      <system.webServer>
        <modules>
    +      <remove name="SystemWebAdapterModule" />
    +      <add name="SystemWebAdapterModule" type="Microsoft.AspNetCore.SystemWebAdapters.SystemWebAdapterModule, Microsoft.AspNetCore.SystemWebAdapters.FrameworkServices" preCondition="managedHandler" />
        </modules>
    </system.webServer>
    

配置 ASP.NET Core 应用程序

对于 ASP.NET Core 应用程序,请将这些值添加到你的 appsettings.json

{
  "RemoteAppApiKey": "...",
  "RemoteAppUri": "https://localhost:44300"
}

若要将 ASP.NET Core 应用设置为能够将请求发送到 ASP.NET 应用,请在向 System.Web 适配器服务AddSystemWebAdapters注册后调用AddRemoteAppClient来配置远程应用客户端。

将此配置添加到 Program.cs 文件:

builder.Services.AddSystemWebAdapters()
    .AddRemoteAppClient(options =>
    {
        options.RemoteAppUrl = new(builder.Configuration["RemoteAppUri"]);
        options.ApiKey = builder.Configuration["RemoteAppApiKey"];
    });

更新 ASP.NET 和 ASP.NET 核心应用后,扩展方法现在可以根据需要用于设置 远程应用身份验证远程会话

启用代理

若要启用从 ASP.NET Core 应用程序到 ASP.NET Framework 应用程序的代理,可以设置回退路由,将不匹配的请求转发到旧应用程序。 这使得可以逐步迁移,其中 ASP.NET Core 应用处理已迁移的功能,同时回退到原始应用以获取未迁移的功能。

  1. 按照 最新指南安装 YARP(又一个反向代理)NuGet 包。

  2. 将所需的 using 语句添加到 Program.cs

    using Microsoft.Extensions.Options;
    using Microsoft.AspNetCore.SystemWebAdapters;
    
  3. 在您的 Program.cs 中注册反向代理服务。

    builder.Services.AddReverseProxy();
    
  4. 生成应用并配置其他中间件后,添加回退路由映射:

    var app = builder.Build();
    
    // Configure your other middleware here (authentication, routing, etc.)
    
    // Map the fallback route
    app.MapForwarder("/{**catch-all}", app.Services.GetRequiredService<IOptions<RemoteAppClientOptions>>().Value.RemoteAppUrl.OriginalString)
    
        // Ensures this route has the lowest priority (runs last)
        .WithOrder(int.MaxValue)
    
        // Skips remaining middleware when this route matches
        .ShortCircuit();
    
    app.Run();
    

设置 Aspire 业务流程

重要

这仍处于预览版,在 NuGet.org 上不可用,因此必须将 NuGet 配置配置为从 .NET 库每日源拉取库:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <packageSources>
    <!--To inherit the global NuGet package sources remove the <clear/> line below -->
    <clear />
    <add key="nuget" value="https://api.nuget.org/v3/index.json" />
    <add key=".NET Libraries Daily" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-libraries/nuget/v3/index.json" />
  </packageSources>
</configuration>

注意:这需要 System.Web 适配器的 v2.0.1-preview1.25351.5 或更高版本。

警告

注意:这是第三方组件,可帮助在 Aspire 中运行应用程序。 目前,Aspire 中不支持 ASP.NET 框架应用程序,但此项目对此有所帮助。 此依赖项适用于生成和开发,但不需要部署到生产环境。

  1. 为 ASP.NET Framework 应用程序添加 Aspire 编排

  2. 将新的 ASP.NET Core 应用程序添加到解决方案,并将其添加到 Aspire 业务流程

  3. 将 AppHost 更新以设定 Windows 为目标平台,因为 IIS 集成需要这样做。

    - <TargetFramework>net9.0</TargetFramework>
    + <TargetFramework>net9.0-windows</TargetFramework>
    
  4. 将以下 Aspire 集成添加到应用主机:

    • Aspire.Hosting.IncrementalMigration
    • C3D.Extensions.Aspire.IISExpress
  5. 将 IIS Express 配置为本地托管框架应用程序,并配置增量迁移回退:

    var builder = DistributedApplication.CreateBuilder(args);
    
    var frameworkApp = builder.AddIISExpress("iis")
        .AddSiteProject<Projects.FrameworkApplication>("framework")
        .WithDefaultIISExpressEndpoints()
        .WithOtlpExporter()
        .WithHttpHealthCheck();
    
    var coreApp = builder.AddProject<Projects.CoreApplication>("core")
        .WithHttpHealthCheck()
        .WaitFor(frameworkApp)
        .WithIncrementalMigrationFallback(frameworkApp, options => options.RemoteSession = RemoteSession.Enabled);
    
    builder.Build().Run();
    
  6. 为您希望支持的情境配置增量迁移备用方案的选项。

配置 ServiceDefaults 以支持 ASP.NET Framework

  1. 将包 Aspire.Microsoft.AspNetCore.SystemWebAdapters 添加到应用程序。
  2. 更新 ServiceDefaults 项目以支持 .NET Framework。 这基于默认 ServiceDefaults,如果已自定义任何内容,则可能有所不同。
    • 将目标框架更新为多目标:

      - <TargetFramework>net9.0</TargetFramework>
      + <TargetFrameworks>net9.0;net48</TargetFrameworks>
      
    • 更新 PackageReferences 以适应不同框架:

       <ItemGroup>
          <PackageReference Include="Microsoft.Extensions.Http.Resilience" />
          <PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" />
          <PackageReference Include="OpenTelemetry.Extensions.Hosting" />
          <PackageReference Include="OpenTelemetry.Instrumentation.Http" />
          <PackageReference Include="OpenTelemetry.Instrumentation.Runtime" />
          <PackageReference Include="OpenTelemetry.Instrumentation.SqlClient" />
        </ItemGroup>
      
        <ItemGroup Condition=" '$(TargetFramework)' == 'net9.0'">
          <FrameworkReference Include="Microsoft.AspNetCore.App" />
      
          <PackageReference Include="Microsoft.Extensions.ServiceDiscovery" />
          <PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" />
        </ItemGroup>
      
        <ItemGroup Condition=" '$(TargetFramework)' == 'net48' ">
          <PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks" />
          <PackageReference Include="OpenTelemetry.Instrumentation.AspNet" />
        </ItemGroup>
      
    • 在Extensions.cs文件中,需要有条件地排除 ServiceDiscovery API,因为 .NET Framework 当前不支持这些 API:

      + #if NET
              builder.Services.AddServiceDiscovery();
      + #endif
      
              builder.Services.ConfigureHttpClientDefaults(http =>
              {
                  // Turn on resilience by default
                  http.AddStandardResilienceHandler();
      
      + #if NET
                  // Turn on service discovery by default
                  http.AddServiceDiscovery();
      + #endif
              });
      
    • 若要启用遥测,请更新指标和跟踪注册:

              builder.Services.AddOpenTelemetry()
                  .WithMetrics(metrics =>
                  {
                      metrics
      + #if NET
                          .AddAspNetCoreInstrumentation()
      + #else
      +                   .AddAspNetInstrumentation()
      + #endif
                          .AddSqlClientInstrumentation()
                          .AddHttpClientInstrumentation()
                          .AddRuntimeInstrumentation();
                  })
                  .WithTracing(tracing =>
                  {
                      tracing.AddSource(builder.Environment.ApplicationName)
      + #if NET
                          .AddAspNetCoreInstrumentation()
      + #else
      +                   .AddAspNetInstrumentation()
      + #endif
                          .AddSqlClientInstrumentation()
                          .AddHttpClientInstrumentation();
                  });
      
    • 禁用默认终结点,因为该终结点仅适用于 ASP.NET Core:

      + #if NET
          public static WebApplication MapDefaultEndpoints(this WebApplication app)
          {
              // Default endpoint registrations
          }
      + #endif
      

配置 ASP.NET Framework 应用程序

  1. 引用 ServiceDefaults 项目

  2. 将配置代码添加到您的 Global.asax.cs 文件中的 Application_Start 方法内:

    protected void Application_Start()
    {
        HttpApplicationHost.RegisterHost(builder =>
        {
            builder.AddServiceDefaults();
            builder.AddSystemWebAdapters();
        });
    }
    

配置 ASP.NET Core 应用程序

  1. 引用 ServiceDefaults 项目

  2. 在 Programs.cs 中添加 System.Web 适配器:

    var builder = WebApplication.CreateBuilder();
    
    builder.AddServiceDefaults();
    + builder.AddSystemWebAdapters();
    
    ...
    
    var app = builder.Build();
    
    ...
    
    + // Must be placed after routing if manually added
    + app.UseSystemWebAdapters();
    
    ...
    
    + app.MapRemoteAppFallback()
    +
    +   // Optional, but recommended unless middleware is needed
    +   .ShortCircuit();
    
    app.Run();
    

使用此配置时:

  1. 本地路由优先:如果 ASP.NET Core 应用程序具有匹配路由,它将在本地处理请求
  2. 回退到旧版应用:不匹配的请求会自动转发到 ASP.NET Framework 应用程序
  3. 中间件优化:此方法 .ShortCircuit() 在转发请求时阻止不必要的中间件执行

此设置可在增量迁移期间实现无缝用户体验,用户可以通过单个终结点访问已迁移功能和旧功能。