views:

340

answers:

1

The "Silverlight Business Application" template bundled with VS2010 / Silverlight 4 uses DataAnnotations on method arguments in its domain service class, which are invoked automagically:

        public CreateUserStatus CreateUser(RegistrationData user,
        [Required(ErrorMessageResourceName = "ValidationErrorRequiredField", ErrorMessageResourceType = typeof(ValidationErrorResources))]
        [RegularExpression("^.*[^a-zA-Z0-9].*$", ErrorMessageResourceName = "ValidationErrorBadPasswordStrength", ErrorMessageResourceType = typeof(ValidationErrorResources))]
        [StringLength(50, MinimumLength = 7, ErrorMessageResourceName = "ValidationErrorBadPasswordLength", ErrorMessageResourceType = typeof(ValidationErrorResources))]
        string password)
    { /* do something */ }

If I need to implement this in my POCO class methods, how do I get the framework to invoke the validations OR how do I invoke the validation on all the arguments imperatively (using Validator or otherwise?).

A: 

We have approached it like this:

We have a ValidationProperty class that takes in a RegularExpression that will be used to validate the value (you could use whatever you wanted).

ValidationProperty.cs

public class ValidationProperty
{
    #region Constructors

    /// <summary>
    /// Constructor for property with validation
    /// </summary>
    /// <param name="regularExpression"></param>
    /// <param name="errorMessage"></param>
    public ValidationProperty(string regularExpression, string errorMessage)
    {
        RegularExpression = regularExpression;
        ErrorMessage = errorMessage;
        IsValid = true;
    }

    #endregion

    #region Properties

    /// <summary>
    /// Will be true if this property is currently valid
    /// </summary>
    public bool IsValid { get; private set; }

    /// <summary>
    /// The value of the Property.
    /// </summary>
    public object Value 
    {
        get { return val; }
        set 
        {
            if (this.Validate(value))//if valid, set it
            {
                val = value;
            }
            else//not valid, throw exception
            {
                throw new ValidationException(ErrorMessage);
            }
        }
    }
    private object val;

    /// <summary>
    /// Holds the regular expression that will accept a vaild value
    /// </summary>
    public string RegularExpression { get; private set; }

    /// <summary>
    /// The error message that will be thrown if invalid
    /// </summary>
    public string ErrorMessage { get; private set; }

    #endregion

    #region Private Methods

    private bool Validate(object myValue)
    {
        if (myValue != null)//Value has been set, validate it
        {
            this.IsValid = Regex.Match(myValue.ToString(), this.RegularExpression).Success;
        }
        else//still valid if it has not been set.  Invalidation of items not set needs to be handled in the layer above this one.
        {
            this.IsValid = true;
        }

        return this.IsValid;
    }

    #endregion
}

Here's how we would create a Validation property. Notice how the public member is a string, but privately I am using a 'ValidationProperty.'

public string TaskNumber
    {
        get { return taskNumber.Value.ToString(); }
        set 
        {
            taskNumber.Value = value;
            OnPropertyChanged("TaskNumber");
        }
    }
    private ValidationProperty taskNumber;

Now, whenever the value is set, the business layer will validate that it's a valid value. If it's not, it will simply throw a new ValidationException (in the ValidationProperty class). In your xaml, you will need to set NotifyOnValidationError & ValidatesOnExceptions to true.

<TextBox Text="{Binding TaskNumber, Mode=TwoWay, NotifyOnValidationError=True, ValidatesOnExceptions=True}"/>

With this approach, you would probably have a form for creating a new 'User' and each field would valitate each time they set it (I hope that makes sense).

This is the approach that we used to get the validation to be on the business layer. I'm not sure if this is exactly what you're looking for, but I hope it helps.

JSprang
As I read back through your question, I realize that I had previously read it wrong :( I thought you were creating a property and trying to validate a property on your object, not a method. I guess I've never done exactly what you're trying to do, but maybe my answer will spark some ideas for you. Sorry!
JSprang
@JSprang - No worries - thanks for the reply. Most of what you're trying to do can be solved with DataAnnotations, though. Just implement the INotifyDataErrorInfo and INotifyPropertyChanged (or simply subclass System.ServiceModel.DomainServices.Client.Entity), and you can get validation error UX for "free" with the ValidationSummary control. You can write custom validation decorators by extending System.ComponentModel.DataAnnotations.ValidationAttribute, or even point to an existing validation method in your code using the System.ComponentModel.DataAnnotations.CustomValidation attribute.
Schemer
Yeah, that's what we are doing. We use this approach though instead of the DataAnnotations so that we can have the validation logic be on the business layer, if that makes sense.
JSprang