I am developing an application where I have a form with a model "StudentListModel".
I have a button in the same page which is not a submit button. I have written an ajax function which calls an action method in the controller specified.
Now my problem is there is a textbox for the studentname ,
[StringLength(160, MinimumLength = 3)]
[Display(Name = "First Name")]
[Required]
[Remote("CheckDuplicateNames", "AddStudent")]
public string StudentName { get; set; }
None of these validations are firing.However if I make the button as submit ,these will work.
Is there any way to do model validation other than using formsubmission?
Model validation is done automatically before your ActionMethod is executed and ModelState will be populated with information about that validation. You do not need to call ValidateModel as long as you are running your Controller and ActionMethods in the default MVC lifecycle.
An action method that has parameters will have the values for parameters populated using MVC Model Binding. This means that any values posted in a Form or QueryString (and a few other sources) will be name matched to simple parameters or properties in complex parameters. Using an HTML form and the MVC HtmlHelper methods for creating input types you get the desired behavior with very little work, but as you have noted it requires a form submit to send the data.
An ajax call will also populate the model using Model Binding but it requires the fields to be sent to the ActionMethod. Using jQuery it is as simple as performing a post or get request on the buttons click event passing a JavaScript object with your model's properties on it.
$('#yourButtonId').click(function() {
var student = {};
student.StudentName = $('#StudentName').val();
$.post('#Url.Action("ActionMethodName")', student).done(function (data) {
//handle returned result from ActionMethod}
});
});
You can call model validation manually in the controller method. The syntax is simply ValidateModel(model). This validates the model based on its current property values, and populates the ModelState dictionary with any errors.
If your model does not get populated with the values, but you have got them at hand, you can populate it using UpdateModel(model, values), another method inherited from the Controller class.
Related
I have a form with few inputs, name, email, message and some checkboxes. I've created a model for these inputs and set all the validations i require.
But now I also want to pass my model (i.e. from #model MyModel) or rather some object property of my model together with those inputs.
Is populating a VewBag/viewData with my model a way to go?
#{
ViewBag.MyModel = Model;
// or ViewBag.ThatProperty = Model.ThatProperty
}
or do i still have a better way up my sleeve?
ViewBag and ViewData persist in one trip from server to client, and not the other way around.
There is no way to pass an object from the view to the controller. If it's a database object, you can pass the object Id using one of the two methods described below, then query the DB on post.
If you have no other way, you can encode the object as a JSON string (using the Newtonsoft package, for example) and pass it also using one of the two methods described below, but this isn't the best option.
To pass a property from the View to the Controller, you have two options:
Url Parameter
Hidden field
Url Parameter
<form ... asp-route-ThatProperty="#Model.ThatProperty">
...
</form>
Form Field
<form>
<input type="hidden" name="ThatProperty" value="#Model.ThatProperty" />
</form>
Controller Action
If 'ThatProperty' doesn't exist on your model, receive it as an extra parameter.
public IActionResult MyAction (MyModel model, string ThatProperty)
{
...
}
I've an ASP.NET MVC application using Fluent Validation. Basically there is a view model Book which has an author as a property on it, like:
class Book {
string Title { get; set; }
Author Author { get; set; }
...
}
class Author {
string Name { get; set; }
...
}
On the view there is a field for the Book.Author.Name.
#Html.EditorFor(m => m.Author.Name)
There is Fluent Validation rule set up for the Book view model something like this
RuleFor(book => book.Author.Name).NotEmpty();
Then I find that this validation won't be fired for the Book.Author.Name field on client side. When inspecting the field's HTML markup, I found that no validation data attributes have been generated. Seems like Fluent Validation cannot handle the multiple level structure properly to generate the client side validation markups. But after it is posted back to the server, the server side validation fires as expected for this field. How can I get the validation fired on the client side?
Eventually to work around this problem, I had to create a custom editor template for the Author class, and a separate Fluent Validator for the Author class with all the rules I needed for the properties on the Author class. This approach worked perfect in this case. The client side validation could be fired as expected this time, and so does the server side as well.
By the way, I've also tried to create a partial view instead of a custom editor template for the Author class. The client side validation was able to be fired, but after post back the partial view couldn't be bound to the Book.Author for the controller's action method.
I have Asp Mvc3 app. In my view I am using kendoui + knockoutjs. I am handling the client side validation with kendo validator. I am very new to asp mvc3 and I cannot make my server side validation work.
This is my business object:
[Validator(typeof(FranchiseInfoValidator))]
public class FranchiseInfo
{
public string FullName { get; set; }
public string ShortName { get; set; }
}
}
I am using FluentValidation. This is the implementation of my validation rules:
public class FranchiseInfoValidator : AbstractValidator<FranchiseInfo>
{
public FranchiseInfoValidator()
{
RuleFor(franchiseInfo => franchiseInfo.FullName).NotEmpty();
RuleFor(franchiseInfo => franchiseInfo.ShortName).NotEmpty();
}
}
This is my view model:
public class FranchiseInfoViewModel
{
public string FullName { get; set; }
public string ShortName { get; set; }
}
This is my view strongly typed to FranchiseInfoViewModel:
#model MvcApplication2.Models.FranchiseInfoViewModel
<script src="../../Scripts/Details.js" type="text/javascript"></script>
<form id="franchiseForm" action="" style="font-family: Trebuchet MS, Verdana, Helvetica, Sans-Serif;">
<table>
<tr>
<td><label for="fullName">FullName:</label></td>
<td><input id="fullName" data-bind= "value: FullName" /></td>
</tr>
<tr>
<td><label for="shortName">ShortName:</label></td>
<td><input id="shortName" data-bind= "value: shortName" /></td>
</tr>
</table>
<button id="submit" class="k-button" data-bind="click: save" form="franchiseForm">Save Franchise</button>
</form>
On submit the form I am calling javascript function save:
$(function () {
save = function () {
// some logic
$.ajax({
url: "/franchise/SaveFranchise",
type: "POST",
data: { franchiseInfoViewModel: jsonData },
dataType: 'json',
success: function (data, textStatus, xhr) {
window.location.href = data.redirectToUrl;
}
});
}
});
On save I am submitting the data in json format and sending the data to the SaveFranchise Controller:
public ActionResult SaveFranchise(string franchiseInfoViewModel)
{
var franchiseInfoVM = JsonConvert.DeserializeObject<FranchiseInfoViewModel>(franchiseInfoViewModel);
if (!ModelState.IsValid)
{
// do some action
}
return View();
}
What I want to accomplish is on (!ModelState.IsValid) to return back to the view and show fluent validation error messages. For some reason, in my case ModelState.IsValid is always true.
As mentioned, I am very new to Asp Mvc 3. From the articles I have read, the examples are submitting the form to the server (without javascript) where there is binding and the server validation messages are returned to the view. But there the view is implemented with Razor and client side validation is done via jquery.
In my view I am using javascript view model with databindings ( kendoui + knockout). What should I do to do the server side validation in my case. Please help me. Thank You for your time and effort!
Short answer:
You should make use of model bindings in the controller action - doing so enables you to make use of ModelState.IsValid.
So your controller action:
public ActionResult SaveFranchise(string franchiseInfoViewModel)
.. should be changed into something like:
public ActionResult Create(FranchiseInfo franchiseInfo)
Be sure to post your form in a format that enables the model binder to instantiate an instance of the FranchiseInfo model. You can use JSON to do so, but I think it would be better (and simpler) if you just post the form using the standard action attribute on a form.
Elaborated answer:
One of the first things I would recommend, is that you use the model validation provided by the ASP.NET MVC framework including model bindings, model state, and data annotations for server side validation, as well as unobtrusive javascript for client side validation. Doing so would give you a way more DRY implementation with clear Separation of Concerns (SoC).
To get there - I suggest you first start taking a look at model bindings in ASP.NET MVC.
As stated in "The Features and Foibles of ASP.NET MVC Model Binding":
With model binding, controller actions can be focused on providing business value and avoid wasting time with mundane request mapping and parsing.
To see this, this MSDN article have a good definition of a model binder:
A model binder in MVC provides a simple way to map posted form values to a .NET Framework type and pass the type to an action method as a parameter. (...) Model binders are like type converters, because they can convert HTTP requests into objects that are passed to an action method.
With that abstraction in hand, you will quickly see that the signature of:
public ActionResult SaveFranchise(string franchiseInfoViewModel)
.. could be changed into something like:
public ActionResult Create(FranchiseInfo franchiseInfo)
... and at this point, things are already starting to look more clean because code like your custom data mapping:
var franchiseInfoVM = JsonConvert.DeserializeObject<FranchiseInfoViewModel>(franchiseInfoViewModel);
... can be removed.
In general, you should not need to serialize the form into JSON and post that - instead you should take advantage of the model binding in MVC and submit the form data the standard way ( by using the action attribute on the form element - well, the model binder is able to bind objects based on JSON, but I think you get my point.. ). Actually, ASP.NET MVC makes it really simple to generate a form for a model using Html.BeginForm - an example use of this is shown here.
So, now when you have refactored the view to make use of a form that posts its data without serializing the form data into JSON, you should take a look at the data annotations in MVC3.
As mentioned in this example, the System.ComponentModel.DataAnnotations namespace of .NET...
provides a built-in set of validation attributes that you can apply declaratively to any class or property. (...) The validation attributes specify behavior that you want to enforce on the model properties they are applied to.
One of the available annotations is the Required attribute - it defines that a particular model property must have a value. There are several other attributes like Range, MaxLength, RegularExpression, etc. An example use of some of the attributes could look like this:
public class Movie
{
public int ID { get; set; }
[Required(ErrorMessage = "Title is required")]
public string Title { get; set; }
[Required(ErrorMessage = "Date is required")]
public DateTime ReleaseDate { get; set; }
[Required(ErrorMessage = "Genre must be specified")]
public string Genre { get; set; }
[Required(ErrorMessage = "Price Required")]
[Range(1, 100, ErrorMessage = "Price must be between $1 and $100")]
public decimal Price { get; set; }
[StringLength(5)]
public string Rating { get; set; }
}
( The example is borrowed from: http://www.asp.net/mvc/tutorials/getting-started-with-aspnet-mvc3/cs/adding-validation-to-the-model )
Populating your models with data annotations makes it very easy for you to check if the model is valid or not, at the point when a given form has been submitted, and your are about the check the validity of the provided model in a given action - it is here ModelState.IsValid proves to be useful.
As mentioned in this post:
(...) The second Create method calls ModelState.IsValid to check whether the movie has any validation errors. Calling this method evaluates any validation attributes that have been applied to the object.
So at this point, you should be able to see that using data annotations to declare constraints/required behavior on your model will allow you to have a simple implementation where the logic is defined in the model and can easily be checked using ModelState.IsValid.
To expand a bit on this I can tell you a bit of my experience with model validation at server and client side in ASP.NET MVC3.
As you might already have guessed, my best experience with ASP.NET MVC3 when it comes to model validation is using data annotations and the built-in support for server-side validation through ModelState.IsValid and client-side validation through unobtrusive JavaScript.
For data annotations I use a combination of the built-in annotations, and the extensions provided by the data annotation extension project.
There are a couple of good things about using ASP.NET MVC3's support for unobtrusive client validation.
First of all, SoC is really easy to achieve, as the model validation logic is only defined one place - and that is in the model where it belongs.
Secondly you can get a more DRY implementation in your view ( avoid duplicated logic and get code that is easier to maintain ) and let the framework do the heavy lifting for you instead.
An example of how to use unobtrusive client side validation in ASP.NET MVC3 can be found here.
However, there are times when using the annotations might not seem that straigt forward - for instance when you want to validate properties such as credit cards and file extensions. In these cases where the need for logic calls for alternatives other than the basic annotations, I tend to use data annotation extensions ( unless I can target my application for .NET 4.5 which, for instance, has added a series of more attributes, like e.g. the FileExtensionAttribute ) as they provide a series of great annotation extensions that just works right out of the box ( there exist a data annotation extensions nuget package for MVC3 - so it is really simple to set up and start using ).
There are also special cases when you might have a property that depends on the state of your databse - e.g. if you want to check if a username already exists when a user is filling out a user registration form. In this scenario, the ASP.NET MVC3 remote validation annotation is your friend. As this MSDN article states:
ASP.NET MVC 3 provides a mechanism that can make a remote server call in order to validate a form field without posting the entire form to the server. This is useful when you have a field that cannot be validated on the client and is therefore likely to fail validation when the form is submitted.
And the nice thing about remote validation in ASP.NET MVC3 is, that it also is expressed using a data annotation ( as illustrated in this blogpost and in this MSDN article ).
So to sum up - using these framework features (imo) really gives you a serious range of tools to cover more or less any kind of model validation "the right way" in ASP.NET MVC3.
I am reading an enum value from the db then bind it to the model. When i post the form with ajax, somehow the enum is unbound or the model property in null or zero but it display properly on the view. I have posted code below. Im using entityframework and mvc3
//model code constructor
public CarModel(Car car)
{
State=(CarState)car.State;
//car.State comes in as an int
//etc setting other variables
}
//CarState property
public CarState {get;set;}
//model code
#Html.DisplayFor(m=>m.CarState)
//Controller code()
Save(CarModel car)
{
//I have code that saves the changes
}
The minute i get to "car", CarState has no value.
It's not quite clear how you are passing this value to the controller action. You have only shown some #Html.DisplayFor(m=>m.CarState) but obviously this only displays a label in the view. It doesn't send anything back to the server. If you want to send some value back you will have to use an input field inside the form.
For example:
#Html.EditorFor(m => m.CarState)
or use a HiddenFor field if you don't want the user to edit it.
In any case you need to send that value to the server if you expect the model binder to be able to retrieve it. The model binder is not a magician. He cannot invent values. He binds values to your model from the Request.
I have created a simple WCF service that is to be configured by an MVC3 UI.
When I call the index page from my controller, I want to display the values held in the configuration, which has been returned by the service. The user could then chose to edit these settings and then send them back to the service.
I want to do something like this in the index view ...
<div>
#Html.ActionLink("Edit", "Edit", model)
</div>
and then consume the model in the controller like this...
[HttpPost]
public ActionResult Edit( SettingsModel Config)
{
try
{
List<string> configErrors = null;
if (ModelState.IsValid)
{
// Set up a channel factory to use the webHTTPBinding
using (WebChannelFactory<IChangeService> serviceChannel = new WebChannelFactory<IChangeService>(new Uri(baseServiceUrl)))
{
IChangeService channel = serviceChannel.CreateChannel();
configErrors = channel.SetSysConfig(Config);
}
}
return RedirectToAction("Index");
}
catch
{
return View();
}
}
but this doesn't work.
Any suggestions???
When the form gets posted, all the input type fields data is collected and sent to the server. You can see this data using FireBug. The key point here is that, is the data that is being posted in a form, that MVC's default model binder can understand and map it to the model object, which is being passed as input parameter to the action method.
In your case, the model is of type "SettingsModel". You have to ensure that, the form data that is being posted is in format, that can be mapped to the "SettingsModel" object.
Same kind of question discussed in another thread : Can't figure out why model is null on postback?
Check Out this article : NerdDinner Step 6: ViewData and ViewModel
In the above article, carefully go through the "Using a ViewModel Pattern" section. My guess is that, this is what you are looking for.
You will need to post the values to populate the SettingsModel object on the Edit action. You can do this using hidden form fields if you don't want the user to see it. Otherwise you could have no parameters on the Edit action and make another call to the web service to populate the Settings model.