Skip to content

Commit

Permalink
Merge pull request #3 from mausworks/feature/aspnet
Browse files Browse the repository at this point in the history
ASP.NET Core middleware
  • Loading branch information
mausworks authored Nov 15, 2017
2 parents e8bb8c0 + 36aaed5 commit 31e5d85
Show file tree
Hide file tree
Showing 37 changed files with 1,394 additions and 47 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
bin/
obj/
.cov/
.packages/

dsn.txt
test/Pidget.AspNetExample/appsettings.json
4 changes: 2 additions & 2 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@
"request": "launch",
"preLaunchTask": "build",
// If you have changed target frameworks, make sure to update the program path.
"program": "${workspaceRoot}/test/Pidget.Client.Test/bin/Debug/netcoreapp2.0/Pidget.Client.Test.dll",
"program": "${workspaceFolder}/examples/Pidget.AspNetExample/bin/Debug/netcoreapp2.0/Pidget.AspNetExample.dll",
"args": [],
"cwd": "${workspaceRoot}/test/Pidget.Client.Test",
"cwd": "${workspaceFolder}/examples/Pidget.AspNetExample",
// For more information about the 'console' field, see https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md#console-terminal-window
"console": "internalConsole",
"stopAtEntry": false,
Expand Down
11 changes: 5 additions & 6 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
{
"version": "0.1.0",
"command": "dotnet",
"isShellCommand": true,
"args": [],
"version": "2.0.0",
"tasks": [
{
"taskName": "build",
"command": "dotnet",
"type": "process",
"args": [
"${workspaceRoot}/test/Pidget.Client.Test/Pidget.Client.Test.csproj"
"build",
"${workspaceFolder}/examples/Pidget.AspNetExample/Pidget.AspNetExample.csproj"
],
"isBuildCommand": true,
"problemMatcher": "$msCompile"
}
]
Expand Down
44 changes: 44 additions & 0 deletions examples/Pidget.AspNetExample/OnExceptionMiddleware.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Options;
using Pidget.AspNet;

namespace Pidget.AspNetExample
{
public class OnExceptionMiddleware
{
private readonly RequestDelegate _next;

public ExceptionReportingOptions Options { get; }

public OnExceptionMiddleware(RequestDelegate next,
IOptions<ExceptionReportingOptions> optionsAccessor)
{
_next = next;
Options = optionsAccessor.Value;
}

public async Task Invoke(HttpContext context)
{
try
{
await _next(context);
}
catch (Exception ex)
{
context.Response.StatusCode = 200;
context.Response.ContentType = "text/plain";

await WriteExceptionAsync(context, ex);
}
}

public async Task WriteExceptionAsync(HttpContext context, Exception ex)
{
await context.Response.WriteAsync($"{ex}\r\n\r\n");
await context.Response.WriteAsync(
$"Sentry event ID: {context.Items[ExceptionReportingMiddleware.EventIdKey]}");
}
}
}
15 changes: 15 additions & 0 deletions examples/Pidget.AspNetExample/Pidget.AspNetExample.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>netcoreapp2.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\Pidget.AspNet\Pidget.AspNet.csproj" />
</ItemGroup>

</Project>
16 changes: 16 additions & 0 deletions examples/Pidget.AspNetExample/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;

namespace Pidget.AspNetExample
{
public class Program
{
public static void Main(string[] args)
=> BuildWebHost(args).Run();

public static IWebHost BuildWebHost(string[] args)
=> WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.Build();
}
}
31 changes: 31 additions & 0 deletions examples/Pidget.AspNetExample/Startup.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Pidget.AspNet.Setup;

namespace Pidget.AspNetExample
{
public class Startup
{
public IConfiguration Configuration { get; }

public Startup(IConfiguration configuration)
=> Configuration = configuration;

public void ConfigureServices(IServiceCollection services)
=> services.AddPidgetMiddleware(
Configuration.GetSection("ExceptionReporting"));

public void Configure(IApplicationBuilder app)
{
// Additional exception handling.
app.UseMiddleware<OnExceptionMiddleware>();

app.UsePidgetMiddleware();

// Throwing application code.
app.Run(_ => throw new Exception("You shall not pass!"));
}
}
}
5 changes: 5 additions & 0 deletions examples/Pidget.AspNetExample/appsettings.example.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"ExceptionReporting": {
"Dsn": "https://PUBLIC:SECRET@sentry.io/PROJECT_ID"
}
}
16 changes: 16 additions & 0 deletions examples/Pidget.AspNetExample/appsettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"ExceptionReporting": {
"Dsn": "https://a9d493018a4b46848d8315334ea897f5:8b0358b0e576424aa37bce67230c3123@sentry.io/233774",
"EventIdKey": "SentryEventId",
"Sanitation": {
"ReplacementValue": "OMITTED",
"ValuePatterns": [
"^(?:\\d[ -]*?){13,16}$"
],
"NamePatterns": [
".?passw.?",
".?secret.?"
]
}
}
}
107 changes: 77 additions & 30 deletions pidget.sln
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,21 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26124.0
MinimumVisualStudioVersion = 15.0.26124.0
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{B26DC7DB-B6E8-44C3-A1EC-A5813AE738C6}"
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{3EB90C1C-5D19-464F-9EFA-B48E3DB13F84}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Pidget.Client", "src\Pidget.Client\Pidget.Client.csproj", "{ABC21006-FE85-4C0A-9C56-0A0BA42CF920}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Pidget.Client", "src\Pidget.Client\Pidget.Client.csproj", "{8849E34F-917F-4EF2-B5B4-3E9EC7A4790A}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{0149F0E1-0BE0-419F-A336-8BF3B67F7C55}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Pidget.AspNet", "src\Pidget.AspNet\Pidget.AspNet.csproj", "{FA3F4052-CF39-4FB4-AD05-00C795718AB5}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Pidget.Client.Test", "test\Pidget.Client.Test\Pidget.Client.Test.csproj", "{92A8731B-2AB2-4819-B509-2017081404B1}"
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{AA379F5D-D46B-47EA-85C1-C7D3BB265D1B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Pidget.Client.Test", "test\Pidget.Client.Test\Pidget.Client.Test.csproj", "{029E9B5B-EE90-435C-825E-B9C1DD7EDBDF}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Pidget.AspNet.Test", "test\Pidget.AspNet.Test\Pidget.AspNet.Test.csproj", "{387A07F9-312A-44AE-9B5E-45B7220A0AB9}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "examples", "examples", "{7219C684-E31E-444C-928A-2B487EA3D6F1}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Pidget.AspNetExample", "examples\Pidget.AspNetExample\Pidget.AspNetExample.csproj", "{84C87327-91E8-4F19-9359-C6A27A7AFDC3}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand All @@ -24,33 +32,72 @@ Global
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{ABC21006-FE85-4C0A-9C56-0A0BA42CF920}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{ABC21006-FE85-4C0A-9C56-0A0BA42CF920}.Debug|Any CPU.Build.0 = Debug|Any CPU
{ABC21006-FE85-4C0A-9C56-0A0BA42CF920}.Debug|x64.ActiveCfg = Debug|x64
{ABC21006-FE85-4C0A-9C56-0A0BA42CF920}.Debug|x64.Build.0 = Debug|x64
{ABC21006-FE85-4C0A-9C56-0A0BA42CF920}.Debug|x86.ActiveCfg = Debug|x86
{ABC21006-FE85-4C0A-9C56-0A0BA42CF920}.Debug|x86.Build.0 = Debug|x86
{ABC21006-FE85-4C0A-9C56-0A0BA42CF920}.Release|Any CPU.ActiveCfg = Release|Any CPU
{ABC21006-FE85-4C0A-9C56-0A0BA42CF920}.Release|Any CPU.Build.0 = Release|Any CPU
{ABC21006-FE85-4C0A-9C56-0A0BA42CF920}.Release|x64.ActiveCfg = Release|x64
{ABC21006-FE85-4C0A-9C56-0A0BA42CF920}.Release|x64.Build.0 = Release|x64
{ABC21006-FE85-4C0A-9C56-0A0BA42CF920}.Release|x86.ActiveCfg = Release|x86
{ABC21006-FE85-4C0A-9C56-0A0BA42CF920}.Release|x86.Build.0 = Release|x86
{92A8731B-2AB2-4819-B509-2017081404B1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{92A8731B-2AB2-4819-B509-2017081404B1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{92A8731B-2AB2-4819-B509-2017081404B1}.Debug|x64.ActiveCfg = Debug|x64
{92A8731B-2AB2-4819-B509-2017081404B1}.Debug|x64.Build.0 = Debug|x64
{92A8731B-2AB2-4819-B509-2017081404B1}.Debug|x86.ActiveCfg = Debug|x86
{92A8731B-2AB2-4819-B509-2017081404B1}.Debug|x86.Build.0 = Debug|x86
{92A8731B-2AB2-4819-B509-2017081404B1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{92A8731B-2AB2-4819-B509-2017081404B1}.Release|Any CPU.Build.0 = Release|Any CPU
{92A8731B-2AB2-4819-B509-2017081404B1}.Release|x64.ActiveCfg = Release|x64
{92A8731B-2AB2-4819-B509-2017081404B1}.Release|x64.Build.0 = Release|x64
{92A8731B-2AB2-4819-B509-2017081404B1}.Release|x86.ActiveCfg = Release|x86
{92A8731B-2AB2-4819-B509-2017081404B1}.Release|x86.Build.0 = Release|x86
{8849E34F-917F-4EF2-B5B4-3E9EC7A4790A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8849E34F-917F-4EF2-B5B4-3E9EC7A4790A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8849E34F-917F-4EF2-B5B4-3E9EC7A4790A}.Debug|x64.ActiveCfg = Debug|x64
{8849E34F-917F-4EF2-B5B4-3E9EC7A4790A}.Debug|x64.Build.0 = Debug|x64
{8849E34F-917F-4EF2-B5B4-3E9EC7A4790A}.Debug|x86.ActiveCfg = Debug|x86
{8849E34F-917F-4EF2-B5B4-3E9EC7A4790A}.Debug|x86.Build.0 = Debug|x86
{8849E34F-917F-4EF2-B5B4-3E9EC7A4790A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8849E34F-917F-4EF2-B5B4-3E9EC7A4790A}.Release|Any CPU.Build.0 = Release|Any CPU
{8849E34F-917F-4EF2-B5B4-3E9EC7A4790A}.Release|x64.ActiveCfg = Release|x64
{8849E34F-917F-4EF2-B5B4-3E9EC7A4790A}.Release|x64.Build.0 = Release|x64
{8849E34F-917F-4EF2-B5B4-3E9EC7A4790A}.Release|x86.ActiveCfg = Release|x86
{8849E34F-917F-4EF2-B5B4-3E9EC7A4790A}.Release|x86.Build.0 = Release|x86
{FA3F4052-CF39-4FB4-AD05-00C795718AB5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FA3F4052-CF39-4FB4-AD05-00C795718AB5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FA3F4052-CF39-4FB4-AD05-00C795718AB5}.Debug|x64.ActiveCfg = Debug|x64
{FA3F4052-CF39-4FB4-AD05-00C795718AB5}.Debug|x64.Build.0 = Debug|x64
{FA3F4052-CF39-4FB4-AD05-00C795718AB5}.Debug|x86.ActiveCfg = Debug|x86
{FA3F4052-CF39-4FB4-AD05-00C795718AB5}.Debug|x86.Build.0 = Debug|x86
{FA3F4052-CF39-4FB4-AD05-00C795718AB5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FA3F4052-CF39-4FB4-AD05-00C795718AB5}.Release|Any CPU.Build.0 = Release|Any CPU
{FA3F4052-CF39-4FB4-AD05-00C795718AB5}.Release|x64.ActiveCfg = Release|x64
{FA3F4052-CF39-4FB4-AD05-00C795718AB5}.Release|x64.Build.0 = Release|x64
{FA3F4052-CF39-4FB4-AD05-00C795718AB5}.Release|x86.ActiveCfg = Release|x86
{FA3F4052-CF39-4FB4-AD05-00C795718AB5}.Release|x86.Build.0 = Release|x86
{029E9B5B-EE90-435C-825E-B9C1DD7EDBDF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{029E9B5B-EE90-435C-825E-B9C1DD7EDBDF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{029E9B5B-EE90-435C-825E-B9C1DD7EDBDF}.Debug|x64.ActiveCfg = Debug|x64
{029E9B5B-EE90-435C-825E-B9C1DD7EDBDF}.Debug|x64.Build.0 = Debug|x64
{029E9B5B-EE90-435C-825E-B9C1DD7EDBDF}.Debug|x86.ActiveCfg = Debug|x86
{029E9B5B-EE90-435C-825E-B9C1DD7EDBDF}.Debug|x86.Build.0 = Debug|x86
{029E9B5B-EE90-435C-825E-B9C1DD7EDBDF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{029E9B5B-EE90-435C-825E-B9C1DD7EDBDF}.Release|Any CPU.Build.0 = Release|Any CPU
{029E9B5B-EE90-435C-825E-B9C1DD7EDBDF}.Release|x64.ActiveCfg = Release|x64
{029E9B5B-EE90-435C-825E-B9C1DD7EDBDF}.Release|x64.Build.0 = Release|x64
{029E9B5B-EE90-435C-825E-B9C1DD7EDBDF}.Release|x86.ActiveCfg = Release|x86
{029E9B5B-EE90-435C-825E-B9C1DD7EDBDF}.Release|x86.Build.0 = Release|x86
{387A07F9-312A-44AE-9B5E-45B7220A0AB9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{387A07F9-312A-44AE-9B5E-45B7220A0AB9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{387A07F9-312A-44AE-9B5E-45B7220A0AB9}.Debug|x64.ActiveCfg = Debug|x64
{387A07F9-312A-44AE-9B5E-45B7220A0AB9}.Debug|x64.Build.0 = Debug|x64
{387A07F9-312A-44AE-9B5E-45B7220A0AB9}.Debug|x86.ActiveCfg = Debug|x86
{387A07F9-312A-44AE-9B5E-45B7220A0AB9}.Debug|x86.Build.0 = Debug|x86
{387A07F9-312A-44AE-9B5E-45B7220A0AB9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{387A07F9-312A-44AE-9B5E-45B7220A0AB9}.Release|Any CPU.Build.0 = Release|Any CPU
{387A07F9-312A-44AE-9B5E-45B7220A0AB9}.Release|x64.ActiveCfg = Release|x64
{387A07F9-312A-44AE-9B5E-45B7220A0AB9}.Release|x64.Build.0 = Release|x64
{387A07F9-312A-44AE-9B5E-45B7220A0AB9}.Release|x86.ActiveCfg = Release|x86
{387A07F9-312A-44AE-9B5E-45B7220A0AB9}.Release|x86.Build.0 = Release|x86
{84C87327-91E8-4F19-9359-C6A27A7AFDC3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{84C87327-91E8-4F19-9359-C6A27A7AFDC3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{84C87327-91E8-4F19-9359-C6A27A7AFDC3}.Debug|x64.ActiveCfg = Debug|x64
{84C87327-91E8-4F19-9359-C6A27A7AFDC3}.Debug|x64.Build.0 = Debug|x64
{84C87327-91E8-4F19-9359-C6A27A7AFDC3}.Debug|x86.ActiveCfg = Debug|x86
{84C87327-91E8-4F19-9359-C6A27A7AFDC3}.Debug|x86.Build.0 = Debug|x86
{84C87327-91E8-4F19-9359-C6A27A7AFDC3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{84C87327-91E8-4F19-9359-C6A27A7AFDC3}.Release|Any CPU.Build.0 = Release|Any CPU
{84C87327-91E8-4F19-9359-C6A27A7AFDC3}.Release|x64.ActiveCfg = Release|x64
{84C87327-91E8-4F19-9359-C6A27A7AFDC3}.Release|x64.Build.0 = Release|x64
{84C87327-91E8-4F19-9359-C6A27A7AFDC3}.Release|x86.ActiveCfg = Release|x86
{84C87327-91E8-4F19-9359-C6A27A7AFDC3}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{ABC21006-FE85-4C0A-9C56-0A0BA42CF920} = {B26DC7DB-B6E8-44C3-A1EC-A5813AE738C6}
{92A8731B-2AB2-4819-B509-2017081404B1} = {0149F0E1-0BE0-419F-A336-8BF3B67F7C55}
{8849E34F-917F-4EF2-B5B4-3E9EC7A4790A} = {3EB90C1C-5D19-464F-9EFA-B48E3DB13F84}
{FA3F4052-CF39-4FB4-AD05-00C795718AB5} = {3EB90C1C-5D19-464F-9EFA-B48E3DB13F84}
{029E9B5B-EE90-435C-825E-B9C1DD7EDBDF} = {AA379F5D-D46B-47EA-85C1-C7D3BB265D1B}
{387A07F9-312A-44AE-9B5E-45B7220A0AB9} = {AA379F5D-D46B-47EA-85C1-C7D3BB265D1B}
{84C87327-91E8-4F19-9359-C6A27A7AFDC3} = {7219C684-E31E-444C-928A-2B487EA3D6F1}
EndGlobalSection
EndGlobal
74 changes: 74 additions & 0 deletions src/Pidget.AspNet/ExceptionReportingMiddleware.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
using System;
using System.Runtime.ExceptionServices;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Options;
using Pidget.AspNet.Sanitizing;
using Pidget.Client;

namespace Pidget.AspNet
{
public class ExceptionReportingMiddleware
{
public const string EventIdKey = "SentryEventId";

public ExceptionReportingOptions Options { get; }

private readonly RequestDelegate _next;

private readonly SentryClient _sentryClient;

public ExceptionReportingMiddleware(RequestDelegate next,
IOptions<ExceptionReportingOptions> optionsAccessor,
SentryClient sentryClient)
{
_next = next;
_sentryClient = sentryClient;
Options = optionsAccessor.Value;
}

public async Task Invoke(HttpContext context)
{
try
{
await _next(context);
}
catch (Exception ex)
{
var eventId = await CaptureAsync(ex, context);

context.Items.Add(EventIdKey, eventId);
ex.Data.Add(EventIdKey, eventId);

SilentlyRethrow(ex);
}
}

private async Task<string> CaptureAsync(Exception ex, HttpContext context)
=> await _sentryClient.CaptureAsync(e
=> BuildEvent(ex, context.Request, e));

private void BuildEvent(Exception ex, HttpRequest request,
SentryEventBuilder sentryEvent)
{
sentryEvent.SetException(ex);

AddRequestData(sentryEvent, request);
}

private void AddRequestData(SentryEventBuilder sentryEvent, HttpRequest request)
{
var provider = new RequestDataProvider(
new RequestSanitizer(Options.Sanitation));

sentryEvent.SetRequestData(provider.GetRequestData(request));
}

/// <summary>
/// Re-throws the provided exception without adding to the stack trace.
/// </summary>
/// <param name="ex">The exception to re-throw.</param>
private static void SilentlyRethrow(Exception ex)
=> ExceptionDispatchInfo.Capture(ex).Throw();
}
}
12 changes: 12 additions & 0 deletions src/Pidget.AspNet/ExceptionReportingOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using Microsoft.AspNetCore.Http;

namespace Pidget.AspNet
{
public class ExceptionReportingOptions
{
public string Dsn { get; set; }

public SanitationOptions Sanitation { get; set; }
= SanitationOptions.Default;
}
}
Loading

0 comments on commit 31e5d85

Please sign in to comment.