-
Notifications
You must be signed in to change notification settings - Fork 838
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add OutputCachePolicy support (#2328)
- Loading branch information
1 parent
c664310
commit 3853af1
Showing
13 changed files
with
252 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
# Output Caching | ||
|
||
## Introduction | ||
The reverse proxy can be used to cache proxied responses and serve requests before they are proxied to the destination servers. This can reduce load on the destination servers, add a layer of protection, and ensure consistent policies are implemented across your applications. | ||
|
||
> This feature is only available when using .NET 7.0 or later | ||
## Defaults | ||
|
||
No output caching is performed unless enabled in the route or application configuration. | ||
|
||
## Configuration | ||
Output Cache policies can be specified per route via [RouteConfig.OutputCachePolicy](xref:Yarp.ReverseProxy.Configuration.RouteConfig) and can be bound from the `Routes` sections of the config file. As with other route properties, this can be modified and reloaded without restarting the proxy. Policy names are case insensitive. | ||
|
||
Example: | ||
```JSON | ||
{ | ||
"ReverseProxy": { | ||
"Routes": { | ||
"route1" : { | ||
"ClusterId": "cluster1", | ||
"OutputCachePolicy": "customPolicy", | ||
"Match": { | ||
"Hosts": [ "localhost" ] | ||
} | ||
} | ||
}, | ||
"Clusters": { | ||
"cluster1": { | ||
"Destinations": { | ||
"cluster1/destination1": { | ||
"Address": "https://localhost:10001/" | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
``` | ||
|
||
[Output cache policies](https://learn.microsoft.com/aspnet/core/performance/caching/output) are an ASP.NET Core concept that the proxy utilizes. The proxy provides the above configuration to specify a policy per route and the rest is handled by existing ASP.NET Core output caching middleware. | ||
|
||
Output cache policies can be configured in Program.cs as follows: | ||
```c# | ||
var builder = WebApplication.CreateBuilder(args); | ||
|
||
builder.Services.AddOutputCache(options => | ||
{ | ||
options.AddPolicy("customPolicy", builder => builder.Expire(TimeSpan.FromSeconds(20))); | ||
}); | ||
``` | ||
|
||
Then add the output caching middleware: | ||
|
||
```c# | ||
var app = builder.Build(); | ||
|
||
app.UseOutputCache(); | ||
|
||
app.MapReverseProxy(); | ||
``` | ||
|
||
See the [Output Caching](https://learn.microsoft.com/aspnet/core/performance/caching/output) docs for setting up your preferred kind of output caching. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
55 changes: 55 additions & 0 deletions
55
src/ReverseProxy/Configuration/IYarpOutputCachePolicyProvider.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
// Copyright (c) Microsoft Corporation. | ||
// Licensed under the MIT License. | ||
|
||
#if NET7_0_OR_GREATER | ||
using System; | ||
using System.Collections; | ||
using System.Reflection; | ||
using Microsoft.AspNetCore.OutputCaching; | ||
using Microsoft.Extensions.Options; | ||
#endif | ||
|
||
using System.Collections.Generic; | ||
using System.Threading.Tasks; | ||
|
||
namespace Yarp.ReverseProxy.Configuration; | ||
|
||
// TODO: update or remove this once AspNetCore provides a mechanism to validate the OutputCache policies https://github.com/dotnet/aspnetcore/issues/52419 | ||
|
||
internal interface IYarpOutputCachePolicyProvider | ||
{ | ||
ValueTask<object?> GetPolicyAsync(string policyName); | ||
} | ||
|
||
internal class YarpOutputCachePolicyProvider : IYarpOutputCachePolicyProvider | ||
{ | ||
#if NET7_0_OR_GREATER | ||
private readonly OutputCacheOptions _outputCacheOptions; | ||
|
||
private readonly IDictionary _policyMap; | ||
|
||
public YarpOutputCachePolicyProvider(IOptions<OutputCacheOptions> outputCacheOptions) | ||
{ | ||
_outputCacheOptions = outputCacheOptions?.Value ?? throw new ArgumentNullException(nameof(outputCacheOptions)); | ||
|
||
var type = typeof(OutputCacheOptions); | ||
var flags = BindingFlags.Instance | BindingFlags.NonPublic; | ||
var proprety = type.GetProperty("NamedPolicies", flags); | ||
if (proprety == null || !typeof(IDictionary).IsAssignableFrom(proprety.PropertyType)) | ||
{ | ||
throw new NotSupportedException("This version of YARP is incompatible with the current version of ASP.NET Core."); | ||
} | ||
_policyMap = (proprety.GetValue(_outputCacheOptions, null) as IDictionary) ?? new Dictionary<string, object>(); | ||
} | ||
|
||
public ValueTask<object?> GetPolicyAsync(string policyName) | ||
{ | ||
return ValueTask.FromResult(_policyMap[policyName]); | ||
} | ||
#else | ||
public ValueTask<object?> GetPolicyAsync(string policyName) | ||
{ | ||
return default; | ||
} | ||
#endif | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
45 changes: 45 additions & 0 deletions
45
src/ReverseProxy/Configuration/RouteValidators/OutputCachePolicyValidator.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Threading.Tasks; | ||
|
||
namespace Yarp.ReverseProxy.Configuration.RouteValidators; | ||
|
||
internal sealed class OutputCachePolicyValidator : IRouteValidator | ||
{ | ||
#if NET7_0_OR_GREATER | ||
private readonly IYarpOutputCachePolicyProvider _outputCachePolicyProvider; | ||
public OutputCachePolicyValidator(IYarpOutputCachePolicyProvider outputCachePolicyProvider) | ||
{ | ||
_outputCachePolicyProvider = outputCachePolicyProvider; | ||
} | ||
|
||
public async ValueTask ValidateAsync(RouteConfig routeConfig, IList<Exception> errors) | ||
{ | ||
var outputCachePolicyName = routeConfig.OutputCachePolicy; | ||
|
||
if (string.IsNullOrEmpty(outputCachePolicyName)) | ||
{ | ||
return; | ||
} | ||
|
||
try | ||
{ | ||
var policy = await _outputCachePolicyProvider.GetPolicyAsync(outputCachePolicyName); | ||
|
||
if (policy is null) | ||
{ | ||
errors.Add(new ArgumentException( | ||
$"OutputCache policy '{outputCachePolicyName}' not found for route '{routeConfig.RouteId}'.")); | ||
} | ||
} | ||
catch (Exception ex) | ||
{ | ||
errors.Add(new ArgumentException( | ||
$"Unable to retrieve the OutputCache policy '{outputCachePolicyName}' for route '{routeConfig.RouteId}'.", | ||
ex)); | ||
} | ||
} | ||
#else | ||
public ValueTask ValidateAsync(RouteConfig routeConfig, IList<Exception> errors) => ValueTask.CompletedTask; | ||
#endif | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.