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

Commit 25c39df

Browse files
Ihar YakimushIhar Yakimush
authored andcommitted
responce body and advanced chaining
1 parent c188820 commit 25c39df

22 files changed

+267
-113
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
<ItemGroup>
1212
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.6" />
13+
<PackageReference Include="Microsoft.AspNetCore.Buffering" Version="0.2.2" />
1314
</ItemGroup>
1415

1516
<ItemGroup>

Commmunity.AspNetCore.ExceptionHandling.Integration/Controllers/ValuesController.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Data;
34
using System.Linq;
45
using System.Threading.Tasks;
56
using Microsoft.AspNetCore.Mvc;
@@ -20,6 +21,11 @@ public IEnumerable<string> Get()
2021
[HttpGet("{id}")]
2122
public string Get(int id)
2223
{
24+
if (id > 15)
25+
{
26+
throw new InvalidConstraintException();
27+
}
28+
2329
if (id > 10)
2430
{
2531
throw new ArgumentOutOfRangeException();

Commmunity.AspNetCore.ExceptionHandling.Integration/Startup.cs

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.IO;
34
using System.Linq;
5+
using System.Text;
46
using System.Threading.Tasks;
57
using Microsoft.AspNetCore.Builder;
68
using Microsoft.AspNetCore.Hosting;
@@ -27,17 +29,39 @@ public void ConfigureServices(IServiceCollection services)
2729

2830
services.AddExceptionHandlingPolicies(options =>
2931
{
30-
options.For<ArgumentOutOfRangeException>().AddLog().AddRethrow();
31-
options.For<InvalidCastException>().AddLog().AddNewResponse(e => 400).WithHeaders((h, e) => h["X-qwe"] = e.Message);
32+
options.For<ArgumentOutOfRangeException>().Log().Rethrow();
33+
options.For<InvalidCastException>()
34+
.NewResponse(e => 400)
35+
.WithHeaders((h, e) => h["X-qwe"] = e.Message)
36+
.WithBody((stream, exception) =>
37+
{
38+
using (StreamWriter sw = new StreamWriter(stream))
39+
{
40+
return sw.WriteAsync(exception.ToString());
41+
}
42+
})
43+
.NextChain();
44+
options.For<Exception>().Log(lo =>
45+
{
46+
lo.Formatter = (o, e) => "qwe";
47+
})
48+
.NewResponse(e => 500, RequestStartedBehaviour.Ignore).WithBody(
49+
async (stream, exception) =>
50+
{
51+
using (StreamWriter sw = new StreamWriter(stream))
52+
{
53+
await sw.WriteAsync("unhandled exception");
54+
}
55+
});
3256
});
3357

34-
services.AddLogging(b => b.AddConsole());
58+
services.AddLogging();
3559
}
3660

3761
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
3862
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
3963
{
40-
app.UseDeveloperExceptionPage().UseExceptionHandler().UseExceptionHandlingPolicies();
64+
app.UseResponseBuffering().UseDeveloperExceptionPage().UseExceptionHandlingPolicies();
4165
app.UseMvc();
4266
}
4367
}

Commmunity.AspNetCore.ExceptionHandling/Builder/IExceptionMapping.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ public interface IExceptionMapping<TException> : IExceptionPolicyBuilder
77
{
88
}
99

10-
public interface IResponseHandlers<TException> : IExceptionPolicyBuilder
10+
public interface IResponseHandlers<TException> : IExceptionMapping<TException>
1111
where TException : Exception
1212
{
1313
}
Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
using System;
22
using System.Threading.Tasks;
3+
using Commmunity.AspNetCore.ExceptionHandling.Handlers;
34
using Microsoft.AspNetCore.Http;
45

56
namespace Commmunity.AspNetCore.ExceptionHandling.Exc
67
{
78
public class ReThrowExceptionHandler : IExceptionHandler
89
{
9-
public Task<bool> Handle(HttpContext httpContext, Exception exception)
10+
public Task<HandlerResult> Handle(HttpContext httpContext, Exception exception)
1011
{
11-
return Task.FromResult(true);
12+
return Task.FromResult(HandlerResult.ReThrow);
1213
}
1314
}
1415
}

Commmunity.AspNetCore.ExceptionHandling/ExceptionHandlingPolicyMiddleware.cs

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Threading.Tasks;
4+
using Commmunity.AspNetCore.ExceptionHandling.Handlers;
45
using Microsoft.AspNetCore.Http;
56
using Microsoft.Extensions.DependencyInjection;
67
using Microsoft.Extensions.Logging;
@@ -28,36 +29,49 @@ private static async Task<bool> EnumerateExceptionMapping(
2829
ILogger logger = context.RequestServices.GetService<ILogger<ExceptionHandlingPolicyMiddleware>>() ??
2930
NullLoggerFactory.Instance.CreateLogger(Const.Category);
3031

31-
bool? throwRequired = null;
32+
bool mappingExists = false;
33+
HandlerResult handleResult = HandlerResult.ReThrow;
3234

3335
foreach (Type type in policyOptions.GetExceptionsInternal())
3436
{
3537
if (type.IsAssignableFrom(exceptionType))
36-
{
37-
throwRequired = await EnumerateHandlers(context, exception, policyOptions, logger);
38+
{
39+
mappingExists = true;
40+
handleResult = await EnumerateHandlers(context, type, exception, policyOptions, logger);
3841

39-
break;
42+
if (handleResult == HandlerResult.ReThrow)
43+
{
44+
return true;
45+
}
46+
47+
if (handleResult != HandlerResult.NextChain)
48+
{
49+
break;
50+
}
4051
}
4152
}
4253

43-
if (!throwRequired.HasValue)
54+
if (!mappingExists)
4455
{
4556
logger.LogWarning(Events.PolicyNotFound,
4657
"Handlers mapping for exception type {exceptionType} not exists. Exception will be re-thrown. RequestId: {RequestId}",
4758
exceptionType, context.TraceIdentifier);
59+
60+
return false;
4861
}
4962

50-
return throwRequired ?? true;
63+
return handleResult == HandlerResult.ReThrow;
5164
}
5265

53-
private static async Task<bool> EnumerateHandlers(
66+
private static async Task<HandlerResult> EnumerateHandlers(
5467
HttpContext context,
68+
Type exceptionType,
5569
Exception exception,
5670
ExceptionHandlingPolicyOptions policyOptions,
5771
ILogger logger)
5872
{
59-
bool? throwRequired = null;
60-
Type exceptionType = exception.GetType();
73+
bool handlerExecuted = false;
74+
HandlerResult handleResult = HandlerResult.ReThrow;
6175

6276
IEnumerable<Type> handlers = policyOptions.GetHandlersInternal(exceptionType);
6377

@@ -70,38 +84,42 @@ private static async Task<bool> EnumerateHandlers(
7084

7185
if (handler == null)
7286
{
73-
throwRequired = true;
87+
handlerExecuted = false;
7488
logger.LogError(Events.HandlerNotCreated,
7589
"Handler type {handlerType} can't be created because it not registered in IServiceProvider. RequestId: {RequestId}",
7690
handlerType, context.TraceIdentifier);
7791
}
7892
else
7993
{
80-
throwRequired = await handler.Handle(context, exception);
94+
handleResult = await handler.Handle(context, exception);
95+
handlerExecuted = true;
8196
}
8297
}
8398
catch (Exception e)
8499
{
85100
logger.LogError(Events.HandlerError, e,
86101
"Unhandled exception executing handler of type {handlerType} on exception of type {exceptionType}. RequestId: {RequestId}",
87102
handlerType, exceptionType, context.TraceIdentifier);
88-
throwRequired = true;
103+
104+
return HandlerResult.ReThrow;
89105
}
90106

91-
if (throwRequired.Value)
107+
if (handleResult != HandlerResult.NextHandler)
92108
{
93109
break;
94110
}
95111
}
96112

97-
if (!throwRequired.HasValue)
113+
if (!handlerExecuted)
98114
{
99115
logger.LogWarning(Events.HandlersNotFound,
100116
"Handlers collection for exception type {exceptionType} is empty. Exception will be re-thrown. RequestId: {RequestId}",
101117
exceptionType, context.TraceIdentifier);
118+
119+
return HandlerResult.ReThrow;
102120
}
103121

104-
return throwRequired ?? true;
122+
return handleResult;
105123
}
106124

107125
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
namespace Commmunity.AspNetCore.ExceptionHandling.Handlers
2+
{
3+
public class HandlerOptions
4+
{
5+
public RequestStartedBehaviour RequestStartedBehaviour { get; set; } = RequestStartedBehaviour.ReThrow;
6+
}
7+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
namespace Commmunity.AspNetCore.ExceptionHandling.Handlers
2+
{
3+
public enum HandlerResult
4+
{
5+
ReThrow = 0,
6+
7+
NextHandler = 1,
8+
9+
NextChain = 2,
10+
11+
Terminate = 3
12+
}
13+
}

Commmunity.AspNetCore.ExceptionHandling/Handlers/HandlerStrongType.cs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
using System;
22
using System.Threading.Tasks;
3-
using Commmunity.AspNetCore.ExceptionHandling.Logs;
43
using Microsoft.AspNetCore.Http;
54
using Microsoft.Extensions.Logging;
65

7-
namespace Commmunity.AspNetCore.ExceptionHandling
6+
namespace Commmunity.AspNetCore.ExceptionHandling.Handlers
87
{
98
public abstract class HandlerStrongType<TException> : HandlerWithLogger, IExceptionHandler
109
where TException : Exception
@@ -16,7 +15,7 @@ protected HandlerStrongType(HandlerWithLoggerOptions options, ILoggerFactory log
1615
{
1716
}
1817

19-
public async Task<bool> Handle(HttpContext httpContext, Exception exception)
18+
public async Task<HandlerResult> Handle(HttpContext httpContext, Exception exception)
2019
{
2120
if (exception is TException e)
2221
{
@@ -28,10 +27,10 @@ public async Task<bool> Handle(HttpContext httpContext, Exception exception)
2827
"Excpetion type {exceptionType} not match current generic type {genericType}. Exception will be re-thrown.",
2928
exception.GetType(), typeof(TException));
3029

31-
return true;
30+
return HandlerResult.ReThrow;
3231
}
3332
}
3433

35-
protected abstract Task<bool> HandleStrongType(HttpContext httpContext, TException exception);
34+
protected abstract Task<HandlerResult> HandleStrongType(HttpContext httpContext, TException exception);
3635
}
3736
}

Commmunity.AspNetCore.ExceptionHandling/Handlers/HandlerWithLogger.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
using System;
22
using Microsoft.Extensions.Logging;
33

4-
namespace Commmunity.AspNetCore.ExceptionHandling
4+
namespace Commmunity.AspNetCore.ExceptionHandling.Handlers
55
{
66
public class HandlerWithLogger
77
{

0 commit comments

Comments
 (0)