Asp.Net Identity Localization PublicKeyToken

时间:2014-04-03 11:19:26

标签: c# .net asp.net-mvc dll asp.net-identity

我试图通过使用以下帖子中的建议来获取针对Asp.Net Identity的瑞典语的本地化错误消息:How to localize ASP.NET Identity UserName and Password error messages?

使用NuGet我下载了德语语言包,然后在dotPeek中打开\ packages \ Microsoft.AspNet.Identity.Core.2.0.0 \ lib \ net45 \ de \ Microsoft.AspNet.Identity.Core.resources.dll然后将其导出到新的VS项目:

https://github.com/nielsbosma/AspNet.Identity.Resources.Swedish/

我已将生成的\ Microsoft.AspNet.Identity.Core.resources.dll复制到\​​ packages \ Microsoft.AspNet.Identity.Core.2.0.0 \ lib \ net45 \ se。下的新文件夹。< / p>

当我在本地运行我的网站时,我发现Microsoft.AspNet.Identity.Core.resources.dll已复制到MySite \ bin \ sv \

但是我无法让它发挥作用:(

如果我在我的Web.config中设置:

<system.web>
    ...
    <globalization culture="sv-SE" uiCulture="sv" />
</system.web>

我仍然收到英文默认错误消息。但如果我改为德语,我已经从NuGet中收录了,我会收到德语错误消息。

使用dotPeek我将我的dll与德语进行了比较,除了我的PublicKeyToken = null和德语的#34; 31bf3856ad364e35&#34;之外,它们是相同的。这可能是我无法加载我的dll的原因吗?无论如何为dll设置PublicKeyToken?任何解决方法?

感谢您的任何指示。

6 个答案:

答案 0 :(得分:8)

除非您拥有Microsoft用于签署dll的私钥。

更新:作为一种解决方法,直到我们添加对插入您自己的资源的支持,您现在可能只使用显式切换包装所有默认标识结果错误消息,应该只有大约10-20个面向用户的错误。

类似的东西:

public static string Localize(string error) {
     switch (error) {
          case "<english error>": return "<localized version";
     }
}

答案 1 :(得分:5)

受到彼得答案的启发,我想出了一个糟糕但快速的解决方案。

我需要在默认的AccountController模板中本地化错误,所以我编写了自己的AddLocalizedErrors方法。我正在使用Resources来本地化错误。

    //Original method
    private void AddErrors(IdentityResult result)
    {
        foreach (var error in result.Errors)
        {
            ModelState.AddModelError("", error);
        }
    }
    //My method
    private void AddLocalizedErrors(IdentityResult result, ApplicationUser user)
    {
        foreach (var error in result.Errors)
        {
            var localizedError = error;
            string userName = "";
            string email = "";
            if (user != null) 
            {
                userName = user.UserName;
                email = user.Email;
            }
            //password errors
            localizedError = localizedError.Replace("Passwords must have at least one uppercase ('A'-'Z').", AspNetValidationMessages.password_uppercase);
            localizedError = localizedError.Replace("Passwords must have at least one digit ('0'-'9').", AspNetValidationMessages.password_digit);
            localizedError = localizedError.Replace("Passwords must have at least one lowercase ('a'-'z').", AspNetValidationMessages.password_lowercase);
            localizedError = localizedError.Replace("Passwords must have at least one non letter or digit character.", AspNetValidationMessages.password_nonletter_nondigit);
            localizedError = localizedError.Replace("Passwords must have at least one non letter or digit character.", AspNetValidationMessages.password_nonletter_nondigit); 
            localizedError = localizedError.Replace("Passwords must have at least one non letter or digit character.", AspNetValidationMessages.password_nonletter_nondigit); 
            //register errors
            localizedError = localizedError.Replace("Name "+userName+" is already taken.", AspNetValidationMessages.name_taken.Replace("{0}", userName));
            localizedError = localizedError.Replace("Email '" + email + "' is already taken.", AspNetValidationMessages.email_taken.Replace("{0}", email)); 

            ModelState.AddModelError("", localizedError);
        }
    }

我正在使用string.Replace(),因为例如密码错误只是单个密码要求的字符串。

当谈到角色的收集时,我应该更有创意。可能使用string.Contains()

答案 2 :(得分:4)

目前这是一个非常糟糕的解决方案,但一个解决方案解决方案。为我们这些需要本地化并且不在Microsoft工作的人节省时间......这就是我作为荷兰语的解决方法所做的。

public class Demo {
    private string LocalizeIdentityError(string error, IdentityUser user)
    {
        if (error == "User already in role.") return "De gebruiker zit reeds in deze rol.";
        else if (error == "User is not in role.") return "De gebruiker zit niet in deze rol.";
        //else if (error == "Role {0} does not exist.") return "De rol bestaat nog niet";
        //else if (error == "Store does not implement IUserClaimStore&lt;TUser&gt;.") return "";
        //else if (error == "No IUserTwoFactorProvider for '{0}' is registered.") return "";
        //else if (error == "Store does not implement IUserEmailStore&lt;TUser&gt;.") return "";
        else if (error == "Incorrect password.") return "Ongeldig wachtwoord";
        //else if (error == "Store does not implement IUserLockoutStore&lt;TUser&gt;.") return "";
        //else if (error == "No IUserTokenProvider is registered.") return "";
        //else if (error == "Store does not implement IUserRoleStore&lt;TUser&gt;.") return "";
        //else if (error == "Store does not implement IUserLoginStore&lt;TUser&gt;.") return "";
        else if (error == "User name {0} is invalid, can only contain letters or digits.") return "De gebruikersnaam '"+user.UserName+"' kan alleen letters of cijfers bevatten.";
        //else if (error == "Store does not implement IUserPhoneNumberStore&lt;TUser&gt;.") return "";
        //else if (error == "Store does not implement IUserConfirmationStore&lt;TUser&gt;.") return "";
        else if (error.StartsWith("Passwords must be at least ")) return "Een wachtwoord moet minstens {0} karakters bevatten.";
        //else if (error == "{0} cannot be null or empty.") return "";
        else if (user != null && error == "Name "+user.UserName+" is already taken.") return "De gebruikersnaam '" + user.UserName + "' is reeds in gebruik.";
        else if (error == "User already has a password set.") return "Deze gebruiker heeft reeds een wachtwoord ingesteld.";
        //else if (error == "Store does not implement IUserPasswordStore&lt;TUser&gt;.") return "";
        else if (error == "Passwords must have at least one non letter or digit character.") return "Wachtwoorden moeten minstens een ander karakter dan een letter of cijfer bevatten.";
        else if (error == "UserId not found.") return "De gebruiker kon niet gevonden worden.";
        else if (error == "Invalid token.") return "Ongeldig token.";
        else if (user != null && error == "Email '" + user.Email + "' is invalid.") return "Het emailadres '" + user.Email + "' is ongeldig.";
        else if (user != null && error == "User " + user.UserName + " does not exist.") return "De gebruiker '" + user.UserName + "' bestaat niet.";
        else if (error == "Store does not implement IQueryableRoleStore&lt;TRole&gt;.") return "";
        else if (error == "Lockout is not enabled for this user.") return "Lockout is niet geactiveerd voor deze gebruiker.";
        //else if (error == "Store does not implement IUserTwoFactorStore&lt;TUser&gt;.") return "";
        else if (error == "Passwords must have at least one uppercase ('A'-'Z').") return "Wachtwoorden moeten minstens één hoofdletter bevatten. (A-Z)";
        else if (error == "Passwords must have at least one digit ('0'-'9').") return "Wachtwoorden moeten minstens één getal bevatten. (0-9)";
        else if (error == "Passwords must have at least one lowercase ('a'-'z').") return "Wachtwoorden moeten minstens één kleine letter bevatten. (a-z)";
        //else if (error == "Store does not implement IQueryableUserStore&lt;TUser&gt;.") return "";
        else if (user != null && error == "Email '" + user.Email + "' is already taken.") return "Het emailadres '" + user.Email + "' is reeds in gebruik. Probeer aan te melden.";
        //else if (error == "Store does not implement IUserSecurityStampStore&lt;TUser&gt;.") return "";
        else if (error == "A user with that external login already exists.") return "Een gebruiker met deze externe login bestaat reeds.";
        else if (error == "An unknown failure has occured.") return "Een onbekende fout is opgetreden. Probeer het later opnieuw.";

        return error;
    }
}

答案 3 :(得分:2)

另一种选择是从Microsoft.AspNet.Identity.PasswordValidator继承然后覆盖ValidateAsync。

然后,您可以使用自己的资源文件进行本地化。英语的原始资源文件可以使用DotPeek或类似文件找到,然后您可以将其用作英语作为您自己翻译的模板。

我的resx文件:

MyLocalization / IdentityResource.resx(与Microsoft.AspNet.Identity.Core.Resources相同)

MyLocalization / IdentityResource.nb-no.resx(我的挪威语翻译)

 var manager = new ApplicationUserManager(new UserStore<ApplicationUser>    (context.Get<ApplicationDbContext>()));

 // Configure validation logic for passwords
 manager.PasswordValidator = new MyCustomPasswordValidator(System.Threading.Thread.CurrentThread.CurrentUICulture)

在MyCustomPasswordValidator.cs中:(另请注意我在ValidateAsync中也必须做的错误修复)

using Resources = MyLocalization.IdentityResource;

public class MyCustomPasswordValidator : Microsoft.AspNet.Identity.PasswordValidator
{
    private readonly CultureInfo _currentUIculture;

    public MyCustomPasswordValidator(CultureInfo currentUIculture)
    {
        _currentUIculture = currentUIculture;
    }

    /// <summary>
    /// Ensures that the string is of the required length and meets the configured requirements
    /// 
    /// </summary>
    /// <param name="item"/>
    /// <returns/>
    public override Task<IdentityResult> ValidateAsync(string item)
    {
        //BUG: CurrentUICulture is not set correctly https://aspnetidentity.codeplex.com/workitem/2060
        System.Threading.Thread.CurrentThread.CurrentUICulture = _currentUIculture;
        if (item == null)
            throw new ArgumentNullException("item");
        List<string> list = new List<string>();
        if (string.IsNullOrWhiteSpace(item) || item.Length < this.RequiredLength)
            list.Add(string.Format((IFormatProvider)CultureInfo.CurrentCulture, Resources.PasswordTooShort, new object[1]
    {
      (object) this.RequiredLength
    }));
        if (this.RequireNonLetterOrDigit && Enumerable.All<char>((IEnumerable<char>)item, new Func<char, bool>(this.IsLetterOrDigit)))
            list.Add(Resources.PasswordRequireNonLetterOrDigit);
        if (this.RequireDigit && Enumerable.All<char>((IEnumerable<char>)item, (Func<char, bool>)(c => !this.IsDigit(c))))
            list.Add(Resources.PasswordRequireDigit);
        if (this.RequireLowercase && Enumerable.All<char>((IEnumerable<char>)item, (Func<char, bool>)(c => !this.IsLower(c))))
            list.Add(Resources.PasswordRequireLower);
        if (this.RequireUppercase && Enumerable.All<char>((IEnumerable<char>)item, (Func<char, bool>)(c => !this.IsUpper(c))))
            list.Add(Resources.PasswordRequireUpper);
        if (list.Count == 0)
            return Task.FromResult<IdentityResult>(IdentityResult.Success);
        return Task.FromResult<IdentityResult>(IdentityResult.Failed(new string[1]
  {
    string.Join(" ", (IEnumerable<string>) list)
  }));
    }

}

`

答案 4 :(得分:2)

Password字段的另一种解决方法是使用RegisterViewModel.Password实现CustomValidationAttribute

public class RegisterViewModel
{
    [CustomValidation(typeof(CustomValidations), "ValidatePassword")]
    public string Password { get; set; }
}

使用CustomValidations.ValidatePassword方法来模仿您为PasswordValidator设置的密码验证规则。即:

public static class CustomValidations
{
    public static ValidationResult ValidatePassword(string password)
    {
        // Implement validation logic here, e.g. require numbers,
        // uppercase etc. and create localized ValidationResult.
        return new ValidationResult(Resources.PasswordValidation.NoNumbers);
    }
}

在这里,您可以使用标准的resx资源文件,显然可以根据个人喜好本地化您的错误消息。因此,总而言之,您只需禁止任何无效密码到达PasswordValidator

对于Email字段,这会有点难看,因为它需要往返DB以验证唯一性等,但它应该是可行的。

使用此解决方案的额外好处是产生的错误将是“每个字段”,即您不必使用@Html.ValidationSummary显示所有验证错误,但可以这样做:

@Html.ValidationMessageFor(m => m.Password, null, new { @class = "text-danger" })

答案 5 :(得分:0)

这是en-US Resources.resx文件键和值列表。这些是需要本地化的值。 http://aspnetidentity.codeplex.com

的源代码

Asp.Net Identity {name} Validator.cs ErrorMessage Resources.resx本地化 请参阅:http://aspnetidentity.codeplex.com/discussions/638351

*DefaultError= An unknown failure has occured.
DuplicateEmail= Email '{0}' is already taken.
DuplicateName= Name {0} is already taken.
ExternalLoginExists= A user with that external login already exists.
InvalidEmail= Email '{0}' is invalid.
InvalidToken= Invalid token.
InvalidUserName= User name {0} is invalid, can only contain letters or digits.
LockoutNotEnabled= Lockout is not enabled for this user.
NoTokenProvider= No IUserTokenProvider is registered.
NoTwoFactorProvider= No IUserTwoFactorProvider for '{0}' is registered.
PasswordMismatch= Incorrect password.
PasswordRequireDigit= Passwords must have at least one digit ('0'-'9').
PasswordRequireLower= Passwords must have at least one lowercase ('a'-'z').
PasswordRequireNonLetterOrDigit= Passwords must have at least one non letter or digit character.
PasswordRequireUpper= Passwords must have at least one uppercase ('A'-'Z').
PasswordTooShort= Passwords must be at least {0} characters.
PropertyTooShort= {0} cannot be null or empty.
RoleNotFound= Role {0} does not exist.
StoreNotIQueryableRoleStore= Store does not implement IQueryableRoleStore<TRole>.
StoreNotIQueryableUserStore= Store does not implement IQueryableUserStore<TUser>.
StoreNotIUserClaimStore= Store does not implement IUserClaimStore<TUser>.
StoreNotIUserConfirmationStore= Store does not implement IUserConfirmationStore<TUser>.
StoreNotIUserEmailStore= Store does not implement IUserEmailStore<TUser>.
StoreNotIUserLockoutStore= Store does not implement IUserLockoutStore<TUser>.
StoreNotIUserLoginStore= Store does not implement IUserLoginStore<TUser>.
StoreNotIUserPasswordStore= Store does not implement IUserPasswordStore<TUser>.
StoreNotIUserPhoneNumberStore= Store does not implement IUserPhoneNumberStore<TUser>.
StoreNotIUserRoleStore= Store does not implement IUserRoleStore<TUser>.
StoreNotIUserSecurityStampStore= Store does not implement IUserSecurityStampStore<TUser>.
StoreNotIUserTwoFactorStore= Store does not implement IUserTwoFactorStore<TUser>.
UserAlreadyHasPassword= User already has a password set.
UserAlreadyInRole= User already in role.
UserIdNotFound= UserId not found.
UserNameNotFound= User {0} does not exist.
UserNotInRole= User is not in role.*