Skip to content

Commit

Permalink
Merge pull request #1 from IharYakimush/develop
Browse files Browse the repository at this point in the history
v2.0
  • Loading branch information
IharYakimush committed Jul 16, 2018
2 parents e064932 + f6338a8 commit 1ea347b
Show file tree
Hide file tree
Showing 43 changed files with 2,044 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
</PropertyGroup>

<ItemGroup>
<Folder Include="wwwroot\" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.1.2" />
<PackageReference Include="Microsoft.AspNetCore.Buffering" Version="0.2.2" />
</ItemGroup>

<ItemGroup>
<DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="2.0.3" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Community.AspNetCore.ExceptionHandling.Mvc\Community.AspNetCore.ExceptionHandling.Mvc.csproj" />
<ProjectReference Include="..\Community.AspNetCore.ExceptionHandling\Community.AspNetCore.ExceptionHandling.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;

namespace Commmunity.AspNetCore.ExceptionHandling.Integration.Controllers
{
[Route("api/[controller]")]
public class ValuesController : Controller
{
// GET api/values
[HttpGet]
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}

// GET api/values/5
[HttpGet("{id}")]
public string Get(int id)
{

if (id > 25)
{
throw new DuplicateWaitObjectException();
}

if (id > 20)
{
throw new DuplicateNameException();
}

if (id > 15)
{
throw new InvalidConstraintException();
}

if (id > 10)
{
throw new ArgumentOutOfRangeException();
}

if (id > 5)
{
throw new InvalidCastException();
}

return "value";
}

// POST api/values
[HttpPost]
public void Post([FromBody]string value)
{
}

// PUT api/values/5
[HttpPut("{id}")]
public void Put(int id, [FromBody]string value)
{
}

// DELETE api/values/5
[HttpDelete("{id}")]
public void Delete(int id)
{
}
}
}
25 changes: 25 additions & 0 deletions Community.AspNetCore.ExceptionHandling.Integration/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;

namespace Commmunity.AspNetCore.ExceptionHandling.Integration
{
public class Program
{
public static void Main(string[] args)
{
BuildWebHost(args).Run();
}

public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.Build();
}
}
63 changes: 63 additions & 0 deletions Community.AspNetCore.ExceptionHandling.Integration/Startup.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Commmunity.AspNetCore.ExceptionHandling.Mvc;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;

namespace Commmunity.AspNetCore.ExceptionHandling.Integration
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}

public IConfiguration Configuration { get; }

// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();

services.AddExceptionHandlingPolicies(options =>
{
options.For<DuplicateNameException>().Retry().NextPolicy();
options.For<DuplicateWaitObjectException>().Retry();
options.For<ArgumentOutOfRangeException>().Log().Rethrow();
options.For<InvalidCastException>()
.Response(e => 400)
.Headers((h, e) => h["X-qwe"] = e.Message)
.WithBody((req,sw, exception) => sw.WriteAsync(exception.ToString()))
.NextPolicy();
options.For<Exception>()
.Log(lo => { lo.Formatter = (o, e) => "qwe"; })
//.Response(e => 500, ResponseAlreadyStartedBehaviour.GoToNextHandler).ClearCacheHeaders().WithBodyJson((r, e) => new { msg = e.Message, path = r.Path })
.Response(e => 500, ResponseAlreadyStartedBehaviour.GoToNextHandler).ClearCacheHeaders().WithObjectResult((r, e) => new { msg = e.Message, path = r.Path })
.Handled();
});

services.AddLogging();
}

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseResponseBuffering().UseDeveloperExceptionPage().UseExceptionHandlingPolicies();
app.UseMvc();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"Logging": {
"IncludeScopes": false,
"Debug": {
"LogLevel": {
"Default": "Warning"
}
},
"Console": {
"LogLevel": {
"Default": "Warning"
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<Description>Extension methods to configure exception handler which write MVC action result to responce body. Userfull for writing objects</Description>
<PackageProjectUrl>https://github.com/IharYakimush/AspNetCore</PackageProjectUrl>
<PackageLicenseUrl>https://github.com/IharYakimush/AspNetCore/blob/develop/LICENSE</PackageLicenseUrl>
<Copyright>IharYakimush</Copyright>
<PackageTags>AspNetCore exception handling policy mvc action result</PackageTags>
<AssemblyVersion>2.0.0.0</AssemblyVersion>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
<FileVersion>2.0.0.0</FileVersion>
<Company />
<Authors>IharYakimush</Authors>
<Version>2.0.0</Version>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>..\sgn.snk</AssemblyOriginatorKeyFile>
<ApplicationIcon />
<OutputType>Library</OutputType>
<StartupObject />
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.Abstractions" Version="2.1.1" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.1.1" />
<PackageReference Include="Microsoft.AspNetCore.Routing.Abstractions" Version="2.1.1" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Community.AspNetCore.ExceptionHandling\Community.AspNetCore.ExceptionHandling.csproj" />
</ItemGroup>

</Project>
148 changes: 148 additions & 0 deletions Community.AspNetCore.ExceptionHandling.Mvc/PolicyBuilderExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
using System;
using Commmunity.AspNetCore.ExceptionHandling.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection;

namespace Commmunity.AspNetCore.ExceptionHandling.Mvc
{
public static class PolicyBuilderExtensions
{
private static readonly RouteData EmptyRouteData = new RouteData();

private static readonly ActionDescriptor EmptyActionDescriptor = new ActionDescriptor();

/// <summary>
/// Set <see cref="IActionResult"/> to response and pass control to next handler.
/// </summary>
/// <typeparam name="TException">
/// The exception type
/// </typeparam>
/// <typeparam name="TResult">
/// The action result type. Should implement <see cref="IActionResult"/>.
/// </typeparam>
/// <param name="builder">
/// The policy builder
/// </param>
/// <param name="resultFactory">
/// The <see cref="IActionResult"/> factory.
/// </param>
/// <param name="index" optional="true">
/// Handler index in the chain. Optional. By default handler added to the end of chain.
/// </param>
/// <returns>
/// Policy builder
/// </returns>
public static IResponseHandlers<TException> WithActionResult<TException, TResult>(
this IResponseHandlers<TException> builder, Func<HttpRequest, TException, TResult> resultFactory, int index = -1)
where TException : Exception
where TResult : IActionResult
{
return builder.WithBody((request, streamWriter, exception) =>
{
var context = request.HttpContext;
var executor = context.RequestServices.GetService<IActionResultExecutor<TResult>>();
if (executor == null)
{
throw new InvalidOperationException($"No result executor for '{typeof(TResult).FullName}' has been registered.");
}
var routeData = context.GetRouteData() ?? EmptyRouteData;
var actionContext = new ActionContext(context, routeData, EmptyActionDescriptor);
return executor.ExecuteAsync(actionContext, resultFactory(request, exception));
});
}

/// <summary>
/// Set <see cref="IActionResult"/> to response and pass control to next handler.
/// </summary>
/// <typeparam name="TException">
/// The exception type
/// </typeparam>
/// <typeparam name="TResult">
/// The action result type. Should implement <see cref="IActionResult"/>.
/// </typeparam>
/// <param name="builder">
/// The policy builder
/// </param>
/// <param name="result">
/// The <see cref="IActionResult"/> action result.
/// </param>
/// <param name="index" optional="true">
/// Handler index in the chain. Optional. By default handler added to the end of chain.
/// </param>
/// <returns>
/// Policy builder
/// </returns>
public static IResponseHandlers<TException> WithActionResult<TException, TResult>(
this IResponseHandlers<TException> builder, TResult result, int index = -1)
where TException : Exception
where TResult : IActionResult
{
return builder.WithActionResult((request, exception) => result);
}

/// <summary>
/// Set <see cref="ObjectResult"/> to response and pass control to next handler.
/// </summary>
/// <typeparam name="TException">
/// The exception type
/// </typeparam>
/// <typeparam name="TObject">
/// The result object type.
/// </typeparam>
/// <param name="builder">
/// The policy builder
/// </param>
/// <param name="value">
/// The result object.
/// </param>
/// <param name="index" optional="true">
/// Handler index in the chain. Optional. By default handler added to the end of chain.
/// </param>
/// <returns>
/// Policy builder
/// </returns>
public static IResponseHandlers<TException> WithObjectResult<TException, TObject>(
this IResponseHandlers<TException> builder, TObject value, int index = -1)
where TException : Exception
{
return builder.WithActionResult(new ObjectResult(value), index);
}

/// <summary>
/// Set <see cref="ObjectResult"/> to response and pass control to next handler.
/// </summary>
/// <typeparam name="TException">
/// The exception type
/// </typeparam>
/// <typeparam name="TObject">
/// The result object type.
/// </typeparam>
/// <param name="builder">
/// The policy builder
/// </param>
/// <param name="valueFactory">
/// The result object factory.
/// </param>
/// <param name="index" optional="true">
/// Handler index in the chain. Optional. By default handler added to the end of chain.
/// </param>
/// <returns>
/// Policy builder
/// </returns>
public static IResponseHandlers<TException> WithObjectResult<TException, TObject>(
this IResponseHandlers<TException> builder, Func<HttpRequest, TException, TObject> valueFactory, int index = -1)
where TException : Exception
{
return builder.WithActionResult(
(request, exception) => new ObjectResult(valueFactory(request, exception)), index);
}
}
}
Loading

0 comments on commit 1ea347b

Please sign in to comment.