企业库验证应用程序块与国际化

5

场景

需要将一个.NET/WPF桌面应用程序本地化(或者按照微软的术语来说,全球化)到英语以外的其他语言。也就是说,用户界面需要完全适配(标签、图标等)。

然而,应用程序的日志文件条目、审计跟踪条目和其他输出应保持为英语,以便英语服务/支持人员进行审核。他们不会讲法语或中文。

该应用程序依赖于RESX文件来完成本地化。

企业库验证块用于验证对象模型上的业务规则。

现在假设有一个服务,在执行真正的业务逻辑之前验证其给定的对象模型参数。在某些情况下,它会接收到无效的对象模型参数,但仍会尽力继续执行。然而,提供无效的对象模型数据应该记录在审计跟踪和日志文件中。

以下是使用验证块的服务示例。

public class Service : IService
{
    public void MyMethod(MyObjectModelObject obj)
    {
        Validator validator = ValidationFactory.CreateValidator(typeof(MyObjectModelObject));
        ValidationResults results = validator.Validate(this);

        // !!! The messages in the validation results are now already localized to CurrentCulture.

        // ... build a log message: msg
        if (results.Count > 0)
        {
            Logger.Log(msg);
        }
    }
}

如代码注释所述,当您在EnterpriseLibrary验证器上调用Validate()时,验证消息已经本地化为法语,您没有机会将它们写入例如英文日志文件中。

在我们应用程序的其他领域中,我们使用一个消息类来封装资源ID和参数,直到我们确定要使用哪种文化才能解析实际字符串值。您可以称之为延迟资源解析。

有什么想法介绍类似的机制到Enterprise Library验证块中吗?目前的想法:

  • 暂时切换当前区域设置(我不喜欢这个方法,而且只解决了一半的问题)
  • 修补Enterprise Library验证块(我也不喜欢这个方法)

感谢您的帮助和分享的想法!

1个回答

4
当我们需要延迟资源解析时,我们放弃使用MessageTemplateResourceName,而是将我们的资源ID作为MessageTemplate属性。然后,我们稍后使用该ID来查找当前区域设置下的资源字符串值。
我们标准化了ID的命名约定,类似于这样:RULESET_RULESETQUALIFIER_OPERATION_OBJECT_PROPERTY_VALIDATIONTYPE。例如:RULESET_BMW_INSERT_CAR_YEAR_RANGERULESET_BMW_UPDATE_CAR_COLOR_LENGTH等。
在VAB配置中,它看起来像这样:
<property name="Color">
   <validator lowerBound="0" lowerBoundType="Ignore" upperBound="50"
    upperBoundType="Inclusive" negated="false" messageTemplate="RULESET_BMW_INSERT_CAR_COLOR_LENGTH"
    messageTemplateResourceName="" messageTemplateResourceType=""
    tag="" type="Microsoft.Practices.EnterpriseLibrary.Validation.Validators.StringLengthValidator, Microsoft.Practices.EnterpriseLibrary.Validation, Version=4.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
    name="String Length Validator" />
                    </property>

主要缺点是您失去了轻松使用消息模板令牌使消息稍微动态的能力。虽然这可以实现,但令牌值必须存储在某个地方(例如您的消息类),以便在评估消息字符串时稍后进行替换。
您可能还希望考虑为每个受众创建多个资源文件。也就是说,一个资源用于用户消息,另一个用于技术消息。因此,您可以拥有UserMessages.resources、UserMessages.fr-BE.resources等用户消息的资源。然后,在另一个资源文件中,使用不同的消息重复ID以记录日志(LogMessages.resources)。这样,您可以为日志消息添加其他技术信息。尽管如此,这可能有些过度设计。
然后,我们使用 ResourceManager 访问字符串值:
ResourceManager userResourceManager = 
    new ResourceManager("UserMessages", Assembly.GetExecutingAssembly());

string userMessage = userResourceManager.GetString(resourceId);

ResourceManager logResourceManager = 
    new ResourceManager("LogMessages", Assembly.GetExecutingAssembly());

// Can also try to use InvariantCulture instead of "en"
string messageToLog = logResourceManager.GetString(resourceId,  new CultureInfo("en"));
//alternative to ensure you get the english user message value:
//    string messageToLog = userResourceManager.GetString(resourceId,  new CultureInfo("en"));

你可以将这些内容抽象成一个帮助类或添加到你的消息类中。你可能还需要编写一些代码来提取ValidationResults并使用所需信息创建消息类。

非常感谢您的输入,Tuzo!提到的缺点对我们来说是一个很大的问题 - 我们绝对需要动态组合的消息。我们目前正在更改EntLib验证块的实现,以完全使用我们的消息类而不是急切解析的字符串。这是一项相当繁琐的任务,但最终我们在整个应用程序中都有一个方法。最大的缺点是维护,但验证块在最新版本的核心概念方面非常稳定。 - olli-MSFT

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接