Localization 从域对象(实体)本地化验证消息

Localization 从域对象(实体)本地化验证消息,localization,dependency-injection,domain-driven-design,globalization,Localization,Dependency Injection,Domain Driven Design,Globalization,我不打算讨论DDD中的验证、代码的归属等问题,而是集中讨论一种可能的方法以及如何解决本地化问题。我在我的一个域对象(实体)上有以下行为(方法),举例说明了该场景: public void ClockIn() { if (WasTerminated) { throw new InvalidOperationException("Cannot clock-in a terminated employee."); } ClockedInAt = Dat

我不打算讨论DDD中的验证、代码的归属等问题,而是集中讨论一种可能的方法以及如何解决本地化问题。我在我的一个域对象(实体)上有以下行为(方法),举例说明了该场景:

public void ClockIn()
{
    if (WasTerminated)
    {
        throw new InvalidOperationException("Cannot clock-in a terminated employee.");
    }

    ClockedInAt = DateTime.Now;
    :
}
如您所见,当调用ClockIn方法时,该方法会检查对象的状态,以确保员工未被终止。如果员工被解雇,我们将抛出一个与“不要让您的实体进入无效状态”方法一致的异常

我的问题是我需要本地化异常消息。这通常是(在此应用程序中)使用应用程序服务(ILocalizationService)完成的,该服务是在需要访问其方法的类中使用MEF导入的。但是,与任何DI框架一样,只有当容器实例化对象时,依赖项才会被注入/导入。DDD的情况通常不是这样

此外,我对DDD的所有了解都表明,我们的域对象不应该有依赖关系,这些问题应该从域对象外部处理。如果是这样的话,我该如何对上面显示的消息进行本地化

这不是一个新的需求,因为许多业务应用程序都需要全球化/本地化。我很感激一些建议,如何使这项工作仍然与DDD的目标保持一致

更新

我最初没有指出我们的本地化都是数据库驱动的,所以我们有一个本地化服务(通过可注入的ILocalizationService接口)。因此,使用VisualStudio提供的静态资源类作为项目的一部分是不可行的

另一次更新


也许它会将讨论转移到声明该应用程序是一个RESTful服务应用程序。因此,客户端可以是一个简单的web浏览器。因此,我不能期望调用方能够在异常发生时执行任何类型的本地化、代码映射等(在这种方法中,试图将域对象置于无效状态是异常),将引发异常,并返回相应的HTTP状态代码以及异常消息,该消息应本地化为调用方的区域性(接受语言)。

如果本地化是域/应用程序的重要组成部分,则应使其成为一级公民,并在其所属的任何位置注入。我不知道你说的“DDD说我们的域对象不应该有依赖关系”是什么意思,请解释一下

不确定这个响应对您有多大帮助,但本地化确实是一个前端问题。根据您的示例本地化异常消息并不是常见做法,因为最终用户不应该看到异常消息中描述的技术细节(无论是谁对您的异常进行故障排除,即使不是他们的母语,也可能有足够的英语水平)


当然,如果有必要,您可以始终处理异常,并在前端向您的用户提供本地化的、用户友好的消息。但是,将其作为字体端关注点应该可以简化您的体系结构。

正如Clafou所说,您不应该使用异常以任何方式将消息传递到UI

如果您仍然坚持这样做,一种选择是抛出错误代码而不是消息

抛出新的InvalidOperationException(“错误\终止\员工\打卡”)


然后,当发生异常时,对异常执行您需要执行的任何操作(日志、查找本地化等)。

尝试避免向域模型对象添加内部依赖项是正确的

更好的解决方案是在服务方法内部处理操作,例如:

public class EmployeeServiceImpl implements EmployeeService {

   public void ClockEmployeeIn(Employee employee) throws InvalidOperationException {
      if (employee.isTerminated()) {
          // Localize using a resource lookup code..
          throw new InvalidOperationException("Error_Clockin_Employee_Terminated");      
      }       
      employee.setClockedInAt(DateTime.Now);
   }
}

然后,您可以使用DI框架在您将进行时钟调用的位置注入服务,并使用该服务将您的域对象与业务逻辑的更改隔离。

Related:.Related,yes,但远不是答案。谢谢你的链接!Framework\Platform为.NET应用程序抛出新异常提供的用户机制(参考资料[“TerminatedEmployeeMessage”])@亚历克斯,谢谢你抓住我的鱼叉!请参阅我的更新。在“域对象依赖项”、“DDD实体依赖项”或其任何变体上进行web搜索,您将找到许多关于此主题的文章、帖子和讨论。而且,根据Evans的说法,这根本不是一个好的实践。要求是在出现异常时向UI显示一条描述性消息。这必须与UI中显示的其余文本一起本地化。它不能仅仅是一个UI问题,原因有二:1。数据存储在数据库中,因此必须有一个后端信息提供者;二,。对于每个可能的异常,它都需要一个唯一的异常类型,以便客户端能够捕获它并查找本地化文本。相反,由于服务器具有本地化的文本,因此在服务器上执行本地化更为简洁。例如,第二个业务规则是不将已经打卡的员工打卡。这也会导致引发InvalidOperationException,但会产生与上面所示不同的错误消息。所以我要么在这里本地化它,在这里我控制我想要的消息,要么我必须创建两个异常类来表示每个情况。当应用到我正在开发的现实世界的企业级应用程序中时,这将变得非常重要,需要执行数百条业务规则。听起来您可能过度依赖异常。验证逻辑不必在有异常的情况下实现。您可以返回已知的错误代码,并将其映射到资源标识符,以便在UI中显示本地化消息