Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Server-side validation

I am having trouble figuring out how to get server-side DbContext validation errors back to the client. I understand that Breeze has default validators that react to a few of the attributes such as Required, but what about all the other attributes? I could write a custom JavaScript validator for Breeze that will check on the client side, but I also need to check to make sure the entity is valid on the server-side.

For example, the application requires a Person to to have a valid email address. A malicious user comes along and gets an email address past the client and posts to the server with a data that would not pass the EmailAddress validator. Thus far my experience with Breeze is that the email address will save and not bubble up any DbContext Entity Framework errors.

Assuming the model below, what would be the best way to get any entity validation errors?

public class PeopleContext : DbContext
{
    public PeopleContext()
        : base("name=ConnectionString"){ }

    public DbSet<Person> People { get; set; }
}

public class Person
{
    public int PersonId { get; set; }
    public string FirstName { get; set; }
    [Required]
    public string LastName { get; set; }
    [EmailAddress]
    [Required]
    public string Email { get; set; }
}

UPDATE 1:

Here are some instructions to re-create the issue that I am experiencing.

  1. Follow the instructions to create the "Todo" sample (http://www.breezejs.com/documentation/start-nuget)
  2. Add a new custom validator to the BreezeSampleTodoItem.cs file:

    [AttributeUsage(AttributeTargets.Property)]
    public class CustomValidator : ValidationAttribute
    {
        public override Boolean IsValid(Object value)
        {
            string val = (string)value;
            if (!string.IsNullOrEmpty(val) && val == "Error")
            {
                ErrorMessage = "{0} equal the word 'Error'";
                return false;
            }
            return true;
        }
    }
    
  3. Decorate the Description field with the new custom validator:

    [CustomValidator]
    public string Description { get; set; }
    
  4. Add the proper usings of course (System and System.ComponentModel.DataAnnotations).

  5. Run the project.
  6. In one of the description fields type "Error" and save.

This is where I would expect to see an error come up through Breeze, or even an DbEntityValidationException be thrown from Entity Framework. I have tried on 2 separate computers with the same result. The entity saves to the database as if there were no error. In fact, if you put a breakpoint anywhere inside IsValid method of the custom validator you will see that its not even being called.

like image 895
adamlj Avatar asked Oct 05 '22 16:10

adamlj


2 Answers

As of Breeze v 0.78.1 all registered DbContext server side validations will now execute during an EntityManager SaveChanges call. Any exceptions encountered will cause the save to rollback, and any validation errors to be serialized back to the Breeze client.

Note that this functionality is not yet supported for older ObjectContext ( as opposed to DbContext) based EF models.

And ... thanks to adamlj for discovering this issue and suggesting the solution.

like image 97
Jay Traband Avatar answered Oct 08 '22 20:10

Jay Traband


I'm not sure what you mean by

get server-side DbContext validation errors back to the client

You could mean that you want the validation error messages to be sent to the client. But the rest of your question suggests that you want to know (a) how to run a custom validation on the server and (b) how to acquire and run a corresponding JavaScript version of that validation on the client. I will address this interpretation of your question.

Server

The Entity Framework (which you're using in your example) automatically runs Data Annotation validation rules for you ... unless you've disabled that feature manually. If you create custom validation rules in the proper way, EF will run these as well. This post by Daniel Wertheim describes how to write such rules. I can't vouch for that post in every detail but it seems correct to me. It even defines a custom Email-validationattribute!

If authoring a custom Data Annotation validation rule seems too Baroque to you (as it often does to me), you can write and call your own validation logic in one of the BeforeSave... methods discussed in "Server-side Interception".

I think these are your best server options. On to the client ...

Client

Breeze registers client-side JavaScript validations to match certain of the server-side Data Annotations (e.g., Required and MaxLength) that come across the wire in the metadata. As I write, custom Data Annotations are not recognized nor included in the metadata and they have no out-of-the-box analogs on the client. If you want the client to prescreen your entities using these rules, you'll have to write your own corresponding JavaScript validators and register them for the pertinent entity types as discussed in the Validation documentation page.

If you have suggestions or better alternatives, we'd love to hear them.

like image 32
Ward Avatar answered Oct 08 '22 19:10

Ward