Search code examples
c#asp.net-corems-yarp

Reproduce MapForwarder logic with MapReverseProxy - YARP


I have a legacy ASP.NET MVC application which I'd like to incrementally migrate to ASP.NET Core 8 app using YARP.

Imagine, that my legacy app is hosted under url foo.com, and my proxy app is hosted using url bar.com. When I go to the main page bar.com, authentication logic is triggered and I am redirected to bar.com/account/login, which displays content from foo.com/account/login. This works great for me. Here is my code:

var httpClient = new HttpMessageInvoker(new SocketsHttpHandler
{
    UseProxy = false,
    AllowAutoRedirect = false,
    AutomaticDecompression = DecompressionMethods.None,
    UseCookies = true,
    EnableMultipleHttp2Connections = true,
    ActivityHeadersPropagator = new ReverseProxyPropagator(DistributedContextPropagator.Current),
    ConnectTimeout = TimeSpan.FromSeconds(60),
});

var transformer = HttpTransformer.Empty;
var requestOptions = new ForwarderRequestConfig();

app.MapForwarder("/{**catch-all}", app.Configuration["ProxyTo"], requestOptions, transformer, httpClient);

Now I'd like to switch from MapForwarder to MapReverseProxy. I changed my code accordingly

builder.Services.AddHttpForwarder();
builder.Services.AddReverseProxy()
    .ConfigureHttpClient((context, handler) =>
    {
        handler.AllowAutoRedirect = false;
        handler.UseProxy = false;
        handler.EnableMultipleHttp2Connections = true;
        handler.UseCookies = true;
        handler.ConnectTimeout = TimeSpan.FromSeconds(60);
    })
    .LoadFromConfig(builder.Configuration.GetSection("ReverseProxy"));

builder.Services.AddSystemWebAdapters()
    .AddRemoteAppClient(options =>
    {
        options.RemoteAppUrl = new Uri(builder.Configuration
            ["ReverseProxy:Clusters:fallbackCluster:Destinations:fallbackApp:Address"]!);
        options.ApiKey = builder.Configuration["RemoteAppApiKey"]!;
    })
    .AddAuthenticationClient(true);

... 

app.MapReverseProxy();

Now, behavior changed. If handler.AllowAutoRedirect is false, then bar.com redirects to foo.com/account/login - I don't want to change domains. If handler.AllowAutoRedirect is true, then bar.com displays content of foo.com/account/login - domain is not changed, but path /account/login is not preserved.

What I am doing wrong?

my config is as simple as that:

 "ReverseProxy": {
    "Routes": {
      "route1": {
        "ClusterId": "fallbackCluster",
        "Match": {
          "Path": "{**catch-all}"
        }
      }
    },
    "Clusters": {
      "fallbackCluster": {
        "Destinations": {
          "fallbackApp": {
            "Address": "https://localhost:44311/"
          }
        }
      }
    }
  },

Solution

  • Adding Microsoft.AspNetCore.SystemWebAdapters.FrameworkServices to legacy .NET Framework project and following line in Application_Start fixed the behavior

    this.AddSystemWebAdapters()
        .AddProxySupport(options => options.UseForwardedHeaders = true);
    

    package also installs modules and handlers in web.config file

    <handlers>
      <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
      <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
    </handlers>
    
    <modules runAllManagedModulesForAllRequests="true">
      <remove name="SystemWebAdapterModule" />
      <add name="SystemWebAdapterModule" type="Microsoft.AspNetCore.SystemWebAdapters.SystemWebAdapterModule, Microsoft.AspNetCore.SystemWebAdapters.FrameworkServices" preCondition="managedHandler" />
    </modules>