diff --git a/samples/MvcSample.Web/HomeController.cs b/samples/MvcSample.Web/HomeController.cs
index 829b8f0b81..8eb7c19886 100644
--- a/samples/MvcSample.Web/HomeController.cs
+++ b/samples/MvcSample.Web/HomeController.cs
@@ -40,6 +40,7 @@ namespace MvcSample.Web
return View();
}
+ [SkipStatusCodePages]
public ActionResult NotFound()
{
return HttpNotFound();
diff --git a/samples/MvcSample.Web/Startup.cs b/samples/MvcSample.Web/Startup.cs
index 86be633d76..0382af244f 100644
--- a/samples/MvcSample.Web/Startup.cs
+++ b/samples/MvcSample.Web/Startup.cs
@@ -23,6 +23,8 @@ namespace MvcSample.Web
{
public void Configure(IApplicationBuilder app)
{
+ app.UseStatusCodePages();
+
app.UseFileServer();
#if ASPNET50
// Set up configuration sources.
@@ -129,4 +131,4 @@ namespace MvcSample.Web
});
}
}
-}
+}
\ No newline at end of file
diff --git a/samples/MvcSample.Web/project.json b/samples/MvcSample.Web/project.json
index 2e08841704..290162f75c 100644
--- a/samples/MvcSample.Web/project.json
+++ b/samples/MvcSample.Web/project.json
@@ -8,6 +8,7 @@
},
"dependencies": {
"Kestrel": "1.0.0-*",
+ "Microsoft.AspNet.Diagnostics": "1.0.0-*",
"Microsoft.AspNet.Mvc": "6.0.0-*",
"Microsoft.AspNet.Mvc.Xml": "6.0.0-*",
"Microsoft.AspNet.Mvc.WebApiCompatShim": "6.0.0-*",
@@ -27,4 +28,4 @@
}
},
"webroot": "wwwroot"
-}
+}
\ No newline at end of file
diff --git a/src/Microsoft.AspNet.Mvc.Core/Filters/SkipStatusCodePagesAttribute.cs b/src/Microsoft.AspNet.Mvc.Core/Filters/SkipStatusCodePagesAttribute.cs
new file mode 100644
index 0000000000..6a1102550a
--- /dev/null
+++ b/src/Microsoft.AspNet.Mvc.Core/Filters/SkipStatusCodePagesAttribute.cs
@@ -0,0 +1,26 @@
+// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using Microsoft.AspNet.Diagnostics;
+
+namespace Microsoft.AspNet.Mvc
+{
+ ///
+ /// Filter to prevent StatusCodePages middleware to handle responses.
+ ///
+ public class SkipStatusCodePagesAttribute : ResultFilterAttribute
+ {
+ ///
+ public override void OnResultExecuted(ResultExecutedContext context)
+ {
+ var statusCodeFeature = context.HttpContext.GetFeature();
+ if (statusCodeFeature != null)
+ {
+ // Turn off the StatusCodePages feature.
+ statusCodeFeature.Enabled = false;
+ }
+
+ base.OnResultExecuted(context);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Microsoft.AspNet.Mvc.Core/project.json b/src/Microsoft.AspNet.Mvc.Core/project.json
index 62a11a8886..5dabe0883b 100644
--- a/src/Microsoft.AspNet.Mvc.Core/project.json
+++ b/src/Microsoft.AspNet.Mvc.Core/project.json
@@ -5,6 +5,7 @@
"warningsAsErrors": true
},
"dependencies": {
+ "Microsoft.AspNet.Diagnostics.Interfaces": "1.0.0-*",
"Microsoft.AspNet.FileProviders": "1.0.0-*",
"Microsoft.AspNet.Hosting": "1.0.0-*",
"Microsoft.AspNet.Http.Extensions": "1.0.0-*",
diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/Filters/SkipStatusCodePagesAttributeTest.cs b/test/Microsoft.AspNet.Mvc.Core.Test/Filters/SkipStatusCodePagesAttributeTest.cs
new file mode 100644
index 0000000000..5266a1eac8
--- /dev/null
+++ b/test/Microsoft.AspNet.Mvc.Core.Test/Filters/SkipStatusCodePagesAttributeTest.cs
@@ -0,0 +1,64 @@
+// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using Microsoft.AspNet.Diagnostics;
+using Microsoft.AspNet.Http.Core;
+using Microsoft.AspNet.Routing;
+using Xunit;
+
+namespace Microsoft.AspNet.Mvc.Core.Test
+{
+ public class SkipStatusCodePagesAttributeTest
+ {
+ [Fact]
+ public void SkipStatusCodePagesAttribute_TurnsOfStatusCodePages()
+ {
+ // Arrange
+ var skipStatusCodeAttribute = new SkipStatusCodePagesAttribute();
+ var resultExecutingContext = CreateResultExecutingContext(new IFilter[] { skipStatusCodeAttribute });
+ var statusCodePagesFeature = new TestStatusCodeFeature();
+ resultExecutingContext.HttpContext.SetFeature(statusCodePagesFeature);
+
+ // Act
+ skipStatusCodeAttribute.OnResultExecuted(CreateResultExecutedContext(resultExecutingContext));
+
+ // Assert
+ Assert.False(statusCodePagesFeature.Enabled);
+ }
+
+ [Fact]
+ public void SkipStatusCodePagesAttribute_Does_Not_Throw_If_Feature_Missing()
+ {
+ // Arrange
+ var skipStatusCodeAttribute = new SkipStatusCodePagesAttribute();
+ var resultExecutingContext = CreateResultExecutingContext(new IFilter[] { skipStatusCodeAttribute });
+
+ // Act
+ skipStatusCodeAttribute.OnResultExecuted(CreateResultExecutedContext(resultExecutingContext));
+ }
+
+ private static ResultExecutedContext CreateResultExecutedContext(ResultExecutingContext context)
+ {
+ return new ResultExecutedContext(context, context.Filters, context.Result, context.Controller);
+ }
+
+ private static ResultExecutingContext CreateResultExecutingContext(IFilter[] filters)
+ {
+ return new ResultExecutingContext(
+ CreateActionContext(),
+ filters,
+ new ObjectResult("Some Value"),
+ controller: new object());
+ }
+
+ private static ActionContext CreateActionContext()
+ {
+ return new ActionContext(new DefaultHttpContext(), new RouteData(), new ActionDescriptor());
+ }
+
+ private class TestStatusCodeFeature : IStatusCodePagesFeature
+ {
+ public bool Enabled { get; set; } = true;
+ }
+ }
+}
\ No newline at end of file