Skip to content
This repository was archived by the owner on Nov 25, 2025. It is now read-only.

Commit 41c49ee

Browse files
author
Ihar Yakimush
committed
json body handler
1 parent a562de5 commit 41c49ee

File tree

9 files changed

+126
-22
lines changed

9 files changed

+126
-22
lines changed

Commmunity.AspNetCore.ExceptionHandling.Integration/Commmunity.AspNetCore.ExceptionHandling.Integration.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
</ItemGroup>
1010

1111
<ItemGroup>
12-
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.6" />
12+
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0" />
1313
<PackageReference Include="Microsoft.AspNetCore.Buffering" Version="0.2.2" />
1414
</ItemGroup>
1515

Commmunity.AspNetCore.ExceptionHandling.Integration/Startup.cs

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public void ConfigureServices(IServiceCollection services)
3838
options.For<InvalidCastException>()
3939
.Response(e => 400)
4040
.WithHeaders((h, e) => h["X-qwe"] = e.Message)
41-
.WithBody((stream, exception) =>
41+
.WithBody((req,stream, exception) =>
4242
{
4343
using (StreamWriter sw = new StreamWriter(stream))
4444
{
@@ -48,17 +48,10 @@ public void ConfigureServices(IServiceCollection services)
4848
.NextChain();
4949
options.For<Exception>()
5050
.Log(lo => { lo.Formatter = (o, e) => "qwe"; })
51-
.Response(e => 500, RequestStartedBehaviour.SkipHandler).WithBody(
52-
async (stream, exception) =>
53-
{
54-
using (StreamWriter sw = new StreamWriter(stream))
55-
{
56-
await sw.WriteAsync("unhandled exception");
57-
}
58-
})
51+
.Response(e => 500, RequestStartedBehaviour.SkipHandler).ClearCacheHeaders().WithBodyJson((r, e) => new { msg = e.Message, path = r.Path })
5952
.Handled();
6053
});
61-
54+
6255
services.AddLogging();
6356
}
6457

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,27 @@
1-
<Project Sdk="Microsoft.NET.Sdk">
1+
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
44
<TargetFramework>netstandard2.0</TargetFramework>
5+
<Description>Middleware to configure exception handling policies. Configure chain of handlers per exception type. OOTB handlers: log, retry, set responce headers and body</Description>
6+
<PackageProjectUrl>https://github.com/IharYakimush/AspNetCore</PackageProjectUrl>
7+
<PackageLicenseUrl>https://github.com/IharYakimush/AspNetCore/blob/develop/LICENSE</PackageLicenseUrl>
8+
<Copyright>IharYakimush</Copyright>
9+
<PackageTags>AspNetCore exception handling policy</PackageTags>
10+
<AssemblyVersion>2.0.0.0</AssemblyVersion>
11+
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
12+
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
13+
<FileVersion>2.0.0.0</FileVersion>
14+
<Company />
15+
<Authors>IharYakimush</Authors>
16+
<Version>2.0.0</Version>
17+
<SignAssembly>true</SignAssembly>
18+
<AssemblyOriginatorKeyFile>..\sgn.snk</AssemblyOriginatorKeyFile>
519
</PropertyGroup>
620

721
<ItemGroup>
822
<PackageReference Include="Microsoft.AspNetCore.Http" Version="2.0.0" />
923
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="2.0.0" />
24+
<PackageReference Include="Newtonsoft.Json" Version="10.0.1" />
1025
</ItemGroup>
1126

1227
</Project>

Commmunity.AspNetCore.ExceptionHandling/PolicyBuilderExtensions.cs

Lines changed: 74 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
using Microsoft.Extensions.DependencyInjection;
1313
using Microsoft.Extensions.DependencyInjection.Extensions;
1414
using Microsoft.Extensions.Options;
15+
using Microsoft.Net.Http.Headers;
16+
using Newtonsoft.Json;
1517

1618
namespace Commmunity.AspNetCore.ExceptionHandling
1719
{
@@ -122,12 +124,10 @@ public static IResponseHandlers<TException> Response<TException>(
122124
builder.Services.Configure<RawResponseHandlerOptions<TException>>(responceOptions =>
123125
{
124126
responceOptions.RequestStartedBehaviour = requestStartedBehaviour;
127+
125128
responceOptions.SetResponse.Add((context, exception) =>
126-
{
127-
context.Response.StatusCode =
128-
statusCodeFactory?.Invoke(exception) ?? (int) HttpStatusCode.InternalServerError;
129-
130-
return Task.CompletedTask;
129+
{
130+
return RawResponseExceptionHandler<TException>.SetStatusCode(context, exception, statusCodeFactory);
131131
});
132132
});
133133

@@ -140,11 +140,38 @@ public static IResponseHandlers<TException> WithHeaders<TException>(
140140
this IResponseHandlers<TException> builder, Action<IHeaderDictionary,TException> settings, int index = -1)
141141
where TException : Exception
142142
{
143+
if (settings == null)
144+
{
145+
throw new ArgumentNullException(nameof(settings));
146+
}
147+
143148
builder.Services.Configure<RawResponseHandlerOptions<TException>>(responceOptions =>
144149
{
145150
responceOptions.SetResponse.Add((context, exception) =>
146151
{
147-
settings?.Invoke(context.Response.Headers, exception);
152+
settings.Invoke(context.Response.Headers, exception);
153+
return Task.CompletedTask;
154+
});
155+
});
156+
157+
return builder;
158+
}
159+
160+
public static IResponseHandlers<TException> ClearCacheHeaders<TException>(
161+
this IResponseHandlers<TException> builder, int index = -1)
162+
where TException : Exception
163+
{
164+
builder.Services.Configure<RawResponseHandlerOptions<TException>>(responceOptions =>
165+
{
166+
responceOptions.SetResponse.Add((context, exception) =>
167+
{
168+
HttpResponse response = context.Response;
169+
170+
response.Headers[HeaderNames.CacheControl] = "no-cache";
171+
response.Headers[HeaderNames.Pragma] = "no-cache";
172+
response.Headers[HeaderNames.Expires] = "-1";
173+
response.Headers.Remove(HeaderNames.ETag);
174+
148175
return Task.CompletedTask;
149176
});
150177
});
@@ -153,20 +180,59 @@ public static IResponseHandlers<TException> WithHeaders<TException>(
153180
}
154181

155182
public static IResponseHandlers<TException> WithBody<TException>(
156-
this IResponseHandlers<TException> builder, Func<Stream, TException, Task> settings, int index = -1)
183+
this IResponseHandlers<TException> builder, Func<HttpRequest, Stream, TException, Task> settings, int index = -1)
157184
where TException : Exception
158185
{
186+
if (settings == null)
187+
{
188+
throw new ArgumentNullException(nameof(settings));
189+
}
190+
159191
builder.Services.Configure<RawResponseHandlerOptions<TException>>(responceOptions =>
160192
{
161193
responceOptions.SetResponse.Add((context, exception) =>
162194
{
163195
if (context.Response.Body.CanSeek)
164196
context.Response.Body.SetLength(0L);
165-
return settings(context.Response.Body, exception);
197+
198+
return settings(context.Request,context.Response.Body, exception);
166199
});
167200
});
168201

169202
return builder;
170203
}
204+
205+
public static IResponseHandlers<TException> WithBodyJson<TException, TObject>(
206+
this IResponseHandlers<TException> builder, Func<HttpRequest, TException, TObject> value, JsonSerializerSettings settings = null, int index = -1)
207+
where TException : Exception
208+
{
209+
return builder.WithBody((request, stream, exception) =>
210+
{
211+
if (settings == null)
212+
{
213+
settings = request.HttpContext.RequestServices.GetService<JsonSerializerSettings>();
214+
}
215+
216+
if (settings == null)
217+
{
218+
settings = new JsonSerializerSettings();
219+
}
220+
221+
JsonSerializer jsonSerializer = JsonSerializer.Create(settings);
222+
223+
var headers = request.HttpContext.Response.Headers;
224+
if (!headers.ContainsKey(HeaderNames.ContentType))
225+
{
226+
headers[HeaderNames.ContentType] = "application/json";
227+
}
228+
229+
using (TextWriter textWriter = new StreamWriter(stream))
230+
{
231+
jsonSerializer.Serialize(textWriter, value(request, exception));
232+
}
233+
234+
return Task.CompletedTask;
235+
});
236+
}
171237
}
172238
}

Commmunity.AspNetCore.ExceptionHandling/Response/RawResponseExceptionHandler.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Net;
23
using System.Threading;
34
using System.Threading.Tasks;
45
using Commmunity.AspNetCore.ExceptionHandling.Handlers;
@@ -12,6 +13,8 @@ namespace Commmunity.AspNetCore.ExceptionHandling.Response
1213
public class RawResponseExceptionHandler<TException> : HandlerStrongType<TException>
1314
where TException : Exception
1415
{
16+
public const string StatusCodeSetKey = "5D1CFED34A39";
17+
1518
private readonly RawResponseHandlerOptions<TException> _options;
1619

1720
private static readonly EventId ResponseHasStarted = new EventId(127, "ResponseAlreadyStarted");
@@ -57,5 +60,23 @@ protected virtual Task HandleResponseAsync(HttpContext httpContext, TException e
5760

5861
return result;
5962
}
63+
64+
public static Task SetStatusCode(HttpContext context, TException exception, Func<TException, int> statusCodeFactory)
65+
{
66+
if(statusCodeFactory == null)
67+
{
68+
if (!context.Items.ContainsKey(StatusCodeSetKey))
69+
{
70+
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
71+
}
72+
}
73+
else
74+
{
75+
context.Response.StatusCode = statusCodeFactory.Invoke(exception);
76+
context.Items[StatusCodeSetKey] = true;
77+
}
78+
79+
return Task.CompletedTask;
80+
}
6081
}
6182
}

Commmunity.AspNetCore.sln

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,13 @@ VisualStudioVersion = 15.0.27428.2015
55
MinimumVisualStudioVersion = 10.0.40219.1
66
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Commmunity.AspNetCore.ExceptionHandling", "Commmunity.AspNetCore.ExceptionHandling\Commmunity.AspNetCore.ExceptionHandling.csproj", "{97ECCF71-494E-48FA-995A-AB1F13975A61}"
77
EndProject
8-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Commmunity.AspNetCore.ExceptionHandling.Integration", "Commmunity.AspNetCore.ExceptionHandling.Integration\Commmunity.AspNetCore.ExceptionHandling.Integration.csproj", "{393C6033-4255-43C3-896D-BFE30E264E4A}"
8+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Commmunity.AspNetCore.ExceptionHandling.Integration", "Commmunity.AspNetCore.ExceptionHandling.Integration\Commmunity.AspNetCore.ExceptionHandling.Integration.csproj", "{393C6033-4255-43C3-896D-BFE30E264E4A}"
9+
EndProject
10+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{C825A429-B51F-4E5D-BC78-5E0A390D0C38}"
11+
ProjectSection(SolutionItems) = preProject
12+
build.ps1 = build.ps1
13+
README.md = README.md
14+
EndProjectSection
915
EndProject
1016
Global
1117
GlobalSection(SolutionConfigurationPlatforms) = preSolution

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
# AspNetCore-ExceptionHandling
2-
Exception handling middleware for AspNetCore
2+
Middleware to configure exception handling policies. Configure chain of handlers per exception type. OOTB handlers: log, retry, set responce headers and body

build.ps1

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
dotnet restore .\Commmunity.AspNetCore.sln
2+
3+
dotnet build .\Commmunity.AspNetCore.sln -c Release

sgn.snk

596 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)