Skip to content
This repository has been archived by the owner on Aug 1, 2022. It is now read-only.

Commit

Permalink
Refactor(MasaException): Refactor MasaException (#82)
Browse files Browse the repository at this point in the history
* Refactor(MasaException): Refactor MasaException

* refactor(Exception): Support MasaExceptionHandler

* chore:  format code

* chore: format code
  • Loading branch information
zhenlei520 authored Jul 8, 2022
1 parent fe83cf2 commit 43f11be
Show file tree
Hide file tree
Showing 34 changed files with 713 additions and 93 deletions.
2 changes: 2 additions & 0 deletions src/Caller/Masa.Utils.Caller.Core/CallerOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ public Assembly[] Assemblies

public JsonSerializerOptions? JsonSerializerOptions { get; set; }

public string RequestIdKey { get; set; } = "Masa-Request-Id";

public CallerOptions(IServiceCollection services)
{
Services = services;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Copyright (c) MASA Stack All rights reserved.
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.

namespace Masa.Utils.Caller.Core;

public class DefaultRequestIdGenerator : IRequestIdGenerator
{
public string NewId() => Guid.NewGuid().ToString();
}
32 changes: 32 additions & 0 deletions src/Caller/Masa.Utils.Caller.Core/DefaultRequestMessage.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright (c) MASA Stack All rights reserved.
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.

namespace Masa.Utils.Caller.Core;

public abstract class DefaultRequestMessage
{
private readonly string _requestIdKey;
private readonly IRequestIdGenerator _requestIdGenerator;
private readonly IHttpContextAccessor? _httpContextAccessor;

public DefaultRequestMessage(string requestIdKey, IRequestIdGenerator requestIdGenerator,
IHttpContextAccessor? httpContextAccessor = null)
{
_requestIdKey = requestIdKey;
_requestIdGenerator = requestIdGenerator;
_httpContextAccessor = httpContextAccessor;
}

protected void TrySetRequestId(HttpRequestMessage requestMessage)
{
var httpContext = _httpContextAccessor?.HttpContext;
if (httpContext == null)
return;

if (!httpContext.Request.Headers.TryGetValue(_requestIdKey, out var requestId))
requestId = _requestIdGenerator.NewId();

if (requestMessage.Headers.All(h => h.Key != _requestIdKey))
requestMessage.Headers.Add(_requestIdKey, requestId.ToString());
}
}
9 changes: 9 additions & 0 deletions src/Caller/Masa.Utils.Caller.Core/IRequestIdGenerator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Copyright (c) MASA Stack All rights reserved.
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.

namespace Masa.Utils.Caller.Core;

public interface IRequestIdGenerator
{
string NewId();
}
14 changes: 11 additions & 3 deletions src/Caller/Masa.Utils.Caller.Core/JsonRequestMessage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,22 @@

namespace Masa.Utils.Caller.Core;

public class JsonRequestMessage : IRequestMessage
public class JsonRequestMessage : DefaultRequestMessage, IRequestMessage
{
private readonly JsonSerializerOptions? _jsonSerializerOptions;

public JsonRequestMessage(CallerOptions callerOptions) => _jsonSerializerOptions = callerOptions.JsonSerializerOptions;
public JsonRequestMessage(
CallerOptions callerOptions,
IRequestIdGenerator requestIdGenerator,
IHttpContextAccessor? httpContextAccessor = null)
: base(callerOptions.RequestIdKey, requestIdGenerator, httpContextAccessor)
=> _jsonSerializerOptions = callerOptions.JsonSerializerOptions;

public virtual Task<HttpRequestMessage> ProcessHttpRequestMessageAsync(HttpRequestMessage requestMessage)
=> Task.FromResult(requestMessage);
{
TrySetRequestId(requestMessage);
return Task.FromResult(requestMessage);
}

public virtual async Task<HttpRequestMessage> ProcessHttpRequestMessageAsync<TRequest>(HttpRequestMessage requestMessage, TRequest data)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public static IServiceCollection AddCaller(this IServiceCollection services, Act
services.TryAddSingleton<ICallerFactory, DefaultCallerFactory>();
services.TryAddSingleton<IRequestMessage, JsonRequestMessage>();
services.TryAddSingleton<IResponseMessage, DefaultResponseMessage>();
services.TryAddSingleton<IRequestIdGenerator, DefaultRequestIdGenerator>();
services.TryAddScoped(serviceProvider => serviceProvider.GetRequiredService<ICallerFactory>().CreateClient());

services.TryAddSingleton<ITypeConvertProvider, DefaultTypeConvertProvider>();
Expand Down
1 change: 1 addition & 0 deletions src/Caller/Masa.Utils.Caller.Core/_Imports.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@
global using System.Runtime.ExceptionServices;
global using System.Text.Json;
global using System.Text.Json.Serialization;
global using Microsoft.AspNetCore.Http;
2 changes: 1 addition & 1 deletion src/Caller/Masa.Utils.Caller.DaprClient/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ Install-Package Masa.Utils.Caller.DaprClient
> Why doesn't `userCallerProvider` get the corresponding Caller through the `CreateClient` method of `CallerFactory`?
>> If no default ICallerProvider is specified, the default CallerProvider is the first one added in the `AddCaller` method

#### Recommended usage
### Recommended usage

1. Modify `Program.cs`

Expand Down
2 changes: 1 addition & 1 deletion src/Caller/Masa.Utils.Caller.DaprClient/README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ Install-Package Masa.Utils.Caller.DaprClient
> 为什么`userCallerProvider`没有通过`CallerFactory`的`CreateClient`方法得到对应的Caller
>> 如果未指定默认的ICallerProvider,则在`AddCaller`方法中第一个被添加的就是默认的CallerProvider

#### 推荐用法
### 推荐用法

1. 修改`Program.cs`

Expand Down
2 changes: 1 addition & 1 deletion src/Caller/Masa.Utils.Caller.HttpClient/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ Install-Package Masa.Utils.Caller.HttpClient
> Why doesn't `userCallerProvider` get the corresponding Caller through the `CreateClient` method of `CallerFactory`?
>> If no default ICallerProvider is specified, the default CallerProvider is the first one added in the `AddCaller` method

#### Recommended usage
### Recommended usage

1. Modify `Program.cs`

Expand Down
2 changes: 1 addition & 1 deletion src/Caller/Masa.Utils.Caller.HttpClient/README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ Install-Package Masa.Utils.Caller.HttpClient
> 为什么`userCallerProvider`没有通过`CallerFactory`的`CreateClient`方法得到对应的Caller
>> 如果未指定默认的ICallerProvider,则在`AddCaller`方法中第一个被添加的就是默认的CallerProvider

#### 推荐用法
### 推荐用法

1. 修改`Program.cs`

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Copyright (c) MASA Stack All rights reserved.
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.

using Masa.Utils.Exceptions.Handlers;

namespace Microsoft.AspNetCore.Builder;

public static class ApplicationBuilderExtensions
Expand All @@ -11,6 +13,7 @@ public static class ApplicationBuilderExtensions
/// <param name="app"></param>
/// <param name="exceptionHandlingOptions"></param>
/// <returns></returns>
[Obsolete("UseMasaExceptionHandler is recommended to use instead.")]
public static IApplicationBuilder UseMasaExceptionHandling(
this IApplicationBuilder app,
Action<MasaExceptionHandlingOptions>? exceptionHandlingOptions = null)
Expand All @@ -27,6 +30,7 @@ public static IApplicationBuilder UseMasaExceptionHandling(
/// <param name="action"></param>
/// <param name="exceptionHandlingOptions"></param>
/// <returns></returns>
[Obsolete("UseMasaExceptionHandler is recommended to use instead.")]
public static IApplicationBuilder UseMasaExceptionHandling(
this IApplicationBuilder app,
Action<RequestLocalizationOptions> action,
Expand All @@ -35,11 +39,42 @@ public static IApplicationBuilder UseMasaExceptionHandling(
var option = new MasaExceptionHandlingOptions();
exceptionHandlingOptions?.Invoke(option);

var options = app.ApplicationServices.GetRequiredService<IOptions<MasaExceptionHandlingOptions>>();
options.Value.CatchAllException = option.CatchAllException;
options.Value.CustomExceptionHandler = option.CustomExceptionHandler;
app.UseMiddleware<ExceptionHandlingMiddleware>(Options.Create(option));
app.UseRequestLocalization(action);
return app;
}

/// <summary>
/// Use localizable <see cref="ExceptionHandlingMiddleware"/>
/// </summary>
/// <param name="app"></param>
/// <param name="exceptionHandlingOptions"></param>
/// <returns></returns>
public static IApplicationBuilder UseMasaExceptionHandler(
this IApplicationBuilder app,
Action<MasaExceptionHandlerOptions>? exceptionHandlingOptions = null)
{
return app.UseMasaExceptionHandler(_ =>
{
}, exceptionHandlingOptions);
}

/// <summary>
/// Use localizable <see cref="ExceptionHandlingMiddleware"/>
/// </summary>
/// <param name="app"></param>
/// <param name="action"></param>
/// <param name="exceptionHandlingOptions"></param>
/// <returns></returns>
public static IApplicationBuilder UseMasaExceptionHandler(
this IApplicationBuilder app,
Action<RequestLocalizationOptions> action,
Action<MasaExceptionHandlerOptions>? exceptionHandlingOptions)
{
var option = new MasaExceptionHandlerOptions();
exceptionHandlingOptions?.Invoke(option);

app.UseMiddleware<ExceptionHandlingMiddleware>();
app.UseMiddleware<ExceptionHandlerMiddleware>(Options.Create(option));
app.UseRequestLocalization(action);
return app;
}
Expand Down
19 changes: 4 additions & 15 deletions src/Masa.Utils.Exceptions/Extensions/MvcBuilderExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,16 @@ namespace Microsoft.Extensions.DependencyInjection;

public static class MvcBuilderExtensions
{
/// <summary>
/// Register <see cref="GlobalExceptionFilter"/> to <see cref="MvcOptions"/>
/// </summary>
/// <param name="builder"></param>
/// <returns></returns>
public static IMvcBuilder AddMasaExceptionHandling(this IMvcBuilder builder)
public static IMvcBuilder AddMasaExceptionHandler(this IMvcBuilder builder)
{
return builder.AddMasaExceptionHandling(_ => { });
return builder.AddMasaExceptionHandler(_ => { });
}

/// <summary>
/// Register <see cref="GlobalExceptionFilter"/> to <see cref="MvcOptions"/>
/// </summary>
/// <param name="builder"></param>
/// <param name="action">Configure handling options</param>
/// <returns></returns>
public static IMvcBuilder AddMasaExceptionHandling(this IMvcBuilder builder, Action<MasaExceptionHandlingOptions> action)
public static IMvcBuilder AddMasaExceptionHandler(this IMvcBuilder builder, Action<MasaExceptionHandlerOptions> action)
{
builder.Services.AddLocalization();

builder.Services.Configure<MvcOptions>(options => { options.Filters.Add<GlobalExceptionFilter>(); });
builder.Services.Configure<MvcOptions>(options => { options.Filters.Add<MvcGlobalExcetionFilter>(); });

builder.Services.Configure(action);

Expand Down
80 changes: 80 additions & 0 deletions src/Masa.Utils.Exceptions/Handlers/ExceptionHandlerMiddleware.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// Copyright (c) MASA Stack All rights reserved.
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.

namespace Masa.Utils.Exceptions.Handlers;

public class ExceptionHandlerMiddleware
{
private readonly RequestDelegate _next;
private readonly IMasaExceptionHandler? _masaExceptionHandler;
private readonly MasaExceptionHandlerOptions _options;
private readonly MasaExceptionLogRelationOptions _logRelationOptions;
private readonly ILogger<ExceptionHandlerMiddleware>? _logger;

public ExceptionHandlerMiddleware(
RequestDelegate next,
IServiceProvider serviceProvider,
IOptions<MasaExceptionHandlerOptions> options,
IOptions<MasaExceptionLogRelationOptions> logRelationOptions,
ILogger<ExceptionHandlerMiddleware>? logger = null)
{
_next = next;
_options = options.Value;
_masaExceptionHandler = ExceptionHandlerExtensions.GetMasaExceptionHandler(serviceProvider, _options.MasaExceptionHandlerType);
_logRelationOptions = logRelationOptions.Value;
_logger = logger;
}

public async Task InvokeAsync(HttpContext httpContext)
{
try
{
await _next(httpContext);
}
catch (Exception exception)
{
var masaExceptionContext = new MasaExceptionContext(exception, httpContext);
if (_options.ExceptionHandler != null)
{
_options.ExceptionHandler.Invoke(masaExceptionContext);
}
else if (_masaExceptionHandler != null)
{
_masaExceptionHandler.OnException(masaExceptionContext);
}

if (httpContext.Response.HasStarted)
return;

if (masaExceptionContext.ExceptionHandled)
{
await httpContext.Response.WriteTextAsync(
masaExceptionContext.StatusCode,
masaExceptionContext.Message ?? masaExceptionContext.Exception.Message,
masaExceptionContext.ContentType);
return;
}

_logger?.WriteLog(masaExceptionContext.Exception,
masaExceptionContext.Exception is UserFriendlyException ? LogLevel.Information : LogLevel.Error,
_logRelationOptions);

if (masaExceptionContext.Exception is UserFriendlyException)
{
await httpContext.Response.WriteTextAsync((int)MasaHttpStatusCode.UserFriendlyException,
masaExceptionContext.Exception.Message);
}
else if (masaExceptionContext.Exception is MasaException || _options.CatchAllException)
{
var message = Constant.DEFAULT_EXCEPTION_MESSAGE;
await httpContext.Response.WriteTextAsync((int)HttpStatusCode.InternalServerError, message);
}
else
{
throw;
}
}
}


}
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
using Masa.Utils.Exceptions.Internal;

// Copyright (c) MASA Stack All rights reserved.
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.

namespace Masa.Utils.Exceptions.Handling;
namespace Masa.Utils.Exceptions.Handlers;

public class ExceptionHandlingMiddleware
{
Expand Down Expand Up @@ -45,7 +43,7 @@ public async Task InvokeAsync(HttpContext httpContext)
}
else if (exception is MasaException || _options.CatchAllException)
{
var message = "An error occur in masa framework";
var message = Constant.DEFAULT_EXCEPTION_MESSAGE;
_logger.LogError(exception, message);
await httpContext.Response.WriteTextAsync((int)HttpStatusCode.InternalServerError, message);
}
Expand Down
Loading

0 comments on commit 43f11be

Please sign in to comment.