From f2432449725fa0d5743119a2d56c3061b287562a Mon Sep 17 00:00:00 2001 From: Praburaj Date: Wed, 11 Feb 2015 10:13:16 -0800 Subject: [PATCH] Adding ability to turn off the status code pages Added a feature named IStatusCodeFeature with an enabled property. MVC or any framework can get this feature and turn it off if it does not want status code pages logic to take over and send HTML response. Also refactored the sample flow to make it easier to understand. --- DiagnosticsPages.sln | 17 ++++- samples/StatusCodePagesSample/Startup.cs | 72 ++++++++++++------- .../project.json | 3 +- .../Compilation/ICompilationException.cs | 2 - .../Compilation/ICompilationFailure.cs | 2 - .../Compilation/ICompilationMessage.cs | 3 - .../IErrorHandlerFeature.cs | 2 - .../IStatusCodePagesFeature.cs | 16 +++++ .../IStatusCodeReExecuteFeature.cs | 3 - ...rosoft.AspNet.Diagnostics.Interfaces.kproj | 20 ++++++ .../project.json | 13 ++++ .../StatusCodePagesFeature.cs | 13 ++++ .../StatusCodePagesMiddleware.cs | 12 +++- src/Microsoft.AspNet.Diagnostics/project.json | 8 +-- 14 files changed, 141 insertions(+), 45 deletions(-) rename src/{Microsoft.AspNet.Diagnostics => Microsoft.AspNet.Diagnostics.Interfaces}/Compilation/ICompilationException.cs (91%) rename src/{Microsoft.AspNet.Diagnostics => Microsoft.AspNet.Diagnostics.Interfaces}/Compilation/ICompilationFailure.cs (95%) rename src/{Microsoft.AspNet.Diagnostics => Microsoft.AspNet.Diagnostics.Interfaces}/Compilation/ICompilationMessage.cs (95%) rename src/{Microsoft.AspNet.Diagnostics => Microsoft.AspNet.Diagnostics.Interfaces}/IErrorHandlerFeature.cs (85%) create mode 100644 src/Microsoft.AspNet.Diagnostics.Interfaces/IStatusCodePagesFeature.cs rename src/{Microsoft.AspNet.Diagnostics => Microsoft.AspNet.Diagnostics.Interfaces}/IStatusCodeReExecuteFeature.cs (86%) create mode 100644 src/Microsoft.AspNet.Diagnostics.Interfaces/Microsoft.AspNet.Diagnostics.Interfaces.kproj create mode 100644 src/Microsoft.AspNet.Diagnostics.Interfaces/project.json create mode 100644 src/Microsoft.AspNet.Diagnostics/StatusCodePagesFeature.cs diff --git a/DiagnosticsPages.sln b/DiagnosticsPages.sln index a04d598db8..28c91bf29d 100644 --- a/DiagnosticsPages.sln +++ b/DiagnosticsPages.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 -VisualStudioVersion = 14.0.22228.1 +VisualStudioVersion = 14.0.22530.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{509A6F36-AD80-4A18-B5B1-717D38DFF29D}" EndProject @@ -38,6 +38,8 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Diagnostic EndProject Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "StatusCodePagesSample", "samples\StatusCodePagesSample\StatusCodePagesSample.kproj", "{CC1F5841-FE10-4DDB-8477-C4DE92BA759F}" EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Diagnostics.Interfaces", "src\Microsoft.AspNet.Diagnostics.Interfaces\Microsoft.AspNet.Diagnostics.Interfaces.kproj", "{83FFB65A-97B1-45AA-BCB8-3F43966BC8A3}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -178,6 +180,18 @@ Global {CC1F5841-FE10-4DDB-8477-C4DE92BA759F}.Release|Mixed Platforms.Build.0 = Release|Any CPU {CC1F5841-FE10-4DDB-8477-C4DE92BA759F}.Release|x86.ActiveCfg = Release|Any CPU {CC1F5841-FE10-4DDB-8477-C4DE92BA759F}.Release|x86.Build.0 = Release|Any CPU + {83FFB65A-97B1-45AA-BCB8-3F43966BC8A3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {83FFB65A-97B1-45AA-BCB8-3F43966BC8A3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {83FFB65A-97B1-45AA-BCB8-3F43966BC8A3}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {83FFB65A-97B1-45AA-BCB8-3F43966BC8A3}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {83FFB65A-97B1-45AA-BCB8-3F43966BC8A3}.Debug|x86.ActiveCfg = Debug|Any CPU + {83FFB65A-97B1-45AA-BCB8-3F43966BC8A3}.Debug|x86.Build.0 = Debug|Any CPU + {83FFB65A-97B1-45AA-BCB8-3F43966BC8A3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {83FFB65A-97B1-45AA-BCB8-3F43966BC8A3}.Release|Any CPU.Build.0 = Release|Any CPU + {83FFB65A-97B1-45AA-BCB8-3F43966BC8A3}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {83FFB65A-97B1-45AA-BCB8-3F43966BC8A3}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {83FFB65A-97B1-45AA-BCB8-3F43966BC8A3}.Release|x86.ActiveCfg = Release|Any CPU + {83FFB65A-97B1-45AA-BCB8-3F43966BC8A3}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -195,5 +209,6 @@ Global {2F9B479D-8247-4210-804B-78E6DD5C3E98} = {2AF90579-B118-4583-AE88-672EFACB5BC4} {624B0019-956A-4157-B008-270C5B229553} = {509A6F36-AD80-4A18-B5B1-717D38DFF29D} {CC1F5841-FE10-4DDB-8477-C4DE92BA759F} = {ACAA0157-A8C4-4152-93DE-90CCDF304087} + {83FFB65A-97B1-45AA-BCB8-3F43966BC8A3} = {509A6F36-AD80-4A18-B5B1-717D38DFF29D} EndGlobalSection EndGlobal diff --git a/samples/StatusCodePagesSample/Startup.cs b/samples/StatusCodePagesSample/Startup.cs index 04e7cb71c8..bf5ccb4668 100644 --- a/samples/StatusCodePagesSample/Startup.cs +++ b/samples/StatusCodePagesSample/Startup.cs @@ -1,6 +1,7 @@ // 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 System.Linq; using System.Net; using System.Text; using System.Threading.Tasks; @@ -25,54 +26,75 @@ namespace StatusCodePagesSample // app.UseStatusCodePagesWithReExecute("/errors/{0}"); // "/[?statuscode=400]" - app.Use((context, next) => + app.Use(async (context, next) => { - if (context.Request.Path.HasValue && !context.Request.Path.Equals(new PathString("/"))) - { - return next(); - } - // Check for ?statuscode=400 var requestedStatusCode = context.Request.Query["statuscode"]; if (!string.IsNullOrEmpty(requestedStatusCode)) { context.Response.StatusCode = int.Parse(requestedStatusCode); - return Task.FromResult(0); + + // To turn off the StatusCode feature - For example the below code turns off the StatusCode middleware + // if the query contains a disableStatusCodePages=true parameter. + var disableStatusCodePages = context.Request.Query["disableStatusCodePages"]; + if (disableStatusCodePages == "true") + { + var statusCodePagesFeature = context.GetFeature(); + if (statusCodePagesFeature != null) + { + statusCodePagesFeature.Enabled = false; + } + } + + await Task.FromResult(0); } - - var builder = new StringBuilder(); - builder.AppendLine(""); - builder.AppendLine("" + - WebUtility.HtmlEncode(context.Request.PathBase.ToString()) + "/missingpage/
"); - - for (int statusCode = 400; statusCode < 600; statusCode++) + else { - builder.AppendLine("" + statusCode + "
"); + await next(); } - builder.AppendLine(""); - return context.Response.SendAsync(builder.ToString(), "text/html"); }); // "/errors/400" - app.Use((context, next) => + app.Map("/errors", error => { - PathString remainder; - if (context.Request.Path.StartsWithSegments(new PathString("/errors"), out remainder)) + error.Run(async context => { var builder = new StringBuilder(); builder.AppendLine(""); - builder.AppendLine("An error occurred, Status Code: " + WebUtility.HtmlEncode(remainder.ToString().Substring(1)) + "
"); + builder.AppendLine("An error occurred, Status Code: " + WebUtility.HtmlEncode(context.Request.Path.ToString().Substring(1)) + "
"); var referrer = context.Request.Headers["referer"]; if (!string.IsNullOrEmpty(referrer)) { builder.AppendLine("Retry " + WebUtility.HtmlEncode(referrer) + "
"); } builder.AppendLine(""); - return context.Response.SendAsync(builder.ToString(), "text/html"); + await context.Response.SendAsync(builder.ToString(), "text/html"); + }); + }); + + app.Run(async context => + { + // Generates the HTML with all status codes. + var builder = new StringBuilder(); + builder.AppendLine(""); + builder.AppendLine("" + + WebUtility.HtmlEncode(context.Request.PathBase.ToString()) + "/missingpage/
"); + + var space = string.Concat(Enumerable.Repeat(" ", 12)); + builder.AppendFormat("
{0}{1}{2}
", "Status Code", space, "Status Code Pages"); + for (int statusCode = 400; statusCode < 600; statusCode++) + { + builder.AppendFormat("{0}{1}{2}{3}
", + statusCode, + space + space, + string.Format("[Enabled]{1}", statusCode, space), + string.Format("[Disabled]{1}", statusCode, space)); } - return next(); + + builder.AppendLine(""); + await context.Response.SendAsync(builder.ToString(), "text/html"); }); } } -} +} \ No newline at end of file diff --git a/src/Microsoft.AspNet.Diagnostics.Elm/project.json b/src/Microsoft.AspNet.Diagnostics.Elm/project.json index 4d832c4969..5c7d1770e0 100644 --- a/src/Microsoft.AspNet.Diagnostics.Elm/project.json +++ b/src/Microsoft.AspNet.Diagnostics.Elm/project.json @@ -2,8 +2,7 @@ "version": "1.0.0-*", "dependencies": { "Microsoft.AspNet.Diagnostics": "1.0.0-*", - "Microsoft.Framework.Logging.Interfaces": { "version": "1.0.0-*", "type": "build" }, - "Microsoft.Framework.Runtime.Interfaces": { "version": "1.0.0-*", "type": "build" } + "Microsoft.Framework.Logging.Interfaces": "1.0.0-*" }, "frameworks": { diff --git a/src/Microsoft.AspNet.Diagnostics/Compilation/ICompilationException.cs b/src/Microsoft.AspNet.Diagnostics.Interfaces/Compilation/ICompilationException.cs similarity index 91% rename from src/Microsoft.AspNet.Diagnostics/Compilation/ICompilationException.cs rename to src/Microsoft.AspNet.Diagnostics.Interfaces/Compilation/ICompilationException.cs index ba9102a35b..31e9a01347 100644 --- a/src/Microsoft.AspNet.Diagnostics/Compilation/ICompilationException.cs +++ b/src/Microsoft.AspNet.Diagnostics.Interfaces/Compilation/ICompilationException.cs @@ -2,14 +2,12 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Collections.Generic; -using Microsoft.Framework.Runtime; namespace Microsoft.AspNet.Diagnostics { /// /// Specifies the contract for an exception representing compilation failure. /// - [AssemblyNeutral] public interface ICompilationException { /// diff --git a/src/Microsoft.AspNet.Diagnostics/Compilation/ICompilationFailure.cs b/src/Microsoft.AspNet.Diagnostics.Interfaces/Compilation/ICompilationFailure.cs similarity index 95% rename from src/Microsoft.AspNet.Diagnostics/Compilation/ICompilationFailure.cs rename to src/Microsoft.AspNet.Diagnostics.Interfaces/Compilation/ICompilationFailure.cs index bf16458fc6..ede7bcd270 100644 --- a/src/Microsoft.AspNet.Diagnostics/Compilation/ICompilationFailure.cs +++ b/src/Microsoft.AspNet.Diagnostics.Interfaces/Compilation/ICompilationFailure.cs @@ -2,14 +2,12 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Collections.Generic; -using Microsoft.Framework.Runtime; namespace Microsoft.AspNet.Diagnostics { /// /// Specifies the contract for a file that fails compilation. /// - [AssemblyNeutral] public interface ICompilationFailure { /// diff --git a/src/Microsoft.AspNet.Diagnostics/Compilation/ICompilationMessage.cs b/src/Microsoft.AspNet.Diagnostics.Interfaces/Compilation/ICompilationMessage.cs similarity index 95% rename from src/Microsoft.AspNet.Diagnostics/Compilation/ICompilationMessage.cs rename to src/Microsoft.AspNet.Diagnostics.Interfaces/Compilation/ICompilationMessage.cs index ed3ca5fed8..237dcd2332 100644 --- a/src/Microsoft.AspNet.Diagnostics/Compilation/ICompilationMessage.cs +++ b/src/Microsoft.AspNet.Diagnostics.Interfaces/Compilation/ICompilationMessage.cs @@ -1,15 +1,12 @@ // 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.Framework.Runtime; - namespace Microsoft.AspNet.Diagnostics { /// /// Specifies the contract for diagnostic messages produced as result of compiling an instance /// of . /// - [AssemblyNeutral] public interface ICompilationMessage { /// diff --git a/src/Microsoft.AspNet.Diagnostics/IErrorHandlerFeature.cs b/src/Microsoft.AspNet.Diagnostics.Interfaces/IErrorHandlerFeature.cs similarity index 85% rename from src/Microsoft.AspNet.Diagnostics/IErrorHandlerFeature.cs rename to src/Microsoft.AspNet.Diagnostics.Interfaces/IErrorHandlerFeature.cs index b53949b2a9..a231a3585c 100644 --- a/src/Microsoft.AspNet.Diagnostics/IErrorHandlerFeature.cs +++ b/src/Microsoft.AspNet.Diagnostics.Interfaces/IErrorHandlerFeature.cs @@ -2,11 +2,9 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using Microsoft.Framework.Runtime; namespace Microsoft.AspNet.Diagnostics { - [AssemblyNeutral] public interface IErrorHandlerFeature { Exception Error { get; } diff --git a/src/Microsoft.AspNet.Diagnostics.Interfaces/IStatusCodePagesFeature.cs b/src/Microsoft.AspNet.Diagnostics.Interfaces/IStatusCodePagesFeature.cs new file mode 100644 index 0000000000..f8fa50b8ec --- /dev/null +++ b/src/Microsoft.AspNet.Diagnostics.Interfaces/IStatusCodePagesFeature.cs @@ -0,0 +1,16 @@ +// 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. + +namespace Microsoft.AspNet.Diagnostics +{ + /// + /// Represents the Status code pages feature. + /// + public interface IStatusCodePagesFeature + { + /// + /// Indicates if the status code middleware will handle responses. + /// + bool Enabled { get; set; } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNet.Diagnostics/IStatusCodeReExecuteFeature.cs b/src/Microsoft.AspNet.Diagnostics.Interfaces/IStatusCodeReExecuteFeature.cs similarity index 86% rename from src/Microsoft.AspNet.Diagnostics/IStatusCodeReExecuteFeature.cs rename to src/Microsoft.AspNet.Diagnostics.Interfaces/IStatusCodeReExecuteFeature.cs index 241b73b9af..2ea75e5ac9 100644 --- a/src/Microsoft.AspNet.Diagnostics/IStatusCodeReExecuteFeature.cs +++ b/src/Microsoft.AspNet.Diagnostics.Interfaces/IStatusCodeReExecuteFeature.cs @@ -1,11 +1,8 @@ // 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.Framework.Runtime; - namespace Microsoft.AspNet.Diagnostics { - [AssemblyNeutral] public interface IStatusCodeReExecuteFeature { string OriginalPathBase { get; set; } diff --git a/src/Microsoft.AspNet.Diagnostics.Interfaces/Microsoft.AspNet.Diagnostics.Interfaces.kproj b/src/Microsoft.AspNet.Diagnostics.Interfaces/Microsoft.AspNet.Diagnostics.Interfaces.kproj new file mode 100644 index 0000000000..fea38c9a39 --- /dev/null +++ b/src/Microsoft.AspNet.Diagnostics.Interfaces/Microsoft.AspNet.Diagnostics.Interfaces.kproj @@ -0,0 +1,20 @@ + + + + 14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + + 83ffb65a-97b1-45aa-bcb8-3f43966bc8a3 + Microsoft.AspNet.Diagnostics.Interfaces + ..\..\artifacts\obj\$(MSBuildProjectName) + ..\..\artifacts\bin\$(MSBuildProjectName)\ + + + + 2.0 + + + \ No newline at end of file diff --git a/src/Microsoft.AspNet.Diagnostics.Interfaces/project.json b/src/Microsoft.AspNet.Diagnostics.Interfaces/project.json new file mode 100644 index 0000000000..7ceb752a0b --- /dev/null +++ b/src/Microsoft.AspNet.Diagnostics.Interfaces/project.json @@ -0,0 +1,13 @@ +{ + "version": "1.0.0-*", + "description": "ASP.NET 5 diagnostics middleware interfaces.", + "compilationOptions": { "warningsAsErrors": true }, + "frameworks": { + "aspnet50": { }, + "aspnetcore50": { + "dependencies": { + "System.Runtime": "4.0.20-beta-*" + } + } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNet.Diagnostics/StatusCodePagesFeature.cs b/src/Microsoft.AspNet.Diagnostics/StatusCodePagesFeature.cs new file mode 100644 index 0000000000..10bd775088 --- /dev/null +++ b/src/Microsoft.AspNet.Diagnostics/StatusCodePagesFeature.cs @@ -0,0 +1,13 @@ +// 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. + +namespace Microsoft.AspNet.Diagnostics +{ + /// + /// Represents the Status code pages feature. + /// + public class StatusCodePagesFeature : IStatusCodePagesFeature + { + public bool Enabled { get; set; } = true; + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNet.Diagnostics/StatusCodePagesMiddleware.cs b/src/Microsoft.AspNet.Diagnostics/StatusCodePagesMiddleware.cs index a123a367bf..f6a17d879f 100644 --- a/src/Microsoft.AspNet.Diagnostics/StatusCodePagesMiddleware.cs +++ b/src/Microsoft.AspNet.Diagnostics/StatusCodePagesMiddleware.cs @@ -13,7 +13,7 @@ namespace Microsoft.AspNet.Diagnostics private readonly RequestDelegate _next; private readonly StatusCodePagesOptions _options; - public StatusCodePagesMiddleware(RequestDelegate next, [NotNull]StatusCodePagesOptions options) + public StatusCodePagesMiddleware(RequestDelegate next, StatusCodePagesOptions options) { _next = next; _options = options; @@ -25,8 +25,18 @@ namespace Microsoft.AspNet.Diagnostics public async Task Invoke(HttpContext context) { + var statusCodeFeature = new StatusCodePagesFeature(); + context.SetFeature(statusCodeFeature); + await _next(context); + if (!statusCodeFeature.Enabled) + { + // Check if the feature is still available because other middleware (such as a web API written in MVC) could + // have disabled the feature to prevent HTML status code responses from showing up to an API client. + return; + } + // Do nothing if a response body has already been provided. if (context.Response.HeadersSent || context.Response.StatusCode < 400 diff --git a/src/Microsoft.AspNet.Diagnostics/project.json b/src/Microsoft.AspNet.Diagnostics/project.json index cee4486e1e..bfadf7dffa 100644 --- a/src/Microsoft.AspNet.Diagnostics/project.json +++ b/src/Microsoft.AspNet.Diagnostics/project.json @@ -2,16 +2,16 @@ "version": "1.0.0-*", "description": "ASP.NET 5 Middleware for error handling, error pages, and diagnostics information.", "dependencies": { + "Microsoft.AspNet.Diagnostics.Interfaces": "1.0.0-*", "Microsoft.AspNet.RequestContainer": "1.0.0-*", - "Microsoft.AspNet.WebUtilities": "1.0.0-*", - "Microsoft.Framework.Runtime.Interfaces": { "version": "1.0.0-*", "type": "build" } + "Microsoft.AspNet.WebUtilities": "1.0.0-*" }, "frameworks": { - "aspnet50": { }, + "aspnet50": {}, "aspnetcore50": { "dependencies": { "System.Reflection.Extensions": "4.0.0-beta-*" } } } -} +} \ No newline at end of file