2

在我的 MVC 应用程序中,我能够从文本文件中获取错误消息,而不是使用默认的错误消息。这在Required 属性(服务器端和客户端)上完美运行。

我现在需要对Compare属性执行相同的操作,但我不知道如何覆盖 Compare 属性。

作为参考,这就是我使用Required属性的方式(我希望与此类似的代码与Compare属性一起使用)......

Public Class RequiredFieldAttribute
    Inherits ValidationAttribute
    Implements IClientValidatable

    Private innerAttribute As New RequiredAttribute()
    Private errormessagecontrolid As String

    Public Sub New(ErrorMessageControlID As String)

        Me.errormessagecontrolid = ErrorMessageControlID

    End Sub

    Protected Overrides Function IsValid(value As Object, validationContext As ValidationContext) As ValidationResult

        If Not innerAttribute.IsValid(value) Then
            Return New ValidationResult(ErrorMsgs.Text(Me.errormessagecontrolid))
        End If

        Return ValidationResult.Success

    End Function

    Public Function GetClientValidationRules(metadata As ModelMetadata, context As ControllerContext) As IEnumerable(Of ModelClientValidationRule) Implements IClientValidatable.GetClientValidationRules

        Dim result = New List(Of ModelClientValidationRule)

        Dim rule = New ModelClientValidationRule() With {.ErrorMessage = ErrorMsgs.Text(Me.errormessagecontrolid), .ValidationType = "required"}

        result.Add(rule)

        Return result

    End Function

End Class

上面,ErrorMsgs.Text 是从文本文件中检索消息的函数。针对我的模型,我然后应用这样的东西......

<RequiredField("AccountDetailsPostcodeError")>
Public Property PostCode As String

然后系统在文本文件中查找名为 AccountDetailsPostcodeError 的条目。

如何使用 Compare 属性实现相同的效果。目前我有一个像这样的硬编码错误消息......

    <Compare("WebPassword", ErrorMessage:="The password and confirmation do not match.")>
    Public Property ConfirmWebPassword As String

编辑:下面建议的修复可能适用于 C#,但不适用于 VB.NET,因此我需要更复杂的覆盖比较属性。我只是不知道如何正确覆盖它。

4

2 回答 2

13

为什么要为您的翻译和消息使用文本文件,.NET 已经内置了翻译选项。您可以使用资源。使用资源的优点是资源是类型安全的,它们在编译时被检查。您的文本文件可能会损坏/丢失的地方。

以下指南可帮助您在 Mvc 项目中设置资源:

第一步

编辑默认汇编语言:

  • (C#) 属性 > 程序集信息 > 中性语言
  • (VB) 我的项目 > 汇编信息 > 中性语言

将此语言设置为您的默认语言。(对于这个例子,我使用English (United States)

第二步

将资源文件添加到您的项目中。调用这个文件Resource.resx。打开这个文件。将访问修饰符更改为Public并开始添加资源字符串。例如: 默认英语资源

第三步

为每种其他语言添加您想要支持另一个资源文件,但将它们命名为Resource.LANGUAGE.resxLANGUAGE 被其他文化名称替换。对于文化名称,您可以查看以下网址:http: //msdn.microsoft.com/en-us/goglobal/bb896001.aspx

然后用本地化的字符串填充新的资源文件。例如: 英语资源

第四步

然后你可以在你的模型中使用属性的默认本地化支持:

例如:

VB:

Imports System.ComponentModel.DataAnnotations
Public Class UserModel
    <Display(Name:="UserNameField", ResourceType:=GetType(My.Resources.Resource))>
    <Required(AllowEmptyStrings:=False, ErrorMessageResourceName:="RequiredUsername", ErrorMessageResourceType:=GetType(My.Resources.Resource))>
    Public Property UserName As String

    <Display(Name:="PasswordField", ResourceType:=GetType(My.Resources.Resource))>
    <MinLength(6, ErrorMessageResourceName:="PasswordLengthError", ErrorMessageResourceType:=GetType(My.Resources.Resource))>
    <Compare("PasswordAgain", ErrorMessageResourceName:="CompareError", ErrorMessageResourceType:=GetType(My.Resources.Resource))>
    <Required(AllowEmptyStrings:=False, ErrorMessageResourceName:="RequiredPassword", ErrorMessageResourceType:=GetType(My.Resources.Resource))>
    Public Property Password As String

    <Display(Name:="PasswordAgainField", ResourceType:=GetType(My.Resources.Resource))>
    <Required(AllowEmptyStrings:=False, ErrorMessageResourceName:="RequiredPasswordAgain", ErrorMessageResourceType:=GetType(My.Resources.Resource))>
    Public Property PasswordAgain As String
End Class

C#

using System.ComponentModel.DataAnnotations;
public class UserModel
{
    [Display(Name = "UserNameField", ResourceType = typeof(My.Resources.Resource))]
    [Required(AllowEmptyStrings = False, ErrorMessageResourceName = "RequiredUsername", ErrorMessageResourceType = typeof(My.Resources.Resource))]
    public string UserName;

    [Display(Name = "PasswordField", ResourceType = typeof(My.Resources.Resource))]
    [MinLength(6, ErrorMessageResourceName = "PasswordLengthError", ErrorMessageResourceType = typeof(My.Resources.Resource))]
    [Compare("PasswordAgain", ErrorMessageResourceName = "CompareError", ErrorMessageResourceType = typeof(My.Resources.Resource))]
    [Required(AllowEmptyStrings = False, ErrorMessageResourceName = "RequiredPassword", ErrorMessageResourceType = typeof(My.Resources.Resource))]
    public string Password;

    [Display(Name = "PasswordAgainField", ResourceType = typeof(My.Resources.Resource))]
    [Required(AllowEmptyStrings = False, ErrorMessageResourceName = "RequiredPasswordAgain", ErrorMessageResourceType = typeof(My.Resources.Resource))]
    public string PasswordAgain;
}

对于本地化,属性需要知道静态属性的名称和从哪里获取属性的静态类的类型(如上所示)。

第五步

然后在您的视图中使用@Html.ValidationSummary()获取所有错误消息,或使用

  • VB @Html.ValidationMessageFor(Function(model) model.Property)
  • C# @Html.ValidationMessageFor(m => m.Property)

获取特定的错误消息。

对于显示属性,您可以使用:

  • VB @Html.DisplayNameFor(Function(model) model.Property)
  • C# @Html.DisplayNameFor(m => m.Property)

更改语言

Web.config最后但并非最不重要的一点是,您可以通过编辑和更改全球化标签来更改应用程序的语言,而不是第一步中定义的中性语言:


<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <system.web>
    <globalization uiCulture="nl" />
  </system.web>
</configuration>

如果您想从代码更改语言,您应该编辑System.Threading.Thread.CurrentThread.CurrentUICulture有关此信息的信息,我建议您使用谷歌或其他 SO 问题。


示例项目

对于这个问题,我很快做了一个示例项目来提供准确的答案。项目可以在这里找到:
MvcVBTest.V1.zip


更新

如果您不想使用资源而是使用单个文本文件,则可以使用资源框架使用的相同概念。您需要一个具有可以引用的静态属性的类。

为此,我做了以下事情:

  1. 我创建了一个名为Resources(Resources.vb) 的类。
  2. 在这个类中,我添加了一个名为的子类Resource
  3. 在这个类的静态构造函数中,我打开resource.xml了我已经映射到一个数组Resource
  4. 然后将该数组转换为Dictionary(Of String, String)
  5. 我为 xml 中的每个项目创建了一个静态 get 属性。并从 Dictionary 中返回正确的项目
  6. 我更改了类ResourceType中的参数UserModel

当然还有一点清理。旧资源可以删除,globalization标签可以从web.config.

现在所有文本都可以resource.xml作为键值对找到。要添加另一行,请将其添加到 XML 并在Resource类中为其创建一个属性。

示例项目

对于此更新,我更新了我的示例项目:
MvcVBTest.V2.zip

于 2012-11-23T12:20:22.237 回答
0

为什么不使用这样的东西?

<RequiredField(ErrorMessage=GetErrorMessage())>

只需创建一个为您获取错误消息的静态函数。您甚至可以为 GetErrorMessage 函数获取一个参数,以便确定要返回的消息。

于 2012-11-19T12:54:54.570 回答