开发者

Server-side Validation for Silverlight Application

I was just about to implement IDataErrorInfo, when I saw INotifyDataErrorInfo was to be used for asynchronous validation. When digging a bit further, I noticed the examples using those interfaces were all on the ViewModel. I need my validation on the model, and I need the errors stored with the model for persistence. I have a large graph with many entities. This graph needs to be passed back to the server for a complex validation. I'm not sure what approach I am supposed to use now.

Do I simply move my inteface implementations to the model?

Another example I saw had a separate validation service. In my case, my validation rules are complex, and I was thinking of using Windows Workflow and its rule engine to improve the maintainability of the validation rules.

Do I need a separate validation service?

Once the validation has completed, the graph must be passed back to the client. Any errors/warnings need to be displayed then.

Should I implement INotifyDataErrors in the model and raise the event when the val开发者_如何学编程idation returns to the client to post the errors to the View (through ViewModel)?

As it turns out, I am having trouble referencing the assembly that contains INotifyDataErrors in the class library. It creates a conflict in an assembly that is sharing those classes.


When you have big projects RIA may not be a good idea, for example applications with different layers (Services, Application, Domain, Infrastructure).

Some time ago I had to implement Validation in a Silverlight app with complex rules. I was using Self-tracking entities generated with the Entity Framework. And one of my need was to rehuse all the validation code.

First I tried to use the EntLib Validation Block and use the same code on both the client and the server. This approach doesn't work as you get some problems as SL and .NET4.0 use different versions of the DataAnnotations assembly.

Finally I ended up writing some sort of validation service on the server that returns the errors of an entity if any. Something like this:

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

And then on the Client make the ViewModels implement INotifyDataErrorInfo (this interface supports async validation), so you can validate the entity with the Service and save the errors on the 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);
    }

    {...}
}

This way all the validation logic lies on the Server and it can change at any time without affecting the client, because all the entities are passed througth this service before being added to a DataBase (if you're using one).

The service could also return the errors and the property associated with the error, this way you could get a richer interaction with Silverlight. So the service could be:

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

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

Here you can notice that the validation rules could change on the server, and it doesn't matter how this logic is implemented. All this works fine and meets your requeriments, the problem is that Silverlight requires that the object being validated contains all the properties with errors.

This is not a common scenario when working with Databases, as you could have for example (and this is a simple model)

Server-side Validation for Silverlight Application

this model was done using Entity Framework 4.1

Because if you have a user instance and want to access to the Email property, you'll have to type: user_instance.Person.Email. So the Email property isn't in the user type, and here is the problem with this solution because you may want to validate the EMails too.

Is this wasn't like this, when you have a ViewModel (implementing INotifyDataErrorInfo) with an Entity (like above) and wants the entity (User in this case) to be validated, you only have to add an error to the property Entity.Person.Email.

But the world isn't perfect, so the solution i found was to duplicate each one of the properties to be validated on the ViewModel, something like this:

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 {...} }

    {...}
}

This way you can bind the controls to the ViewModels properties instead of the entities properties, but it gets a bit hard to work with the change notifications.

You may also want to check: this toolkit. It solves this problem defining a wapper to your entity and using DynamicObject simulates an object that has all the properties from the wrapped one. This is a bit slow when working with large ammounts of data, but simplifies the work a lot.

Hope this helps.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜