diff --git a/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionFilter.cs b/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionFilter.cs index f9fcd1d721..bbcbef6bc1 100644 --- a/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionFilter.cs +++ b/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionFilter.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Abstractions; using Microsoft.AspNetCore.Mvc.Filters; @@ -47,8 +48,12 @@ namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling return true; } - var accept = context.HttpContext.Request.Headers["Accept"]; - if (accept.ToString().Contains("application/json")) //TODO: Optimize + if (context.HttpContext.Request.Headers["Accept"].ToString().Contains("application/json")) //TODO: Optimize? + { + return true; + } + + if (context.HttpContext.Request.IsAjax()) { return true; } 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 97992f706e..891d8fba50 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 @@ -5,6 +5,7 @@ using System.Text; using Volo.Abp.Authorization; using Volo.Abp.DependencyInjection; using Volo.Abp.Domain.Entities; +using Volo.Abp.ExceptionHandling; using Volo.Abp.Http; using Volo.Abp.UI; using Volo.Abp.Validation; @@ -52,7 +53,7 @@ namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling if (exception is IUserFriendlyException) { var userFriendlyException = exception as IUserFriendlyException; - errorInfo.Message = userFriendlyException.Message; + errorInfo.Message = exception.Message; errorInfo.Details = userFriendlyException.Details; } @@ -71,6 +72,12 @@ namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling errorInfo.ValidationErrors = GetValidationErrorInfos(exception as IHasValidationErrors); } + //TODO: For test purpose + if (exception is IBusinessException) + { + errorInfo.Message = (exception as IBusinessException).Code; + } + if (errorInfo.Message.IsNullOrEmpty()) { errorInfo.Message = L("InternalServerError"); diff --git a/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/HttpExceptionStatusCodeFinder.cs b/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/HttpExceptionStatusCodeFinder.cs index c4789a75e2..c099be0e7a 100644 --- a/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/HttpExceptionStatusCodeFinder.cs +++ b/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/HttpExceptionStatusCodeFinder.cs @@ -12,6 +12,8 @@ namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling { public virtual int GetStatusCode(HttpContext httpContext, Exception exception) { + //TODO: If the exception has error code than we can determine the exception from it! + if (exception is AbpAuthorizationException) { return httpContext.User.Identity.IsAuthenticated @@ -29,6 +31,11 @@ namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling return (int)HttpStatusCode.NotFound; } + if (exception is IBusinessException) + { + return (int)HttpStatusCode.Forbidden; + } + return (int)HttpStatusCode.InternalServerError; } } diff --git a/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Http/HttpRequestExtensions.cs b/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Http/HttpRequestExtensions.cs new file mode 100644 index 0000000000..46fdd07630 --- /dev/null +++ b/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Http/HttpRequestExtensions.cs @@ -0,0 +1,22 @@ +using Volo.Abp; + +namespace Microsoft.AspNetCore.Http +{ + public static class HttpRequestExtensions + { + private const string RequestedWithHeader = "X-Requested-With"; + private const string XmlHttpRequest = "XMLHttpRequest"; + + public static bool IsAjax(this HttpRequest request) + { + Check.NotNull(request, nameof(request)); + + if (request.Headers == null) + { + return false; + } + + return request.Headers[RequestedWithHeader] == XmlHttpRequest; + } + } +} diff --git a/src/Volo.Abp.Core/Volo/Abp/BusinessException.cs b/src/Volo.Abp.Core/Volo/Abp/BusinessException.cs new file mode 100644 index 0000000000..b288a6659d --- /dev/null +++ b/src/Volo.Abp.Core/Volo/Abp/BusinessException.cs @@ -0,0 +1,28 @@ +using System; +using Microsoft.Extensions.Logging; +using Volo.Abp.ExceptionHandling; +using Volo.Abp.Logging; + +namespace Volo.Abp +{ + public class BusinessException : Exception, IBusinessException, IHasErrorDetails, IHasLogLevel + { + public string Code { get; set; } + + public string Details { get; set; } + + public LogLevel LogLevel { get; set; } = LogLevel.Warning; + + public BusinessException() + { + + } + + public BusinessException(string code, string message = null, string details = null) + : base(message) + { + Code = code; + Details = details; + } + } +} \ No newline at end of file diff --git a/src/Volo.Abp.Core/Volo/Abp/IHasErrorCode.cs b/src/Volo.Abp.Core/Volo/Abp/ExceptionHandling/IHasErrorCode.cs similarity index 66% rename from src/Volo.Abp.Core/Volo/Abp/IHasErrorCode.cs rename to src/Volo.Abp.Core/Volo/Abp/ExceptionHandling/IHasErrorCode.cs index 1e30895fe6..35f31b1aa0 100644 --- a/src/Volo.Abp.Core/Volo/Abp/IHasErrorCode.cs +++ b/src/Volo.Abp.Core/Volo/Abp/ExceptionHandling/IHasErrorCode.cs @@ -1,4 +1,4 @@ -namespace Volo.Abp +namespace Volo.Abp.ExceptionHandling { public interface IHasErrorCode { diff --git a/src/Volo.Abp.Core/Volo/Abp/ExceptionHandling/IHasErrorDetails.cs b/src/Volo.Abp.Core/Volo/Abp/ExceptionHandling/IHasErrorDetails.cs new file mode 100644 index 0000000000..b2a6826fe9 --- /dev/null +++ b/src/Volo.Abp.Core/Volo/Abp/ExceptionHandling/IHasErrorDetails.cs @@ -0,0 +1,7 @@ +namespace Volo.Abp.ExceptionHandling +{ + public interface IHasErrorDetails + { + string Details { get; set; } + } +} \ No newline at end of file diff --git a/src/Volo.Abp.Core/Volo/Abp/IBusinessException.cs b/src/Volo.Abp.Core/Volo/Abp/IBusinessException.cs new file mode 100644 index 0000000000..c7fcf8b502 --- /dev/null +++ b/src/Volo.Abp.Core/Volo/Abp/IBusinessException.cs @@ -0,0 +1,9 @@ +using Volo.Abp.ExceptionHandling; + +namespace Volo.Abp +{ + public interface IBusinessException : IHasErrorCode + { + + } +} \ No newline at end of file diff --git a/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceExtensions.cs b/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceExtensions.cs deleted file mode 100644 index 9ec0fc5b68..0000000000 --- a/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceExtensions.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using JetBrains.Annotations; - -namespace Volo.Abp.Localization -{ - public static class LocalizationResourceExtensions - { - public static LocalizationResource InheritFrom([NotNull] this LocalizationResource resource, [NotNull] params Type[] baseResourceTypes) - { - Check.NotNull(resource, nameof(resource)); - Check.NotNull(baseResourceTypes, nameof(baseResourceTypes)); - - resource.BaseResourceTypes.AddRange(baseResourceTypes); - - return resource; - } - } -} \ No newline at end of file diff --git a/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceListExtensions.cs b/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceListExtensions.cs index 7cad8126ba..656b3c59ff 100644 --- a/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceListExtensions.cs +++ b/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceListExtensions.cs @@ -40,6 +40,30 @@ namespace Volo.Abp.Localization { Check.NotNull(resourceDictionary, nameof(resourceDictionary)); + GetResource(resourceDictionary).Extensions.Add( + new JsonEmbeddedFileLocalizationDictionaryProvider( + virtualPath + ) + ); + } + + public static void AddBaseTypes( + [NotNull] this LocalizationResourceDictionary resourceDictionary, + [NotNull] params Type[] types) + { + Check.NotNull(resourceDictionary, nameof(resourceDictionary)); + Check.NotNull(types, nameof(types)); + + var resource = GetResource(resourceDictionary); + + foreach (var type in types) + { + resource.BaseResourceTypes.AddIfNotContains(type); + } + } + + private static LocalizationResource GetResource(LocalizationResourceDictionary resourceDictionary) + { var resourceType = typeof(TResource); var resource = resourceDictionary.GetOrDefault(resourceType); @@ -48,9 +72,7 @@ namespace Volo.Abp.Localization throw new AbpException("Can not find a resource with given type: " + resourceType.AssemblyQualifiedName); } - resource.Extensions.Add(new JsonEmbeddedFileLocalizationDictionaryProvider( - virtualPath - )); + return resource; } } } \ No newline at end of file diff --git a/src/Volo.Abp.UI/Volo/Abp/Ui/IUserFriendlyException.cs b/src/Volo.Abp.UI/Volo/Abp/Ui/IUserFriendlyException.cs index 14d716432a..91885c1e91 100644 --- a/src/Volo.Abp.UI/Volo/Abp/Ui/IUserFriendlyException.cs +++ b/src/Volo.Abp.UI/Volo/Abp/Ui/IUserFriendlyException.cs @@ -1,13 +1,9 @@ +using Volo.Abp.ExceptionHandling; + namespace Volo.Abp.UI { - /* TODO: - * - define an interface to split Details, like IHasExceptionDetails - */ - - public interface IUserFriendlyException + public interface IUserFriendlyException : IHasErrorDetails { - string Message { get; } - string Details { get; set; } } } \ No newline at end of file diff --git a/src/Volo.Abp.UI/Volo/Abp/Ui/UserFriendlyException.cs b/src/Volo.Abp.UI/Volo/Abp/Ui/UserFriendlyException.cs index 95c5e0a265..1991fb4011 100644 --- a/src/Volo.Abp.UI/Volo/Abp/Ui/UserFriendlyException.cs +++ b/src/Volo.Abp.UI/Volo/Abp/Ui/UserFriendlyException.cs @@ -1,6 +1,7 @@ using System; using System.Runtime.Serialization; using Microsoft.Extensions.Logging; +using Volo.Abp.ExceptionHandling; using Volo.Abp.Logging; namespace Volo.Abp.UI