Silverlight应用程序的服务器端验证

时间:2011-09-07 14:31:33

标签: silverlight validation asynchronous server-side

当我看到INotifyDataErrorInfo用于异步验证时,我正准备实现IDataErrorInfo。在进一步挖掘时,我注意到使用这些接口的示例都在ViewModel上。我需要对模型进行验证,并且我需要将模型中存储的错误用于持久性。我有一个包含许多实体的大图。需要将此图传递回服务器以进行复杂验证。我不确定我现在应该采用什么方法。

我只是简单地将我的界面实现移动到模型中吗?

我看到的另一个例子有一个单独的验证服务。就我而言,我的验证规则很复杂,我正在考虑使用Windows Workflow及其规则引擎来提高验证规则的可维护性。

我是否需要单独的验证服务?

验证完成后,必须将图表传递回客户端。然后需要显示任何错误/警告。

我应该在模型中实现INotifyDataErrors并在验证返回客户端时将事件发送到View(通过ViewModel)吗?

事实证明,我无法在类库中引用包含INotifyDataErrors的程序集。它会在共享这些类的程序集中产生冲突。

1 个答案:

答案 0 :(得分:0)

当您拥有大型项目时,RIA可能不是一个好主意,例如具有不同层的应用程序(服务,应用程序,域,基础架构)。

前段时间我不得不在具有复杂规则的Silverlight应用程序中实现验证。我使用的是使用Entity Framework生成的自我跟踪实体。我需要的是重新使用所有验证码。

首先,我尝试使用EntLib验证块,并在客户端和服务器上使用相同的代码。由于SL和.NET4.0使用不同版本的DataAnnotations程序集,因此遇到问题时,此方法不起作用。

最后,我最终在服务器上编写了某种验证服务,返回实体的错误(如果有的话)。像这样:

interface IValidate
{
    IEnumerable<string> Validate(Entity entity); 
}

然后在客户端上使ViewModel实现INotifyDataErrorInfo(此接口支持异步验证),这样您就可以使用Service验证实体并将错误保存在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之前通过此服务传递(如果您正在使用它)。 / p>

该服务还可以返回错误以及与错误相关的属性,这样您就可以与Silverlight进行更丰富的交互。所以服务可能是:

interface IValidate
{
    IEnumerable<PropertyError> Validate(Entity entity); 
}

class PropertyError
{
    public string PropertyName { get; }
    public IEnumerable<string> Errors { get; }
}

在这里您可以注意到验证规则可能会在服务器上发生变化,并且这个逻辑的实现方式并不重要。所有这些都可以正常工作并满足您的要求,问题是Silverlight要求被验证的对象包含所有有错误的属性。

使用数据库时,这不是常见的情况,例如,您可以拥有(这是一个简单的模型)

simple model

此模型是使用Entity Framework 4.1

完成的

因为如果您有一个用户实例并且想要访问Email属性,则必须输入:user_instance.Person.Email。因此,电子邮件属性不在用户类型中,此解决方案存在问题,因为您可能也想验证电子邮件。

这是不是这样的,当你有一个ViewModel(实现INotifyDataErrorInfo)与一个实体(如上所述)并希望验证实体(在这种情况下是用户)时,你只需要向它添加一个错误property 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属性而不是实体属性,但是使用更改通知会有点困难。

您可能还想查看:this工具包。它解决了为您的实体定义wapper的问题,并使用DynamicObject模拟具有包装的所有属性的对象。在处理大量数据时,这有点慢,但会大大简化工作。

希望这有帮助。