In my ASP.NET MVC 4 application I am trying to use unobtrusive client validation with Fluent Validation.
<script src="/Scripts/jquery.validate.min.js" type="text/javascript">
</script>
<script src="/Scripts/jquery.validate.unobtrusive.min.js" type="text/javascript">
</script>
I have these two .js files that VS2010 provides when new ASP.NET MVC 4 application is created. I have also enabled client side validation on my web.config file.
<appSettings>
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
</appSettings>
As far as I know when client validation and unobtrusive JavaScript is enabled, input fields with a client-validation rule contain the data-val="true" attribute to trigger unobtrusive client validation. And I have these field on my input fields.
For instance,
<input class="input-validation-error" data-val="true" data-val-
required="error text here" id="purchasePrice"
name="PurchasePrice" type="text" value="">
<span class="field-validation-error error" data-valmsg-for="PurchasePrice"
data-valmsg-replace="true">'Purchase Price' must not be empty.</span>
However, when I submit my form, it is posted to controller and my model is checked on my controller code instead of client side.
EDIT :
This is my form opening tag.
#using (Html.BeginForm("Create", "Product", FormMethod.Post,
new { enctype = "multipart/form-data", #class = "mainForm",
#id = "productCreateForm" }))
Any ideas? Thanks.
Did you add the configuration for MVC?
protected void Application_Start() {
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
// this line is required for fluent validation
FluentValidationModelValidatorProvider.Configure();
}
You also need to configure each view model / validator:
[Validator(typeof(PersonValidator))]
public class Person {
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public int Age { get; set; }
}
public class PersonValidator : AbstractValidator<Person> {
public PersonValidator() {
RuleFor(x => x.Id).NotNull();
RuleFor(x => x.Name).Length(0, 10);
RuleFor(x => x.Email).EmailAddress();
RuleFor(x => x.Age).InclusiveBetween(18, 60);
}
}
If this does not help, could you post an example of a validator that is not working correctly? Not all validation can be done client side. For example, the following validator will only work server side:
// when validator rules are always server side
public class ServerSideValidator : AbstractValidator<Person> {
public ServerSideValidator() {
When(x => x.Name == "Foo", () => {
RuleFor(x => x.Email).EmailAddress();
});
}
}
Related
I'm building a dynamic form creator in .net core. A "form" will consist of many different form elements. So the form model will look something like this:
public class FormModel {
public string FormName {get;set;}
public List<IElements> Elements{get;set;}
}
I have classes for TextBoxElement, TextAreaElement, CheckBoxElement that all implement the IElemets interface. And I have EditorTemplates for each element. The code to render the form works great. Though posting the form does not work because of the List of Interfaces.
I've been looking on how to implement a custom model binder, and seen some few examples on the web but I did not get anyone to work.
I would appreciate if someone could show me how to implement a custom model binder for this example.
Plan B:
Post form as json to a web api and let JSON.Net covert it. I have tried it and it worked. In startup.cs i added:
services.AddMvc().AddJsonOptions(opts => opts.SerializerSettings.TypeNameHandling = TypeNameHandling.Auto);
It returns type when it has to, eg. the objects in the Elements-list but not on the FormModel. But i really would like to know how to solve it with a custom model binder instead.
Ok, this works for me. I'm still getting to grips with the new model binding so I may be doing something silly but it's a start!
TEST FORM
<form method="post">
<input type="hidden" name="Elements[0].Value" value="Hello" />
<input type="hidden" name="Elements[0].Type" value="InterfacePost.Model.Textbox" />
<input type="hidden" name="Elements[1].Value" value="World" />
<input type="hidden" name="Elements[1].Type" value="InterfacePost.Model.Textbox" />
<input type="hidden" name="Elements[2].Value" value="True" />
<input type="hidden" name="Elements[2].Type" value="InterfacePost.Model.Checkbox" />
<input type="submit" value="Submit" />
</form>
INTERFACE
public interface IElement
{
string Value { get; set; }
}
TEXTBOX IMPLEMENTATION
public class Textbox : IElement
{
public string Value { get; set; }
}
CHECKBOX IMPLEMENTATION
public class Checkbox : IElement
{
public string Value { get; set; }
}
MODEL BINDER PROVIDER
public class ModelBinderProvider : IModelBinderProvider
{
public IModelBinder GetBinder(ModelBinderProviderContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (context.Metadata.ModelType == typeof(IElement))
{
return new ElementBinder();
}
// else...
return null;
}
}
MODEL BINDER
public class ElementBinder : IModelBinder
{
public async Task BindModelAsync(ModelBindingContext bindingContext)
{
if (bindingContext.ModelType == typeof(IElement))
{
var type = bindingContext.ValueProvider.GetValue($"{bindingContext.ModelName}.Type").FirstValue;
if (!String.IsNullOrWhiteSpace(type))
{
var element = Activator.CreateInstance(Type.GetType(type)) as IElement;
element.Value = bindingContext.ValueProvider.GetValue($"{bindingContext.ModelName}.Value").FirstValue;
bindingContext.Result = ModelBindingResult.Success(element);
}
}
}
}
HOOK UP MODEL BINDER PROVIDER
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(options =>
{
options.ModelBinderProviders.Insert(0, new ModelBinderProvider());
});
}
}
FORM MODEL
public class FormModel
{
public string FormName { get; set; } // Not using this
public List<IElement> Elements { get; set; }
}
ACTION
Notice the three types, Textbox, Textbox and Checkbox.
This is for the first time I'm working on validations in Asp.Net MVC-4.
The problem here is that the validation messages don't show for the
required fields even when I post an empty form.
This is the form I'm using:
#using (Ajax.BeginForm("Save","DSA",
new AjaxOptions { OnSuccess = "OnSuccess", OnFailure = "OnFailure" }))
{
#Html.TextBoxFor(m => m.Insert_DSA.DSAId)
#Html.ValidationMessageFor(m => m.Insert_DSA.DSAId)
#Html.TextBoxFor(m => m.Insert_DSA.Firstname)
#Html.ValidationMessageFor(m => m.Insert_DSA.Firstname)
<input type="submit" value="Save" />
}
And in the Model Class:
[Required(ErrorMessage = "DSA ID is required")]
public string DSAId { get; set; }
[Required(ErrorMessage = "First Name is required")]
public string Firstname { get; set; }
And this is the controller:
public ActionResult Save(Models.clsDSAMaster MyModel,string submit)
{
string data = "";
if (ModelState.IsValid)
{
MyModel.Insert_DSA.addDSA(MyModel.Insert_DSA, Session["EmpCode"].ToString());
data="success";
}
else
{
data="Faliure";
}
return Content(data, "text/html");
}
Can anyone please help me get it to work and enlighten me a little on how validations work in MVC.
P.S : The model binding and the data retrieval from the model on the form submit is working perfectly.
You have to enable unobtrusive JavaScript. You can do it in the configuration file:
<configuration>
<appSettings>
<add key="ClientValidationEnabled" value="true"/>
<add key="UnobtrusiveJavaScriptEnabled" value="true"/>
</appSettings>
</configuration>
or you can also turn it on form the code:
HtmlHelper.ClientValidationEnabled = true;
HtmlHelper.UnobtrusiveJavaScriptEnabled = true;
Driving me crazy.... validation not firing.
When I leave the field blank and hit submit it behaves as if the model were valid.
I have used dbFirst entity framework to create the model and added the required data annotation after the fact.
My Model (Entity)
public partial class Certificate
{
public Certificate()
{
this.Travelers = new HashSet<Traveler>();
}
public int ID { get; set; }
public System.DateTime InsertDate { get; set; }
[Required(ErrorMessage = "Please enter your card number.")]
public string CertificateNumber { get; set; }
public Nullable<int> BuyerID { get; set; }
public string Used { get; set; }
public string Active { get; set; }
public virtual ICollection<Traveler> Travelers { get; set; }
}
My Controller:
[HttpPost]
public ActionResult Index(Certificate CertificateNumber)
{
if (ModelState.IsValid)
{
return RedirectToAction("Create", "Travelers");
}
return View();
}
My View:
#model GrandCelebration.Models.Certificate
#{
ViewBag.Title = "Validation";
}
<div>
<h2>Please enter your card number below to validate</h2>
<div id="searchbar">
#using (Html.BeginForm())
{#Html.ValidationSummary(true)
<fieldset>
#Html.TextBoxFor(model => model.CertificateNumber)
<input type="submit" class="btn" alt="Validate" style="display:inline" value="Validate" />
#Html.ValidationMessageFor(model => model.CertificateNumber)
</fieldset>
}
</div>
</div>
The problem was that the required js files weren't included.
Firstly make sure that unobtrusive validation is enabled in Web.config:
<appSettings>
<add key="ClientValidationEnabled" value="true"/>
<add key="UnobtrusiveJavaScriptEnabled" value="true"/>
</appSettings>
Then include 3 js files in the _Layout page:
<script src="http://ajax.microsoft.com/ajax/jQuery/jquery-1.4.2.min.js"></script>
<script src="http://ajax.microsoft.com/ajax/jquery.validate/1.7/jquery.validate.min.js"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
When cient-side validation is successfully enabled, if you look at the textbox HTML you will see a data-val property has been added.
I have a drop down list in MVC
Model:
[Required]
[Display(Name = "State of Residency:")]
public string StateCode { get; set; }
My View:
#Html.DropDownList("StateCode", "Select")
#Html.ValidationMessageFor(model => model.StateCode)
The drop down list works fine but how to make the validator validate the select. So it say please select a value in Select is there.
Example for ASP.NET MVC 5 web application:
In your case I would make like so:
1) Enable validation in web.config
<appSettings>
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
</appSettings>
2) add proper jQuery files
<script src="~/Scripts/jquery-1.11.1.min.js"></script>
<script src="~/Scripts/jquery.validate.min.js"></script> <!--v1.13.0-->
<script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script> <!-- For ASP.NET MVC 5.0 -->
3) StateCode.cs
public class StateCode
{
public int Id { get; set; }
public int Code { get; set; }
}
4) MyModel.cs
public class MyModel
{
[Required(ErrorMessage = "Please select")]
public int IdSelected { get; set; }
[Display(Name = "State of Residency:")]
public IEnumerable<StateCode> StateCodes { get; set; }
}
5) Action
[HttpGet]
public virtual ActionResult Index()
{
var model = new MyModel
{
StateCodes = new List<StateCode>
{
new StateCode{Id=1, Code=22333},
new StateCode{Id=2, Code=44433},
new StateCode{Id=3, Code=55533},
}
};
return View(model);
}
6) View
#model MyModel
#using (Html.BeginForm())
{
#Html.DropDownListFor(model => model.IdSelected, new SelectList(Model.StateCodes, "Id", "Code"), "Please Select")
#Html.ValidationMessageFor(model => model.IdSelected)
<input type="submit" value="OK" />
}
btw. here very good list of jQuery files for ASP.NET MVC unobtrusive validation.
I am trying to get Fluent Validation to work correctly on my client side validation. I am using ASP.NET MVC 3.
I have a title that is required and it must be between 1 and 100 characters long. So while I am typing in the title an error message displays that is not in my ruleset. Here is my rule set:
RuleFor(x => x.Title)
.NotEmpty()
.WithMessage("Title is required")
.Length(1, 100)
.WithMessage("Title must be less than or equal to 100 characters");
Here is the error message that is displayed:
Please enter a value less than or equal to 100
I'm not sure what I am doing wrong. Here is my global.asax:
// FluentValidation
DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false;
ModelValidatorProviders.Providers.Clear();
ModelValidatorProviders.Providers.Add(
new FluentValidationModelValidatorProvider(new AttributedValidatorFactory()));
ModelMetadataProviders.Current = new FluentValidationModelMetadataProvider(
new AttributedValidatorFactory());
Works fine for me. Here are the steps:
Create a new ASP.NET MVC 3 RTM project using the default Visual Studio Template
Download the latest FluentValidation.NET
Reference the FluentValidation.dll and FluentValidation.Mvc.dll assemblies (be careful there are two folders inside the .zip: MVC2 and MVC3 so make sure to pick the proper assembly)
Add a model:
[Validator(typeof(MyViewModelValidator))]
public class MyViewModel
{
public string Title { get; set; }
}
and a corresponding validator:
public class MyViewModelValidator : AbstractValidator<MyViewModel>
{
public MyViewModelValidator()
{
RuleFor(x => x.Title)
.NotEmpty()
.WithMessage("Title is required")
.Length(1, 5)
.WithMessage("Title must be less than or equal to 5 characters");
}
}
Add to Application_Start:
DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false;
ModelValidatorProviders.Providers.Clear();
ModelValidatorProviders.Providers.Add(
new FluentValidationModelValidatorProvider(new AttributedValidatorFactory()));
ModelMetadataProviders.Current = new FluentValidationModelMetadataProvider(
new AttributedValidatorFactory());
Add a controller:
public class HomeController : Controller
{
public ActionResult Index()
{
return View(new MyViewModel());
}
[HttpPost]
public ActionResult Index(MyViewModel model)
{
return View(model);
}
}
and the corresponding view:
#model SomeApp.Models.MyViewModel
#{
ViewBag.Title = "Home Page";
}
<script src="#Url.Content("~/Scripts/jquery.validate.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.js")" type="text/javascript"></script>
#using (Html.BeginForm())
{
#Html.TextBoxFor(x => x.Title)
#Html.ValidationMessageFor(x => x.Title)
<input type="submit" value="OK" />
}
Now try to submit the form leaving the Title input empty => client side validation kicks in and the Title is required message is shown. Now start typing some text => the error message disappears. Once you type more than 5 characters in the input box the Title must be less than or equal to 5 characters validation message appears. So everything seems to work as expected.