Skip to content

Commit 40b66e7

Browse files
authored
Support SkipStatusCodePages on endpoints and authorized routes
1 parent 47b044e commit 40b66e7

File tree

8 files changed

+77
-2
lines changed

8 files changed

+77
-2
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
namespace Microsoft.AspNetCore.Http.Metadata;
5+
6+
/// <summary>
7+
/// Defines a contract used to specify metadata for skipping the StatusCodePage
8+
/// middleware in <see cref="Endpoint.Metadata"/>.
9+
/// </summary>
10+
public interface ISkipStatusCodePagesMetadata
11+
{
12+
/// <summary>
13+
/// Gets whether or not status code pages are enabled for an endpoint.
14+
/// </summary>
15+
bool Enabled { get; }
16+
}
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
#nullable enable
22
*REMOVED*abstract Microsoft.AspNetCore.Http.HttpResponse.ContentType.get -> string!
33
abstract Microsoft.AspNetCore.Http.HttpResponse.ContentType.get -> string?
4+
Microsoft.AspNetCore.Http.Metadata.ISkipStatusCodePagesMetadata
5+
Microsoft.AspNetCore.Http.Metadata.ISkipStatusCodePagesMetadata.Enabled.get -> bool

src/Middleware/Diagnostics/src/StatusCodePage/StatusCodePagesMiddleware.cs

+4-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System.Threading.Tasks;
66
using Microsoft.AspNetCore.Builder;
77
using Microsoft.AspNetCore.Http;
8+
using Microsoft.AspNetCore.Http.Metadata;
89
using Microsoft.Extensions.Options;
910

1011
namespace Microsoft.AspNetCore.Diagnostics;
@@ -41,10 +42,12 @@ public async Task Invoke(HttpContext context)
4142
{
4243
var statusCodeFeature = new StatusCodePagesFeature();
4344
context.Features.Set<IStatusCodePagesFeature>(statusCodeFeature);
45+
var endpoint = context.GetEndpoint();
46+
var statusCodeMetadata = endpoint?.Metadata.GetMetadata<ISkipStatusCodePagesMetadata>();
4447

4548
await _next(context);
4649

47-
if (!statusCodeFeature.Enabled)
50+
if (!statusCodeFeature.Enabled || statusCodeMetadata?.Enabled is false)
4851
{
4952
// Check if the feature is still available because other middleware (such as a web API written in MVC) could
5053
// have disabled the feature to prevent HTML status code responses from showing up to an API client.

src/Middleware/Diagnostics/test/UnitTests/Microsoft.AspNetCore.Diagnostics.Tests.csproj

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
<Reference Include="Microsoft.Extensions.DiagnosticAdapter" />
2121
<Reference Include="Microsoft.Extensions.FileProviders.Embedded" />
2222
<Reference Include="Microsoft.AspNetCore" />
23+
<Reference Include="Microsoft.AspNetCore.Mvc.ViewFeatures" />
2324
</ItemGroup>
2425

2526
</Project>

src/Middleware/Diagnostics/test/UnitTests/StatusCodeMiddlewareTest.cs

+35
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using Microsoft.AspNetCore.Builder;
99
using Microsoft.AspNetCore.Hosting;
1010
using Microsoft.AspNetCore.Http;
11+
using Microsoft.AspNetCore.Mvc;
1112
using Microsoft.AspNetCore.TestHost;
1213
using Microsoft.Extensions.DependencyInjection;
1314
using Microsoft.Extensions.Hosting;
@@ -283,4 +284,38 @@ public async Task Reexecute_WorksAfterUseRoutingWithGlobalRouteBuilder()
283284
var content = await response.Content.ReadAsStringAsync();
284285
Assert.Equal("errorPage", content);
285286
}
287+
288+
[Fact]
289+
public async Task SkipStatusCodePages_SupportsEndpoints()
290+
{
291+
var builder = WebApplication.CreateBuilder();
292+
builder.WebHost.UseTestServer();
293+
await using var app = builder.Build();
294+
295+
app.UseRouting();
296+
297+
app.UseStatusCodePages();
298+
299+
app.UseEndpoints(endpoints =>
300+
{
301+
endpoints.MapGet("/", [SkipStatusCodePages] (c) =>
302+
{
303+
c.Response.StatusCode = 404;
304+
return Task.CompletedTask;
305+
});
306+
});
307+
308+
app.Run((context) =>
309+
{
310+
throw new InvalidOperationException("Invalid input provided.");
311+
});
312+
313+
await app.StartAsync();
314+
315+
using var server = app.GetTestServer();
316+
var client = server.CreateClient();
317+
var response = await client.GetAsync("/");
318+
var content = await response.Content.ReadAsStringAsync();
319+
Assert.Empty(content);
320+
}
286321
}
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
#nullable enable
2+
Microsoft.AspNetCore.Mvc.SkipStatusCodePagesAttribute.Enabled.get -> bool

src/Mvc/Mvc.ViewFeatures/src/SkipStatusCodePagesAttribute.cs

+14-1
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,25 @@
44
using System;
55
using Microsoft.AspNetCore.Diagnostics;
66
using Microsoft.AspNetCore.Mvc.Filters;
7+
using Microsoft.AspNetCore.Http.Metadata;
78

89
namespace Microsoft.AspNetCore.Mvc;
910

1011
/// <summary>
1112
/// A filter that prevents execution of the StatusCodePages middleware.
1213
/// </summary>
1314
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
14-
public class SkipStatusCodePagesAttribute : Attribute, IResourceFilter
15+
public class SkipStatusCodePagesAttribute : Attribute, IResourceFilter, ISkipStatusCodePagesMetadata
1516
{
17+
/// <summary>
18+
/// Initializes a new instace of <see cref="SkipStatusCodePagesAttribute" />
19+
/// with <see cref="ISkipStatusCodePagesMetadata.Enabled" /> set to <lang ref="false" />.
20+
/// </summary>
21+
public SkipStatusCodePagesAttribute()
22+
{
23+
Enabled = false;
24+
}
25+
1626
/// <inheritdoc />
1727
public void OnResourceExecuted(ResourceExecutedContext context)
1828
{
@@ -33,4 +43,7 @@ public void OnResourceExecuting(ResourceExecutingContext context)
3343
statusCodeFeature.Enabled = false;
3444
}
3545
}
46+
47+
/// <inheritdoc />
48+
public bool Enabled { get; }
3649
}

src/Mvc/Mvc.ViewFeatures/test/SkipStatusCodePagesAttributeTest.cs

+4
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ public void SkipStatusCodePagesAttribute_TurnsOfStatusCodePages()
2828

2929
// Assert
3030
Assert.False(statusCodePagesFeature.Enabled);
31+
Assert.False(skipStatusCodeAttribute.Enabled);
3132
}
3233

3334
[Fact]
@@ -39,6 +40,9 @@ public void SkipStatusCodePagesAttribute_Does_Not_Throw_If_Feature_Missing()
3940

4041
// Act
4142
skipStatusCodeAttribute.OnResourceExecuting(resourceExecutingContext);
43+
44+
// Assert
45+
Assert.False(skipStatusCodeAttribute.Enabled);
4246
}
4347

4448
private static ResourceExecutingContext CreateResourceExecutingContext(IFilterMetadata[] filters)

0 commit comments

Comments
 (0)