Outline for StatusCodePages middleware.
This commit is contained in:
parent
a09d8a4ead
commit
cd238d4545
|
|
@ -33,8 +33,11 @@ EndProject
|
||||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Diagnostics.Entity.Tests", "test\Microsoft.AspNet.Diagnostics.Entity.Tests\Microsoft.AspNet.Diagnostics.Entity.Tests.kproj", "{5486117B-A742-49E0-94FC-12B76F061803}"
|
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Diagnostics.Entity.Tests", "test\Microsoft.AspNet.Diagnostics.Entity.Tests\Microsoft.AspNet.Diagnostics.Entity.Tests.kproj", "{5486117B-A742-49E0-94FC-12B76F061803}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Diagnostics.Entity.FunctionalTests", "test\Microsoft.AspNet.Diagnostics.Entity.FunctionalTests\Microsoft.AspNet.Diagnostics.Entity.FunctionalTests.kproj", "{2F9B479D-8247-4210-804B-78E6DD5C3E98}"
|
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Diagnostics.Entity.FunctionalTests", "test\Microsoft.AspNet.Diagnostics.Entity.FunctionalTests\Microsoft.AspNet.Diagnostics.Entity.FunctionalTests.kproj", "{2F9B479D-8247-4210-804B-78E6DD5C3E98}"
|
||||||
|
EndProject
|
||||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Diagnostics.Elm", "src\Microsoft.AspNet.Diagnostics.Elm\Microsoft.AspNet.Diagnostics.Elm.kproj", "{624B0019-956A-4157-B008-270C5B229553}"
|
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Diagnostics.Elm", "src\Microsoft.AspNet.Diagnostics.Elm\Microsoft.AspNet.Diagnostics.Elm.kproj", "{624B0019-956A-4157-B008-270C5B229553}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "StatusCodePagesSample", "samples\StatusCodePagesSample\StatusCodePagesSample.kproj", "{CC1F5841-FE10-4DDB-8477-C4DE92BA759F}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
|
@ -163,6 +166,18 @@ Global
|
||||||
{624B0019-956A-4157-B008-270C5B229553}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
{624B0019-956A-4157-B008-270C5B229553}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||||
{624B0019-956A-4157-B008-270C5B229553}.Release|x86.ActiveCfg = Release|Any CPU
|
{624B0019-956A-4157-B008-270C5B229553}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
{624B0019-956A-4157-B008-270C5B229553}.Release|x86.Build.0 = Release|Any CPU
|
{624B0019-956A-4157-B008-270C5B229553}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{CC1F5841-FE10-4DDB-8477-C4DE92BA759F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{CC1F5841-FE10-4DDB-8477-C4DE92BA759F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{CC1F5841-FE10-4DDB-8477-C4DE92BA759F}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||||
|
{CC1F5841-FE10-4DDB-8477-C4DE92BA759F}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||||
|
{CC1F5841-FE10-4DDB-8477-C4DE92BA759F}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{CC1F5841-FE10-4DDB-8477-C4DE92BA759F}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{CC1F5841-FE10-4DDB-8477-C4DE92BA759F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{CC1F5841-FE10-4DDB-8477-C4DE92BA759F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{CC1F5841-FE10-4DDB-8477-C4DE92BA759F}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||||
|
{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
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|
@ -179,5 +194,6 @@ Global
|
||||||
{5486117B-A742-49E0-94FC-12B76F061803} = {2AF90579-B118-4583-AE88-672EFACB5BC4}
|
{5486117B-A742-49E0-94FC-12B76F061803} = {2AF90579-B118-4583-AE88-672EFACB5BC4}
|
||||||
{2F9B479D-8247-4210-804B-78E6DD5C3E98} = {2AF90579-B118-4583-AE88-672EFACB5BC4}
|
{2F9B479D-8247-4210-804B-78E6DD5C3E98} = {2AF90579-B118-4583-AE88-672EFACB5BC4}
|
||||||
{624B0019-956A-4157-B008-270C5B229553} = {509A6F36-AD80-4A18-B5B1-717D38DFF29D}
|
{624B0019-956A-4157-B008-270C5B229553} = {509A6F36-AD80-4A18-B5B1-717D38DFF29D}
|
||||||
|
{CC1F5841-FE10-4DDB-8477-C4DE92BA759F} = {ACAA0157-A8C4-4152-93DE-90CCDF304087}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Microsoft.AspNet.Diagnostics": "",
|
"Microsoft.AspNet.Diagnostics": "1.0.0-*",
|
||||||
"Microsoft.AspNet.Server.WebListener": "1.0.0-*",
|
"Microsoft.AspNet.Server.WebListener": "1.0.0-*",
|
||||||
"Microsoft.AspNet.Server.IIS": "1.0.0-*"
|
"Microsoft.AspNet.Server.IIS": "1.0.0-*"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,75 @@
|
||||||
|
// 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.Net;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNet.Builder;
|
||||||
|
using Microsoft.AspNet.Diagnostics;
|
||||||
|
using Microsoft.AspNet.Http;
|
||||||
|
|
||||||
|
namespace StatusCodePagesSample
|
||||||
|
{
|
||||||
|
public class Startup
|
||||||
|
{
|
||||||
|
public void Configure(IApplicationBuilder app)
|
||||||
|
{
|
||||||
|
app.UseErrorPage(ErrorPageOptions.ShowAll);
|
||||||
|
app.UseStatusCodePages(new StatusCodePagesOptions() // There is a default response but any of the following can be used to change the behavior.
|
||||||
|
// .WithHandler(context => context.HttpContext.Response.SendAsync("Handler, status code: " + context.HttpContext.Response.StatusCode, "text/plain"))
|
||||||
|
// .WithResponse("text/plain", "Response, status code: {0}")
|
||||||
|
// .WithRedirect("~/errors/{0}") // PathBase relative
|
||||||
|
// .WithRedirect("/base/errors/{0}") // Absolute
|
||||||
|
// .WithTangent(builder => builder.UseWelcomePage())
|
||||||
|
// .WithReExecute("/errors/{0}")
|
||||||
|
);
|
||||||
|
|
||||||
|
// "/[?statuscode=400]"
|
||||||
|
app.Use((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);
|
||||||
|
}
|
||||||
|
|
||||||
|
var builder = new StringBuilder();
|
||||||
|
builder.AppendLine("<html><body>");
|
||||||
|
builder.AppendLine("<a href=\"" + context.Request.PathBase + "/missingpage/\">" + context.Request.PathBase + "/missingpage/</a><br>");
|
||||||
|
for (int statusCode = 400; statusCode < 600; statusCode++)
|
||||||
|
{
|
||||||
|
builder.AppendLine("<a href=\"?statuscode=" + statusCode + "\">" + statusCode + "</a><br>");
|
||||||
|
}
|
||||||
|
builder.AppendLine("</body></html>");
|
||||||
|
return context.Response.SendAsync(builder.ToString(), "text/html");
|
||||||
|
});
|
||||||
|
|
||||||
|
// "/errors/400"
|
||||||
|
app.Use((context, next) =>
|
||||||
|
{
|
||||||
|
PathString remainder;
|
||||||
|
if (context.Request.Path.StartsWithSegments(new PathString("/errors"), out remainder))
|
||||||
|
{
|
||||||
|
var builder = new StringBuilder();
|
||||||
|
builder.AppendLine("<html><body>");
|
||||||
|
builder.AppendLine("An error occurred, Status Code: " + WebUtility.HtmlEncode(remainder.ToString().Substring(1)) + "<br>");
|
||||||
|
var referrer = context.Request.Headers["referer"];
|
||||||
|
if (!string.IsNullOrEmpty(referrer))
|
||||||
|
{
|
||||||
|
builder.AppendLine("<a href=\"" + WebUtility.HtmlEncode(referrer) + "\">Retry " + WebUtility.HtmlEncode(referrer) + "</a><br>");
|
||||||
|
}
|
||||||
|
builder.AppendLine("</body></html>");
|
||||||
|
return context.Response.SendAsync(builder.ToString(), "text/html");
|
||||||
|
}
|
||||||
|
return next();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<PropertyGroup>
|
||||||
|
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
|
||||||
|
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VSToolsPath)\AspNet\Microsoft.Web.AspNet.Props" Condition="'$(VSToolsPath)' != ''" />
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<ProjectGuid>cc1f5841-fe10-4ddb-8477-c4de92ba759f</ProjectGuid>
|
||||||
|
<RootNamespace>StatusCodePagesSample</RootNamespace>
|
||||||
|
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
|
||||||
|
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<SchemaVersion>2.0</SchemaVersion>
|
||||||
|
<DevelopmentServerPort>21211</DevelopmentServerPort>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VSToolsPath)\AspNet\Microsoft.Web.AspNet.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||||
|
<ProjectExtensions>
|
||||||
|
<VisualStudio>
|
||||||
|
<UserProperties project_1json__JSONSchema="http://www.asp.net/media/4878834/project.json" />
|
||||||
|
</VisualStudio>
|
||||||
|
</ProjectExtensions>
|
||||||
|
</Project>
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
{
|
||||||
|
"webroot": "wwwroot",
|
||||||
|
"version": "1.0.0-*",
|
||||||
|
"exclude": [
|
||||||
|
"wwwroot"
|
||||||
|
],
|
||||||
|
"packExclude": [
|
||||||
|
"node_modules",
|
||||||
|
"bower_components",
|
||||||
|
"**.kproj",
|
||||||
|
"**.user",
|
||||||
|
"**.vspscc"
|
||||||
|
],
|
||||||
|
"commands": { "web": "Microsoft.AspNet.Hosting server=Microsoft.AspNet.Server.WebListener server.urls=http://localhost:5001/base" },
|
||||||
|
"dependencies": {
|
||||||
|
"Microsoft.AspNet.Diagnostics": "1.0.0-*",
|
||||||
|
"Microsoft.AspNet.Server.IIS": "1.0.0-*",
|
||||||
|
"Microsoft.AspNet.Server.WebListener": "1.0.0-*"
|
||||||
|
},
|
||||||
|
"frameworks" : {
|
||||||
|
"aspnet50" : { },
|
||||||
|
"aspnetcore50" : { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
// 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; }
|
||||||
|
|
||||||
|
string OriginalPath { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,66 @@
|
||||||
|
// 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.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Diagnostics
|
||||||
|
{
|
||||||
|
// TODO: Move this into Abstractions
|
||||||
|
public static class ReasonPhraseHelper
|
||||||
|
{
|
||||||
|
private static IDictionary<int, string> Phrases = new Dictionary<int, string>()
|
||||||
|
{
|
||||||
|
{ 200, "OK" },
|
||||||
|
{ 201, "Created" },
|
||||||
|
{ 202, "Accepted" },
|
||||||
|
{ 203, "Non-Authoritative Information" },
|
||||||
|
{ 204, "No Content" },
|
||||||
|
{ 205, "Reset Content" },
|
||||||
|
{ 206, "Partial Content" },
|
||||||
|
|
||||||
|
{ 300, "Multiple Choices" },
|
||||||
|
{ 301, "Moved Permanently" },
|
||||||
|
{ 302, "Found" },
|
||||||
|
{ 303, "See Other" },
|
||||||
|
{ 304, "Not Modified" },
|
||||||
|
{ 305, "Use Proxy" },
|
||||||
|
{ 306, "Switch Proxy" },
|
||||||
|
{ 307, "Temporary Redirect" },
|
||||||
|
|
||||||
|
{ 400, "Bad Request" },
|
||||||
|
{ 401, "Unauthorized" },
|
||||||
|
{ 402, "Payment Required" },
|
||||||
|
{ 403, "Forbidden" },
|
||||||
|
{ 404, "Not Found" },
|
||||||
|
{ 405, "Method Not Allowed" },
|
||||||
|
{ 406, "Not Acceptable" },
|
||||||
|
{ 407, "Proxy Authentication Required" },
|
||||||
|
{ 408, "Request Timeout" },
|
||||||
|
{ 409, "Conflict" },
|
||||||
|
{ 410, "Gone" },
|
||||||
|
{ 411, "Length Required" },
|
||||||
|
{ 412, "Precondition Failed" },
|
||||||
|
{ 413, "Request Entity Too Large" },
|
||||||
|
{ 414, "Request-URI Too Long" },
|
||||||
|
{ 415, "Unsupported Media Type" },
|
||||||
|
{ 416, "Requested Range Not Satisfiable" },
|
||||||
|
{ 417, "Expectation Failed" },
|
||||||
|
{ 418, "I'm a teapot" },
|
||||||
|
{ 419, "Authentication Timeout" },
|
||||||
|
|
||||||
|
{ 500, "Internal Server Error" },
|
||||||
|
{ 501, "Not Implemented" },
|
||||||
|
{ 502, "Bad Gateway" },
|
||||||
|
{ 503, "Service Unavailable" },
|
||||||
|
{ 504, "Gateway Timeout" },
|
||||||
|
{ 505, "HTTP Version Not Supported" },
|
||||||
|
{ 506, "Variant Also Negotiates" },
|
||||||
|
};
|
||||||
|
|
||||||
|
public static string GetReasonPhrase(int statusCode)
|
||||||
|
{
|
||||||
|
string phrase;
|
||||||
|
return Phrases.TryGetValue(statusCode, out phrase) ? phrase : string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
// 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.Builder;
|
||||||
|
using Microsoft.AspNet.Http;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Diagnostics
|
||||||
|
{
|
||||||
|
public class StatusCodeContext
|
||||||
|
{
|
||||||
|
public StatusCodeContext(HttpContext context, StatusCodePagesOptions options, RequestDelegate next)
|
||||||
|
{
|
||||||
|
HttpContext = context;
|
||||||
|
Options = options;
|
||||||
|
Next = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HttpContext HttpContext { get; private set; }
|
||||||
|
|
||||||
|
public StatusCodePagesOptions Options { get; private set; }
|
||||||
|
|
||||||
|
public RequestDelegate Next { get; private set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,133 @@
|
||||||
|
// 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;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNet.Diagnostics;
|
||||||
|
using Microsoft.AspNet.Http;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Builder
|
||||||
|
{
|
||||||
|
public static class StatusCodePagesExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a middleware that checks for responses with status codes between 400 and 599 that do not
|
||||||
|
/// have a body. Several approaches can be used to generate the response body.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="app"></param>
|
||||||
|
/// <param name="options"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static IApplicationBuilder UseStatusCodePages(this IApplicationBuilder app, StatusCodePagesOptions options)
|
||||||
|
{
|
||||||
|
return app.UseMiddleware<StatusCodePagesMiddleware>(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies the handler to invoke to generate the response body.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="options"></param>
|
||||||
|
/// <param name="handler"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static StatusCodePagesOptions WithHandler(this StatusCodePagesOptions options, Func<StatusCodeContext, Task> handler)
|
||||||
|
{
|
||||||
|
options.HandleAsync = handler;
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies the response body to send. This may include a '{0}' placeholder for the status code.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="options"></param>
|
||||||
|
/// <param name="contentType"></param>
|
||||||
|
/// <param name="bodyFormat"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static StatusCodePagesOptions WithResponse(this StatusCodePagesOptions options, string contentType, string bodyFormat)
|
||||||
|
{
|
||||||
|
return options.WithHandler(context =>
|
||||||
|
{
|
||||||
|
var body = string.Format(CultureInfo.InvariantCulture, bodyFormat, context.HttpContext.Response.StatusCode);
|
||||||
|
return context.HttpContext.Response.SendAsync(body, contentType);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies that responses should be handled by redirecting with the given location url template.
|
||||||
|
/// This may include a '{0}' placeholder for the status code. Ulrs starting with '~' will have PathBase prepeneded,
|
||||||
|
/// where any other url will be used as is.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="options"></param>
|
||||||
|
/// <param name="locationFormat"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static StatusCodePagesOptions WithRedirect(this StatusCodePagesOptions options, string locationFormat)
|
||||||
|
{
|
||||||
|
if (locationFormat.StartsWith("~"))
|
||||||
|
{
|
||||||
|
locationFormat = locationFormat.Substring(1);
|
||||||
|
return options.WithHandler(context =>
|
||||||
|
{
|
||||||
|
var location = string.Format(CultureInfo.InvariantCulture, locationFormat, context.HttpContext.Response.StatusCode);
|
||||||
|
context.HttpContext.Response.Redirect(context.HttpContext.Request.PathBase + location);
|
||||||
|
return Task.FromResult(0);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return options.WithHandler(context =>
|
||||||
|
{
|
||||||
|
var location = string.Format(CultureInfo.InvariantCulture, locationFormat, context.HttpContext.Response.StatusCode);
|
||||||
|
context.HttpContext.Response.Redirect(location);
|
||||||
|
return Task.FromResult(0);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies an alternate middleware pipeline to execute to generate the response body.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="options"></param>
|
||||||
|
/// <param name="configuration"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static StatusCodePagesOptions WithTangent(this StatusCodePagesOptions options, Action<IApplicationBuilder> configuration)
|
||||||
|
{
|
||||||
|
var builder = new ApplicationBuilder(serviceProvider: null); // TODO: services
|
||||||
|
configuration(builder);
|
||||||
|
var tangent = builder.Build();
|
||||||
|
return options.WithHandler(context => tangent(context.HttpContext));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies that the response body should be generated by re-executing the request pipeline using an alternate path.
|
||||||
|
/// This path may contain a '{0}' placeholder of the status code.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="options"></param>
|
||||||
|
/// <param name="pathFormat"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static StatusCodePagesOptions WithReExecute(this StatusCodePagesOptions options, string pathFormat)
|
||||||
|
{
|
||||||
|
return options.WithHandler(async context =>
|
||||||
|
{
|
||||||
|
var newPath = new PathString(string.Format(CultureInfo.InvariantCulture, pathFormat, context.HttpContext.Response.StatusCode));
|
||||||
|
|
||||||
|
var originalPath = context.HttpContext.Request.Path;
|
||||||
|
// Store the original paths so the app can check it.
|
||||||
|
context.HttpContext.SetFeature<IStatusCodeReExecuteFeature>(new StatusCodeReExecuteFeature()
|
||||||
|
{
|
||||||
|
OriginalPathBase = context.HttpContext.Request.PathBase.Value,
|
||||||
|
OriginalPath = originalPath.Value,
|
||||||
|
});
|
||||||
|
|
||||||
|
context.HttpContext.Request.Path = newPath;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await context.Next(context.HttpContext);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
context.HttpContext.Request.Path = originalPath;
|
||||||
|
context.HttpContext.SetFeature<IStatusCodeReExecuteFeature>(null);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
// 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;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNet.Builder;
|
||||||
|
using Microsoft.AspNet.Http;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Diagnostics
|
||||||
|
{
|
||||||
|
public class StatusCodePagesMiddleware
|
||||||
|
{
|
||||||
|
private readonly RequestDelegate _next;
|
||||||
|
private readonly StatusCodePagesOptions _options;
|
||||||
|
|
||||||
|
public StatusCodePagesMiddleware(RequestDelegate next, StatusCodePagesOptions options)
|
||||||
|
{
|
||||||
|
_next = next;
|
||||||
|
_options = options;
|
||||||
|
if (_options.HandleAsync == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Missing HandleAsync implementation.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Invoke(HttpContext context)
|
||||||
|
{
|
||||||
|
await _next(context);
|
||||||
|
|
||||||
|
// Do nothing if a response body has already been provided.
|
||||||
|
if (context.Response.HeadersSent
|
||||||
|
|| context.Response.StatusCode < 400
|
||||||
|
|| context.Response.StatusCode >= 600
|
||||||
|
|| context.Response.ContentLength.HasValue
|
||||||
|
|| !string.IsNullOrEmpty(context.Response.ContentType))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var statusCodeContext = new StatusCodeContext(context, _options, _next);
|
||||||
|
await _options.HandleAsync(statusCodeContext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
// 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;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNet.Http;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Diagnostics
|
||||||
|
{
|
||||||
|
public class StatusCodePagesOptions
|
||||||
|
{
|
||||||
|
public StatusCodePagesOptions()
|
||||||
|
{
|
||||||
|
HandleAsync = context =>
|
||||||
|
{
|
||||||
|
// TODO: Render with a pre-compiled html razor view.
|
||||||
|
// Note the 500 spaces are to work around an IE 'feature'
|
||||||
|
var statusCode = context.HttpContext.Response.StatusCode;
|
||||||
|
var body = string.Format(CultureInfo.InvariantCulture, "Status Code: {0}; {1}",
|
||||||
|
statusCode, ReasonPhraseHelper.GetReasonPhrase(statusCode)) + new string(' ', 500);
|
||||||
|
return context.HttpContext.Response.SendAsync(body, "text/plain");
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public Func<StatusCodeContext, Task> HandleAsync { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +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.
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Diagnostics
|
||||||
|
{
|
||||||
|
public class StatusCodeReExecuteFeature : IStatusCodeReExecuteFeature
|
||||||
|
{
|
||||||
|
public string OriginalPath { get; set; }
|
||||||
|
|
||||||
|
public string OriginalPathBase { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue