Skip to content

Commit 1ea347b

Browse files
author
IharYakimush
authored
Merge pull request #1 from IharYakimush/develop
v2.0
2 parents e064932 + f6338a8 commit 1ea347b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+2044
-2
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<Project Sdk="Microsoft.NET.Sdk.Web">
2+
3+
<PropertyGroup>
4+
<TargetFramework>netcoreapp2.1</TargetFramework>
5+
</PropertyGroup>
6+
7+
<ItemGroup>
8+
<Folder Include="wwwroot\" />
9+
</ItemGroup>
10+
11+
<ItemGroup>
12+
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.1.2" />
13+
<PackageReference Include="Microsoft.AspNetCore.Buffering" Version="0.2.2" />
14+
</ItemGroup>
15+
16+
<ItemGroup>
17+
<DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="2.0.3" />
18+
</ItemGroup>
19+
20+
<ItemGroup>
21+
<ProjectReference Include="..\Community.AspNetCore.ExceptionHandling.Mvc\Community.AspNetCore.ExceptionHandling.Mvc.csproj" />
22+
<ProjectReference Include="..\Community.AspNetCore.ExceptionHandling\Community.AspNetCore.ExceptionHandling.csproj" />
23+
</ItemGroup>
24+
25+
</Project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Data;
4+
using System.Linq;
5+
using System.Threading.Tasks;
6+
using Microsoft.AspNetCore.Mvc;
7+
8+
namespace Commmunity.AspNetCore.ExceptionHandling.Integration.Controllers
9+
{
10+
[Route("api/[controller]")]
11+
public class ValuesController : Controller
12+
{
13+
// GET api/values
14+
[HttpGet]
15+
public IEnumerable<string> Get()
16+
{
17+
return new string[] { "value1", "value2" };
18+
}
19+
20+
// GET api/values/5
21+
[HttpGet("{id}")]
22+
public string Get(int id)
23+
{
24+
25+
if (id > 25)
26+
{
27+
throw new DuplicateWaitObjectException();
28+
}
29+
30+
if (id > 20)
31+
{
32+
throw new DuplicateNameException();
33+
}
34+
35+
if (id > 15)
36+
{
37+
throw new InvalidConstraintException();
38+
}
39+
40+
if (id > 10)
41+
{
42+
throw new ArgumentOutOfRangeException();
43+
}
44+
45+
if (id > 5)
46+
{
47+
throw new InvalidCastException();
48+
}
49+
50+
return "value";
51+
}
52+
53+
// POST api/values
54+
[HttpPost]
55+
public void Post([FromBody]string value)
56+
{
57+
}
58+
59+
// PUT api/values/5
60+
[HttpPut("{id}")]
61+
public void Put(int id, [FromBody]string value)
62+
{
63+
}
64+
65+
// DELETE api/values/5
66+
[HttpDelete("{id}")]
67+
public void Delete(int id)
68+
{
69+
}
70+
}
71+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Linq;
5+
using System.Threading.Tasks;
6+
using Microsoft.AspNetCore;
7+
using Microsoft.AspNetCore.Hosting;
8+
using Microsoft.Extensions.Configuration;
9+
using Microsoft.Extensions.Logging;
10+
11+
namespace Commmunity.AspNetCore.ExceptionHandling.Integration
12+
{
13+
public class Program
14+
{
15+
public static void Main(string[] args)
16+
{
17+
BuildWebHost(args).Run();
18+
}
19+
20+
public static IWebHost BuildWebHost(string[] args) =>
21+
WebHost.CreateDefaultBuilder(args)
22+
.UseStartup<Startup>()
23+
.Build();
24+
}
25+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Data;
4+
using System.IO;
5+
using System.Linq;
6+
using System.Text;
7+
using System.Threading.Tasks;
8+
using Commmunity.AspNetCore.ExceptionHandling.Mvc;
9+
using Microsoft.AspNetCore.Builder;
10+
using Microsoft.AspNetCore.Hosting;
11+
using Microsoft.Extensions.Configuration;
12+
using Microsoft.Extensions.DependencyInjection;
13+
using Microsoft.Extensions.Logging;
14+
using Microsoft.Extensions.Options;
15+
16+
namespace Commmunity.AspNetCore.ExceptionHandling.Integration
17+
{
18+
public class Startup
19+
{
20+
public Startup(IConfiguration configuration)
21+
{
22+
Configuration = configuration;
23+
}
24+
25+
public IConfiguration Configuration { get; }
26+
27+
// This method gets called by the runtime. Use this method to add services to the container.
28+
public void ConfigureServices(IServiceCollection services)
29+
{
30+
services.AddMvc();
31+
32+
services.AddExceptionHandlingPolicies(options =>
33+
{
34+
options.For<DuplicateNameException>().Retry().NextPolicy();
35+
36+
options.For<DuplicateWaitObjectException>().Retry();
37+
38+
options.For<ArgumentOutOfRangeException>().Log().Rethrow();
39+
40+
options.For<InvalidCastException>()
41+
.Response(e => 400)
42+
.Headers((h, e) => h["X-qwe"] = e.Message)
43+
.WithBody((req,sw, exception) => sw.WriteAsync(exception.ToString()))
44+
.NextPolicy();
45+
46+
options.For<Exception>()
47+
.Log(lo => { lo.Formatter = (o, e) => "qwe"; })
48+
//.Response(e => 500, ResponseAlreadyStartedBehaviour.GoToNextHandler).ClearCacheHeaders().WithBodyJson((r, e) => new { msg = e.Message, path = r.Path })
49+
.Response(e => 500, ResponseAlreadyStartedBehaviour.GoToNextHandler).ClearCacheHeaders().WithObjectResult((r, e) => new { msg = e.Message, path = r.Path })
50+
.Handled();
51+
});
52+
53+
services.AddLogging();
54+
}
55+
56+
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
57+
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
58+
{
59+
app.UseResponseBuffering().UseDeveloperExceptionPage().UseExceptionHandlingPolicies();
60+
app.UseMvc();
61+
}
62+
}
63+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"Logging": {
3+
"IncludeScopes": false,
4+
"LogLevel": {
5+
"Default": "Debug",
6+
"System": "Information",
7+
"Microsoft": "Information"
8+
}
9+
}
10+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"Logging": {
3+
"IncludeScopes": false,
4+
"Debug": {
5+
"LogLevel": {
6+
"Default": "Warning"
7+
}
8+
},
9+
"Console": {
10+
"LogLevel": {
11+
"Default": "Warning"
12+
}
13+
}
14+
}
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>netcoreapp2.1</TargetFramework>
5+
<Description>Extension methods to configure exception handler which write MVC action result to responce body. Userfull for writing objects</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 mvc action result</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>
19+
<ApplicationIcon />
20+
<OutputType>Library</OutputType>
21+
<StartupObject />
22+
</PropertyGroup>
23+
24+
<ItemGroup>
25+
<PackageReference Include="Microsoft.AspNetCore.Mvc.Abstractions" Version="2.1.1" />
26+
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.1.1" />
27+
<PackageReference Include="Microsoft.AspNetCore.Routing.Abstractions" Version="2.1.1" />
28+
</ItemGroup>
29+
30+
<ItemGroup>
31+
<ProjectReference Include="..\Community.AspNetCore.ExceptionHandling\Community.AspNetCore.ExceptionHandling.csproj" />
32+
</ItemGroup>
33+
34+
</Project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
using System;
2+
using Commmunity.AspNetCore.ExceptionHandling.Builder;
3+
using Microsoft.AspNetCore.Http;
4+
using Microsoft.AspNetCore.Mvc;
5+
using Microsoft.AspNetCore.Mvc.Abstractions;
6+
using Microsoft.AspNetCore.Mvc.Infrastructure;
7+
using Microsoft.AspNetCore.Routing;
8+
using Microsoft.Extensions.DependencyInjection;
9+
10+
namespace Commmunity.AspNetCore.ExceptionHandling.Mvc
11+
{
12+
public static class PolicyBuilderExtensions
13+
{
14+
private static readonly RouteData EmptyRouteData = new RouteData();
15+
16+
private static readonly ActionDescriptor EmptyActionDescriptor = new ActionDescriptor();
17+
18+
/// <summary>
19+
/// Set <see cref="IActionResult"/> to response and pass control to next handler.
20+
/// </summary>
21+
/// <typeparam name="TException">
22+
/// The exception type
23+
/// </typeparam>
24+
/// <typeparam name="TResult">
25+
/// The action result type. Should implement <see cref="IActionResult"/>.
26+
/// </typeparam>
27+
/// <param name="builder">
28+
/// The policy builder
29+
/// </param>
30+
/// <param name="resultFactory">
31+
/// The <see cref="IActionResult"/> factory.
32+
/// </param>
33+
/// <param name="index" optional="true">
34+
/// Handler index in the chain. Optional. By default handler added to the end of chain.
35+
/// </param>
36+
/// <returns>
37+
/// Policy builder
38+
/// </returns>
39+
public static IResponseHandlers<TException> WithActionResult<TException, TResult>(
40+
this IResponseHandlers<TException> builder, Func<HttpRequest, TException, TResult> resultFactory, int index = -1)
41+
where TException : Exception
42+
where TResult : IActionResult
43+
{
44+
return builder.WithBody((request, streamWriter, exception) =>
45+
{
46+
var context = request.HttpContext;
47+
var executor = context.RequestServices.GetService<IActionResultExecutor<TResult>>();
48+
49+
if (executor == null)
50+
{
51+
throw new InvalidOperationException($"No result executor for '{typeof(TResult).FullName}' has been registered.");
52+
}
53+
54+
var routeData = context.GetRouteData() ?? EmptyRouteData;
55+
56+
var actionContext = new ActionContext(context, routeData, EmptyActionDescriptor);
57+
58+
return executor.ExecuteAsync(actionContext, resultFactory(request, exception));
59+
});
60+
}
61+
62+
/// <summary>
63+
/// Set <see cref="IActionResult"/> to response and pass control to next handler.
64+
/// </summary>
65+
/// <typeparam name="TException">
66+
/// The exception type
67+
/// </typeparam>
68+
/// <typeparam name="TResult">
69+
/// The action result type. Should implement <see cref="IActionResult"/>.
70+
/// </typeparam>
71+
/// <param name="builder">
72+
/// The policy builder
73+
/// </param>
74+
/// <param name="result">
75+
/// The <see cref="IActionResult"/> action result.
76+
/// </param>
77+
/// <param name="index" optional="true">
78+
/// Handler index in the chain. Optional. By default handler added to the end of chain.
79+
/// </param>
80+
/// <returns>
81+
/// Policy builder
82+
/// </returns>
83+
public static IResponseHandlers<TException> WithActionResult<TException, TResult>(
84+
this IResponseHandlers<TException> builder, TResult result, int index = -1)
85+
where TException : Exception
86+
where TResult : IActionResult
87+
{
88+
return builder.WithActionResult((request, exception) => result);
89+
}
90+
91+
/// <summary>
92+
/// Set <see cref="ObjectResult"/> to response and pass control to next handler.
93+
/// </summary>
94+
/// <typeparam name="TException">
95+
/// The exception type
96+
/// </typeparam>
97+
/// <typeparam name="TObject">
98+
/// The result object type.
99+
/// </typeparam>
100+
/// <param name="builder">
101+
/// The policy builder
102+
/// </param>
103+
/// <param name="value">
104+
/// The result object.
105+
/// </param>
106+
/// <param name="index" optional="true">
107+
/// Handler index in the chain. Optional. By default handler added to the end of chain.
108+
/// </param>
109+
/// <returns>
110+
/// Policy builder
111+
/// </returns>
112+
public static IResponseHandlers<TException> WithObjectResult<TException, TObject>(
113+
this IResponseHandlers<TException> builder, TObject value, int index = -1)
114+
where TException : Exception
115+
{
116+
return builder.WithActionResult(new ObjectResult(value), index);
117+
}
118+
119+
/// <summary>
120+
/// Set <see cref="ObjectResult"/> to response and pass control to next handler.
121+
/// </summary>
122+
/// <typeparam name="TException">
123+
/// The exception type
124+
/// </typeparam>
125+
/// <typeparam name="TObject">
126+
/// The result object type.
127+
/// </typeparam>
128+
/// <param name="builder">
129+
/// The policy builder
130+
/// </param>
131+
/// <param name="valueFactory">
132+
/// The result object factory.
133+
/// </param>
134+
/// <param name="index" optional="true">
135+
/// Handler index in the chain. Optional. By default handler added to the end of chain.
136+
/// </param>
137+
/// <returns>
138+
/// Policy builder
139+
/// </returns>
140+
public static IResponseHandlers<TException> WithObjectResult<TException, TObject>(
141+
this IResponseHandlers<TException> builder, Func<HttpRequest, TException, TObject> valueFactory, int index = -1)
142+
where TException : Exception
143+
{
144+
return builder.WithActionResult(
145+
(request, exception) => new ObjectResult(valueFactory(request, exception)), index);
146+
}
147+
}
148+
}

0 commit comments

Comments
 (0)