From fd3b79395ed6c9e05733a18c88be647b4a15537e Mon Sep 17 00:00:00 2001 From: Yunus Emre Kalkan Date: Fri, 4 Sep 2020 17:07:02 +0300 Subject: [PATCH] Remote exceptions localization data --- .../DefaultExceptionToErrorInfoConverter.cs | 7 ++- .../Abp/Http/Client/AbpRemoteCallException.cs | 8 +++ .../Volo/Abp/Http/RemoteServiceErrorInfo.cs | 6 +- .../Volo/Abp/Identity/Localization/en.json | 56 +++++++++---------- .../Volo/Abp/Identity/Localization/tr.json | 56 +++++++++---------- .../Identity/AbpIdentityResultExtensions.cs | 41 +++++++++++++- .../Identity/AbpIdentityResultException.cs | 9 ++- 7 files changed, 120 insertions(+), 63 deletions(-) diff --git a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/DefaultExceptionToErrorInfoConverter.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/DefaultExceptionToErrorInfoConverter.cs index cd2f393104..339b249e49 100644 --- a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/DefaultExceptionToErrorInfoConverter.cs +++ b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/DefaultExceptionToErrorInfoConverter.cs @@ -72,7 +72,7 @@ namespace Volo.Abp.AspNetCore.ExceptionHandling } var errorInfo = new RemoteServiceErrorInfo(); - + if (exception is IUserFriendlyException) { errorInfo.Message = exception.Message; @@ -101,6 +101,8 @@ namespace Volo.Abp.AspNetCore.ExceptionHandling errorInfo.Message = L["InternalServerErrorMessage"]; } + errorInfo.Data = exception.Data; + return errorInfo; } @@ -190,7 +192,6 @@ namespace Volo.Abp.AspNetCore.ExceptionHandling return exception; } - protected virtual RemoteServiceErrorInfo CreateDetailedErrorInfoFromException(Exception exception) { var detailBuilder = new StringBuilder(); @@ -213,7 +214,7 @@ namespace Volo.Abp.AspNetCore.ExceptionHandling detailBuilder.AppendLine(exception.GetType().Name + ": " + exception.Message); //Additional info for UserFriendlyException - if (exception is IUserFriendlyException && + if (exception is IUserFriendlyException && exception is IHasErrorDetails) { var details = ((IHasErrorDetails) exception).Details; diff --git a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/AbpRemoteCallException.cs b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/AbpRemoteCallException.cs index d5cbc10c0b..71966868f9 100644 --- a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/AbpRemoteCallException.cs +++ b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/AbpRemoteCallException.cs @@ -28,6 +28,14 @@ namespace Volo.Abp.Http.Client : base(error.Message) { Error = error; + + if (error?.Data != null) + { + foreach (var dataKey in error.Data.Keys) + { + Data[dataKey] = error.Data[dataKey]; + } + } } } } diff --git a/framework/src/Volo.Abp.Http/Volo/Abp/Http/RemoteServiceErrorInfo.cs b/framework/src/Volo.Abp.Http/Volo/Abp/Http/RemoteServiceErrorInfo.cs index 25792d1b24..287b423c20 100644 --- a/framework/src/Volo.Abp.Http/Volo/Abp/Http/RemoteServiceErrorInfo.cs +++ b/framework/src/Volo.Abp.Http/Volo/Abp/Http/RemoteServiceErrorInfo.cs @@ -1,4 +1,6 @@ using System; +using System.Collections; +using System.Collections.Generic; namespace Volo.Abp.Http { @@ -23,6 +25,8 @@ namespace Volo.Abp.Http /// public string Details { get; set; } + public IDictionary Data { get; set; } + /// /// Validation errors if exists. /// @@ -49,4 +53,4 @@ namespace Volo.Abp.Http Code = code; } } -} \ No newline at end of file +} diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/en.json b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/en.json index 6d8a5c58c5..8259e1abb2 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/en.json +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/en.json @@ -35,34 +35,34 @@ "DisplayName:NewPasswordConfirm": "Confirm new password", "PasswordChangedMessage": "Your password has been changed successfully.", "PersonalSettingsSavedMessage": "Your personal settings has been saved successfully.", - "Identity.DefaultError": "An unknown failure has occurred.", - "Identity.ConcurrencyFailure": "Optimistic concurrency failure, object has been modified.", - "Identity.DuplicateEmail": "Email '{0}' is already taken.", - "Identity.DuplicateRoleName": "Role name '{0}' is already taken.", - "Identity.DuplicateUserName": "User name '{0}' is already taken.", - "Identity.InvalidEmail": "Email '{0}' is invalid.", - "Identity.InvalidPasswordHasherCompatibilityMode": "The provided PasswordHasherCompatibilityMode is invalid.", - "Identity.InvalidPasswordHasherIterationCount": "The iteration count must be a positive integer.", - "Identity.InvalidRoleName": "Role name '{0}' is invalid.", - "Identity.InvalidToken": "Invalid token.", - "Identity.InvalidUserName": "User name '{0}' is invalid, can only contain letters or digits.", - "Identity.LoginAlreadyAssociated": "A user with this login already exists.", - "Identity.PasswordMismatch": "Incorrect password.", - "Identity.PasswordRequiresDigit": "Passwords must have at least one digit ('0'-'9').", - "Identity.PasswordRequiresLower": "Passwords must have at least one lowercase ('a'-'z').", - "Identity.PasswordRequiresNonAlphanumeric": "Passwords must have at least one non alphanumeric character.", - "Identity.PasswordRequiresUpper": "Passwords must have at least one uppercase ('A'-'Z').", - "Identity.PasswordTooShort": "Passwords must be at least {0} characters.", - "Identity.RoleNotFound": "Role {0} does not exist.", - "Identity.UserAlreadyHasPassword": "User already has a password set.", - "Identity.UserAlreadyInRole": "User already in role '{0}'.", - "Identity.UserLockedOut": "User is locked out.", - "Identity.UserLockoutNotEnabled": "Lockout is not enabled for this user.", - "Identity.UserNameNotFound": "User {0} does not exist.", - "Identity.UserNotInRole": "User is not in role '{0}'.", - "Identity.PasswordConfirmationFailed": "Password does not match the confirm password.", - "Identity.StaticRoleRenamingErrorMessage": "Static roles can not be renamed.", - "Identity.StaticRoleDeletionErrorMessage": "Static roles can not be deleted.", + "Volo.Abp.Identity:DefaultError": "An unknown failure has occurred.", + "Volo.Abp.Identity:ConcurrencyFailure": "Optimistic concurrency failure, object has been modified.", + "Volo.Abp.Identity:DuplicateEmail": "Email '{0}' is already taken.", + "Volo.Abp.Identity:DuplicateRoleName": "Role name '{0}' is already taken.", + "Volo.Abp.Identity:DuplicateUserName": "User name '{0}' is already taken.", + "Volo.Abp.Identity:InvalidEmail": "Email '{0}' is invalid.", + "Volo.Abp.Identity:InvalidPasswordHasherCompatibilityMode": "The provided PasswordHasherCompatibilityMode is invalid.", + "Volo.Abp.Identity:InvalidPasswordHasherIterationCount": "The iteration count must be a positive integer.", + "Volo.Abp.Identity:InvalidRoleName": "Role name '{0}' is invalid.", + "Volo.Abp.Identity:InvalidToken": "Invalid token.", + "Volo.Abp.Identity:InvalidUserName": "User name '{0}' is invalid, can only contain letters or digits.", + "Volo.Abp.Identity:LoginAlreadyAssociated": "A user with this login already exists.", + "Volo.Abp.Identity:PasswordMismatch": "Incorrect password.", + "Volo.Abp.Identity:PasswordRequiresDigit": "Passwords must have at least one digit ('0'-'9').", + "Volo.Abp.Identity:PasswordRequiresLower": "Passwords must have at least one lowercase ('a'-'z').", + "Volo.Abp.Identity:PasswordRequiresNonAlphanumeric": "Passwords must have at least one non alphanumeric character.", + "Volo.Abp.Identity:PasswordRequiresUpper": "Passwords must have at least one uppercase ('A'-'Z').", + "Volo.Abp.Identity:PasswordTooShort": "Passwords must be at least {0} characters.", + "Volo.Abp.Identity:RoleNotFound": "Role {0} does not exist.", + "Volo.Abp.Identity:UserAlreadyHasPassword": "User already has a password set.", + "Volo.Abp.Identity:UserAlreadyInRole": "User already in role '{0}'.", + "Volo.Abp.Identity:UserLockedOut": "User is locked out.", + "Volo.Abp.Identity:UserLockoutNotEnabled": "Lockout is not enabled for this user.", + "Volo.Abp.Identity:UserNameNotFound": "User {0} does not exist.", + "Volo.Abp.Identity:UserNotInRole": "User is not in role '{0}'.", + "Volo.Abp.Identity:PasswordConfirmationFailed": "Password does not match the confirm password.", + "Volo.Abp.Identity:StaticRoleRenamingErrorMessage": "Static roles can not be renamed.", + "Volo.Abp.Identity:StaticRoleDeletionErrorMessage": "Static roles can not be deleted.", "Identity.OrganizationUnit.DuplicateDisplayNameWarning": "There is already an organization unit with name {0}. Two units with same name can not be created in same level.", "Identity.OrganizationUnit.MaxUserMembershipCount": "Maximum allowed organization unit membership count for a user", "Volo.Abp.Identity:010001": "You can not delete your own account!", diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/tr.json b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/tr.json index 0b17e51276..b270f344ef 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/tr.json +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/tr.json @@ -35,34 +35,34 @@ "DisplayName:NewPasswordConfirm": "Yeni şifre (tekrar)", "PasswordChangedMessage": "Şifreniz başarıyla değiştirildi.", "PersonalSettingsSavedMessage": "Kişisel bilgileriniz başarıyla kaydedildi.", - "Identity.StaticRoleRenamingErrorMessage": "Bir Sabit rolün ismi değiştirilemez.", - "Identity.StaticRoleDeletionErrorMessage": "Bir Sabit rol silinemez.", - "Identity.DefaultError": "Bilinmeyen bir hata oluştu.", - "Identity.ConcurrencyFailure": "İyimser eşzamanlılık hatası. Nesne değiştirilmiş.", - "Identity.DuplicateEmail": "'{0}' email adresi zaten alınmış.", - "Identity.DuplicateRoleName": "'{0}' rol ismi zaten alınmış.", - "Identity.DuplicateUserName": "'{0}' kullanıcı adı zaten alınmış.", - "Identity.InvalidEmail": "'{0}' email adresi hatalı.", - "Identity.InvalidPasswordHasherCompatibilityMode": "Belirtilen PasswordHasherCompatibilityMode geçersiz.", - "Identity.InvalidPasswordHasherIterationCount": "Iterasyon sayısı sıfırdan büyük bir sayı olmalı.", - "Identity.InvalidRoleName": "'{0}' rol ismi geçersizdir.", - "Identity.InvalidToken": "Geçersiz token.", - "Identity.InvalidUserName": "'{0}' kullanıcı adı geçersiz, sadece harf ve rakamlardan oluşmalı.", - "Identity.LoginAlreadyAssociated": "Bu giriş bilgilerine sahip bir kullanıcı zaten var.", - "Identity.PasswordMismatch": "Hatalı şifre.", - "Identity.PasswordRequiresDigit": "Şifre en az bir sayı içermeli ('0'-'9').", - "Identity.PasswordRequiresLower": "Şifre en az bir küçük harf içermeli ('a'-'z').", - "Identity.PasswordRequiresNonAlphanumeric": "Şifre en az bir sayı ya da harf olmayan karakter içermeli.", - "Identity.PasswordRequiresUpper": "Şifre en az bir büyük harf içermeli ('A'-'Z').", - "Identity.PasswordTooShort": "Şifre en az {0} karakter uzunluğunda olmalı.", - "Identity.RoleNotFound": "{0} rolü bulunamadı.", - "Identity.UserAlreadyHasPassword": "Kullanıcının zaten bir şifresi var.", - "Identity.UserAlreadyInRole": "Kullanıcı zaten '{0}' rolünde.", - "Identity.UserLockedOut": "Kullanıcı hesabı kilitlenmiş.", - "Identity.UserLockoutNotEnabled": "Bu kullanıcı için hesap kilitleme etkin değil.", - "Identity.UserNameNotFound": "{0} kullanıcısı bulunamadı.", - "Identity.UserNotInRole": "Kullanıcı '{0}' rolünde değil.", - "Identity.PasswordConfirmationFailed": "Yeni şifre ile onay şifresi uyuşmuyor.", + "Volo.Abp.Identity:StaticRoleRenamingErrorMessage": "Bir Sabit rolün ismi değiştirilemez.", + "Volo.Abp.Identity:StaticRoleDeletionErrorMessage": "Bir Sabit rol silinemez.", + "Volo.Abp.Identity:DefaultError": "Bilinmeyen bir hata oluştu.", + "Volo.Abp.Identity:ConcurrencyFailure": "İyimser eşzamanlılık hatası. Nesne değiştirilmiş.", + "Volo.Abp.Identity:DuplicateEmail": "'{0}' email adresi zaten alınmış.", + "Volo.Abp.Identity:DuplicateRoleName": "'{0}' rol ismi zaten alınmış.", + "Volo.Abp.Identity:DuplicateUserName": "'{0}' kullanıcı adı zaten alınmış.", + "Volo.Abp.Identity:InvalidEmail": "'{0}' email adresi hatalı.", + "Volo.Abp.Identity:InvalidPasswordHasherCompatibilityMode": "Belirtilen PasswordHasherCompatibilityMode geçersiz.", + "Volo.Abp.Identity:InvalidPasswordHasherIterationCount": "Iterasyon sayısı sıfırdan büyük bir sayı olmalı.", + "Volo.Abp.Identity:InvalidRoleName": "'{0}' rol ismi geçersizdir.", + "Volo.Abp.Identity:InvalidToken": "Geçersiz token.", + "Volo.Abp.Identity:InvalidUserName": "'{0}' kullanıcı adı geçersiz, sadece harf ve rakamlardan oluşmalı.", + "Volo.Abp.Identity:LoginAlreadyAssociated": "Bu giriş bilgilerine sahip bir kullanıcı zaten var.", + "Volo.Abp.Identity:PasswordMismatch": "Hatalı şifre.", + "Volo.Abp.Identity:PasswordRequiresDigit": "Şifre en az bir sayı içermeli ('0'-'9').", + "Volo.Abp.Identity:PasswordRequiresLower": "Şifre en az bir küçük harf içermeli ('a'-'z').", + "Volo.Abp.Identity:PasswordRequiresNonAlphanumeric": "Şifre en az bir sayı ya da harf olmayan karakter içermeli.", + "Volo.Abp.Identity:PasswordRequiresUpper": "Şifre en az bir büyük harf içermeli ('A'-'Z').", + "Volo.Abp.Identity:PasswordTooShort": "Şifre en az {0} karakter uzunluğunda olmalı.", + "Volo.Abp.Identity:RoleNotFound": "{0} rolü bulunamadı.", + "Volo.Abp.Identity:UserAlreadyHasPassword": "Kullanıcının zaten bir şifresi var.", + "Volo.Abp.Identity:UserAlreadyInRole": "Kullanıcı zaten '{0}' rolünde.", + "Volo.Abp.Identity:UserLockedOut": "Kullanıcı hesabı kilitlenmiş.", + "Volo.Abp.Identity:UserLockoutNotEnabled": "Bu kullanıcı için hesap kilitleme etkin değil.", + "Volo.Abp.Identity:UserNameNotFound": "{0} kullanıcısı bulunamadı.", + "Volo.Abp.Identity:UserNotInRole": "Kullanıcı '{0}' rolünde değil.", + "Volo.Abp.Identity:PasswordConfirmationFailed": "Yeni şifre ile onay şifresi uyuşmuyor.", "Identity.OrganizationUnit.DuplicateDisplayNameWarning": "{0} isminde bir birim zaten var. Aynı seviyede aynı isimli iki birim olamaz.", "Identity.OrganizationUnit.MaxUserMembershipCount": "Bir kullanıcı için izin verilen en fazla organizasyon birimi sayısı", "Volo.Abp.Identity:010001": "Kendi hesabınızı silemezsiniz!", diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Microsoft/AspNetCore/Identity/AbpIdentityResultExtensions.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Microsoft/AspNetCore/Identity/AbpIdentityResultExtensions.cs index 0ef3582af1..f71f8f76e9 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Microsoft/AspNetCore/Identity/AbpIdentityResultExtensions.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Microsoft/AspNetCore/Identity/AbpIdentityResultExtensions.cs @@ -1,4 +1,5 @@ using System; +using System.Collections; using System.Linq; using System.Collections.Generic; using System.Globalization; @@ -26,6 +27,41 @@ namespace Microsoft.AspNetCore.Identity throw new AbpIdentityResultException(identityResult); } + public static string[] GetValuesFromErrorMessage(this IdentityResult identityResult, IStringLocalizer localizer) + { + if (identityResult.Succeeded) + { + throw new ArgumentException( + "identityResult.Succeeded should be false in order to get values from error."); + } + + if (identityResult.Errors == null) + { + throw new ArgumentException("identityResult.Errors should not be null."); + } + + var error = identityResult.Errors.First(); + var key = $"Volo.Abp.Identity:{error.Code}"; + + using (CultureHelper.Use(CultureInfo.GetCultureInfo("en"))) + { + var englishLocalizedString = localizer[key]; + + if (englishLocalizedString.ResourceNotFound) + { + return Array.Empty(); + } + + if (FormattedStringValueExtracter.IsMatch(error.Description, englishLocalizedString.Value, + out var values)) + { + return values; + } + + return Array.Empty(); + } + } + public static string LocalizeErrors(this IdentityResult identityResult, IStringLocalizer localizer) { if (identityResult.Succeeded) @@ -43,7 +79,7 @@ namespace Microsoft.AspNetCore.Identity public static string LocalizeErrorMessage(this IdentityError error, IStringLocalizer localizer) { - var key = $"Identity.{error.Code}"; + var key = $"Volo.Abp.Identity:{error.Code}"; var localizedString = localizer[key]; @@ -54,7 +90,8 @@ namespace Microsoft.AspNetCore.Identity var englishLocalizedString = localizer[key]; if (!englishLocalizedString.ResourceNotFound) { - if (FormattedStringValueExtracter.IsMatch(error.Description, englishLocalizedString.Value, out var values)) + if (FormattedStringValueExtracter.IsMatch(error.Description, englishLocalizedString.Value, + out var values)) { return string.Format(localizedString.Value, values.Cast().ToArray()); } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpIdentityResultException.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpIdentityResultException.cs index de02081a1d..b608720576 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpIdentityResultException.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpIdentityResultException.cs @@ -18,7 +18,7 @@ namespace Volo.Abp.Identity public AbpIdentityResultException([NotNull] IdentityResult identityResult) : base( - code: $"Identity.{identityResult.Errors.First().Code}", + code: $"Volo.Abp.Identity:{identityResult.Errors.First().Code}", message: identityResult.Errors.Select(err => err.Description).JoinAsString(", ")) { IdentityResult = Check.NotNull(identityResult, nameof(identityResult)); @@ -32,6 +32,13 @@ namespace Volo.Abp.Identity public virtual string LocalizeMessage(LocalizationContext context) { + var values = IdentityResult.GetValuesFromErrorMessage(context.LocalizerFactory.Create()); + + for (var index = 0; index < values.Length; index++) + { + Data[index.ToString()] = values[index]; + } + return IdentityResult.LocalizeErrors(context.LocalizerFactory.Create()); } }