Webapi validation against database

1.1k Views Asked by At

Assume your webapi call creates database objects like this:

class Task
{
  public Guid AssignedUser {get; set;}
  public Guid FarmId {get; set;}
  public Guid FieldId {get; set;}
  ... etc
}

When a new task is created on a mobile device and API is called to create this task on the server I need to perform some validation. There are validation that can be performed pretty easily with the DataAnnotations attributes, such as if a filed is required or within Range or what not.

But assume that I also need to validate the following:

  • The current user (from context) belongs to specified Farm
  • AssignedUser belongs to the specified Farm
  • Field belongs to specified Farm and AssignedUser is allocated to a group working on this Field

All these checks require information from the database. I'm trying to use ExpressiveAnnotations and with them I could do something like

[AssertThat("CurrentUserBelongsToThatFarm(FarmId)")]
public Guid FarmId {get; set;}

the only problem, that validation runs during json desalinization, before code enters my controller action and I cannot figure out how do I inject database context so that it could be available for the validation function. That is I of course can query it directly from the IoC container, but I'd rather not.

Is there a clean way of performing such validations?

Update

To address CodeUniquely's comment below, I'd like to clarify that this is an "occasionally connected" scenario. That is, the devices that are using the API are out of network coverage most of the time, and they sync using the API from time to time.

Practically this means that most of the data that is needed to sync are aggregated into zero or one "push updates to server" call followed by "get latest state from server" call. With Sql Server and EF in the back-end that leads to several different (and sometimes unrelated) entities and collections are contained within single json. Eg:

class TaskData
{ 
    public IList<Product> Products {get; set;} 
    public Task Task {get; set}
    ...
}

Also the model classes that are used to generate json for GET calls are separate from EF Entites, as the database schema does not exactly match the API object model.

1

There are 1 best solutions below

0
On BEST ANSWER

What I ended up doing here is the following.

I split all the validations to two sets "Immediate" that are attribute based and do not need database and "Database". If any of the "Immediate" validations fail, the request fails and return these errors to the client. In theory these should only fail if client did not do the proper job of validating these client-side. Otherwise these will always succeed.

If "Immediate" validation succeeded, I run "Database" validations on each of the objects. I the persist changes to the DB for the changes that passed validation and return errors for the objects that did not.

This is more or less what @CodeUniquely suggested in his comment.