Data Access has been discontinued. Please refer to this page for more information.

Model Validation

This article is relevant to entity models that utilize the deprecated Visual Studio integration of Telerik Data Access. The current documentation of the Data Access framework is available here.

This topic demonstrates how to validate data in your api controllers before doing any processing.

Adding Metadata Class

ASP.NET Web API supports the ability to annotate persistent classes and properties. Annotations are implemented with partial classes called metadata classes. You use metadata classes when you want to annotate generated persistent classes, but do not want to lose those annotations when the persistent class is regenerated. You can use attributes from the System.ComponentModel.DataAnnotations namespace to set validation rules for properties on your model.

To add a metadata class:

  1. Add a new class with the same name as the persistent class that you want to annotate. For example: Car.cs (for C#) or Car.vb (for VB).
  2. Add the partial keyword to make the class a partial class.
  3. In the partial class, create an internal class that will serve as a metadata class.
  4. Add a MetadataTypeAttribute attribute to the partial class and include the type of the metadata class.
  5. In the metadata class, add all properties you want to annotate. They should have the same names as the corresponding properties in the persistent class.

In the following example, the Required attribute says that the Make and Model properties of the Car entity must not be null.

[MetadataType( typeof( CarMetadata ) )]
public partial class Car
{
   internal sealed class CarMetadata
   {
       [Required]
       public string Make
       {
           get;
           set;
       }
       [Required]
       public string Model
       {
           get;
           set;
       }
   }
}
<MetadataType(GetType(Car.CarMetadata))>
Partial Public Class Car
    Friend NotInheritable Class CarMetadata
        <Required>
        Public Property Make() As String
        <Required>
        Public Property Model() As String
    End Class
End Class

Validating Data

Suppose that a client sends the following JSON as a POST request:

{"TagNumber":"TE 2312 IK","CarYear":1993,"CategoryID":1,"Mp3Player":true}

As you can see, the Make and Model properties are not included and the same time they are marked as required. When ASP.NET Web API converts the JSON into a Car instance, it validates the Car entity against the validation attributes. In your controller method, you can check whether the model is valid in the following way:

public partial class CarsController
{
   public override HttpResponseMessage Post( Car entity )
   {
       if ( ModelState.IsValid )
       {
           return base.Post( entity );
       }

       HttpResponseMessage response = new HttpResponseMessage()
       {
           StatusCode = HttpStatusCode.BadRequest,
           Content = new StringContent("Invalid car")
       };
       throw new HttpResponseException(response);
   }
}
Partial Public Class CarsController
    Public Overrides Function Post(ByVal entity As Car) As HttpResponseMessage
        If ModelState.IsValid Then
            Return MyBase.Post(entity)
        End If

        Dim response As HttpResponseMessage = New HttpResponseMessage With {
            .StatusCode = HttpStatusCode.BadRequest,
            .Content = New StringContent("Invalid car")}
        Throw New HttpResponseException(response)
    End Function
End Class

You can also create an action filter to validate the model before the actual controller method is invoked. If the model validation fails, the filter returns to the client an HTTP response that contains the validation errors.

public class ValidationFilterAttribute : ActionFilterAttribute
{
   public override void OnActionExecuting( HttpActionContext actionContext )
   {
       if ( actionContext.ModelState.IsValid == false )
       {
           IDictionary<string, IEnumerable<string>> errors = 
                new Dictionary<string, IEnumerable<string>>();
           foreach ( KeyValuePair<string, ModelState> state in actionContext.ModelState )
           {
               errors[state.Key] = state.Value.Errors.Select( e => e.ErrorMessage );
           }
           actionContext.Response = actionContext.Request.
                CreateResponse( HttpStatusCode.BadRequest, errors );
       }
       base.OnActionExecuting( actionContext );
   }
}
Public Class ValidationFilterAttribute
    Inherits ActionFilterAttribute
    Public Overrides Sub OnActionExecuting(ByVal actionContext As HttpActionContext)
        If actionContext.ModelState.IsValid = False Then
            Dim errors As IDictionary(Of String, IEnumerable(Of String)) = 
                New Dictionary(Of String, IEnumerable(Of String))()
            For Each state As KeyValuePair(Of String, ModelState) In actionContext.ModelState
                errors(state.Key) = state.Value.Errors.Select(Function(e) e.ErrorMessage)
            Next state
            actionContext.Response = actionContext.Request. _
                CreateResponse(HttpStatusCode.BadRequest, errors)
        End If
        MyBase.OnActionExecuting(actionContext)
    End Sub
End Class

You can apply the filter locally by marking the specific controller actions:

public partial class CarsController
{
   [ValidationFilter]
   public override HttpResponseMessage Post( Car entity )
   {
       return base.Post( entity );
   }
}
Partial Public Class CarsController
    <ValidationFilter>
    Public Overrides Function Post(ByVal entity As Car) As HttpResponseMessage
        Return MyBase.Post(entity)
    End Function
End Class

Or, you can apply it globally by adding it to the GlobalConfiguration.Configuration.Filters collection in the Application_Start method of Global.asax.

GlobalConfiguration.Configuration.Filters.Add( new ValidationFilterAttribute() );
GlobalConfiguration.Configuration.Filters.Add(New ValidationFilterAttribute())