Apply Required Attribute if the value was binded by Model Binder - c#

I have to handle following validation scenario:
If Some condition is met then we're displaying textbox which should be mandatory
If not met value for the property should be optional
Model Looking kind of this:
public class Setting
{
[Required]
public string Domain { get; set; }
}
Is that possible to differentiate somehow when field value was omitted or it didn't bind? Cause as I know if the value was omitted or not bound the value of it would be a default(string). In this case, I'm not able to definite should Domain be provided or not

If you have situations where it may or may not be required, you're best bet may be to have your Setting class inherit from IValidatableObject and implement your own Validate() method. Do whatever checksyou need to to see if it's required or not and do a yield return new ValidationResult("Description", new[] { nameof(Domain ) }) to explain why it's not valid.
If you can't make that determination inside your Settings class, then you'll likely have to do it in your controller action, and use something like ModelState.AddModelError("Description", nameof(model.Domain))); followed by checking ModelState.IsValid to see if the action should kick out and return a redirect/view

Related

Handling multiple forms on the same Razor Page

Has anyone found a trick for handling multiple forms on a Razor Page?
My page has two forms, each with a corresponding model that is decorated with a BindProperty attribute.
[BindProperty]
public TripDetailsUpdateDto UpdateTrip { get; set; }
[BindProperty]
public TripNoteUpdateDto UpdateNote { get; set; }
The problem is that, although either one works fine on its own, having both of them causes ModelState.IsValid to return false. Both models are combined and when one model is submitted, the properties of the other model haven't been set.
Surely I'm not the first to struggle with this. Is there a way to deal with this case without writing manual code to remove the unused items from ModelState?
So, as suggested, the problem is that every property of every model decorated with the [BindProperty] is combined into the ModelState.
To resolve the issue, first remove all [BindProperty] attributes.
Then bind to your values with a parameter:
public async Task<IActionResult> OnPostUpdateNoteAsync(int noteId, TripNoteUpdateDto updateNote)
{
// ...
}
Notes:
You can still have the original model members (in my case, UpdateTrip and UpdateNote). You can still reference them from your markup. This allows your markup to consider validation attributes, and also lets you specify default values.
If your markup references your original model members, your model argument must have the same name in order to match.

What does [Required] do?

I found nothing on the web what [Required] actually does. The msdn-article is not explorative at all.
static class Program
{
public static Main()
{
var vustomer = new CustomerClass();
}
}
public class CustomerClass
{
public string m_FirstName;
[Required]
public string m_LastName;
}
As far as i understand, that should throw an exception since m_LastName is required, but not set. But i don't get one. I don't get what it's good for and what this actually does.
RequiredAttribute, like all other attributes, does nothing by itself other than annotate something (in this case, a field of a type). It is entirely up to the application that consumes the type to detect the presence of the attribute and respond accordingly.
Your sample program does not do this, so the attribute does not have any visible effect. Certain frameworks such as ASP.NET MVC and WPF do check for and respond to the presence of the attribute.
This attribute is used by the Validator class to add validation errors based on any types that inherit from ValidationAttribute. This is used by MVC model validation, for example.
In C#, attributes are almost decoration to classes and properties.
Except for a few security related attributes, most do nothing. They are used by a higher-level framework to do something.
In the case of ASP.NET 4 MVC, only when the object is part of a request that attribute is used to generate an error.
If you want to use that attribute in any other environment, you must write code to inspect it.
It won't do anything from a plain old public static void Main()
Documentation on RequiredAttribute:
Specifies that a data field value is required.
However this validation is typically only performed in the UI layer. It is not "baked" into the constructor or other low-level usage. If you want to manually fire the validation you could do something like:
var customer = new CustomerClass();
var context = new ValidationContext(customer, serviceProvider: null, items: null);
var results = new List<ValidationResult>();
var isValid = Validator.TryValidateObject(customer, context, results);
if (!isValid)
{
foreach (var validationResult in results)
{
Console.WriteLine(validationResult.ErrorMessage);
}
}
To add to the current answers, these are some of the practical uses I can think of out of my head:
Entity Framework use this to model the database as not nullable fields.
Javascript client side validation provides javascript libraries for checking if the input field has any data, else prevent the form submission avoiding unnecesary roundtrips to the server.
Server side validation (when doing model binding) also check when you are posting a model with that decorator that the attribute passed in is in the request. This determines if the model state should be set to an invalid state or not. (1)
There are also annotation for JSON.NET library that changes how the model is serialized/unserialized. I'm pretty confident (but not sure) that the Validate Schema of Json.net does take into consideration the 'Required' attribute when validating a schema.
Other attribute decorators are used on web services, but 'Required' is not one I know has it uses in this scenario.
Web api uses this attribute to mark the property as required on documentation help pages and model binding.
You can create your own application logic that can be aware of the 'Required' property. For example, on a view to mark the property with an * in the label if it's required.
This are some uses but you are not limited to them.
(1) Note: if your property is, for example, an int and you decorate it with Required, model state will never be on a invalid state. You should use Nullable properties for this use-cases.

How to set/remove attributes dynamically in c#?

I am using from attribute validation in my project.
[Required(ErrorMessage = "DepartmentCode is Required")]
public string DepartmentCode { get; set; }
In some case DepartmentCode isn't required. How can I dynamically ignore Validation in my case?
Take a look at: Remove C# attribute of a property dynamically
Anyway I think the proper solution is to inherit an attribute from RequiredAttribute and override the Validate() method (so you can check when that field is required or not). You may check CompareAttribute implementation if you want to keep client side validation working.
Instead of dynamically adding and removing validation, you would be better served to create an attribute that better serves this purpose.
The following article demonstrates this (MVC3 with client-side validation too):
http://blogs.msdn.com/b/simonince/archive/2011/02/04/conditional-validation-in-asp-net-mvc-3.aspx
I would remove the RequiredAttribute from your model and check it once you've hit your controller and check it against whatever causes it to not be required.
If it falls into a case where it is required and the value is not filled in, add the error to the ModelState manually
ModelState.AddModelError("DepartmantCode", "DepartmantCode is Required");
You would just lose the validation on the client side this way
I've got round this issue in the model, in some cases it's not ideal but it's the cheapest and quickest way.
public string NonMandatoryDepartmentCode
{
get
{
return DepartmentCode;
}
set
{
DepartmentCode = value;
}
}
I used this approach for MVC when a base model I inherited contained attributes I wanted to override.

Mvc ModelState KeyFor property

Whenever there is some custom validation to do or any fiddling with ModelState I had to rely on magic strings (that reflect property names) so far. Surely there must be a better way.
say you have a form with 2 submit buttons. You've already set validation rules by adding Required attributes:
public class MyModel
{
[Required]
public string ValueOne { get; set; }
[Required]
public string ValueTwo { get; set; }
}
This will always validate both fields. But say I've added two buttons to the form showing and editor for above model. Button one only requires ValueOne and button two only required ValueTwo.
Typically I would have custom validation code that checks which button was clicked and do something along the lines:
private void ValidateViewModel(MyModel viewModel)
{
foreach (var key in ModelState.Keys)
ModelState[key].Errors.Clear();
if (Request[{ButtonOneName}] != null && string.IsNullOrEmpty(viewModel.ValueOne))
ModelState.AddModelError("ValueOne", "Required");
else if (Request[{ButtonTwoName}] != null && string.IsNullOrEmpty(viewModel.ValueTwo))
ModelState.AddModelError("ValueTwo", "Required");
}
Not very pretty, I know but ... My beef is with magic string "ValueOne" and "ValueTwo". Also with the way errors are cleared out. Is there a way to generate those keys? I'm looking for something like:
ModelState.KeyFor<MyModel>(m => m.ValueOne)
And then a logical extension:
ModelState.Get<MyModel>(m => m.ValueOne)
Before I start reinventing the wheel - is there something like this hidden somewhere already?
Before you ask, I normally define static class SubmitActions, containing constant strings that represent submit button names. And no, I can't split it up into multiple forms because of the was the view is rendered.
Thanks for any suggestions.
There is a Model Validation Improvements in MVC 3, which will make you be able to check validate based on property related to each other
So by using the IValidatableObject interface built-into .NET 4 to implement a custom validation method on a class. This method can apply validation rules across multiple properties and yield back multiple validation errors,
Have you look at it?
Model Validation Improvements part

How can I collect model validation error messages?

I am building an ASP.NET MVC application, and I am trying to find a way where I can collect data from the user in a custom view model, try and set these values to one or more of my entities, then based on validation logic on those entities, collect error messages if any and get them back to the view. I am new to MVC and web design in general, it is therefore quite possible that I am making major conceptual errors, but I have tried to research as far as I could.
I realize that this is more work than having the view be strongly typed to the entity, where it would then be easy to have the validation errors display, as in this tutorial. However, I don't want to do this for security and because there are some places where I want to have values collected from a single view model to be set in multiple different entities.
I also realize that I could set validation rules on the view model itself, rather then on the entity, but this seems like poor architecture, as I would have to define them redundantly in different view models, and I would then be less sure whether I had prevented bad values from being persisted to the database.
My plan is therefore to have the validation rules be set on the entity itself and to have the view model as a dumb container. Then, in a different location in the application, I would apply the values from the view model to my entity(ies) in accordance my business logic. At this point, I would like my validation logic to be called. If the data is invalid, I plan on setting the error string in the custom attribute on the view model to the error from the validation logic on the entity. I am thinking it would go something like this:
public class CustomViewModel()
{
[SomeCustomValidation()] //Has a place for an error string and a boolean IsValid
String Property { get; set; }
}
public class BusinessLogic()
{
CustomViewModel TestForValidity(CustomViewModel viewModel)
{
MyEntity.Property = viewModel.Property;
// if(MyEntity.IsValid)? catch SomeSortOfException?
// collect error message, put it in the attribute on the view model, set IsValid to false
}
}
public class MyEntity()
{
[MoreCustomValidation()]
public String Property { get; set; }
}
I therefore have three questions:
When I try to pass data that does not satisfy my validation rules, will some sort of error or exception be thrown? Is there some indication I can use or collect when I try to pass in invalid data?
If there is some error or exception thrown, how can I collect the error message so I can assign it to my view model?
Most importantly, am I going about this all wrong? Can attributes not be modified at runtime, for example to include a new error message or to change IsValid to false? I know that I can use reflection to access the attributes. If I can modify them, how would I do so?
Thank you in advance for your help. I apologize if I misunderstand something big.
It seems you might be over-complicating things a bit. I think what you want to do is prevent the model binder from binding to properties that it should not be able to, as well as retaining the ability to check ModelState.IsValid when properties on your model do not meet the requirements of their validation attributes.
IMO the best way to accomplish this is through the use of what I call "strongly-typed binding filters". First define an interface with only the properties that you want the model binder to be allowed to bind on your model.
public interface INewBlogPost
{
string Title { get; set; }
string Body { get; set; }
}
Then ensure your entity inherits from the binding filter interface.
public class BlogPost : INewBlogPost
{
...
}
Next, modify your action method to create a new entity and manually invoke the model binder whilst typing it to the interface you just defined.
public ActionMethod NewBlogPost()
{
BlogPost newBlogPost = new BlogPost();
TryUpdateModel<INewBlogPost>(newBlogPost);
if (ModelState.IsValid)
{
...
}
}
Because you passed in a type when invoking the model binder via TryUpdateModel you explicitly told the model binder what type to bind to. This means that the model binder will only have access to the properties listed in the interface. Now when you pass a model into the method to be bound it will have to be of type INewBlogPost. Because your entity inherits from your binding filter interface, an instance of it will satisfy this requirement. The model binder will happily bind to the properties on the interface completely oblivious of any other properties your model object may have.
See this blog post for more information.
Aside
It is sometimes easy to run into action method ambiguity when you have two action methods with the same name; one for POST and one for GET like this:
[HttpGet]
public ActionResult NewBlogPost()
{
return View();
}
[HttpPost]
public ActionResult NewBlogPost()
{
BlogPost newBlogPost = new BlogPost();
TryUpdateModel<INewBlogPost>(newBlogPost);
if (ModelState.IsValid) { ... }
}
An easy way to fix that is to modify your POST action method to look like this:
[HttpPost]
public ActionResult NewBlogPost(FormCollection formCollection)
{
BlogPost newBlogPost = new BlogPost();
TryUpdateModel<INewBlogPost>(newBlogPost, formCollection);
if (ModelState.IsValid) { ... }
}
The MVC model binder knows how to bind the request form collection to an argument of type FormCollection so it will populate this just fine. Because your POST action now accepts an argument, it is no longer ambiguous with your GET method. You can pass this formCollection into TryUpdateModel to be used as the binding source if you wish, but you don't have to as it will default to the request form collection anyway. But since you are passing it in you may as well use it :)

Categories