从数据库读取本地化文本

在开发ASP.NETMVC应用程序时,经常需要从数据库中读取本地化文本。这不仅可以提高应用程序的灵活性,还可以方便地进行国际化。本文将介绍如何从数据库读取本地化文本,并使用DataAnnotations进行模型验证。

在模型中,DataAnnotations可以用来定义模型属性的标签和验证消息。以登录页面的简单模型为例:

public class LoginModel { [Required(ErrorMessage = "用户名是必需的!")] [Display(Name = "用户名")] public string UserName { get; set; } [Required(ErrorMessage = "密码是必需的!")] [Display(Name = "密码")] public string Password { get; set; } }

在相应的视图中,可以使用以下代码自动渲染模型的"UserName"属性的标签、文本框和初始不可见的验证消息:

@Html.LabelFor(m => m.UserName) @Html.TextBoxFor(m => m.UserName) @Html.ValidationMessageFor(m => m.UserName)

在浏览器中,视图可能看起来像这样:

现在,如果想从数据库中读取本地化文本,可以简单地将文本ID(或您在数据库中使用的任何唯一键)写入注释属性:

[Required(ErrorMessage = "27")] [Display(Name = "42")] public string UserName { get; set; }

要将Display属性中的文本ID替换为数据库中的文本,需要创建自己的MetadataProvider:

public class MetadataProvider : AssociatedMetadataProvider { protected override ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes, Type containerType, Func<object> modelAccessor, Type modelType, string propertyName) { var metadata = new ModelMetadata(this, containerType, modelAccessor, modelType, propertyName); if (propertyName != null) { var displayAttribute = attributes.OfType<DisplayAttribute>().FirstOrDefault(); if (displayAttribute != null) { int textId; if (Int32.TryParse(displayAttribute.Name, out textId)) { // TODO: 从数据库获取文本 metadata.DisplayName = "数据库中的文本ID " + textId; } } } return metadata; } }

然后需要在Global.asax.cs的Application_Start()方法中注册这个类:

ModelMetadataProviders.Current = new MetadataProvider();

对于验证属性,情况要复杂一些。首先,需要一个ValidatorProvider类,它告诉MVC验证系统使用哪个类来执行模型验证。在LocalizableModelValidatorProvider类中的实现返回LocalizableModelValidator的实例:

public class LocalizableModelValidatorProvider : DataAnnotationsModelValidatorProvider { protected override IEnumerable<ModelValidator> GetValidators(ModelMetadata metadata, ControllerContext context, IEnumerable<Attribute> attributes) { var validators = base.GetValidators(metadata, context, attributes); return validators.Select(validator => new LocalizableModelValidator(validator, metadata, context)).ToList(); } }

验证提供程序也需要在Global.asax.cs的Application_Start()方法中注册:

var provider = ModelValidatorProviders.Providers.FirstOrDefault(p => p.GetType() == typeof(DataAnnotationsModelValidatorProvider)); if (provider != null) { ModelValidatorProviders.Providers.Remove(provider); } ModelValidatorProviders.Providers.Add(new LocalizableModelValidatorProvider());

如您所见,移除了现有的DataAnnotationsModelValidatorProvider类型的验证器提供程序,并用自己的LocalizableModelValidatorProvider类中的实现替换它。

第二个类是实际需要的ModelValidatorProvider,在LocalizableModelValidator类中实现它:

public class LocalizableModelValidator : ModelValidator { private readonly ModelValidator innerValidator; public LocalizableModelValidator(ModelValidator innerValidator, ModelMetadata metadata, ControllerContext controllerContext) : base(metadata, controllerContext) { this.innerValidator = innerValidator; } public override IEnumerable<ModelClientValidationRule> GetClientValidationRules() { var rules = innerValidator.GetClientValidationRules(); var modelClientValidationRules = rules as ModelClientValidationRule[] ?? rules.ToArray(); foreach (var rule in modelClientValidationRules) { int textId; if (Int32.TryParse(rule.ErrorMessage, out textId)) { // TODO: 从数据库读取文本 rule.ErrorMessage = "数据库中的文本_" + textId; } } return modelClientValidationRules; } public override IEnumerable<ModelValidationResult> Validate(object container) { // 执行内部验证,没有本地化 var results = innerValidator.Validate(container); // 将错误消息(文本ID)转换为本地化值 return results.Select(result => { int textId; if (Int32.TryParse(result.Message, out textId)) { // TODO: 从数据库读取文本 result.Message = "数据库中的文本ID " + textId; } return new ModelValidationResult() { Message = result.Message }; }); } }

第一个方法GetClientValidationRules()负责客户端验证。每当视图渲染模型时,它将被调用,用于模型中具有验证属性的每个属性。但是,如果您在Web.config中禁用客户端验证,这个方法将不会被调用。

第二个方法ModelValidationResult()负责服务器端验证。它将在表单提交回服务器后,被调用用于模型中具有验证属性的每个属性。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485