Web API 2- Data Annotations Validation-No Duplicates in the Request - asp.net-web-api

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!")
}
}
}
}

Related

Injecting Non-User-Submitted Data For Use During Validation

From what I can tell, ASP.Net Core performs model state validation before calling the relevant controller action method. This means that code in the action method isn't given an opportunity to add data to the model before it is validated.
What is the ASP.Net Core way of giving a view model access to additional, non-user-submitted data prior to validation?
Example
What I'm trying to do (doesn't work).
The view model's Validate method expects data to be in ValidOptions. However, since validation occurs before the controller can set this property, validation causes the view model to throw an ArgumentNullException.
// From the Controller
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Process([Bind("SelectedId")]ViewModels.Import details)
{
// data needed for validation
details.ValidOptions = await service.ImportTypes.ToListAsync();
if (ModelState.ValidationState != ModelValidationState.Valid) {
// ...
}
}
// From ViewModels.Import
public IEnumerable<Option> ValidOptions { get; set; }
public int SelectdId {get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
// throws ArgumentNullException because ValidOptions hasn't been set when this is executed
var option = ValidOptions.Single(t => t.Id == SelectdId);
//...
}
Probably many ways to skin a cat here. But the easiest for you is probably custom model binders. It's a way to "supplement" or change the binding of your model before it hits the controller. I will say that some see it as extremely bad practice to call an external service/repository at the point of model binding, but it does work and can come in handy.
You need to implement a class that inherits from IModelBinder.
public class MyViewModelBinder : IModelBinder
{
public Task BindModelAsync(ModelBindingContext bindingContext)
{
//Bind here. Including calling external services if you want.
}
}
Then you need to implement a provider, this essentially says "when" to bind.
public class MyViewModelBinderProvider : IModelBinderProvider
{
public IModelBinder GetBinder(ModelBinderProviderContext context)
{
if (context.Metadata.ModelType == typeof(MyViewModel))
return new MyViewModelBinder();
return null;
}
}
In your configure method of your startup.cs, you need to add the provider to the ModelBinderProviders list.
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddMvc(config =>
config.ModelBinderProviders.Add(new MyViewModelBinderProvider())
);
}
Further Documentation :
http://dotnetcoretutorials.com/2016/12/28/custom-model-binders-asp-net-core/
http://intellitect.com/custom-model-binding-in-asp-net-core-1-0/
I don't think the official documentation has an article on custom model binders yet unfortunately.

Where to validate DTO

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.

How does one bind the value of a field to a property with a different name using ASP.NET MVC 3?

Consider the following model which uses XmlSerializer and JSON.net to serialize the object to and from the respective formats.
[XmlRoot("my_model")]
[JsonObject("my_model")]
public class MyModel {
[JsonProperty("property1")]
[XmlElement("property1")]
public string Property1 { get; set; }
[JsonProperty("important")]
[XmlElement("important")]
public string IsReallyImportant { get; set; }
}
Now consider the following ASP.NET MVC 3 action that accept JSON or XML requests and returns model in the respective format (based on the accept header).
public class MyController {
public ActionResult Post(MyModel model) {
// process model
string acceptType = Request.AcceptTypes[0];
int index = acceptType.IndexOf(';');
if (index > 0)
{
acceptType = item.Substring(0, index);
}
switch(acceptType) {
case "application/xml":
case "text/xml":
return new XmlResult(model);
case "application/json":
return new JsonNetResult(model);
default:
return View();
}
}
}
Custom ValueProviderFactory implementations exist for JSON and XML inputs. As it stands the IsReallyImportant is being ignored when the input is being mapped to MyModel. However, if I define the attributes of IsReallyImportant to use "isreallyimportant", then information is correctly serialized.
[JsonProperty("isreallyimportant")]
[XmlElement("isreallyimportant")]
public string IsReallyImportant { get; set; }
As expected the default binder uses the property name when mapping incoming values to the model. I had a look at the BindAttribute, however its not supported on properties.
How does one tell ASP.NET MVC 3 that the property IsReallyImportant should be bound to "important" in the incoming request?
I have too many models to write a custom binder for each. Note that I don't use ASP.NET Web API.
You can do only one custom ModelBinder which will look for JSonProperty and XMLElement attributes to map the right properties. This way you could use it everywhere and you won't have to develop a modelbinder for each model. Unfortunately, there is no other option to modify the property bindings than custom modelbinders.

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:

MVC3 / EF CustomValidator two fields in model

Using MVC3 and EF4.1 how do I validate on client and server more than one field in my view model?
I have a start date text box (that can be modified) and I have the original start date in a hidden field. When the user submits the form I want to check that the modied start date is no more than one month either side of the original start date.
I can't figure out how this can be done with DataAnnotation and CustomValidation (or maybe I'm going down the wrong road)? This is an example of whay I've been working with:
[MetadataType(typeof(Metadata.MyUserMetaData))]
public partial class MyUser
{
public System.DateTime DateOfBirth { get; set; }
}
Partial Class
public class MyUserMetaData
{
[CustomValidation(typeof(AmendedStartDate), "amendedstartdate", ErrorMessage = "Invalid date."]
public DateTime StartDate { get; set; };
public DateTime OriginalStartDate { get; set; };
}
Custom Validator
public class AmendedStartDate : ValidationAttribute, IClientValidatable
{
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
// How do I get multiple field values from object value?
}
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(Modelmetadata metadate, ControllerContext context)
{
var rule = new ModelClientValidationRule
{
ErrorMessage = FormatErrorMessage(metadata.GetDisplayName()),
ValidationType = "amendedstartdate"
};
yield return rule;
}
}
I know I've still to add jQuery to the view for this validator.
Instead of using data annotations implement IValidatableObject on your model class - it is simpler and much more clear in scenarios with cross validation.
If you still want to use ValidationAttribute you have two parameters in the IsValid method:
value represents validated value of the property where the attribute is assigned
context is context in which the property is validated. It also contains ObjectInstance and ObjectType properties to access the whole model and its type so you can cast the instance and access other properties.
The question asked in MVC custom validation: compare two dates has an example of a validator which compares to a second value in the model. That should get you started.

Resources