diff --git a/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/DefaultExceptionToErrorInfoConverter.cs b/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/DefaultExceptionToErrorInfoConverter.cs index 6ef1df1060..8062f1cae8 100644 --- a/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/DefaultExceptionToErrorInfoConverter.cs +++ b/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/DefaultExceptionToErrorInfoConverter.cs @@ -27,69 +27,94 @@ namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling return errorInfo; } - private RemoteServiceErrorInfo CreateErrorInfoWithoutCode(Exception exception) + protected virtual RemoteServiceErrorInfo CreateErrorInfoWithoutCode(Exception exception) { if (SendAllExceptionsToClients) { return CreateDetailedErrorInfoFromException(exception); } - if (exception is AggregateException && exception.InnerException != null) + exception = TryToGetActualException(exception); + + if (exception is EntityNotFoundException) { - var aggException = exception as AggregateException; - if (aggException.InnerException is UserFriendlyException || - aggException.InnerException is AbpValidationException) - { - exception = aggException.InnerException; - } + return CreateEntityNotFoundError(exception as EntityNotFoundException); } - if (exception is UserFriendlyException) + if (exception is AbpAuthorizationException) { - var userFriendlyException = exception as UserFriendlyException; - return new RemoteServiceErrorInfo(userFriendlyException.Message, userFriendlyException.Details); + var authorizationException = exception as AbpAuthorizationException; + return new RemoteServiceErrorInfo(authorizationException.Message); } - if (exception is AbpValidationException) + var errorInfo = new RemoteServiceErrorInfo(); + + if (exception is IUserFriendlyException) { - return new RemoteServiceErrorInfo(L("ValidationError")) - { - ValidationErrors = GetValidationErrorInfos(exception as AbpValidationException), - Details = GetValidationErrorNarrative(exception as AbpValidationException) - }; + var userFriendlyException = exception as IUserFriendlyException; + errorInfo.Message = userFriendlyException.Message; + errorInfo.Details = userFriendlyException.Details; } - if (exception is EntityNotFoundException) + if (exception is IHasValidationErrors) { - var entityNotFoundException = exception as EntityNotFoundException; + if (errorInfo.Message.IsNullOrEmpty()) + { + errorInfo.Message = L("ValidationError"); + } - if (entityNotFoundException.EntityType != null) + if (errorInfo.Details.IsNullOrEmpty()) { - return new RemoteServiceErrorInfo( - string.Format( - L("EntityNotFound"), - entityNotFoundException.EntityType.Name, - entityNotFoundException.Id - ) - ); + errorInfo.Details = GetValidationErrorNarrative(exception as IHasValidationErrors); } + errorInfo.ValidationErrors = GetValidationErrorInfos(exception as IHasValidationErrors); + } + + if (errorInfo.Message.IsNullOrEmpty()) + { + errorInfo.Message = L("InternalServerError"); + } + + return errorInfo; + } + + protected virtual RemoteServiceErrorInfo CreateEntityNotFoundError(EntityNotFoundException exception) + { + if (exception.EntityType != null) + { return new RemoteServiceErrorInfo( - entityNotFoundException.Message + string.Format( + L("EntityNotFound"), + exception.EntityType.Name, + exception.Id + ) ); } - if (exception is AbpAuthorizationException) + return new RemoteServiceErrorInfo(exception.Message); + } + + protected virtual Exception TryToGetActualException(Exception exception) + { + if (exception is AggregateException && exception.InnerException != null) { - var authorizationException = exception as AbpAuthorizationException; - return new RemoteServiceErrorInfo(authorizationException.Message); + var aggException = exception as AggregateException; + + if (aggException.InnerException is IUserFriendlyException || + aggException.InnerException is AbpValidationException || + aggException.InnerException is EntityNotFoundException || + aggException.InnerException is AbpAuthorizationException) + { + return aggException.InnerException; + } } - return new RemoteServiceErrorInfo(L("InternalServerError")); + return exception; } - private RemoteServiceErrorInfo CreateDetailedErrorInfoFromException(Exception exception) + protected virtual RemoteServiceErrorInfo CreateDetailedErrorInfoFromException(Exception exception) { var detailBuilder = new StringBuilder(); @@ -105,15 +130,15 @@ namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling return errorInfo; } - private void AddExceptionToDetails(Exception exception, StringBuilder detailBuilder) + protected virtual void AddExceptionToDetails(Exception exception, StringBuilder detailBuilder) { //Exception Message detailBuilder.AppendLine(exception.GetType().Name + ": " + exception.Message); //Additional info for UserFriendlyException - if (exception is UserFriendlyException) + if (exception is IUserFriendlyException) { - var userFriendlyException = exception as UserFriendlyException; + var userFriendlyException = exception as IUserFriendlyException; if (!string.IsNullOrEmpty(userFriendlyException.Details)) { detailBuilder.AppendLine(userFriendlyException.Details); @@ -158,7 +183,7 @@ namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling } } - private RemoteServiceValidationErrorInfo[] GetValidationErrorInfos(AbpValidationException validationException) + protected virtual RemoteServiceValidationErrorInfo[] GetValidationErrorInfos(IHasValidationErrors validationException) { var validationErrorInfos = new List(); @@ -177,7 +202,7 @@ namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling return validationErrorInfos.ToArray(); } - private string GetValidationErrorNarrative(AbpValidationException validationException) + protected virtual string GetValidationErrorNarrative(IHasValidationErrors validationException) { var detailBuilder = new StringBuilder(); detailBuilder.AppendLine(L("ValidationNarrativeTitle")); @@ -191,7 +216,7 @@ namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling return detailBuilder.ToString(); } - private string L(string name) + protected virtual string L(string name) { //TODO: Localization? //try diff --git a/src/Volo.Abp/Volo/Abp/Ui/IUserFriendlyException.cs b/src/Volo.Abp/Volo/Abp/Ui/IUserFriendlyException.cs new file mode 100644 index 0000000000..aef58c5fd0 --- /dev/null +++ b/src/Volo.Abp/Volo/Abp/Ui/IUserFriendlyException.cs @@ -0,0 +1,9 @@ +namespace Volo.Abp.Ui +{ + public interface IUserFriendlyException + { + string Message { get; } + + string Details { get; set; } + } +} \ No newline at end of file diff --git a/src/Volo.Abp/Volo/Abp/Ui/UserFriendlyException.cs b/src/Volo.Abp/Volo/Abp/Ui/UserFriendlyException.cs index 4bd7bc2d0a..a19fc761f5 100644 --- a/src/Volo.Abp/Volo/Abp/Ui/UserFriendlyException.cs +++ b/src/Volo.Abp/Volo/Abp/Ui/UserFriendlyException.cs @@ -9,12 +9,12 @@ namespace Volo.Abp.Ui /// This exception type is directly shown to the user. /// [Serializable] - public class UserFriendlyException : AbpException, IHasLogLevel, IHasErrorCode + public class UserFriendlyException : AbpException, IHasLogLevel, IHasErrorCode, IUserFriendlyException { /// /// Additional information about the exception. /// - public string Details { get; private set; } + public string Details { get; set; } /// /// An arbitrary error code. @@ -41,7 +41,7 @@ namespace Volo.Abp.Ui public UserFriendlyException(SerializationInfo serializationInfo, StreamingContext context) : base(serializationInfo, context) { - + } /// @@ -58,7 +58,7 @@ namespace Volo.Abp.Ui /// Constructor. /// /// Exception message - /// Exception severity + /// Exception severity public UserFriendlyException(string message, LogLevel logLevel) : base(message) { diff --git a/src/Volo.Abp/Volo/Abp/Validation/AbpValidationException.cs b/src/Volo.Abp/Volo/Abp/Validation/AbpValidationException.cs index e10a58ee7c..427e369e4f 100644 --- a/src/Volo.Abp/Volo/Abp/Validation/AbpValidationException.cs +++ b/src/Volo.Abp/Volo/Abp/Validation/AbpValidationException.cs @@ -11,7 +11,7 @@ namespace Volo.Abp.Validation /// This exception type is used to throws validation exceptions. /// [Serializable] - public class AbpValidationException : AbpException, IHasLogLevel + public class AbpValidationException : AbpException, IHasLogLevel, IHasValidationErrors { /// /// Detailed list of validation errors for this exception. diff --git a/src/Volo.Abp/Volo/Abp/Validation/IHasValidationErrors.cs b/src/Volo.Abp/Volo/Abp/Validation/IHasValidationErrors.cs new file mode 100644 index 0000000000..67cbbc908d --- /dev/null +++ b/src/Volo.Abp/Volo/Abp/Validation/IHasValidationErrors.cs @@ -0,0 +1,10 @@ +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; + +namespace Volo.Abp.Validation +{ + public interface IHasValidationErrors + { + IList ValidationErrors { get; set; } + } +} \ No newline at end of file