ASP.NET MVC Modify view model property before validation - c#

I've been googling like crazy without result, maybe I'm just missing the correct keywords.
I have a class with a custom validation attribute on a property. I want to "clean" the value before validation, removing the white-space and special characters that we accept but that we don't want to save to the database.
public class PersonViewModel
{
[SocialSecurityNumberLuhn(ErrorMessage = "Incorrect social security number")]
public string SocialSecurityNumber { get; set; }
}
I would want to do something like this:
public class PersonViewModel
{
[CleanWhiteSpace]
[SocialSecurityNumberLuhn(ErrorMessage = "Incorrect social security number")]
public string SocialSecurityNumber { get; set; }
}
For example 1985-03-15-1234 should be saved and validated as 19850315-1234.
Any suggestions? What's the neatest approach?

If you change the auto-implemented property into a manual-implemented property then you can perform the "cleaning" step when the value is set, so it can only be stored in the model in a "clean" state. Something like this:
public class PersonViewModel
{
private string _socialSecurityNumber;
[SocialSecurityNumberLuhn(ErrorMessage = "Incorrect social security number")]
public string SocialSecurityNumber
{
get { return _socialSecurityNumber; }
set
{
_socialSecurityNumber = CleanSocialSecurityNumber(value);
}
}
}

The recommended approach here is to use a service layer. View models should not include any logic. With a service layer Your controller would call a method on its associated service and this method would return your view model with the clean SSN.
In this tutorial you will see how the service layer can be structured and you could adapt the pattern to clean your data before validation.
http://www.asp.net/mvc/tutorials/older-versions/models-(data)/validating-with-a-service-layer-cs
The use of a ValidationAttribute in your example would be an incorrect usage also.
Controller where you would inject / instantiate the service class
public ActionResult GetPerson(int PersonId){
return _personService.GetPerson(personId);
}
The service method
public PersonViewModel GetPerson(int Id){
// get the data (maybe from DAL) and clean returning view model
return new PersonViewModel(){SocialSecurityNumber = Clean(...)};
}
Hope this gives you some direction.

Related

Model validation with respect to action being taken over entity being validated

How can we validate data based on action being taken over particular entity? What other more advanced alternatives are there to data annotations model validation? Possibly pluggable into Asp.net MVC and WebAPI, so validation is still being done automatically.
Example
Suppose a user join form of a web application.
public class User
{
// required when providing user as input
// not provided when creating new instance
public int Id { get; set; }
// required when user joins and of specific format AND IS UNIQUE based on data store users
// optional when providing user as input
public string Email { get; set; }
...
}
Maybe object inheritance could help but as much as I think of it, inheritance would only be as a hack. Base class would hardly have any properties and we could end up with several extremely similar (properties) classes but with different annotations just to use data annotations. And that's not good.
Desired implementation
I was thinking of validation based on action being taken over particular entity. So we'd be able to define something like:
public class User
{
[Required(Action = ValidationAction.Provide)] // or whatever action we'd define
public int Id { get; set; }
[Required(Action = ValidationAction.Create)]
[IsUnique(Action = ValidationAction.Create)] // custom DataAnnotations validator
[EmailAddress]
public string Email { get; set; }
...
}
Asp.net MVC and WebAPI controller actions would require some sort of attribute to provide information what's being done with particular entities a parameters
[HttpPost]
[ValidateForAction("user", ValidationAction.Create)]
[ValidateForAction("user.InvitedBy", ValidationAction.Provide)]
public ActionResult Join(User user)
{
...
}
or set it uniformly for all parameters (and their object entities in subtrees)
[HttpPost]
[ValidateForAction(ValidationAction.Create)]
public ActionResult Join(User user)
{
...
}
When ValidateForActionAttribute isn't present on controller action validation should only check validation action independent annotations (like the EmailAddressAttribute set above on my entity example).
A similar example could be Stackoverflow scenario of adding an answer where posted answer details would be validated by create action, and related question entity (a property inside an answer) would be validated per provide action because we'd mainly just need its Id.
Is there any such validation library? Anybody done something similar?
How would you go about doing such validation?
This sounds like its similar to a requiredif validator where the validation is dependent upon another property. However, model validation will not work here since the model is "supposed" to be independent of views or controllers.
Assume though that you have a view model associated with individual actions on a controller, then the view model could use data annotations consistent with the requirements of the view. See ASP.Net MVC and MVVM for more detail on the MVVM pattern.
One last comment with regard to the Id. Not sure a Required attribute will work since the default for an int is a valid value. Perhaps a regex? ([1-9]|[0-9]{2,10})
public class RegistrationController
[HttpPost]
public ActionResult Provide(UserProvideViewModel user)
{
...
}
[HttpPost]
public ActionResult Join(UserJoinViewModel user)
{
...
}
}
[MetadataType(typeof(UserProvideViewModel_Validation))]
public partial class UserProvideViewModel : User
{
// properties unique to the view model
}
public class UserProvideViewModel_Validation
{
[RegularExpression(#"^([1-9]|\d{2,10})$")]
public Id { get; set; }
}
[MetadataType(typeof(UserJoinViewModel_Validation))]
public partial class UserJoinViewModel : User
{
// properties unique to the view model
}
public class UserJoinViewModel_Validation
{
[Required]
[EmailAddress]
public Email { get; set; }
}

Asp.net MVC 3 - Data Validation

I'm new at ASP.NET MVC web framework. My database is compound of a single model class("Movie"). I need to validate user's from entering existing data, for instance, a database row could be:
Title - "Indiana Jones and the lost Arc"
Price - $10.00
If another user tries to insert into the database the same data above, provide an error message and prevent from submitting the form collection.
First of all, I think that your question need a "program as answer" but I'll try to suggest you from where to start for working with validation. Suppose you have this model:
class Movie {
public Guid Id { get; set; }
[Required(ErrorMessage="Title is required.")]
[Remote("UniqueTitle", "Validation")]
public String Title { get; set; }
[Required(ErrorMessage="Price is required.")]
public float Price { get; set; }
}
You can decorate it for "simple validation" using Data Annotation. I've used a specific attribute, called Remote.
This attribute allow you to define a custom, server-side, logic to validate the model.
Now, you can create a validation controller where check that provided value is not already in use:
class ValidationController : Controller {
private IDbContext db = ...;
public ActionResult UniqueTitle(String title) {
var item = db.Movies.FirstOrDefault(m => m.Title.Equals(title));
return Json(item == null, JsonRequestBehavior.AllowGet);
}
}
Now you are ready to validate your model.
I hope this can help.

Model to Controller / View Error Message

I'm wanting to check if I can send a message from a Model to a Controller, I'll explain.
So I have a Model
public class Car()
{
public int Id { get; set; }
public string Make { get; set; }
}
So when a user adds a new Car, I could make it required by using Fluent API or the [Required] annotation.
But what if I wanted to make sure I had only certain characters in there, so I wouldn't want the percentage symbol in there (unless there are any cars out there?!).
So I thought I'll use a constructor:
public class Car()
{
public Car(string _name)
{
if(this.Make.Contains("%"))
{
//Let the user know this isn't valid there is an error
}
}
public int Id { get; set; }
public string Make { get; set; }
}
I usually place the error logic in the Controller. So I would have
public ActionResult AddCar(Car car)
{
if(car.Make.Contains("%"))
{
//let user know this is not valid
}
if(ModelState.IsValid)
{
}
///
}
But then I thought, I'm never going to want to have a car Make with a % sign (I've picked on % sign, but actually there is a host of validation I would use, such as a list containing invalid characters), and every place in which I allowed for a user to add a car, I would duplicate the validation code, which just felt inefficient.
Maybe producing a the error checking in the controller is the correct way?
Again for clarity. The question, is there a way to pass a message from a Model to a Controller, which I can then pass to the User's view?
Kind regards
You should not use validation logic in your controller, we have DataAnnotations which allows us to validate model's properties value.
for your purpose you can use RegularExpression validator for this.
Refer to this Link for more details

Domain object to ViewModel & vice versa using Automapper

I'm developing a new MVC site for my company & kind of confused as how to create mapping from Domain/POCO objects to ViewModel classes [contains validation] & vice versa. Here's an sample example.
My domain class [just to keep it simple I'hv omitted other properties]:
public partial class Glossary
{
public int Id { get; set; }
public string GlossaryItem { get; set; }
public string Definition { get; set; }
}
my ViewModel class inside my MVC app's model folder [with corrosponding validation]:
public class GlossaryModel
{
[HiddenInput(DisplayValue = false)]
public int Id { get; set; }
[Required(ErrorMessage = "Please enter a GlossaryItem")]
public string GlossaryItem { get; set; }
[Required(ErrorMessage = "Please enter a Definition")]
public string Definition { get; set; }
}
my Automapper configuration for DTO to Domain Model:
protected override void Configure()
{
CreateMap<GlossaryModel, Glossary>();
//....... etc
}
My controller's action method for editing an item:
public class GlossaryController : Controller
{
IGlossaryRepository _glossaryRepository;
IMappingService _mappingService;
public GlossaryController(IGlossaryRepository glossaryRepository, IMappingService autoMapperMappingService)
{
_glossaryRepository = glossaryRepository;
_mappingService = autoMapperMappingService;
}
// .... etc
[HttpPost, ValidateAntiForgeryToken]
public virtual ActionResult Edit(GlossaryModel glossaryModel)
{
if (ModelState.IsValid)
{
var glossary = _mappingService.Map<GlossaryModel, Glossary>(glossaryModel);
if (glossaryModel.Id <= 0)
_glossaryRepository.Add(glossary);
else
_glossaryRepository.Edit(glossary);
_glossaryRepository.Save();
TempData["message"] = string.Format("{0} has been saved", glossaryModel.Definition);
return RedirectToAction("All");
}
return View(glossaryModel);
}
//....etc
}
And it's working fine, but my question is... Now say I need an action that will list down all glossary items like..
public ActionResult All()
{
var allItems = _glossaryRepository.Glossary;
if (allItems.Count() == 0) return View(new List<GlossaryModel>());
// **The below line is the reverse mapping one**
var allItemsModel = _mappingService.Map<IEnumerable<Glossary>, IEnumerable<GlossaryModel>>(allItems);
return View(allItemsModel);
}
But now I need automapper to convert from Domain objects to DTO [from List(Glossary) to List(GlossaryModel)], just opposite of the Edit method, to push the data to the view. So do I again need to map the opposite binding in the automapper config...!! like
protected override void Configure()
{
CreateMap<GlossaryModel, Glossary>(); // Added before for DTO to Domain object
CreateMap<Glossary, GlossaryModel>();// Added for Domain object to DTO
//....... etc
}
Is it a good design to bind both ways? or there's better solution I'm missing, Please help
Thanks,
Sanjay
Jimmy Bogard also asked the same question. But there was enough demand for it that direct support has been added for simple cases like you've listed. In fact, in this answer Jimmy also suggested that there's nothing wrong with it if it works for you. A simple example is:
protected override void Configure()
{
CreateMap<GlossaryModel, Glossary>()
.ReverseMap();
//....... etc
}
Note that ReverseMap doesn't work for more complex mappings. See this answer for more details.
Automapper was build to Domain to ViewModel (Domain to DTO in the manner in which you've described it) mapping
Summed up well by #Marius' answer here What is wrong with two-way mapping?
In some medium sized projects I've used two way mapping and for larger projects I use Domain To View Model mapping and then used a CQRS system for sending the ViewModel values to the underlying persistence store.
When it comes down to it, it is up to you how you choose to use Automapper and what Architectural decisions make sense to you.
The world will not stop rotating if you do 2 way mapping.

asp.NET MVC 2 DataAnnotations UpdateModel<T> validation

I'm trying to use DataAnnotations to add validation to my models in asp.NET MVC 2 RC2, using TryUpdateModel
var user = UserManager.Find(id);
this.TryUpdateModel<IProvisioningObject>(user, form.ToValueProvider());
This updates the model, but the validation is never called. I tried using TryUpdateModel as well (which is the direct type of user), not using the form value provider, using ProvisioningObject directly (which has the validation metadata), to no avail.
Googling for examples only gives me ways to use DataAnnotations by binding through a parameter
public ActionResult Update(User user)
Which I dislike for update scenarios.
Any tips and/or solutions?
EDIT
My objects are auto-generated objects from a WCF service.
I made partials to be able to add DataAnnotations.
I call TryUpdateModel three times because it apparently doesn't support inheritance, which I think is also my problem with DataAnnotations. I specify the validation attributes for ProvisioningObject, and the binding doesn't look for inherited stuff like that.
[MetadataType(typeof(ProvisioningObjectMetadata))]
public partial class ProvisioningObject : IProvisioningObject
{
public string DisplayNameInvariant { get { return string.IsNullOrEmpty(this.DisplayName) ? this.Name : this.DisplayName; } }
}
[MetadataType(typeof(UserMetadata))]
public partial class User : IUser
{
}
public class ProvisioningObjectMetadata
{
[DisplayName("Country")]
public string CountryIsoCode { get; set; }
[Required(ErrorMessageResourceType = typeof(Properties.Validation), ErrorMessageResourceName = "DisplayNameIsRequired")]
[TempValidator]
public string DisplayName { get; set; }
}
public class UserMetadata
{
[DisplayName("Username")]
public string Name { get; set; }
}
// Controller action
public ActionResult Update(string id, FormCollection form)
{
var user = UserManager.Find(id);
this.TryUpdateModel<IUser>(user.User, form.ToValueProvider());
this.TryUpdateModel<IPerson>(user.User, form.ToValueProvider());
this.TryUpdateModel<IProvisioningObject>(user.User, form.ToValueProvider());
if (ModelState.IsValid) // always true
{
return Redirect;
}
else
{
return View();
}
}
If I add the metadata for DisplayName in UserMetadata, it works as expected, but that seems very redundant for nothing. And it would mean I would also have to copy/paste all my inherited interfaces so TryUpdateModel behaves appropriately.
I guess I'm looking for a way that doesn't require me to copy and paste my validation attributes to inherited classes.
New Answer:
"My objects are auto-generated objects from a WCF service."
Autogenerated objects won't have any attributes on them. Are you defining your objects and their attributes on the server side or on the client side?
Old Answer:
If your metadata is not on IProvisioningObject then no validation will be called. The MVC2 default model binder only knows how to find "extra" [MetadataType(buddyClass)] validation information.
For update scenarios bind against DTOs and then map the DTOs, if IsValid() to your main model classes.
Implement IDataErrorInfo interface in your partial class
You will have to write custom validation for each field(where you can use data annotation class to validate each required property)
If you need code example then let me know. I will write it for you!
source: http://www.asp.net/(S(pdfrohu0ajmwt445fanvj2r3))/learn/mvc/tutorial-37-cs.aspx
How do you know that the validation is not being called? Are you checking ModelState.IsValid in your update controller and finding that it is erroneously coming back true?
A typical update pattern is:
UpdateModel(model);
if(!ModelState.IsValid) return View(model);
return RedirectToAction("Index");
If you are expecting some "IsValid" on your model to automatically be called, that will not happen. The data annotations work behind the scenes with the ModelState dictionary on the Controller base class.

Categories

Resources