我正要实现IDataErrorInfo,这时我发现INotifyDataErrorInfo将用于异步验证。当进一步挖掘时,我注意到使用这些接口的示例都在ViewModel上。我需要对模型进行验证,并且需要将错误与模型一起存储,以便持久化。我有一个包含许多实体的大图。此图需要传递回服务器以进行复杂的验证。我不确定我现在应该使用什么方法。
我是否简单地将我的接口实现移动到模型中?
我看到的另一个例子有一个单独的验证服务。在我的例子中,我的验证规则很复杂,我正在考虑使用Windows工作流及其规则引擎来提高验证规则的可维护性。
我是否需要单独的验证服务?
验证完成后,必须将图形传递回客户端。然后需要显示任何错误/警告。
我是否应该在模型中实现INotifyDataErrors,并在验证返回到客户端时引发事件,以便(通过ViewModel)将错误发布到视图?
事实证明,我在引用类库中包含INotifyDataErrors的程序集时遇到了问题。它会在共享这些类的程序集中产生冲突。
发布于 2011-09-08 08:11:20
当您有大型项目时,RIA可能不是一个好主意,例如具有不同层(服务、应用程序、域、基础设施)的应用程序。
不久前,我不得不在Silverlight应用程序中使用复杂的规则来实现验证。我使用的是Entity Framework生成的自我跟踪实体。我的一个需求就是重新调用所有的验证代码。
首先,我尝试使用EntLib验证块,并在客户端和服务器端使用相同的代码。这种方法不起作用,因为SL和.NET4.0使用不同版本的DataAnnotations程序集,因此会遇到一些问题。
最后,我在服务器上编写了某种验证服务,用于返回实体的错误。如下所示:
interface IValidate
{
IEnumerable<string> Validate(Entity entity);
}然后在客户端使ViewModels实现INotifyDataErrorInfo (此接口支持异步验证),这样您就可以使用服务验证实体并将错误保存在ViewModel上。
class SomeViewModel : INotifyDataErrorInfo
{
public Entity Entity { get; set; }
public void Validate()
{
this.ClearErrors();
// this method make the service calls
var service = -- service instance --;
var errors = -- get errors from service --;
foreach (string error in errors)
this.AddTopLevelError(error);
}
{...}
}这样,所有的验证逻辑都依赖于服务器,它可以随时更改而不会影响客户端,因为所有实体在添加到DataBase (如果您正在使用它)之前都要通过此服务。
该服务还可以返回错误和与错误相关的属性,这样您就可以与Silverlight进行更丰富的交互。因此,服务可以是:
interface IValidate
{
IEnumerable<PropertyError> Validate(Entity entity);
}
class PropertyError
{
public string PropertyName { get; }
public IEnumerable<string> Errors { get; }
}在这里,您可以注意到,服务器上的验证规则可能会发生变化,而这个逻辑是如何实现的并不重要。所有这些都运行良好,并满足您的请求,问题是Silverlight要求被验证的对象包含所有有错误的属性。
在使用数据库时,这不是常见的场景,例如,您可能会遇到这种情况(这是一个简单的模型)

这个模型是使用Entity Framework4.1完成的
因为如果您有一个用户实例,并且想要访问电子邮件属性,则必须输入: user_instance.Person.Email。所以Email属性不在用户类型中,而是这个解决方案的问题所在,因为您可能也想验证EMails。
这不是这样的,当你有一个带有实体(类似于上面)的ViewModel (实现INotifyDataErrorInfo),并且想要验证实体(本例中是用户)时,你只需要在属性Entity.Person.Email中添加一个错误。
但世界并不完美,所以我找到的解决方案是将每个属性复制到ViewModel上进行验证,如下所示:
class SomeViewModel : INotifyDataErrorInfo
{
public User Entity { get; set; }
public string Name { get { return Entity.UserName; } set {...} }
public string Email { get { return Entity.Person.Email; } set {...} }
{...}
}通过这种方式,您可以将控件绑定到ViewModels属性,而不是entities属性,但是使用更改通知会有点困难。
您可能还想检查:this工具包。它解决了这个问题,为你的实体定义了一个wapper,并使用DynamicObject模拟一个对象,该对象具有包装的对象的所有属性。这在处理大量数据时有点慢,但大大简化了工作。
希望这能有所帮助。
https://stackoverflow.com/questions/7335642
复制相似问题