Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,15 @@

namespace Boilerplate.Server.Api.Services;

/// <summary>
/// An implementation of this interface can update how the current request is cached.
/// </summary>
public class AppResponseCachePolicy(IHostEnvironment env) : IOutputCachePolicy
{
/// <summary>
/// Updates the <see cref="OutputCacheContext"/> before the cache middleware is invoked.
/// At that point the cache middleware can still be enabled or disabled for the request.
/// </summary>
public async ValueTask CacheRequestAsync(OutputCacheContext context, CancellationToken cancellation)
{
var responseCacheAtt = context.HttpContext.GetResponseCacheAttribute();
Expand Down Expand Up @@ -35,6 +42,7 @@ public async ValueTask CacheRequestAsync(OutputCacheContext context, Cancellatio
if (env.IsDevelopment())
{
// To enhance the developer experience, return from here to make it easier for developers to debug cacheable responses.
edgeCacheTtl = -1;
outputCacheTtl = -1;
browserCacheTtl = -1;
}
Expand Down Expand Up @@ -76,22 +84,33 @@ public async ValueTask CacheRequestAsync(OutputCacheContext context, Cancellatio
}

// ASP.NET Core Output Cache
if (outputCacheTtl != -1)
if (outputCacheTtl > 0)
{
context.Tags.Add(requestUrl);
context.AllowCacheLookup = true;
context.AllowCacheStorage = true;
context.ResponseExpirationTimeSpan = TimeSpan.FromSeconds(outputCacheTtl);
}

//#if (api == "Integrated")
context.HttpContext.Items["AppResponseCachePolicy__DisableStreamPrerendering"] = outputCacheTtl > 0 || edgeCacheTtl > 0;
//#endif
context.HttpContext.Response.Headers.TryAdd("App-Cache-Response", FormattableString.Invariant($"Output:{outputCacheTtl},Edge:{edgeCacheTtl},Browser:{browserCacheTtl}"));
}

/// <summary>
/// Updates the <see cref="OutputCacheContext"/> before the cached response is used.
/// At that point the freshness of the cached response can be updated.
/// </summary>
public async ValueTask ServeFromCacheAsync(OutputCacheContext context, CancellationToken cancellation)
{

}

/// <summary>
/// Updates the <see cref="OutputCacheContext"/> before the response is served and can be cached.
/// At that point cacheability of the response can be updated.
/// </summary>
public async ValueTask ServeResponseAsync(OutputCacheContext context, CancellationToken cancellation)
{
var response = context.HttpContext.Response;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@
<LoadingComponent @rendermode="null" />
}

@if (HttpContext.Request.IsCrawlerClient())
@if (HttpContext.Request.DisableStreamPrerendering())
{
// For StreamRenderingDisabledContainer, read comments in App.razor.cs
<StreamRenderingDisabledContainer>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,14 @@ public static Uri GetUri(this HttpRequest request)
return new Uri($"{request.Scheme}://{((!request.Host.HasValue) ? "UNKNOWN-HOST" : ((request.Host.Value.IndexOf(',') > 0) ? "MULTIPLE-HOST" : request.Host.Value))}{(request.PathBase.HasValue ? request.PathBase.Value : string.Empty)}{(request.Path.HasValue ? request.Path.Value : string.Empty)}{(request.QueryString.HasValue ? request.QueryString.Value : string.Empty)}");
}

public static bool DisableStreamPrerendering(this HttpRequest request)
{
if (request.HttpContext.Items.TryGetValue("AppResponseCachePolicy__DisableStreamPrerendering", out var val) && val is true)
return true; // The response from streaming pre-rendering is not suitable for caching in ASP.NET Core's output caching mechanism or on CDN edge servers.

return request.IsCrawlerClient();
}

public static bool IsCrawlerClient(this HttpRequest request)
{
var agent = GetLoweredUserAgent(request);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,8 @@ private static void UseSiteMap(this WebApplication app)

var baseUrl = context.Request.GetBaseUrl();

context.Response.Headers.ContentType = "application/xml";

await context.Response.WriteAsync(string.Format(SITEMAP_INDEX_FORMAT, baseUrl), context.RequestAborted);
}).CacheOutput("AppResponseCachePolicy").WithTags("Sitemaps");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,15 @@

namespace Boilerplate.Server.Web.Services;

/// <summary>
/// An implementation of this interface can update how the current request is cached.
/// </summary>
public class AppResponseCachePolicy(IHostEnvironment env) : IOutputCachePolicy
{
/// <summary>
/// Updates the <see cref="OutputCacheContext"/> before the cache middleware is invoked.
/// At that point the cache middleware can still be enabled or disabled for the request.
/// </summary>
public async ValueTask CacheRequestAsync(OutputCacheContext context, CancellationToken cancellation)
{
var responseCacheAtt = context.HttpContext.GetResponseCacheAttribute();
Expand Down Expand Up @@ -35,6 +42,7 @@ public async ValueTask CacheRequestAsync(OutputCacheContext context, Cancellatio
if (env.IsDevelopment())
{
// To enhance the developer experience, return from here to make it easier for developers to debug cacheable responses.
edgeCacheTtl = -1;
outputCacheTtl = -1;
browserCacheTtl = -1;
}
Expand Down Expand Up @@ -74,22 +82,31 @@ public async ValueTask CacheRequestAsync(OutputCacheContext context, Cancellatio
}

// ASP.NET Core Output Cache
if (outputCacheTtl != -1)
if (outputCacheTtl > 0)
{
context.Tags.Add(requestUrl);
context.AllowCacheLookup = true;
context.AllowCacheStorage = true;
context.ResponseExpirationTimeSpan = TimeSpan.FromSeconds(outputCacheTtl);
}

context.HttpContext.Items["AppResponseCachePolicy__DisableStreamPrerendering"] = outputCacheTtl > 0 || edgeCacheTtl > 0;
context.HttpContext.Response.Headers.TryAdd("App-Cache-Response", FormattableString.Invariant($"Output:{outputCacheTtl},Edge:{edgeCacheTtl},Browser:{browserCacheTtl}"));
}

/// <summary>
/// Updates the <see cref="OutputCacheContext"/> before the cached response is used.
/// At that point the freshness of the cached response can be updated.
/// </summary>
public async ValueTask ServeFromCacheAsync(OutputCacheContext context, CancellationToken cancellation)
{

}

/// <summary>
/// Updates the <see cref="OutputCacheContext"/> before the response is served and can be cached.
/// At that point cacheability of the response can be updated.
/// </summary>
public async ValueTask ServeResponseAsync(OutputCacheContext context, CancellationToken cancellation)
{
var response = context.HttpContext.Response;
Expand Down
Loading