Disable 'The value 'xxx' is not valid for 'yyy' message - asp.net-mvc

In my ASP.NET MVC application, I have a form and I'm using a ViewModel, so the ModelBinder can bind to my Strongly Typed Class. I'm using DataAnnotations for validation
public class FormViewModel
{
[Required]
public string SomeValue {get;set;}
[Range(0, 10, ErrorMessage="Enter a number between 0 and 10.")]
public byte? SomeOtherValue {get;set;}
}
This works great. The problem however is when the user doesn't enter a valid value for the SomeOtherValue (like abc), a standard MVC-error pops up: 'The value 'abc' is not valid for 'SomeOtherValue'. This is really annoying, as I can't customize this message. I know there are ways to Localize this message, but that just doesn't make sense (I don't want a general message, I want a value-specific value).
I tried applying a RegularExpression-attribute to the 'SomeOtherValue', which only allows byte-values, but probably the standard-validation 'overrides' this validation. Is there some way to apply a custom 'the value is not valid' message for a property, or otherwise disable the standard-message?

Here is a different (non-ideal way, IMHO) to fix it if the custom validation attribute is not working for you. In the controller:
if (!ModelState.IsValid)
{
string fieldName = "ThatFieldName";
var m = ViewData.ModelState[fieldName];
if (m != null && m.Errors.Count > 0)
{
ViewData.ModelState.Remove(fieldName);
ViewData.ModelState.AddModelError(fieldName, "You mucked that field up.");
}
}

Related

How do I specify multiple parameters in Asp.Net MVC 5 Route attributes?

I'm using the Kendo AutoComplete client javascript widget, which sends server requests such as the following:
https://domainName/Proto2/api/Goal/Lookup?text=ABC&goalId=8b625c56-7b04-4281-936f-b88d7ca27d76&filter%5Blogic%5D=and&filter%5Bfilters%5D%5B0%5D%5Bvalue%5D=&filter%5Bfilters%5D%5B0%5D%5Boperator%5D=contains&filter%5Bfilters%5D%5B0%5D%5Bfield%5D=Description&filter%5Bfilters%5D%5B0%5D%5BignoreCase%5D=true&_=1423833493290
The MVC server side method to receive this is:
[Route("api/Goal/Lookup")]
[HttpGet] // if the action name doesn't start with "Get", then we need to specify this attribute
public ICollection<IAllegroGoalContract> Lookup(Guid goalId, string text = "")
The problem occurs if the client sends an empty value for the text parameter (ex: text=&goalId=8b625c56-7b04-4281-936f-b88d7ca27d76). In this case .net returns the following error.
"System error - unable to process parameters
(goalId,text,text.String) - invalid data detected"
I've tried various Route attribute values:
[Route("api/Goal/Lookup/{goalId:guid},{text?}")]
[Route("api/Goal/Lookup/{text?}")]
Looks like your parameters are used as a filter, so instead of the GoalId and Text parameters to be part of the route, define a class like this:
public class LookupOptions
{
public Guid GoalId { get; set; } // change this to Guid? if the client can send a nullable goalId.
public string Text { get; set; }
}
So your method signature will be :
[Route("api/Goal/Lookup")]
[HttpGet]
public ICollection<IAllegroGoalContract> Lookup([FromUri]LookupOptions options)
{
// Note that [FromUri] will allow the mapping of the querystring into LookupOptions class.
}
Now, you can pass your options from the client as part of the Query string and it will be assigned to the LookupOptions parameter.
Hope this helps.

Nancy and request validation

I have sample app in Nancy and have problem with request validation.
I am using FluentValidator with BindAndValidate extension. So for example i have model :
public class User
{
public string Name { get; set; }
public int Age { get; set; }
}
And module with :
Post["/create-user"] = m => this.BindAndValidate<User>());
And there is problem, if client app call module with parameters Name:"foo,Age:"some-string",
then Nancy throw exception :
System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.Exception: some-string is not a valid value for Int32. ---> System.FormatException: Input string was not in a correct format.
Is here any workaround for exception by parameter ("property Age was not in correct format") ?
Thanks
The problem is that the bind fails so the validator never runs. You can tell nancy to ignore binding errors, but it doesn't do so gracefully (it basically stops binding on the first error). So then your validation step does run, but may complain about properties that were ok, but simply were not set by the binder.
You can get around this by providing your own BodyDeserializer that uses Newtonsoft's handling of errors so that the binding doesn't stop on the first error found. See Handle multiple binding errors from ModelBindingException in NancyFX when binding to JSON in Request.Body
Before binding you could try to check if Age is int, and if it is then to validation. Something like this:
int age;
bool isInt = int.TryParse(Request.Form("Age"), out age);
if (isInt)
{
this.BindAndValidate<User>();
}
Hope it helps.

MVC Form Submit ModelState Invalid-

I am wanting to further my MVC learning. I do not understand why my form won't validate; well, actually I can read the message and it is straightforward enough but I can't find where I'm slipping up.
I'm only including what is relevant to the error message.
My model is this:
[Validator(typeof(ExtForumValidator))]
public partial class ExtrnlSubsModel : BaseEntityModel
{
.....snip......
public int ExtForumBoardId { get; set; }
}
My Validator:
public ExtForumValidator(ILocalizationService localizationService)
{
RuleFor(x => x.ExtForumBoardId)
.NotEqual(0).WithMessage(localizationService.GetResource("ExternalForumBoards.Fields.AvailBoard.Required"));
}
Razor:
<td>
#Html.DropDownListFor(model => model.ExtForumBoardId, Model.AvailableForumBoards)
#Html.RequiredHint()
#Html.ValidationMessageFor(model => model.AvailableForumBoards)
</td>
On submit all my other elements check out except this one has the ModelState error. For attempted value it shows as a string array???? 0,11 or 0,12 or 0,4 etc. It always has a zero and a comma prepended. The second number is correct as that is the id of the item selected in the drop down.
For exception it says null and for error message it says...well it says what I have for the validation message.
So it seems to me that it is getting hung up on this string array 0, stuff and I am at a loss as for where it comes from to go looking for the fix.

In MVC, how can I make a field in a model non-required after a checkbox is checked?

I have a page written using .NET MVC. In the model for a Person called PersonModel I have this defined which requires the user to enter some text in the last name field:
<DisplayName("Last Name"), Required()> _
Public Property LastName() As String
Get
Return _LastName
End Get
Set(ByVal value As String)
_LastName = value
End Set
End Property
On the form, there is a checkbox that a user can check to do some other things. Is there a way, using JQuery preferablly, to change that Last Name field to be non-Required? If not using JQuery I am open to other suggestions but since I am doing alot of things when this check box is checked anyways, I was hoping I could add this logic in there. Here is some sample of what I am doing when this box is checked to demonstrate...
function doOwnerBusiness(event) {
if ($(this).is(':checked')) {
$('input[name="People_1__LastName"], label[for="People[1]_LastName"]').hide();​
$("#People_1__LastName").hide();
$("#People_1__LastName").val("");
$("#People_1__LastName :input").attr('disabled', true);
$('input[name="People[1]_Suffix"], label[for="People[1]_Suffix"]').hide();​
$("#People_1__Suffix").attr('disabled', true);
$('#People_1__Suffix')[0].selectedIndex = 0;
$('#People_1__Suffix').hide();
}
else {
$('input[name="People_1__LastName"], label[for="People[1]_LastName"]').show();
$("#People_1__LastName").show();
$('#People_1__LastName :input').attr('disabled', false);
}
}
Any help with this would be appreciated folks.
Thank you
William
Here is how I am declaring my checkbox and also part of the function where I am trying to check if it is checked or not...
<%=Html.CheckBoxFor(Function(model) model.FirstNameAsBusiness)%>
<%=Html.LabelFor(Function(model) model.FirstNameAsBusiness)%>
Function Nominate(ByVal m As NominationModel, ByVal captchaValid As Boolean) As ActionResult
If Not m.FirstNameAsBusiness.checked AndAlso String.IsNullOrEmpty(m.lastnametext) Then
ModelState.AddModelError("LastName", "Last Name field is required if you don't yada yada...")
Return View()
End If
Short answer: no. You can't bypass the DataAnnotation with a jQuery call.
Technically, the Last Name field isn't required. So, I'd remove the DataAnnotation for Required, and then on the backend, when the user submits the form, verify that a field value exists when the checkbox isn't checked. If the conditional doesn't pass, and an error to ModelState for that field, and redirect to the page. (apologies for the c#):
public ActionResult Index(HomeIndexModel form)
{
if (!form.Checked && string.IsNullOrEmpty(form.LastName))
{
ModelState.AddModelError("LastName", "Last Name field is required if you don't yada yada...");
return View();
}
//conditional requirement passed...
}
If you want to get a little fancier, you can check out this thread, though all of the suggestions here are also server-side:
ASP.NET MVC Conditional validation

asp.net mvc validation must be a number custom error

I am new to asp.net and I have a problem. When the users insert in a editor for a decimal field something other than numbers, they get an error "Field name" is not a number. But I don't want them to receive this message I want them to receive another message. I have no problem with this with required and range validators.
Is there any way for me to do this?
I am not refering necessarily to changing the culture just displaying another message.
Thanks.
Hope I understand your, to change RangeValidator ErrorMessage just initialize ErrorMessage parameter:
[Range(0, 100, ErrorMessage = "Some another error message insert here!")]
[RegularExpression("\d", ErrorMessage = "!!!")]
public decimal DecimalField { get; set; }
This is the actual answer:
Create a class CustomClientDataTypeModelValidatorProvider. Copy the code from the MVC sources. Change the method MakeErrorString to output the appropiate message like this:
private static string MakeErrorString(string displayName)
{
return string.Format(
CultureInfo.CurrentCulture,
Core.Resources.Errors.EroareNuENr,
displayName);
}
I couldn't find a way not to copy the code just extend it as it uses this static method.
If anyone knows this please tell me.
Then, in global.asax, I wrote this:
var cdProvider = ModelValidatorProviders.Providers.SingleOrDefault(p => p.GetType().Equals(typeof(ClientDataTypeModelValidatorProvider)));
if(cdProvider != null)
{
ModelValidatorProviders.Providers.Remove(cdProvider);
ModelValidatorProviders.Providers.Add(
new CustomClientDataTypeModelValidatorProvider());
}
so that the flow would actually be routed to my class and not the class in the asp.net MVC dll
I got the idea from here:
Unfortunately this is is not a trivial task. However you can try the following hack...
Better to do this only on essential fields, as this is more code to maintain.
In the controller's action method
if(ModelState.IsValid)
{
// code
}
else
{
if (ModelState["YourField"].Errors.Count > 0)
{
ModelState["YourField"].Errors.Clear();
ModelState.AddModelError("YourField", "Your custom message here");
}
// code
}
You can set ResourceClassKey of ClientDataTypeModelValidatorProvider class to name of a global resource that contains FieldMustBeNumeric key to replace mvc validation error message of number with your custom message. Also key of date validation error message is FieldMustBeDate.
ClientDataTypeModelValidatorProvider.ResourceClassKey="MyResources"; // MyResource is my global resource
See here for more details on how to add the MyResources.resx file to your project:
The field must be a number. How to change this message to another language?
To change the error message you get after server side validation you need to change 'PropertyValueInvalid' key in your resource file and assign the resource file name to DefaultModelBinder.ResourceClassKey. See this question for details: localize default model validation in mvc 2
Look for solution at the end of this page:
http://jwwishart.wordpress.com/2010/03/22/custom-server-and-client-side-required-validator-in-mvc-2-using-jquery-validate/
I checked this in my MVC 3 RTM project and it works well.
... or use jQuery to change to message on the client.
A quick and simple hack for Customize RangeValidator ErrorMessage --"'Field name' is not a number"-- is using RegularExpression
[Range(0.5, 1000, ErrorMessage = "Amount should be in range {1} to {2}.")]
[DataType(DataType.Currency)]
[RegularExpression(#"\d", ErrorMessage = "Amount is not valid.")]
public decimal Amount{ get; set; }
You could implement your own custom validation attribute: http://haacked.com/archive/2009/11/19/aspnetmvc2-custom-validation.aspx
It seems that since Para's answer MVC evolved and now the ClientDataTypeModelValidatorProvider accepts a ResourceClassKey property. It uses the FieldMustBeNumeric and FieldMustBeNumeric messages specified in your resource class.

Resources