mirror of https://github.com/abpframework/abp.git
16 changed files with 826 additions and 2 deletions
@ -0,0 +1,35 @@ |
|||
using System; |
|||
using System.Reflection; |
|||
using System.Threading.Tasks; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
|
|||
namespace Volo.Abp.AspNetCore.Mvc |
|||
{ |
|||
public static class ActionResultHelper |
|||
{ |
|||
public static bool IsObjectResult(Type returnType) |
|||
{ |
|||
//Get the actual return type (unwrap Task)
|
|||
if (returnType == typeof(Task)) |
|||
{ |
|||
returnType = typeof(void); |
|||
} |
|||
else if (returnType.GetTypeInfo().IsGenericType && returnType.GetGenericTypeDefinition() == typeof(Task<>)) |
|||
{ |
|||
returnType = returnType.GenericTypeArguments[0]; |
|||
} |
|||
|
|||
if (typeof(IActionResult).GetTypeInfo().IsAssignableFrom(returnType)) |
|||
{ |
|||
if (typeof(JsonResult).GetTypeInfo().IsAssignableFrom(returnType) || typeof(ObjectResult).GetTypeInfo().IsAssignableFrom(returnType)) |
|||
{ |
|||
return true; |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,84 @@ |
|||
using System.Net; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Microsoft.AspNetCore.Mvc.Filters; |
|||
using Microsoft.Extensions.Logging; |
|||
using Microsoft.Extensions.Logging.Abstractions; |
|||
using Volo.Abp.Authorization; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.Domain.Entities; |
|||
using Volo.Abp.Http; |
|||
using Volo.Abp.Validation; |
|||
|
|||
namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling |
|||
{ |
|||
public class AbpExceptionFilter : IExceptionFilter, ITransientDependency |
|||
{ |
|||
public ILogger<AbpExceptionFilter> Logger { get; set; } |
|||
|
|||
//TODO: Use EventBus to trigger error handled event like in previous ABP
|
|||
|
|||
private readonly IExceptionToErrorInfoConverter _errorInfoConverter; |
|||
|
|||
public AbpExceptionFilter(IExceptionToErrorInfoConverter errorInfoConverter) |
|||
{ |
|||
_errorInfoConverter = errorInfoConverter; |
|||
|
|||
Logger = NullLogger<AbpExceptionFilter>.Instance; |
|||
} |
|||
|
|||
public void OnException(ExceptionContext context) |
|||
{ |
|||
if (!context.ActionDescriptor.IsControllerAction()) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
//TODO: Create DontWrap attribute to control wrapping..?
|
|||
|
|||
Logger.LogException(context.Exception); |
|||
HandleAndWrapException(context); |
|||
} |
|||
|
|||
private void HandleAndWrapException(ExceptionContext context) |
|||
{ |
|||
if (!ActionResultHelper.IsObjectResult(context.ActionDescriptor.GetMethodInfo().ReturnType)) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
context.HttpContext.Response.StatusCode = GetStatusCode(context); |
|||
|
|||
context.Result = new ObjectResult( |
|||
new RemoteServiceErrorResponse( |
|||
_errorInfoConverter.Convert(context.Exception) |
|||
) |
|||
); |
|||
|
|||
//EventBus.Trigger(this, new AbpHandledExceptionData(context.Exception));
|
|||
|
|||
context.Exception = null; //Handled!
|
|||
} |
|||
|
|||
private int GetStatusCode(ExceptionContext context) |
|||
{ |
|||
if (context.Exception is AbpAuthorizationException) |
|||
{ |
|||
return context.HttpContext.User.Identity.IsAuthenticated |
|||
? (int)HttpStatusCode.Forbidden |
|||
: (int)HttpStatusCode.Unauthorized; |
|||
} |
|||
|
|||
if (context.Exception is AbpValidationException) |
|||
{ |
|||
return (int)HttpStatusCode.BadRequest; |
|||
} |
|||
|
|||
if (context.Exception is EntityNotFoundException) |
|||
{ |
|||
return (int)HttpStatusCode.NotFound; |
|||
} |
|||
|
|||
return (int)HttpStatusCode.InternalServerError; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,209 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using Volo.Abp.Authorization; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.Domain.Entities; |
|||
using Volo.Abp.Http; |
|||
using Volo.Abp.Ui; |
|||
using Volo.Abp.Validation; |
|||
|
|||
namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling |
|||
{ |
|||
public class DefaultExceptionToErrorInfoConverter : IExceptionToErrorInfoConverter, ITransientDependency |
|||
{ |
|||
public bool SendAllExceptionsToClients { get; set; } = false; |
|||
|
|||
public RemoteServiceErrorInfo Convert(Exception exception) |
|||
{ |
|||
var errorInfo = CreateErrorInfoWithoutCode(exception); |
|||
|
|||
if (exception is IHasErrorCode) |
|||
{ |
|||
errorInfo.Code = (exception as IHasErrorCode).Code; |
|||
} |
|||
|
|||
return errorInfo; |
|||
} |
|||
|
|||
private RemoteServiceErrorInfo CreateErrorInfoWithoutCode(Exception exception) |
|||
{ |
|||
if (SendAllExceptionsToClients) |
|||
{ |
|||
return CreateDetailedErrorInfoFromException(exception); |
|||
} |
|||
|
|||
if (exception is AggregateException && exception.InnerException != null) |
|||
{ |
|||
var aggException = exception as AggregateException; |
|||
if (aggException.InnerException is UserFriendlyException || |
|||
aggException.InnerException is AbpValidationException) |
|||
{ |
|||
exception = aggException.InnerException; |
|||
} |
|||
} |
|||
|
|||
if (exception is UserFriendlyException) |
|||
{ |
|||
var userFriendlyException = exception as UserFriendlyException; |
|||
return new RemoteServiceErrorInfo(userFriendlyException.Message, userFriendlyException.Details); |
|||
} |
|||
|
|||
if (exception is AbpValidationException) |
|||
{ |
|||
return new RemoteServiceErrorInfo(L("ValidationError")) |
|||
{ |
|||
ValidationErrors = GetValidationErrorInfos(exception as AbpValidationException), |
|||
Details = GetValidationErrorNarrative(exception as AbpValidationException) |
|||
}; |
|||
} |
|||
|
|||
if (exception is EntityNotFoundException) |
|||
{ |
|||
var entityNotFoundException = exception as EntityNotFoundException; |
|||
|
|||
if (entityNotFoundException.EntityType != null) |
|||
{ |
|||
return new RemoteServiceErrorInfo( |
|||
string.Format( |
|||
L("EntityNotFound"), |
|||
entityNotFoundException.EntityType.Name, |
|||
entityNotFoundException.Id |
|||
) |
|||
); |
|||
} |
|||
|
|||
return new RemoteServiceErrorInfo( |
|||
entityNotFoundException.Message |
|||
); |
|||
} |
|||
|
|||
if (exception is AbpAuthorizationException) |
|||
{ |
|||
var authorizationException = exception as AbpAuthorizationException; |
|||
return new RemoteServiceErrorInfo(authorizationException.Message); |
|||
} |
|||
|
|||
return new RemoteServiceErrorInfo(L("InternalServerError")); |
|||
} |
|||
|
|||
|
|||
private RemoteServiceErrorInfo CreateDetailedErrorInfoFromException(Exception exception) |
|||
{ |
|||
var detailBuilder = new StringBuilder(); |
|||
|
|||
AddExceptionToDetails(exception, detailBuilder); |
|||
|
|||
var errorInfo = new RemoteServiceErrorInfo(exception.Message, detailBuilder.ToString()); |
|||
|
|||
if (exception is AbpValidationException) |
|||
{ |
|||
errorInfo.ValidationErrors = GetValidationErrorInfos(exception as AbpValidationException); |
|||
} |
|||
|
|||
return errorInfo; |
|||
} |
|||
|
|||
private void AddExceptionToDetails(Exception exception, StringBuilder detailBuilder) |
|||
{ |
|||
//Exception Message
|
|||
detailBuilder.AppendLine(exception.GetType().Name + ": " + exception.Message); |
|||
|
|||
//Additional info for UserFriendlyException
|
|||
if (exception is UserFriendlyException) |
|||
{ |
|||
var userFriendlyException = exception as UserFriendlyException; |
|||
if (!string.IsNullOrEmpty(userFriendlyException.Details)) |
|||
{ |
|||
detailBuilder.AppendLine(userFriendlyException.Details); |
|||
} |
|||
} |
|||
|
|||
//Additional info for AbpValidationException
|
|||
if (exception is AbpValidationException) |
|||
{ |
|||
var validationException = exception as AbpValidationException; |
|||
if (validationException.ValidationErrors.Count > 0) |
|||
{ |
|||
detailBuilder.AppendLine(GetValidationErrorNarrative(validationException)); |
|||
} |
|||
} |
|||
|
|||
//Exception StackTrace
|
|||
if (!string.IsNullOrEmpty(exception.StackTrace)) |
|||
{ |
|||
detailBuilder.AppendLine("STACK TRACE: " + exception.StackTrace); |
|||
} |
|||
|
|||
//Inner exception
|
|||
if (exception.InnerException != null) |
|||
{ |
|||
AddExceptionToDetails(exception.InnerException, detailBuilder); |
|||
} |
|||
|
|||
//Inner exceptions for AggregateException
|
|||
if (exception is AggregateException) |
|||
{ |
|||
var aggException = exception as AggregateException; |
|||
if (aggException.InnerExceptions.IsNullOrEmpty()) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
foreach (var innerException in aggException.InnerExceptions) |
|||
{ |
|||
AddExceptionToDetails(innerException, detailBuilder); |
|||
} |
|||
} |
|||
} |
|||
|
|||
private RemoteServiceValidationErrorInfo[] GetValidationErrorInfos(AbpValidationException validationException) |
|||
{ |
|||
var validationErrorInfos = new List<RemoteServiceValidationErrorInfo>(); |
|||
|
|||
foreach (var validationResult in validationException.ValidationErrors) |
|||
{ |
|||
var validationError = new RemoteServiceValidationErrorInfo(validationResult.ErrorMessage); |
|||
|
|||
if (validationResult.MemberNames != null && validationResult.MemberNames.Any()) |
|||
{ |
|||
validationError.Members = validationResult.MemberNames.Select(m => m.ToCamelCase()).ToArray(); |
|||
} |
|||
|
|||
validationErrorInfos.Add(validationError); |
|||
} |
|||
|
|||
return validationErrorInfos.ToArray(); |
|||
} |
|||
|
|||
private string GetValidationErrorNarrative(AbpValidationException validationException) |
|||
{ |
|||
var detailBuilder = new StringBuilder(); |
|||
detailBuilder.AppendLine(L("ValidationNarrativeTitle")); |
|||
|
|||
foreach (var validationResult in validationException.ValidationErrors) |
|||
{ |
|||
detailBuilder.AppendFormat(" - {0}", validationResult.ErrorMessage); |
|||
detailBuilder.AppendLine(); |
|||
} |
|||
|
|||
return detailBuilder.ToString(); |
|||
} |
|||
|
|||
private string L(string name) |
|||
{ |
|||
//TODO: Localization?
|
|||
//try
|
|||
//{
|
|||
// return _localizationManager.GetString(AbpWebConsts.LocalizaionSourceName, name);
|
|||
//}
|
|||
//catch (Exception)
|
|||
//{
|
|||
// return name;
|
|||
//}
|
|||
|
|||
return name; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,19 @@ |
|||
using System; |
|||
using Volo.Abp.Http; |
|||
|
|||
namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling |
|||
{ |
|||
/// <summary>
|
|||
/// This interface can be implemented to convert an <see cref="Exception"/> object to an <see cref="RemoteServiceErrorInfo"/> object.
|
|||
/// Implements Chain Of Responsibility pattern.
|
|||
/// </summary>
|
|||
public interface IExceptionToErrorInfoConverter |
|||
{ |
|||
/// <summary>
|
|||
/// Converter method.
|
|||
/// </summary>
|
|||
/// <param name="exception">The exception</param>
|
|||
/// <returns>Error info or null</returns>
|
|||
RemoteServiceErrorInfo Convert(Exception exception); |
|||
} |
|||
} |
|||
@ -0,0 +1,105 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using Volo.Abp.Logging; |
|||
using Volo.Abp.Validation; |
|||
|
|||
namespace Microsoft.Extensions.Logging |
|||
{ |
|||
public static class LoggerExtensions |
|||
{ |
|||
public static void LogWithLevel(this ILogger logger, LogLevel logLevel, string message) |
|||
{ |
|||
switch (logLevel) |
|||
{ |
|||
case LogLevel.Critical: |
|||
logger.LogCritical(message); |
|||
break; |
|||
case LogLevel.Error: |
|||
logger.LogError(message); |
|||
break; |
|||
case LogLevel.Warning: |
|||
logger.LogWarning(message); |
|||
break; |
|||
case LogLevel.Information: |
|||
logger.LogInformation(message); |
|||
break; |
|||
case LogLevel.Trace: |
|||
logger.LogTrace(message); |
|||
break; |
|||
default: // LogLevel.Debug || LogLevel.None
|
|||
logger.LogDebug(message); |
|||
break; |
|||
} |
|||
} |
|||
|
|||
public static void LogWithLevel(this ILogger logger, LogLevel logLevel, string message, Exception exception) |
|||
{ |
|||
switch (logLevel) |
|||
{ |
|||
case LogLevel.Critical: |
|||
logger.LogCritical(exception, message); |
|||
break; |
|||
case LogLevel.Error: |
|||
logger.LogError(exception, message); |
|||
break; |
|||
case LogLevel.Warning: |
|||
logger.LogWarning(exception, message); |
|||
break; |
|||
case LogLevel.Information: |
|||
logger.LogInformation(exception, message); |
|||
break; |
|||
case LogLevel.Trace: |
|||
logger.LogTrace(exception, message); |
|||
break; |
|||
default: // LogLevel.Debug || LogLevel.None
|
|||
logger.LogDebug(message); |
|||
break; |
|||
} |
|||
} |
|||
|
|||
public static void LogException(this ILogger logger, Exception ex) |
|||
{ |
|||
var logLevel = (ex as IHasLogLevel)?.LogLevel ?? LogLevel.Error; |
|||
|
|||
logger.LogWithLevel(logLevel, ex.Message, ex); |
|||
LogValidationErrors(logger, ex); |
|||
} |
|||
|
|||
private static void LogValidationErrors(ILogger logger, Exception exception) |
|||
{ |
|||
//Try to find inner validation exception
|
|||
if (exception is AggregateException && exception.InnerException != null) |
|||
{ |
|||
var aggException = exception as AggregateException; |
|||
if (aggException.InnerException is AbpValidationException) |
|||
{ |
|||
exception = aggException.InnerException; |
|||
} |
|||
} |
|||
|
|||
if (!(exception is AbpValidationException)) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
var validationException = exception as AbpValidationException; |
|||
if (validationException.ValidationErrors.IsNullOrEmpty()) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
logger.LogWithLevel(validationException.LogLevel, "There are " + validationException.ValidationErrors.Count + " validation errors:"); |
|||
foreach (var validationResult in validationException.ValidationErrors) |
|||
{ |
|||
var memberNames = ""; |
|||
if (validationResult.MemberNames != null && validationResult.MemberNames.Any()) |
|||
{ |
|||
memberNames = " (" + string.Join(", ", validationResult.MemberNames) + ")"; |
|||
} |
|||
|
|||
logger.LogWithLevel(validationException.LogLevel, validationResult.ErrorMessage + memberNames); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,58 @@ |
|||
using System; |
|||
using System.Runtime.Serialization; |
|||
using Microsoft.Extensions.Logging; |
|||
using Volo.Abp.Logging; |
|||
|
|||
namespace Volo.Abp.Authorization |
|||
{ |
|||
/// <summary>
|
|||
/// This exception is thrown on an unauthorized request.
|
|||
/// </summary>
|
|||
[Serializable] |
|||
public class AbpAuthorizationException : AbpException, IHasLogLevel |
|||
{ |
|||
/// <summary>
|
|||
/// Severity of the exception.
|
|||
/// Default: Warn.
|
|||
/// </summary>
|
|||
public LogLevel LogLevel { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Creates a new <see cref="AbpAuthorizationException"/> object.
|
|||
/// </summary>
|
|||
public AbpAuthorizationException() |
|||
{ |
|||
LogLevel = LogLevel.Warning; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Creates a new <see cref="AbpAuthorizationException"/> object.
|
|||
/// </summary>
|
|||
public AbpAuthorizationException(SerializationInfo serializationInfo, StreamingContext context) |
|||
: base(serializationInfo, context) |
|||
{ |
|||
|
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Creates a new <see cref="AbpAuthorizationException"/> object.
|
|||
/// </summary>
|
|||
/// <param name="message">Exception message</param>
|
|||
public AbpAuthorizationException(string message) |
|||
: base(message) |
|||
{ |
|||
LogLevel = LogLevel.Warning; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Creates a new <see cref="AbpAuthorizationException"/> object.
|
|||
/// </summary>
|
|||
/// <param name="message">Exception message</param>
|
|||
/// <param name="innerException">Inner exception</param>
|
|||
public AbpAuthorizationException(string message, Exception innerException) |
|||
: base(message, innerException) |
|||
{ |
|||
LogLevel = LogLevel.Warning; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,7 @@ |
|||
namespace Volo.Abp |
|||
{ |
|||
public interface IHasErrorCode |
|||
{ |
|||
int Code { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,15 @@ |
|||
using Microsoft.Extensions.Logging; |
|||
|
|||
namespace Volo.Abp.Logging |
|||
{ |
|||
/// <summary>
|
|||
/// Interface to define a <see cref="LogLevel"/> property (see <see cref="LogLevel"/>).
|
|||
/// </summary>
|
|||
public interface IHasLogLevel |
|||
{ |
|||
/// <summary>
|
|||
/// Log severity.
|
|||
/// </summary>
|
|||
LogLevel LogLevel { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,125 @@ |
|||
using System; |
|||
using System.Runtime.Serialization; |
|||
using Microsoft.Extensions.Logging; |
|||
using Volo.Abp.Logging; |
|||
|
|||
namespace Volo.Abp.Ui |
|||
{ |
|||
/// <summary>
|
|||
/// This exception type is directly shown to the user.
|
|||
/// </summary>
|
|||
[Serializable] |
|||
public class UserFriendlyException : AbpException, IHasLogLevel, IHasErrorCode |
|||
{ |
|||
/// <summary>
|
|||
/// Additional information about the exception.
|
|||
/// </summary>
|
|||
public string Details { get; private set; } |
|||
|
|||
/// <summary>
|
|||
/// An arbitrary error code.
|
|||
/// </summary>
|
|||
public int Code { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Severity of the exception.
|
|||
/// Default: Warn.
|
|||
/// </summary>
|
|||
public LogLevel LogLevel { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Constructor.
|
|||
/// </summary>
|
|||
public UserFriendlyException() |
|||
{ |
|||
LogLevel = LogLevel.Warning; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Constructor for serializing.
|
|||
/// </summary>
|
|||
public UserFriendlyException(SerializationInfo serializationInfo, StreamingContext context) |
|||
: base(serializationInfo, context) |
|||
{ |
|||
|
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Constructor.
|
|||
/// </summary>
|
|||
/// <param name="message">Exception message</param>
|
|||
public UserFriendlyException(string message) |
|||
: base(message) |
|||
{ |
|||
LogLevel = LogLevel.Warning; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Constructor.
|
|||
/// </summary>
|
|||
/// <param name="message">Exception message</param>
|
|||
/// <param name="severity">Exception severity</param>
|
|||
public UserFriendlyException(string message, LogLevel logLevel) |
|||
: base(message) |
|||
{ |
|||
LogLevel = logLevel; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Constructor.
|
|||
/// </summary>
|
|||
/// <param name="code">Error code</param>
|
|||
/// <param name="message">Exception message</param>
|
|||
public UserFriendlyException(int code, string message) |
|||
: this(message) |
|||
{ |
|||
Code = code; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Constructor.
|
|||
/// </summary>
|
|||
/// <param name="message">Exception message</param>
|
|||
/// <param name="details">Additional information about the exception</param>
|
|||
public UserFriendlyException(string message, string details) |
|||
: this(message) |
|||
{ |
|||
Details = details; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Constructor.
|
|||
/// </summary>
|
|||
/// <param name="code">Error code</param>
|
|||
/// <param name="message">Exception message</param>
|
|||
/// <param name="details">Additional information about the exception</param>
|
|||
public UserFriendlyException(int code, string message, string details) |
|||
: this(message, details) |
|||
{ |
|||
Code = code; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Constructor.
|
|||
/// </summary>
|
|||
/// <param name="message">Exception message</param>
|
|||
/// <param name="innerException">Inner exception</param>
|
|||
public UserFriendlyException(string message, Exception innerException) |
|||
: base(message, innerException) |
|||
{ |
|||
LogLevel = LogLevel.Warning; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Constructor.
|
|||
/// </summary>
|
|||
/// <param name="message">Exception message</param>
|
|||
/// <param name="details">Additional information about the exception</param>
|
|||
/// <param name="innerException">Inner exception</param>
|
|||
public UserFriendlyException(string message, string details, Exception innerException) |
|||
: this(message, innerException) |
|||
{ |
|||
Details = details; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,81 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.ComponentModel.DataAnnotations; |
|||
using System.Runtime.Serialization; |
|||
using Microsoft.Extensions.Logging; |
|||
using Volo.Abp.Logging; |
|||
|
|||
namespace Volo.Abp.Validation |
|||
{ |
|||
/// <summary>
|
|||
/// This exception type is used to throws validation exceptions.
|
|||
/// </summary>
|
|||
[Serializable] |
|||
public class AbpValidationException : AbpException, IHasLogLevel |
|||
{ |
|||
/// <summary>
|
|||
/// Detailed list of validation errors for this exception.
|
|||
/// </summary>
|
|||
public IList<ValidationResult> ValidationErrors { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Exception severity.
|
|||
/// Default: Warn.
|
|||
/// </summary>
|
|||
public LogLevel LogLevel { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Constructor.
|
|||
/// </summary>
|
|||
public AbpValidationException() |
|||
{ |
|||
ValidationErrors = new List<ValidationResult>(); |
|||
LogLevel = LogLevel.Warning; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Constructor for serializing.
|
|||
/// </summary>
|
|||
public AbpValidationException(SerializationInfo serializationInfo, StreamingContext context) |
|||
: base(serializationInfo, context) |
|||
{ |
|||
ValidationErrors = new List<ValidationResult>(); |
|||
LogLevel = LogLevel.Warning; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Constructor.
|
|||
/// </summary>
|
|||
/// <param name="message">Exception message</param>
|
|||
public AbpValidationException(string message) |
|||
: base(message) |
|||
{ |
|||
ValidationErrors = new List<ValidationResult>(); |
|||
LogLevel = LogLevel.Warning; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Constructor.
|
|||
/// </summary>
|
|||
/// <param name="message">Exception message</param>
|
|||
/// <param name="validationErrors">Validation errors</param>
|
|||
public AbpValidationException(string message, IList<ValidationResult> validationErrors) |
|||
: base(message) |
|||
{ |
|||
ValidationErrors = validationErrors; |
|||
LogLevel = LogLevel.Warning; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Constructor.
|
|||
/// </summary>
|
|||
/// <param name="message">Exception message</param>
|
|||
/// <param name="innerException">Inner exception</param>
|
|||
public AbpValidationException(string message, Exception innerException) |
|||
: base(message, innerException) |
|||
{ |
|||
ValidationErrors = new List<ValidationResult>(); |
|||
LogLevel = LogLevel.Warning; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,24 @@ |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Volo.Abp.AspNetCore.Mvc; |
|||
using Volo.Abp.Ui; |
|||
|
|||
namespace Volo.Abp.AspNetCore.App |
|||
{ |
|||
[Route("api/exception-test")] |
|||
public class ExceptionTestController : AbpController |
|||
{ |
|||
[HttpGet] |
|||
[Route("UserFriendlyException1")] |
|||
public void UserFriendlyException1() |
|||
{ |
|||
throw new UserFriendlyException("This is a sample exception!"); |
|||
} |
|||
|
|||
[HttpGet] |
|||
[Route("UserFriendlyException2")] |
|||
public ActionResult UserFriendlyException2() |
|||
{ |
|||
throw new UserFriendlyException("This is a sample exception!"); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,30 @@ |
|||
using System.Net; |
|||
using System.Threading.Tasks; |
|||
using Shouldly; |
|||
using Volo.Abp.Http; |
|||
using Volo.Abp.Ui; |
|||
using Xunit; |
|||
|
|||
namespace Volo.Abp.AspNetCore.Mvc |
|||
{ |
|||
public class ExceptionTestController_Tests : AspNetCoreMvcTestBase |
|||
{ |
|||
[Fact] |
|||
public async Task Should_Return_RemoteServiceErrorResponse_For_UserFriendlyException_For_Void_Return_Value() |
|||
{ |
|||
var result = await GetResponseAsObjectAsync<RemoteServiceErrorResponse>("/api/exception-test/UserFriendlyException1", HttpStatusCode.InternalServerError); |
|||
result.Error.ShouldNotBeNull(); |
|||
result.Error.Message.ShouldBe("This is a sample exception!"); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task Should_Not_Handle_Exceptions_For_ActionResult_Return_Values() |
|||
{ |
|||
await Assert.ThrowsAsync<UserFriendlyException>( |
|||
async () => await GetResponseAsObjectAsync<RemoteServiceErrorResponse>( |
|||
"/api/exception-test/UserFriendlyException2" |
|||
) |
|||
); |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue