ASP.NET MVC4 不显眼的验证本地化

发布于 2024-12-18 15:08:57 字数 765 浏览 0 评论 0原文

问题

我在使用不显眼的 jquery 验证将默认消息本地化为隐式 [Required] 属性时遇到问题。我不想将 [Required] 放在我的模型和关联的资源文件中的每个 int (和其他不可空类型)上。我想知道是否有人测试过 ASP.NET MVC4 Dev Preview 并注意到同样的问题?当我查看 mvc 代码时,它显然应该可以工作。

尝试的解决方案:

在global.asax中添加:

DefaultModelBinder.ResourceClassKey = "ErrorMessages";

在具有PropertyValueInvalid和PropertyValueRequired的全局资源中添加名为“ErrorMessages.resx”和“ErrorMessages.fr.resx”的资源文件。

有趣的信息:

我注意到的一件好事是他们修复了“字段必须是数字”或“字段必须是日期”的硬编码在内部密封类中。

ClientDataTypeModelValidatorProvider.ResourceClassKey = "ErrorMessages"; 

如果您在全局资源文件夹和 FieldMustBeNumeric/FieldMustBeDate 中有名为“ErrorMessages.resx”和“ErrorMessages.fr.resx”的资源文件,则可以使用

Problem:

I have issues getting the default messages to be localized for implicit [Required] attributes using unobtrusive jquery validation. I do not want to put [Required] on every int (and other non-nullable types) in my model and the ressource file associated. I am wondering if anyone has tested the ASP.NET MVC4 Dev Preview and noticed the same issue? When I look at the mvc code it clearly seems like it should work.

Attempted solution:

Added in the global.asax:

DefaultModelBinder.ResourceClassKey = "ErrorMessages";

Have a resource file called "ErrorMessages.resx" and "ErrorMessages.fr.resx" in the global resources with PropertyValueInvalid and PropertyValueRequired.

Interesting information:

A good thing I have noticed is that they fixed the "Field must be a number" or "Field must be a date" from being hard coded in an internal sealed class.

ClientDataTypeModelValidatorProvider.ResourceClassKey = "ErrorMessages"; 

Does work if you have a resource file called "ErrorMessages.resx" and "ErrorMessages.fr.resx" in the global ressources folder and FieldMustBeNumeric/FieldMustBeDate

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

花开浅夏 2024-12-25 15:08:57

我知道这已经很旧了,但是要将本地化消息放入元数据中,需要子类化 DataAnnotationsModelValidator 并重写 GetClientValidationRules 和 Validate 以提供您自己的消息。

您可以使用 DataAnnotationsModelValidatorProvider.RegisterAdapterFactory 注册适配器。

我构建了一个包装工厂构建器来创建工厂委托。 out 参数就在这里,因为我在循环中使用它,因为我通过反射发现程序集中的所有适配器,因此我需要获取每个适配器的属性类型才能调用 RegisterAdpaterFactory。我本可以内联注册,但在此之后我使用适配器/属性信息执行其他操作

public static class ModelValidationFactory
{
    /// <summary>
    /// Builds a Lamda expression with the Func<ModelMetadata, ControllerContext, ValidationAttribute, ModelValidator> signature
    /// to instantiate a strongly typed constructor.  This used by the <see cref="DataAnnotationsModelValidatorProvider.RegisterAdapterFactory"/>
    /// and used (ultimately) by <see cref="ModelValidatorProviderCollection.GetValidators"/> 
    /// </summary>
    /// <param name="adapterType">Adapter type, expecting subclass of <see cref="ValidatorResourceAdapterBase{TAttribute}"/> where T is one of the <see cref="ValidationAttribute"/> attributes</param>
    /// <param name="attrType">The <see cref="ValidationAttribute"/> generic argument for the adapter</param>
    /// <returns>The constructor invoker for the adapter. <see cref="DataAnnotationsModelValidationFactory"/></returns>
    public static DataAnnotationsModelValidationFactory BuildFactory(Type adapterType, out Type attrType)
    {
        attrType = adapterType.BaseType.GetGenericArguments()[0];

        ConstructorInfo ctor = adapterType.GetConstructor(new[] { typeof(ModelMetadata), typeof(ControllerContext), attrType });

        ParameterInfo[] paramsInfo = ctor.GetParameters();

        ParameterExpression modelMetadataParam = Expression.Parameter(typeof(ModelMetadata), "metadata");
        ParameterExpression contextParam = Expression.Parameter(typeof(ControllerContext), "context");
        ParameterExpression attributeParam = Expression.Parameter(typeof(ValidationAttribute), "attribute");

        Expression[] ctorCallArgs = new Expression[]
        {
            modelMetadataParam,
            contextParam,
            Expression.TypeAs( attributeParam, attrType )
        };

        NewExpression ctorInvoker = Expression.New(ctor, ctorCallArgs);

        // ( ModelMetadata metadata, ControllerContext context, ValidationAttribute attribute ) => new {AdapterType}(metadata, context, ({AttrType})attribute)
        return Expression
            .Lambda(typeof(DataAnnotationsModelValidationFactory), ctorInvoker, modelMetadataParam, contextParam, attributeParam)
            .Compile()
            as DataAnnotationsModelValidationFactory;
    }
}

,这也适用于 MVC3,我认为 MVC2 也适用。

I know this is old, but to get localised messages into the metadata is to subclass DataAnnotationsModelValidator and override GetClientValidationRules and Validate to supply your own messages.

You register the adapter using DataAnnotationsModelValidatorProvider.RegisterAdapterFactory.

I built a wrapper factory builder to create the factory delegate. The out parameter is here as I use this inside a loop as I discover all adapters in the assembly via reflection, so I need to get the attribute type for each adapter in order to call RegisterAdpaterFactory. I could have inlined the registration but I do other stuff after this using the adapter/attribute information

public static class ModelValidationFactory
{
    /// <summary>
    /// Builds a Lamda expression with the Func<ModelMetadata, ControllerContext, ValidationAttribute, ModelValidator> signature
    /// to instantiate a strongly typed constructor.  This used by the <see cref="DataAnnotationsModelValidatorProvider.RegisterAdapterFactory"/>
    /// and used (ultimately) by <see cref="ModelValidatorProviderCollection.GetValidators"/> 
    /// </summary>
    /// <param name="adapterType">Adapter type, expecting subclass of <see cref="ValidatorResourceAdapterBase{TAttribute}"/> where T is one of the <see cref="ValidationAttribute"/> attributes</param>
    /// <param name="attrType">The <see cref="ValidationAttribute"/> generic argument for the adapter</param>
    /// <returns>The constructor invoker for the adapter. <see cref="DataAnnotationsModelValidationFactory"/></returns>
    public static DataAnnotationsModelValidationFactory BuildFactory(Type adapterType, out Type attrType)
    {
        attrType = adapterType.BaseType.GetGenericArguments()[0];

        ConstructorInfo ctor = adapterType.GetConstructor(new[] { typeof(ModelMetadata), typeof(ControllerContext), attrType });

        ParameterInfo[] paramsInfo = ctor.GetParameters();

        ParameterExpression modelMetadataParam = Expression.Parameter(typeof(ModelMetadata), "metadata");
        ParameterExpression contextParam = Expression.Parameter(typeof(ControllerContext), "context");
        ParameterExpression attributeParam = Expression.Parameter(typeof(ValidationAttribute), "attribute");

        Expression[] ctorCallArgs = new Expression[]
        {
            modelMetadataParam,
            contextParam,
            Expression.TypeAs( attributeParam, attrType )
        };

        NewExpression ctorInvoker = Expression.New(ctor, ctorCallArgs);

        // ( ModelMetadata metadata, ControllerContext context, ValidationAttribute attribute ) => new {AdapterType}(metadata, context, ({AttrType})attribute)
        return Expression
            .Lambda(typeof(DataAnnotationsModelValidationFactory), ctorInvoker, modelMetadataParam, contextParam, attributeParam)
            .Compile()
            as DataAnnotationsModelValidationFactory;
    }
}

This also works in MVC3, and i think MVC2 as well.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文