I'm really lost trying to create custom generic validation messages for my MVC3 application.
I read many tutorials and the biggest part of them suggest one of these options:
Create an App_GlobalResources folder and inside that put my custom resource, them I change global.asax, passing the string name of my resource to DefaultModelBinder.ResourceClassKey property. Change the resource's build action to "Embeded Resource".
Right click the project, then go properties, click "Resources" tab and create your custom resource. Set it's access modifier to "Public".
The first one didn't work to me, I have the following keys in my resource:
DefaultModelBinder_ValueRequired, InvalidPropertyValue, PropertyValueInvalid, PropertyValueRequired
and none of them was used when my I tried to submit and form with empty value in a required attribute of my model.
I've put this code at global.asax Application_Start method:
DefaultModelBinder.ResourceClassKey = "My_Resource_Name";
With the second method, I've created an resource with the same keys as the first one. None of them was used by default when a property is invalid or empty (I've changed the ResourceClassKey in global.asax too, but without success). But when I added some parameters to data annotation in my model:
[Required(ErrorMessageResourceType = typeof(MyResourceFile), ErrorMessageResourceName = "MyCustomKey")]
When the attribute of that data annotation is empty, my message defined with "MyCustomKey" is used!
But I really don't want to manually set this to all my attributes, I want to replace the default error messages like: "The {0} field is required."
That message is part of DataAnnotations. The default message is compiled into the DataAnnotations assembly in the resource file under System.ComponentModel.DataAnnotations.Resources.DataAnnotationsResources.resources and is RequiredAttribute_ValidationError=The {0} field is required. You can try to download the source, change that part and rebuild it.
There doesn't seem to be a simple global way of changing it. You could try this, otherwise it looks like you are stuck with adding your attribute to every field. Or use something like this:
public class SomeModel
{
[Required(ErrorMessage = "The article is required")]
public string Article { get; set; }
[StringLength(512, ErrorMessage = "Must be less than 512 characters.")]
public string URL { get; set; }
}
Related
I'm doing asp.net MVC3 project , In my class model (CarModel) , I putted an Integer attribute to validate property ModelYear, I tried to customize my error message based on localization , my code:
[Integer(ErrorMessageResourceName = "OnlyNumberValidator", ErrorMessageResourceType = typeof(AddNewCar))]
public Nullable<int> ModelYear { get; set; }
but it didn't take my error message and just shown the default message "The field ModelYear must be a number"
Note: it works on Required attribute !
Please check your references and make sure you're using the DataAnnotationsExtensions.Mvc in addition to DataAnnotationsExtensions in the Nuget packages. Without the Mvc specific library it will result in the same output as you're currently experiencing.
I have a view model sent to the edit action of my controller. The ViewModel contains references to EntityObjects. (yea i'm fine with it and don't need to want to duplicate all the entities properties in the viewmodel).
I instantiate the view model and then call UpdateModel. I get an error that a property is "null" which is fine since it is a related model. I am trying to exclude the property from being bound during model binding. On debugging it I see in the entity where the model binder is trying to set the value of the property to null.
Here is my edit action:
var model = new SimplifiedCompanyViewModel(id);
var excludeProperties = new string[] {
"Entity.RetainedEarningsAccount.AccountNo"
,"Property.DiscountEarnedAccount.ExpenseCodeValue"
,"Entity.EntityAlternate.EntityID"
,"Property.BankAccount.BankAccountID"
,"Entity.PLSummaryAccount.AccountNo"
,"Property.RefundBank.BankAccountID"
,"Company.Transmitter.TCC"
};
try
{
UpdateModel<SimplifiedCompanyViewModel>(model, String.Empty, null, excludeProperties);
if (ModelState.IsValid)
{
//db.SaveChanges();
}
return RedirectToAction("Index");
}
catch
{
return View(model);
}
I have looked at a few other issues about specifying a "prefix" but I don't think that is the issue since I am telling it to bind to the viewmodel instance not just the entity object.
Am I excluding the properties correctly? Strange thing is is only seems to happen on this item. I suspect it may be an issue with the fact that there is actually no refund bank related to my entity. But I have other related items that don't exist and don't see the same issue.
More info... since I'm told me model isn't designed well.
The Company is related to a BankAccount. The Company view shows the currently related BankAccount.BankAccountId and there is a hidden field with the BankAccount.Key. I use jQueryUI autocomplete feature to provide a dropdown of bank account displaying the BankAccount.BankAccountId and when one is selected the jQuery code changes the hidden field to have the correct Key value. So, when this is posted I don't want the current bankaccounts BankAccountID modified, hence I want it to skip binding that field.
If I exclude BankAccountId in the model then on the BankAccount edit view the user would never be able to change the BankAccountId since it won't be bound. I'm not sure how this indicates a poor model design.
Use the Exclude property of the Bind attribute:
[Bind(Exclude="Id,SomeOtherProperty")]
public class SimplifiedCompanyViewModel
{
public int Id { get; set; }
// ...
}
This is part of the System.Web.Mvc namespace. It takes a comma-separated list of property names to exclude when binding.
Also you should consider using TryUpdateModel instead of UpdateModel. You can also just have the default model binder figure it out by passing it as an argument to the constructor:
public ActionResult Create([Bind(Exclude="Id")]SimplifiedCompanyViewModel model)
{
// ...
}
A very simple solution that I figured out.
try
{
UpdateModel<SimplifiedCompanyViewModel>(model, String.Empty, null, excludeProperties);
ModelState.Remove("Entity.RetainedEarningsAccount.AccountNo");
ModelState.Remove("Property.DiscountEarnedAccount.ExpenseCodeValue");
ModelState.Remove("Entity.EntityAlternate.EntityID");
ModelState.Remove("Property.BankAccount.BankAccountID");
ModelState.Remove("Entity.PLSummaryAccount.AccountNo");
ModelState.Remove("Property.RefundBank.BankAccountID");
ModelState.Remove("ompany.Transmitter.TCC");
if (ModelState.IsValid)
{
//db.SaveChanges();
}
return RedirectToAction("Index");
}
catch
{
return View(model);
}
Another option here is simply don't include this attribute in your view and it won't be bound. Yes - you are still open to model injection then if someone creates it on the page but it is another alternative. The default templates in MVC will create your EditorFor, etc as separate items so you can just remove them. This prevents you from using a single line view editor with EditorForModel, but the templates don't generate it that way for you anyways.
EDIT (adding above comment)
DRY generally applies to logic, not to view models. One view = one view model. Use automapper to easily map between them. Jimmy Bogard has a great attribute for this that makes it almost automatic - ie you create the view model, load up your Customer entity for example, and return it in the action method. The AutpMap attribute will then convert it to a ViewModel. See lostechies.com/jimmybogard/2009/06/30/how-we-do-mvc-view-models
Try the Exclude attribute.
I admit that I haven't ever used it.
[Exclude]
public Entity Name {get; set;}
So, I am using ASP.NET MVC 3 and Entity Framework 4.1 (code-first).
I have a class like this:
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
[Range(18, 99)]
public int Age { get; set; }
}
The range validation is fired correctly. But, for example, in some situations I would like to change the range for the Age attribute. Or even turn it off. How could I do it without changing my Model class? Is this possible to made programatically?
You can use the IValidatableObject interface and define custom validation rules.
See my answer at:
Using Data Annotations to make a field required while searching for another in a form mvc 3
Its usually just a matter of implementing the interface and determine when to enforce your rules.
I just realised the solution for this case.
Eg. A user can have an authorization to create a 14 years old person.
Before save the Model, we can invoke DataContext.GetValidationErrors() and infer if the only error validation is that we want to disable, and then set
DataContext.Configuration.ValidateOnSaveEnabled = false;
So, this way we are able to save the model.
Yes, it is possible to inject validators programmatically. Altering existing validators presents separate issues, as some attributes are read-only, so you may have to delete and replace your existing validator.
You can add a class to work on the validators by following my answer to this question.
I have an EF4 model with table's columns doesn't allow null.
At the SL client application I always receieve the "columnName is required" because I have the binding in xaml with [NotifyOnValidationError=True,ValidatesOnExceptions=True] for the textboxes.
My questions is:
I can overide the default required errormessage at the metadata class, but how can I have it as a custom validation? I mean I don't wnat to do this at the sealed metadata class:
[Required(ErrorMessage = "Coin English Name Is required")]
[CustomValidation(typeof (CustomCoinVaidation), "ValidateCoinName")]
public string coin_name_1 { get; set; }
I want to have it inside the custom validation method that I will define for all types of errors regards that coin_name_1, as follows:
public static ValidationResult ValidateCoinName(string name, ValidationContext validationContext)
{
if (string.IsNullOrWhiteSpace(name))
{
return new ValidationResult("The Coin Name should be specified", new [] { "Coin Name" });
}
return ValidationResult.Success;
}
Why?
for two reasons :
1- Group all the validation isdie one container (for easy localization further).
2- I don't want the coin_name_1 to be displayed to the end-user, but a meanigful as "Coin English Name".
Second question:
I have a ValidationSummary control on my xaml page where all the errors are displayed but is displaying the orignal name of the column "coin_name_1" how can I chnge that to be a meanigfil also.
Best regards
Waleed
A1:
I just left the required as it is implemented right now..
A2:
I went through different sources and find this artical.
It shows how to style the validation summary:
http://www.ditran.net/common-things-you-want-know-about-silverlight-validationsummary
I am also implementing a client-side validation asyncronizly.
Regards
I'm using System.ComponeneModel.DataAnnotations attributes such as Required and StringLength. Is it possible to localize its error messages globally?
I know I can do this
[Required(ErrorMessageResourceName = "Required", ErrorMessageResourceType = typeof(Resources.Validation))]
But doing this everywhere I use required attribute would be just insane. Also I'd like to avoid stuff like:
public class LocalizedRequiredAttribute : RequiredAttribute {
public LocalizedRequiredAttribute()
: base() {
ErrorMessageResourceName = "Required";
ErrorMessageResourceType = typeof(Resources.Validation);
}
}
(but if there isn't any other way, I'll settle for this)
AFAIK you need either a custom attribute or specify the ErrorMessageResourceName and ErrorMessageResourceType properties. There is another possibility detailed here:
Create a global resource class in
App_GlobalResources, and set
DefaultModelBinder.ResourceClassKey to
the name of this class (for example,
if you made "Messages.resx", then set
ResourceClassKey to "Messages").
There are two strings you can override
in MVC 2:
The string value for
"PropertyValueInvalid" is used when
the data the user entered isn't
compatible with the data type (for
example, typing in "abc" for an
integer field). The default message
for this is: "The value '{0}' is not
valid for {1}."
The string value for
"PropertyValueRequired" is used when
the user did not enter any data for a
field which is not nullable (for
example, an integer field). The
default message for this is: "A value
is required."
It's important to note
in the second case that, if you have
the
DataAnnotationsModelValidatorProvider
in your validator providers list
(which it is by default), then you
will never see this second message.
This provider sees non-optional fields
and adds an implied [Required]
attribute to them so that their
messages will be consistent with other
fields with explicit [Required]
attributes and to ensure that you get
client-side validation for required
fields.
For MVC3 see DataAnnotationsResources. It's "RequiredAttribute_ValidationError" and more.
You may solve it by installing .NET Framework language pack(s).
See also