forked from dotnet/yarp
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathProgram.cs
More file actions
108 lines (93 loc) · 3.77 KB
/
Program.cs
File metadata and controls
108 lines (93 loc) · 3.77 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Collections.Generic;
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Yarp.ReverseProxy.Configuration;
using Microsoft.AspNetCore.Http;
using Yarp.ReverseProxy.Model;
const string DEBUG_HEADER = "Debug";
const string DEBUG_METADATA_KEY = "debug";
const string DEBUG_VALUE = "true";
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddReverseProxy()
.LoadFromMemory(GetRoutes(), GetClusters());
var app = builder.Build();
app.Map("/update", context =>
{
context.RequestServices.GetRequiredService<InMemoryConfigProvider>().Update(GetRoutes(), GetClusters());
return Task.CompletedTask;
});
// We can customize the proxy pipeline and add/remove/replace steps
app.MapReverseProxy(proxyPipeline =>
{
// Use a custom proxy middleware, defined below
proxyPipeline.Use(MyCustomProxyStep);
// Don't forget to include these two middleware when you make a custom proxy pipeline (if you need them).
proxyPipeline.UseSessionAffinity();
proxyPipeline.UseLoadBalancing();
});
app.Run();
RouteConfig[] GetRoutes()
{
return
[
new RouteConfig()
{
RouteId = "route" + Random.Shared.Next(), // Forces a new route id each time GetRoutes is called.
ClusterId = "cluster1",
Match = new RouteMatch
{
// Path or Hosts are required for each route. This catch-all pattern matches all request paths.
Path = "{**catch-all}"
}
}
];
}
ClusterConfig[] GetClusters()
{
var debugMetadata = new Dictionary<string, string>
{
{ DEBUG_METADATA_KEY, DEBUG_VALUE }
};
return
[
new ClusterConfig()
{
ClusterId = "cluster1",
SessionAffinity = new SessionAffinityConfig { Enabled = true, Policy = "Cookie", AffinityKeyName = ".Yarp.ReverseProxy.Affinity" },
Destinations = new Dictionary<string, DestinationConfig>(StringComparer.OrdinalIgnoreCase)
{
{ "destination1", new DestinationConfig() { Address = "https://example.com" } },
{ "debugdestination1", new DestinationConfig() {
Address = "https://bing.com",
Metadata = debugMetadata }
},
}
}
];
}
/// <summary>
/// Custom proxy step that filters destinations based on a header in the inbound request
/// Looks at each destination metadata, and filters in/out based on their debug flag and the inbound header
/// </summary>
Task MyCustomProxyStep(HttpContext context, Func<Task> next)
{
// Can read data from the request via the context
var useDebugDestinations = context.Request.Headers.TryGetValue(DEBUG_HEADER, out var headerValues) && headerValues.Count == 1 && headerValues[0] == DEBUG_VALUE;
// The context also stores a ReverseProxyFeature which holds proxy specific data such as the cluster, route and destinations
var availableDestinationsFeature = context.Features.Get<IReverseProxyFeature>();
var filteredDestinations = new List<DestinationState>();
// Filter destinations based on criteria
foreach (var d in availableDestinationsFeature.AvailableDestinations)
{
//Todo: Replace with a lookup of metadata - but not currently exposed correctly here
if (d.DestinationId.Contains("debug") == useDebugDestinations) { filteredDestinations.Add(d); }
}
availableDestinationsFeature.AvailableDestinations = filteredDestinations;
// Important - required to move to the next step in the proxy pipeline
return next();
}