Where to validate DTO - validation

I am writing a Webservice which sends and receives DTO's
A DTO might look like this(in this example its C#)
[Serializable]
public class GetCardStatusRequest : RequestBase
{
public GetCardStatusRequest()
{
}
public String CardId { get; set; }
}
when receiving such a request DTO I want to validate that the CardId is for example not empty.
So I currently have a validation class
internal class Validation
{
internal static bool IsValidGetGiftCardStatusRequest(GetCardStatusRequest getCardStatusRequest)
{
return getCardStatusRequest.CardId != null && !string.IsNullOrEmpty(getCardStatusRequest.CardId);
}
}
There are more "complex" DTO's so I wanted to place the validation logic somewhere to ensure that the incoming requests are valid before mapping them to the business objects.
My question is where should I place the validation logic and how should I do it ? I currently have this class with only static methods which seem wrong to me.
Should this validation be placed in the service layer ?
I feel quite close with this logic above, but nevertheless it seems not correct.

Related

Mapping of Dynamic fields in RestfulController POST (save) method

How do I enable RestfulController to auto-map or even manually map the dynamic fields to domain classes implementing MongoEntity? I have a domain class as below:
class Company implements MongoEntity<Company> {
String id = UUID.randomUUID().toString()
String name
String email
String phone
}
And I have a RestfulController setup for CRUD operations as below
class CompanyController extends RestfulController<Company> {
#Transactional
def save(Company company) {
if(company.hasErrors()) {
respond company.errors
}
else {
company.insert(flush:true)
respond company, status: CREATED
}
}
}
When I POST a request with some additional JSON fields, how do I get them auto-mapped to gorm_dynamic_attributes ? Currently the company object does not return any information on the dynamic attributes. Another problem I am facing is that request.JSON is also null so I cannot manually map either. Any suggestions would be highly appreciated.
I'm pretty sure, that the problem is not in data binding of your controller, but rather in persisting of the domain class instance.
I would change the domain class like so:
import grails.gorm.annotation.Entity
#Entity
class Company {
String id
String name
String email
String phone
def beforeValidate() {
if( !id ) setId UUID.randomUUID().toString()
}
static mapping = {
id generator:'assigned'
}
}
to use the assigned generator. You could put your id generation either in the controller / service code, or leave it inside the domain class' beforeValidate. In the later case pay special attention to when the id shall be generated, as beforeValidate() is called pretty often. Also note, that inside beforeValidate() a setter must be called.
I tested the similar domain class of mine with save() and insert() and in both cases that works like charm.

Web API 2- Data Annotations Validation-No Duplicates in the Request

I am using WEB API 2.
In my request I pass the request as Collection of Mytype
MyType has following properties:
Id(int),
PaymentId(int).
I need the following validation. Every Id of the request should be Unique.
Do I need to write custom validation or Is there any builtin DataAnnotationValidation exist for that?
The only way I can think of is writing a model class inheriting IValidatableObject or writing a custom validation attribute for the entire model. Web API will validate your model on the custom validation logic.
public class MyModel : IValidatableObject
{
public IEnumerable<MyType> MyTypes { get; set;}
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
foreach(var myType in this.MyTypes)
{
// do validation logic
if (error)
{
yield return new ValidationResult("All Ids must be unique!")
}
}
}
}

N-Tier Service Layer Validation Show Business Logic Error in Presentation Layer

I am converting from the old ways of ASP.NET Web Forms to ASP.NET MVC. I have a project that I am working on that has about 40-50 tables in the database. I have decided to use Entity Framework as my data access layer. I have also decided to put a repository layer and unit of work abstraction over EF so that I am not tied to it and so that I can do unit testing. Finally, I want to make my controllers "thin" so I am looking at implementing a business "service" layer for my business logic.
The thing I am struggling with is how do I propagate Business Logic Errors from my service layer to my Presentation UI layer so that an appropriate error can be shown? Please note that I am trying to look for a solution that is NOT MVC specific as this service/business logic layer will likely be used in other things besides an MVC app (console app's, web services, etc.)
On to some code...
Lets say I have a POCO / data / domain model like so:
public class Category
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public bool IsActive { get; set; }
// other properties (navigation, etc)...
}
An Entity Framework fluent configuration/mapping class like so:
public class CategoryMap : EntityTypeConfiguration<Category>
{
public CategoryMap()
{
this.HasKey(c => c.Id);
this.Property(c => c.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); // auto increment identity in our DB schema
this.Property(c=> c.Name)
.IsRequired() // defined as NOT NULL in DB schema so we put a constraint here
.HasMaxLength(150); // defined as varchar(150) in DB schema so we put a constraint here
this.Property(c=> c.Description)
.IsRequired(); // defined as NOT NULL in DB schema so we put a constraint here
// fluent config for related entities (navigation properties) would go here...
}
}
A unit of work encapsulating multiple repositories like so:
public class UnitOfWork : IUnitOfWork
{
private readonly MyDbContext context;
private CategoryRepository catRepo;
public UnitOfWork()
{
this.context = new MyDbContext();
}
public ICategoryRepository Categories
{
get { return this.catRepo?? (this.catRepo= new CategoryRepository (this.context)); }
}
}
A service / business logic layer like so:
public class CategoryService : ICategoryService
{
private readonly IUnitOfWork unitOfWork;
public CategoryService(IUnitOfWork uow) // injected by IoC
{
this.unitOfWork = uow;
}
public Category CreateNewCategory(Category category)
{
if (category == null)
{
throw new ArgumentNullException("category cannot be null");
}
// Simple business logic here to make sure another category with this name does not already exist.
int count = this.unitOfWork.Categories.Count(cat => cat.Name == category.Name);
if (count > 0)
{
// *** This is the error I want the user to see in the UI ***
throw new Exception("Sorry - a category with that name already exists!");
}
}
}
And a controller like this:
public ManageCategoriesController : Controller
{
ICategoryService catSvc;
public ManageCategoriesController(ICategoryService svc) // injected by IoC
{
this.catSvc = svc;
}
[HttpPost]
public ActionResult(CategoryCreateModel createModel) // my View Models / Create Models have Data Annotations on them
{
if (ModelState.IsValid)
{
// use of AutoMapper to map from View Model to domain model...
Category cat = Mapper.Map<CategoryCreateModel , Category>(createModel);
this.catSvc.CreateNewCategory(cat); // ***need to get potential errors from Service and display on form.***
return this.RedirectToAction("Index");
}
}
}
First of all, can anybody tell me if I am on the right track with using View Models? I feel like I almost have three View Models (Create, Edit, View/List) per domain model.
Secondly, my EF configuration/mapping class takes care of the database constraints. Some of these constraints (e.g. Max length) are also data annotations in the View Models and can easily be displayed on the UI. But where can I show my custom business logic errors?
First, your overall approach to MVC looks good to me :-)
Second, you most likely want to use DataAnnotation on your view models for model validation. Have a look this blog post for a good intro on using it in ASP.MVC.
In case of custom validation not suitable for data annotation you can do the following in your controller:
try
{
// the following exception could be thown by some nested validation logic
// e.g. while processing a post request
throw new ValidationException("the error description");
}
catch (ValidationException exception)
{
ModelState.AddModelError("", exception.Message);
}
This is a pretty old question, but for future readers I'd like to add something.
If you're actually using a N-Tier pattern, entity validation should be in your Service layer. Not in your MVC Controller.
The right way to do it is to do basic model validations in your model class, using ValidationAttributes, but re-validate your entities in your service layer.
Add a handling of custom exceptions in your controller to catch any validation error raised from the service layer, and display error messages.
If your service layer is just there to call your repositories, you're doing something wrong ;)

ASP.Net Web API - How can I make it so that prefixes are not required when model binding from the query string?

In ASP.Net Web API (RC) I have a test model class like so:
[ModelBinder]
public class TestRequest
{
public string Foo { get; set; }
public string Bar { get; set; }
}
My controller looks like this:
public class TestController : ApiController
{
public TestRequest Get(TestRequest model)
{
return model;
}
}
Now if I invoke the action via:
http://.../test?foo=abc&bar=xyz
neither values bind, because the model binder is expecting model prefixes, such that I actually need to call:
http://.../test?model.foo=abc&model.bar=xyz
I can understand that this is so that other action parameters can bind correctly, but in my case the model is a clean way of encapsulating all the possible action parameters so that I don't need to have a nasty action method signature with a whole lot of optional parameters. It also allows for easy model validation.
Is there any easy way to cause model binding to behave the same way as it would in MVC, or in a POST request?
Removing the ModelBinder attribute from your model class should work in the example you've posted. You'll run into issues for more complex method signatures, see Rick Strahl's comment: http://blogs.msdn.com/b/jmstall/archive/2012/04/16/how-webapi-does-parameter-binding.aspx#10302750

How to inject dependencies used for validation in .NET MVC3?

We have quite a few validation methods that need to access repositories / database to do their work. So far we have been using the service locator pattern (albeit sparingly) to accomplish this in custom ValidationAttributes:
public override bool IsValid(object value)
{
// use custom service locator in our app's infrastructure
var repos = DependencyInjector.Current.GetService<IXyzRepository>();
...
}
I know this is :( upon as an anti-pattern, and we would like to use a more correct approach. We use unity, and I read this post that says to use a build-up method. However the link in the accepted answer says that the documentation is outdated (retired content).
The solution does not need to use a validation attribute, I suppose it could use IValidatableObject, however the problem remains: how to inject the dependency into the model. Do we need a custom model binder to do this?
Another solution would be to perform the validation in the controller, where dependency injection is easy. To me this feels cluttered though. I would like the model to be validated by the time it gets to the action method.
Also we sometimes use [RemoteAttribute] to perform some of these validations on the client. Currently those methods construct a viewmodel and delegate validation to the model by using the static Validator.TryValidateObject method.
How have you accomplished validation that requires an injected dependency to do its work, without using the SL anti-pattern?
How have you accomplished validation that requires an injected
dependency to do its work, without using the SL anti-pattern?
I use FluentValidation.NET to perform validation in my applications. It allows me to inject dependencies into my validators. It has a really nice integration with ASP.NET MVC. It also supports automatic client side validation for the standard rules just the same way as data annotations using jquery unobtrusive validate:
NotNull/NotEmpty
Matches (regex)
InclusiveBetween (range)
CreditCard
Email
EqualTo (cross-property equality comparison)
Length
I have never used data annotations to perform validation. They are absolutely useless when you need to handle some more complex validation scenarios where you need to validate dependent properties and even use some service. I put complex in italics in the previous sentence because, I don't think that validating that one of the 2 properties is required is a really complex validation scenario and yet, just checkout the amount of infrastructure crap you have to write in order to implement it using data annotations. Looking at this code you no longer know what you are validating.
Inject your validation into your Model.
Validation Attributes can become awkward to work with when your validation stories become more complex. Yuck!
I like to use Entity Framework with Code First. I have full control of my model at that point. I also use FluentValidation like #Darin Dimitrov and I really like its ease of use and simple syntax.
Here’s how you put it together.
I assume you have assembly with your interfaces or contracts.
This will be the base interface for your models…
using System.ComponentModel;
using FluentValidation.Results;
public interface IAbstractBase : IDataErrorInfo
{
bool IsValid { get; }
ValidationResult SelfValidate();
}
and its counterpart in your business layer looks like this…
using System;
using System.Linq;
using FluentValidation.Results;
using Contracts;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
public abstract class AbstractBase : IAbstractBase
{
#region IDataErrorInfo
public abstract ValidationResult SelfValidate();
[NotMapped]
public bool IsValid
{
get
{
return SelfValidate().IsValid;
}
}
[NotMapped]
public string Error
{
get
{
var results = SelfValidate().Errors.Select(s => string.Format("● {0}{1}", s.ErrorMessage, Environment.NewLine)).ToArray();
return string.Join("", results);
}
}
[NotMapped]
public IList<ValidationFailure> Errors
{
get
{
var results = SelfValidate().Errors;
return results;
}
}
[NotMapped]
public string this[string columnName]
{
get
{
var validationResults = SelfValidate();
if (validationResults == null) return string.Empty;
var columnResults = validationResults.Errors.FirstOrDefault(x => string.Compare(x.PropertyName, columnName, true) == 0);
return columnResults != null ? columnResults.ErrorMessage : string.Empty;
}
}
#endregion
}
This is your base class for your models. Make sure you implement the abstract method in your models. It should look like this.
public class MyModel : AbstractBase, IMyModel
{
private AbstractValidator<IMyModelValidator> _myModelValidator;
public MyModel():this(new MyModelValidator()){};
public MyModel(AbstractValidator<IMyModelValidator> myModelValidator){
_myModelValidator = myModelValidator;
};
public int MyModelId { get; set; }
public string Name { get; set; }
public DateTime CreatedDate { get; set; }
public override ValidationResult SelfValidate()
{
return _myModelValidator.Validate(this);
}
}
Your validator class will look something like this.
public class MyModelValidator : AbstractValidator<IMyModelValidator>
{
private IMyModelProvider _myModelProvider;
public MyModelValidator(IMyModelProvider myModelProvider){ _myModelProvider = myModelProvider;};
private void SetRules()
{
RuleFor(x => x.Name).NotEmpty().WithMessage("Please specify a project name.");
RuleFor(x => x.Name.Length).LessThanOrEqualTo(100).WithMessage("The project name must be less than or equal to 100 characters.");
}
public override ValidationResult Validate(IMyModel instance)
{
SetRules();
return base.Validate(instance);
}
}
Pass your validation results from your Model to your view in your Controller using the following call in your controller.
TryValidateModel(your model here);
After you call this in your controller call your model.IsValid property.
Make sure you register everything and you should be good to go. I assume you can fill in the missing pieces.
The big picture looks like this:

Resources