I have a Person Model
public class Person
{
public int ID { get; set; }
[Required]
[Remote("UserNameExists", "People", "Username is already taken.")]
public string Name { get; set; }
[Required]
public string LastName { get; set; }
}
This is my UserNameExists method
public JsonResult UserNameExists(string name)
{
bool exists = personRepository.GetPersonByName(name.Trim());
if (!exists)
return Json(true, JsonRequestBehavior.AllowGet);
return Json(string.Format("{0} is not avavfddvilable.", name),
JsonRequestBehavior.AllowGet);
}
When I have Javascript enabled it works just fine but when I disable javascript this rule is not enforced...
Why is this?
Please Help.
Edit for expected behavior:
According to msdn it should respect this rule even without Javacript
Optionally, disable client script in your browser, run the page again,
and enter data that violates the
validation constraints.
As you leave the field that contains
the invalid data, you do not see a
validation error because scripting is
disabled. Because ASP.NET MVC is using
unobtrusive JavaScript, you do not see
client-side script errors. However,
server-side validation is performed
when you submit the form. (It is a
good practice to test your Web
application with a browser that has
scripting disabled.)
See my MSDN article How to: Implement Remote Validation in ASP.NET MVC I use the remote client validation code in the HttpPost Create method to test server side when JavaScript is disabled.
[HttpPost]
public ActionResult Create(CreateUserModel model) {
// Verify user name for clients who have JavaScript disabled
if (_repository.UserExists(model.UserName)) {
ModelState.AddModelError("UserName", ValidationController.GetAltName(model.UserName, _repository));
return View("Create", model);
}
You must duplicate a validation call on the server - this DOES NOT work as outlined as per my testing.
See my post at:
DRY Remote Validation in ASP.NET MVC 3
It sounds like you have JavaScript disabled, and your Remote Validation fails.
Remote Validation requires JavaScript enabled in the browser. It's using jQuery and an AJAX call to get this done.
The quote from MSDN is exactly what you're observing:
you do not see a validation error
server-side validation is performed when you submit the form
Related
.Net Core 3.0 MVC view. Needs to apply - Client Side validation for below model.
Tried as follow:
Model:Person
public class Person {
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public int Age { get; set; }
}
Validation Rules:
public class PersonValidator : AbstractValidator<Person> {
public PersonValidator() {
RuleFor(x => x.Id).NotNull().NotEmpty();
RuleFor(x => x.Name).Length(0, 10);
RuleFor(x => x.Email).EmailAddress();
RuleFor(x => x.Age).InclusiveBetween(18, 60);
}
}
Followed documentation, it shows, "validator" attribute but I could not find in namespace.
https://docs.fluentvalidation.net/en/latest/mvc5.html
Solution 1: Use AddFluentValidationClientsideAdapters
You may use the FluentValidation.AspNetCore and register the client-side validation by adding:
services.AddFluentValidationClientsideAdapters();
Solution 2: Use FormHelper
You may also use the FormHelper and, instead of using client-side validation you could instead execute your full server-side rules via AJAX.
Details
The FluentValidation GitHub readme says:
Clientside Validation
FluentValidation is a server-library and does not provide any
client-side validation directly. However, it can provide metadata
which can be applied to the generated HTML elements for use with a
client-side framework such as jQuery Validate in the same way that
ASP.NET's default validation attributes work.
Note that not all rules defined in FluentValidation will work with
ASP.NET's client-side validation. For example, any rules defined using
a condition (with When/Unless), custom validators, or calls to Must
will not run on the client side. Nor will any rules in a RuleSet
(although this can be changed - see below). The following validators
are supported on the client:
NotNull/NotEmpty
Matches (regex)
InclusiveBetween (range)
CreditCard
Email
EqualTo (cross-property equality comparison)
MaxLength
MinLength
Length
To enable clientside integration you need to install the
FluentValidation.AspNetCore package and call the
AddFluentValidationClientsideAdapters in your application startup:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddFluentValidationClientsideAdapters();
services.AddScoped<IValidator<Person>, PersonValidator>();
// etc
}
Note that the AddFluentValidationClientsideAdapters method is only available in FluentValidation 11.1 and newer. In older versions,
you should use the AddFluentValidation method which enables both
auto-validation and clientside adapters. If you only want clientside
adapters and don't want auto validation in 11.0 and older, you can
configure this by calling services.AddFluentValidation(config => config.AutomaticValidationEnabled = false)
Alternatively, instead of using client-side validation you could
instead execute your full server-side rules via AJAX using a library
such as FormHelper. This allows you to use the full power of
FluentValidation, while still having a responsive user experience.
Specifying a RuleSet for client-side messages
If you're using rulesets alongside ASP.NET MVC, then you'll notice
that by default FluentValidation will only generate client-side error
messages for rules not part of any ruleset. You can instead specify
that FluentValidation should generate clientside rules from a
particular ruleset by attributing your controller action with a
RuleSetForClientSideMessagesAttribute:
[RuleSetForClientSideMessages("MyRuleset")]
public ActionResult Index(){ return View(new Person()); }
You can also use the SetRulesetForClientsideMessages extension method
within your controller action, which has the same affect:
public ActionResult Index()
{
ControllerContext.SetRulesetForClientsideMessages("MyRuleset");
return View(new Person());
}
You can force all rules to be used to generate client-side error
message by specifying a ruleset of "*".
Read more
Read more at:
GitHub
Documentation
Was able to figure it out.
this needs to be added under, Startup file, .AddMvc().AddFluentValidation()
So, it automatically able to pick the validation at client side as well as server side.
Thanks.
You need to add .AddFluentValidation() after .AddMvc() (or .AddControllersWithViews()) to enable Fluent Validation.
Fluent Validation supports some basic client-side validations like required, maxlength etc. If you want to use all server-side validations on client-side, you need to use third party libraries like FormHelper.
Form Helper helps you to create ajax forms and validations without writing any javascript code. It transforms server-side validations to client-side. It's very to use just add .AddFormHelper() and .UseFormHelper() on Startup.cs.
FormHelper: https://nuget.org/packages/FormHelper
Document: https://github.com/sinanbozkus/formhelper
I have a simple ASP.NET Core MVC application, my view model has a property with [Remote] validation attribute which works fine, almost...
[Remote("CustomName", "Index",
ErrorMessage = "Invalid name.",
AdditionalFields = "__RequestVerificationToken,UserId",
HttpMethod = "post"
)]
public string CustomName { get; set; }
Here is my remote validation action:
[HttpPost]
public IActionResult CustomName(Guid UserId, string CustomName)
{
// Some logic which is fine and works...
//.....
//...
//..
//.
return new JsonResult(true);
}
I have standard way of form implementation with POST action which is working fine. Post request fires the correct controller action...etc.
My problem is, when I have this Remote attribute, my form's POST action does not work in first time. When I clicked the button, first Remote Validation action works but not the original post action. After a second click to button, my form's post action works fine.
I could not understand the reason and fine a way to solve this issue. What might the reason be? And solution?
*My application is ASP.NET Core 3.1
In my ASP.NET MVC 2 application, I have this encoded image url -
<img src="/Image?Selected_Nme=Mayag%26%23252%3Bez%2C%20PR/>
The uncoded Selected_Nme is "Mayagüez, PR".
I will get an exception error like this -
[HttpRequestValidationException (0x80004005): A potentially dangerous Request.QueryString value was detected from the client (amp;Selected_Nme="Mayagüez, PR").]
Then I decorated my action in controller with "[ValidateInput(false)]", like this -
[ValidateInput(false)]
[HttpGet]
[OutputCache(CacheProfile = "test")]
public ActionResult Image(string Selected_Nme = ""){
...
}
I still see the same error after this.
What can I do to eliminate the problem?
Thanks,
You need to configure the requestValidationMode:
<system.Web>
...
<httpRuntime requestValidationMode="2.0"/>
From Request Validation in ASP.NET:
You can disable request validation for an entire application, but
doing so is not recommended. The recommendation is to selectively
disable request validation only for the virtual paths or specific
pages where you want to allow markup.
In either case, you must make two changes in the Web.config file. The
first change is to set the requestValidationMode attribute of the
httpRuntime element to "2.0". This setting makes request validation
occur later in the sequence of request processing events. The setting
is required for applications that use ASP.NET 4 and later, because as
of ASP.NET 4, request validation takes place earlier in the request
life cycle than it did in previous versions of ASP.NET
One last worthwhile note. Using [ValidateInput(false)] disables validation for all data sent into the method. If you would still like to keep validation in place for any other properties being sent, you can disable the validation on a specific property of a class:
public class SomeModel {
[AllowHtml]
public string Selected_Nme { get; set; }
// this property will still be validated!
public string PleaseDontXSSMe { get; set; }
}
How does one configure a Remote validator via data annotations to make its call at /api/{controller} instead of /{controller}/{action}?
My model:
public class MyModel
{
[Required]
public string Name { get; set; }
[EmailAddress(ErrorMessage="We need a valid email."), Remote(....)]
public string Email { get; set; }
}
No matter what I try, the URL called by that remote validator is /foo/bar instead of just doing a get to /api/foo.
Is there any support for WebAPI in remote validators?
I'd like my email uniqueness check to use the .NET validators if at all possible (rather than having to do it manually), my form is submitted via AJAX, I'd like to validate the email prior to form submission, and using a remote validator pointing at an API controller seems like a natural choice.
Cannot use a Web API controller. This is a limitation of the RemoteAttribute. To avoid conflicts with MVC controllers, to match a Web API route you must include an httproute key, which RemoteAttribute doesn't do.
You should be able to inherit RemoteAttribute and override GetUrl to make it work.
I have 2 actions, one for GET and the other handles POST requests.
Although I have validation on the client side, there are some things I check for on the server-side also (in my action method).
In the POST action, when I find errors etc. that I want to report back to the UI, what options do I have to send back messages/errors to the client side?
Note:
I am using the popular jQuery validation plugin als.
I you are using Model binding from your View to your Post Action, it has built in validation that can be used for this.
Some people however prefer to do validation outside of the Model. To return these errors back to the View, you need to update the ModelState, then do the normal check if it is valid (contains errors):
public Dictionary<string, string> ValidateEntry(Object obj)
{
var errors = new Dictionary<string, string>();
if (string.IsNullOrEmpty(obj.Owner))
{
errors.Add("Owner", "You must select Owned By.");
}
//... whatever else
return errors;
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(Object cap)
{
var errors = ValidateEntry(cap);
if (errors.Count > 0)
{
foreach (var err in errors)
{
ModelState.AddModelError(err.Key, err.Value);
}
}
if (ModelState.IsValid)
{
//... do if valid
}
return View(ViewModel);
}
Some rules I go by when implementing validation in web applications/sites:
The validation should occur client side and server side
Server side validation should mirror the client side validation for users with scripting turned off
Even though the validation rules are enforced in two places the logic should not be duplicated
Going by those rules I use the following solution:
xVal (found from ScottGu's blog)
IDataError solution from Adam
Schroder
Business rules are implemented in the model with DataAnnotations
The service may throw custom exceptions for unique business constraints
Its amazing how easy this is to use and how well it works. It uses the JQuery validation plugin transparently and just does what it is supposed to with minimal coding.
Client side validation in your view consists of:
<%= Html.ClientSideValidation<Foo>() %>
Server side validation in your action consists of
ModelState.IsValid