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

Commit 45d3c4f

Browse files
Ihar YakimushIhar Yakimush
authored andcommitted
add raw response head modifications
1 parent 544c892 commit 45d3c4f

14 files changed

+247
-93
lines changed

Commmunity.AspNetCore.ExceptionHandling.Integration/Startup.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ public void ConfigureServices(IServiceCollection services)
2727

2828
services.AddExceptionHandlingPolicies(options =>
2929
{
30-
options.AddLogHandler(l => l.Level = LogLevel.Debug);
31-
options.ForException<ArgumentOutOfRangeException>().AddLogHandler().AddRethrowHandler();
30+
options.For<ArgumentOutOfRangeException>().AddLog().AddRethrow();
31+
options.For<InvalidCastException>().AddLog().AddStatusCode(e => 400).AddHeaders((h, e) => h["X-qwe"] = e.Message);
3232
});
3333

3434
services.AddLogging(b => b.AddConsole());
@@ -38,7 +38,6 @@ public void ConfigureServices(IServiceCollection services)
3838
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
3939
{
4040
app.UseDeveloperExceptionPage().UseExceptionHandlingPolicies();
41-
app.UseExceptionHandler()
4241
app.UseMvc();
4342
}
4443
}

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

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,4 @@
99
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="2.0.0" />
1010
</ItemGroup>
1111

12-
<ItemGroup>
13-
<Folder Include="Response\" />
14-
</ItemGroup>
15-
1612
</Project>

Commmunity.AspNetCore.ExceptionHandling/ExceptionHandlingPolicyOptions.cs

Lines changed: 1 addition & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@ public class ExceptionHandlingPolicyOptions : IOptions<ExceptionHandlingPolicyOp
1313

1414
private readonly OrderedDictionary handlers = new OrderedDictionary();
1515

16-
private readonly List<Type> commonHandlers = new List<Type>();
17-
1816
public ExceptionHandlingPolicyOptions EnsureException(Type exceptionType, int index = -1)
1917
{
2018
if (!typeof(Exception).IsAssignableFrom(exceptionType))
@@ -74,19 +72,6 @@ public ExceptionHandlingPolicyOptions EnsureHandler(Type exceptionType, Type han
7472
return this;
7573
}
7674

77-
public ExceptionHandlingPolicyOptions EnsureCommonHandler(Type handlerType, int index = -1)
78-
{
79-
if (!typeof(IExceptionHandler).IsAssignableFrom(handlerType))
80-
{
81-
throw new ArgumentOutOfRangeException(nameof(handlerType), handlerType,
82-
$"Handler type should implement {typeof(IExceptionHandler).Name}");
83-
}
84-
85-
ProcessHandlersList(this.commonHandlers, handlerType, index);
86-
87-
return this;
88-
}
89-
9075
private static void ProcessHandlersList(List<Type> list, Type handlerType, int index)
9176
{
9277
if (list.Any(type => type == handlerType))
@@ -124,17 +109,7 @@ public ExceptionHandlingPolicyOptions RemoveHandler(Type exceptionType, Type han
124109

125110
return this;
126111
}
127-
128-
public ExceptionHandlingPolicyOptions RemoveCommonHandler(Type handlerType)
129-
{
130-
if (this.commonHandlers.Contains(handlerType))
131-
{
132-
this.commonHandlers.Remove(handlerType);
133-
}
134-
135-
return this;
136-
}
137-
112+
138113
public ExceptionHandlingPolicyOptions ClearExceptions()
139114
{
140115
this.handlers.Clear();
@@ -153,13 +128,6 @@ public ExceptionHandlingPolicyOptions ClearHandlers(Type exceptionType)
153128
return this;
154129
}
155130

156-
public ExceptionHandlingPolicyOptions ClearCommonHandlers()
157-
{
158-
this.commonHandlers.Clear();
159-
160-
return this;
161-
}
162-
163131
internal IEnumerable<Type> GetHandlersInternal(Type exceptionType)
164132
{
165133
if (this.handlers.Contains(exceptionType))
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
using System;
2+
using System.Threading.Tasks;
3+
using Commmunity.AspNetCore.ExceptionHandling.Logs;
4+
using Microsoft.AspNetCore.Http;
5+
using Microsoft.Extensions.Logging;
6+
7+
namespace Commmunity.AspNetCore.ExceptionHandling
8+
{
9+
public abstract class HandlerStrongType<TException> : HandlerWithLogger, IExceptionHandler
10+
where TException : Exception
11+
{
12+
private static readonly EventId ExceptionTypeNotMatchGenericType = new EventId(136, "ExceptionTypeNotMatchGenericType");
13+
14+
protected HandlerStrongType(HandlerWithLoggerOptions options, ILoggerFactory loggerFactory) : base(options,
15+
loggerFactory)
16+
{
17+
}
18+
19+
public async Task<bool> Handle(HttpContext httpContext, Exception exception)
20+
{
21+
if (exception is TException e)
22+
{
23+
return await this.HandleStrongType(httpContext, e);
24+
}
25+
else
26+
{
27+
this.Logger.LogError(ExceptionTypeNotMatchGenericType,
28+
"Excpetion type {exceptionType} not match current generic type {genericType}. Exception will be re-thrown.",
29+
exception.GetType(), typeof(TException));
30+
31+
return true;
32+
}
33+
}
34+
35+
protected abstract Task<bool> HandleStrongType(HttpContext httpContext, TException exception);
36+
}
37+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
using System;
2+
using Microsoft.Extensions.Logging;
3+
4+
namespace Commmunity.AspNetCore.ExceptionHandling
5+
{
6+
public class HandlerWithLogger
7+
{
8+
private readonly HandlerWithLoggerOptions _options;
9+
private readonly ILoggerFactory _loggerFactory;
10+
11+
public HandlerWithLogger(HandlerWithLoggerOptions options, ILoggerFactory loggerFactory)
12+
{
13+
_options = options ?? throw new ArgumentNullException(nameof(options));
14+
_loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory));
15+
}
16+
17+
protected ILogger Logger => this._loggerFactory.CreateLogger(_options.LoggerCategory);
18+
}
19+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
namespace Commmunity.AspNetCore.ExceptionHandling
2+
{
3+
public class HandlerWithLoggerOptions
4+
{
5+
private string _loggerCategory = null;
6+
7+
public string LoggerCategory
8+
{
9+
get => _loggerCategory ?? Const.Category;
10+
set
11+
{
12+
if (!string.IsNullOrWhiteSpace(value))
13+
{
14+
this._loggerCategory = value;
15+
}
16+
}
17+
}
18+
}
19+
}

Commmunity.AspNetCore.ExceptionHandling/Logs/CommonConfigurationException.cs

Lines changed: 0 additions & 12 deletions
This file was deleted.

Commmunity.AspNetCore.ExceptionHandling/PolicyBuilderExtensions.cs

Lines changed: 29 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,16 @@
22
using Commmunity.AspNetCore.ExceptionHandling.Builder;
33
using Commmunity.AspNetCore.ExceptionHandling.Exc;
44
using Commmunity.AspNetCore.ExceptionHandling.Logs;
5+
using Commmunity.AspNetCore.ExceptionHandling.Response;
6+
using Microsoft.AspNetCore.Http;
57
using Microsoft.Extensions.DependencyInjection;
68
using Microsoft.Extensions.DependencyInjection.Extensions;
79

810
namespace Commmunity.AspNetCore.ExceptionHandling
911
{
1012
public static class PolicyBuilderExtensions
1113
{
12-
public static ExceptionMapping<TException> ForException<TException>(
14+
public static ExceptionMapping<TException> For<TException>(
1315
this IExceptionPolicyBuilder builder, int index = -1) where TException : Exception
1416
{
1517
builder.Options.EnsureException(typeof(TException), index);
@@ -27,15 +29,6 @@ public static ExceptionMapping<TException> EnsureHandler<TException,THandler>(
2729
return builder;
2830
}
2931

30-
public static IExceptionPolicyBuilder EnsureCommonHandler<THandler>(
31-
this IExceptionPolicyBuilder builder, int index = -1)
32-
where THandler : class, IExceptionHandler
33-
{
34-
builder.Options.Value.EnsureCommonHandler(typeof(THandler), index);
35-
builder.Services.TryAddSingleton<THandler>();
36-
return builder;
37-
}
38-
3932
public static ExceptionMapping<TException> RemoveHandler<TException, THandler>(
4033
this ExceptionMapping<TException> builder)
4134
where THandler : IExceptionHandler
@@ -45,14 +38,6 @@ public static ExceptionMapping<TException> RemoveHandler<TException, THandler>(
4538
return builder;
4639
}
4740

48-
public static IExceptionPolicyBuilder RemoveCommonHandler<THandler>(
49-
this IExceptionPolicyBuilder builder, int index = -1)
50-
where THandler : class, IExceptionHandler
51-
{
52-
builder.Options.RemoveCommonHandler(typeof(THandler));
53-
return builder;
54-
}
55-
5641
public static ExceptionMapping<TException> Clear<TException>(
5742
this ExceptionMapping<TException> builder)
5843
where TException : Exception
@@ -61,30 +46,16 @@ public static ExceptionMapping<TException> Clear<TException>(
6146
return builder;
6247
}
6348

64-
public static IExceptionPolicyBuilder ClearCommonHandlers(
65-
this IExceptionPolicyBuilder builder)
66-
{
67-
builder.Options.ClearCommonHandlers();
68-
return builder;
69-
}
70-
7149
// rethrow
72-
public static ExceptionMapping<TException> AddRethrowHandler<TException>(
50+
public static IExceptionPolicyBuilder AddRethrow<TException>(
7351
this ExceptionMapping<TException> builder, int index = -1)
7452
where TException : Exception
75-
{
53+
{
7654
return builder.EnsureHandler<TException,ReThrowExceptionHandler>(index);
7755
}
7856

79-
public static IExceptionPolicyBuilder AddRethrowHandler<TException>(
80-
this IExceptionPolicyBuilder builder, int index = -1)
81-
where TException : Exception
82-
{
83-
return builder.EnsureCommonHandler<ReThrowExceptionHandler>(index);
84-
}
85-
8657
// Log
87-
public static ExceptionMapping<TException> AddLogHandler<TException>(
58+
public static ExceptionMapping<TException> AddLog<TException>(
8859
this ExceptionMapping<TException> builder, Action<LogHandlerOptions<TException>> settings = null, int index = -1)
8960
where TException : Exception
9061
{
@@ -94,14 +65,31 @@ public static ExceptionMapping<TException> AddLogHandler<TException>(
9465
return builder.EnsureHandler<TException, LogExceptionHandler<TException>>(index);
9566
}
9667

97-
public static IExceptionPolicyBuilder AddLogHandler(
98-
this IExceptionPolicyBuilder builder, Action<LogHandlerOptions<CommonConfigurationException>> settings = null, int index = -1)
68+
// Set status code
69+
public static ExceptionMapping<TException> AddStatusCode<TException>(
70+
this ExceptionMapping<TException> builder, Func<TException,int> settings = null, int index = -1)
71+
where TException : Exception
72+
{
73+
if (settings != null)
74+
{
75+
builder.Services.Configure<SetStatusCodeOptions<TException>>(codeOptions =>
76+
codeOptions.StatusCodeFactory = settings);
77+
}
78+
79+
return builder.EnsureHandler<TException, SetStatusCodeHandler<TException>>(index);
80+
}
81+
82+
public static ExceptionMapping<TException> AddHeaders<TException>(
83+
this ExceptionMapping<TException> builder, Action<IHeaderDictionary,TException> settings = null, int index = -1)
84+
where TException : Exception
9985
{
100-
LogHandlerOptions<CommonConfigurationException> options = new LogHandlerOptions<CommonConfigurationException>();
101-
settings?.Invoke(options);
102-
builder.Services.TryAddSingleton(options);
86+
if (settings != null)
87+
{
88+
builder.Services.Configure<SetHeadersOptions<TException>>(codeOptions =>
89+
codeOptions.SetHeadersAction = settings);
90+
}
10391

104-
return builder.EnsureCommonHandler<LogExceptionHandler<CommonConfigurationException>>(index);
92+
return builder.EnsureHandler<TException, SetHeadersHandler<TException>>(index);
10593
}
10694
}
10795
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
using System;
2+
using System.Threading;
3+
using System.Threading.Tasks;
4+
using Commmunity.AspNetCore.ExceptionHandling.Logs;
5+
using Microsoft.AspNetCore.Http;
6+
using Microsoft.Extensions.Logging;
7+
using Microsoft.Extensions.Options;
8+
9+
namespace Commmunity.AspNetCore.ExceptionHandling.Response
10+
{
11+
public class RawResponseExceptionHandler<TException> : HandlerStrongType<TException>
12+
where TException : Exception
13+
{
14+
private readonly RawResponseHandlerOptions<TException> _options;
15+
16+
private static readonly EventId ResponseHasStarted = new EventId(127, "ResponseAlreadyStarted");
17+
18+
public RawResponseExceptionHandler(IOptions<RawResponseHandlerOptions<TException>> options, ILoggerFactory loggerFactory)
19+
: base(options.Value, loggerFactory)
20+
{
21+
_options = options.Value ?? throw new ArgumentNullException(nameof(options));
22+
}
23+
24+
protected override async Task<bool> HandleStrongType(HttpContext httpContext, TException exception)
25+
{
26+
if (httpContext.Response.HasStarted)
27+
{
28+
this.Logger.LogError(ResponseHasStarted,
29+
"Unable to execute {handletType} handler, because respnse already started. Exception will be re-thrown.",
30+
this.GetType());
31+
32+
return true;
33+
}
34+
35+
await HandleResponseAsync(httpContext, exception);
36+
37+
return false;
38+
}
39+
40+
protected virtual async Task HandleResponseAsync(HttpContext httpContext, TException exception)
41+
{
42+
if (_options.SetResponse != null) await _options.SetResponse(httpContext, exception);
43+
}
44+
}
45+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
using System;
2+
using System.Threading.Tasks;
3+
using Microsoft.AspNetCore.Http;
4+
using Microsoft.Extensions.Options;
5+
6+
namespace Commmunity.AspNetCore.ExceptionHandling.Response
7+
{
8+
public class RawResponseHandlerOptions<TException> : HandlerWithLoggerOptions,
9+
IOptions<RawResponseHandlerOptions<TException>>
10+
where TException : Exception
11+
{
12+
public Func<HttpContext, TException, Task> SetResponse { get; set; } = null;
13+
public RawResponseHandlerOptions<TException> Value => this;
14+
}
15+
}

0 commit comments

Comments
 (0)