Validation error message not displaying MVC4 - asp.net-mvc-3

I am using MVC4.
Validation is failing but validation error messages are not getting displayed.
This is my model.
public class Configuration
{
public int Id { get; set; }
[Required(AllowEmptyStrings = false, ErrorMessage = "Site name is required.")]
[MinLength(6, ErrorMessage = "Name should be at least 6 characters.")]
public string SiteName { get; set; }
}
Controller.
[HttpPost]
public ActionResult Create(Configuration configItem)
{
if (ModelState.IsValid)
{
// do something.
}
return View("Index", configItem);
}
View is
#model Models.SitesConfig.Configuration
#{
ViewBag.Title = "Sites Configurations";
}
<div>
#Html.ActionLink("Sites List", "List", "SiteConfig")
</div>
#using (Html.BeginForm("Create", "SiteConfig", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<fieldset>
<legend>New Satellitesite</legend>
<div>
#Html.LabelFor(m => m.SiteName, "Name")
#Html.TextBoxFor(m => m.SiteName)
#Html.ValidationMessageFor(m=>m.SiteName)
</div>
<br />
<input type="submit" value="Save" />
</fieldset>
}
Please also suggest me if there is any better way of doing the validations.

I don't know what was the problem. After clean and build the application, I am able to see the error message.
Thanks,
Naresh

There should be #Html.ValidationSummary("Please correct the errors") in the View

#using (Html.BeginForm("Create", "SiteConfig", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.ValidationSummary()
<fieldset>
<legend>New Satellitesite</legend>
<div>
#Html.LabelFor(m => m.SiteName, "Name")
#Html.TextBoxFor(m => m.SiteName)
#Html.ValidationMessageFor(m=>m.SiteName)
</div>
<br />
<input type="submit" value="Save" />
</fieldset>
}
Try this one .. #Html.ValidationSummary() helps in displaying the error messages.

If you try the above solutions and still didn't work, then maybe you need to format your View file. Go to Edit-Advanced-Format Document. Remember not to be in the debug mode when trying to format your file because you wouldn't see the above listed procedures if you are debugging your project.

Make sure your View is referencing the jQuery validations in the Scripts tag -
#section Scripts
{
#Scripts.Render("~/bundles/jqueryval")
}

Related

MVC3 custom server-side data annotation validation not working in partial view

I am trying to add custom data validation via data annotations. I am only concerned about server-side validation at this point. Everything I have seen here and elsewhere references client-side validation. I've stripped down all my code, ran a few test cases and I can get this working just fine on a regular view but as soon as the form is in a partial view, the code no longer breaks in the method to override IsValid.
In either case I can see the custom attribute being initialized. When the form is in a regular view I can see the override method being executed upon submitting the form, but when in a partial view the code never gets executed and it goes right to the HttpPost action.
I have spent the better parts of two days trying to figure this out and am at a loss. Any help would be GREATLY appreciated.
Note:
The code below does return the same view when it enters the HttpPost action. I have it like this for testing purposes. I know my override is never getting called from the partial view and thus IsValid is always true.
View showing form where the validation works
#model eRecruitBoard.ViewModels.HomeIndexViewModel
#{
ViewBag.Title = "eRecruitBoard";
}
#*<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>*#
<h2>Login/homepage</h2>
<br /><br />
<div class="errorMessage">
#Html.DisplayFor(m => m.LoginErrorMsg)
</div>
<br />
#using (Html.BeginForm("Index", "Home")) {
<div id="loginControlBox">
<fieldset>
<legend>Welcome to eRecruitBoard</legend>
<div class="editor-label">
#Html.LabelFor(m => m.UserName)
</div>
<div class="editor-field">
#Html.TextBoxFor(m => m.UserName)
#Html.ValidationMessageFor(m => m.UserName)
</div>
<div class="editor-label">
#Html.LabelFor(m => m.Password)
</div>
<div class="editor-field">
#Html.PasswordFor(m => m.Password)
#Html.ValidationMessageFor(m => m.Password)
</div>
<div class="editor-label">
#Html.CheckBoxFor(m => m.RememberMe)
#Html.LabelFor(m => m.RememberMe)
</div>
<div class="editor-label">
#Html.EditorFor(m => m.Date)
#Html.ValidationMessageFor(m => m.Date)
</div>
<p>
<input type="submit" value="Log In" />
</p>
</fieldset>
</div>
}
<div>
#Html.Action("BlankForm", "TestForm")
</div>
Partial View (these script calls also come in via _Layout, but I had them here for testing as well)
#model eRecruitBoard.ViewModels.TestFormViewModel
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/MicrosoftAjax.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/MicrosoftMvcAjax.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/MicrosoftMvcValidation.js")" type="text/javascript"></script>
#using (Html.BeginForm("NewActivity2", "TestForm", FormMethod.Post))
{
<fieldset>
<legend>Test Form</legend>
<br />
#Html.LabelFor(m => m.Date)
#Html.EditorFor(m => m.Date)
#Html.ValidationMessageFor(m => m.Date)
<input id="activityTimelineSubmit" type="submit" value="Submit" />
</fieldset>
}
ViewModel (for partial view)
namespace eRecruitBoard.ViewModels
{
public class TestFormViewModel
{
[Required]
[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:MM/dd/yyyy}")]
[NonFutureDate()]
[Display(Name = "Date")]
public DateTime Date { get; set; }
}
}
Controller (for partial view)
namespace eRecruitBoard.Controllers
{
public class TestFormController :BaseController
{
public ActionResult BlankForm()
{
var viewModel = new TestFormViewModel
{
Date = DateTime.Today
};
return PartialView("_TestForm", viewModel);
}
[HttpPost]
public ActionResult NewActivity2(DateTime Date)
{
if (!ModelState.IsValid)
return RedirectToAction("Index", "Home");
else
return RedirectToAction("Index", "Home");
}
}
}
Validation code
using System;
using System.ComponentModel.DataAnnotations;
namespace eRecruitBoard.WebLibrary.Validation
{
[AttributeUsageAttribute(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false, Inherited = true)]
public class NonFutureDateAttribute : ValidationAttribute //public sealed class
{
public NonFutureDateAttribute(): base("Activity can only be saved for today or dates in the past.")
{
}
public override bool IsValid(object value)
{
DateTime dateToCheck = (DateTime)value;
return (dateToCheck <= DateTime.Today);
}
}
}
If you RedirectToAction you lose all validation. You have to return PartialView(model) in your POST action. That would require changing the parameter type of NewActivity2 to TestFormViewModel instead of DateTime.
Update your code with example of how you display the partial view (#Html.Partial() or javascript) if it still doesnt work.

Receiving a NullReference Exception error during HttpPost Action when using a ViewModel

I am trying to create what I feel is a very simple form submission using a ViewModel. I have worked on this off and on all day and for some reason cannot understand why when my app gets to my HttpPost action my EmailViewModel is empty. I get a "NullReference Exception Occurred" "Object reference not set to an instance of an object" error.
Can you take a look at my code and tell me where I am being crazy?
Here is my httpPost action:
[HttpPost]
public ActionResult SendStudentAnEmail(EmailViewModel email)
{
Debug.Write(email.Subject); // First NullReferenceException
Debug.Write(email.Body);
Debug.Write(email.Email);
etc. . .
My ViewModel:
namespace MyApp.ViewModels
{
public class EmailViewModel
{
public string Email { get; set; }
public string Subject { get; set; }
public string Body { get; set; }
}
}
and My View:
#model MyApp.ViewModels.EmailViewModel
#{
ViewBag.Title = "SendStudentAnEmail";
}
<h2>SendStudentAnEmail</h2>
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>EmailViewModel</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Email)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Email)
#Html.ValidationMessageFor(model => model.Email)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Subject)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Subject)
#Html.ValidationMessageFor(model => model.Subject)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Body)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Body)
#Html.ValidationMessageFor(model => model.Body)
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
Thank you.
*UPDATE*
If I change my HttpPost Action to use FormCollection, I can use the values just fine, I can even re-cast the FormCollection values back to my EmailViewModel. Why is this?
[HttpPost]
public ActionResult SendStudentAnEmail(FormCollection emailFormCollection)
{
Debug.Write(emailFormCollection["email"]);
Debug.Write(emailFormCollection["subject"]);
Debug.Write(emailFormCollection["body"]);
var email = new EmailViewModel
{
Email = emailFormCollection["email"],
Subject = emailFormCollection["subject"],
Body = emailFormCollection["body"]
};
. . . . then the rest of my code works just how I wanted. . .
Why do I have to cast from FormCollection over to my EmailViewModel? Why isn't it giving me the NullReference Exception if I attempt to simply push an EmailViewModel into my Action?
Your EmailViewModel class has a property called Email of type string. And your controller action takes an argument called email of type EmailViewModel. This confuses the default model binder. So either rename the property inside the view model or the action argument:
[HttpPost]
public ActionResult SendStudentAnEmail(EmailViewModel model)
{
Debug.Write(model.Subject);
Debug.Write(model.Body);
Debug.Write(model.Email);
...
}

This property cannot be set to a null value

As I am newbie to asp.net mvc 3, I have no good knowledge of it's internal process. I have two action to create new category as Get and Post method:
public ActionResult Create()
{
List<Category> cat = this.display_children(null, 0);
List<SelectListItem> items = new SelectList(cat, "ID", "CategoryName").ToList();
items.Insert(0, (new SelectListItem { Text = "root", Value = "" }));
ViewBag.ParentCategoryID = items;
return View();
}
[HttpPost]
public ActionResult Create(Category category)
{
if (ModelState.IsValid)
{
db.Categories.AddObject(category);
db.SaveChanges();
return RedirectToAction("Index");
}
List<Category> cat = this.display_children(null, 0);
List<SelectListItem> items = new SelectList(cat, "ID", "CategoryName").ToList();
items.Insert(0, (new SelectListItem { Text = "root", Value = "" }));
ViewBag.ParentCategoryID = items;
return View(category);
}
Below is View:
#model IVRControlPanel.Models.Category
#{
ViewBag.Title = "Create";
}
<h2>Create</h2>
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>Category</legend>
<div class="editor-label">
#Html.LabelFor(model => model.CategoryName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.CategoryName)
#Html.ValidationMessageFor(model => model.CategoryName)
</div>
<div class="editor-label">
#Html.Label("Select Category")
</div>
<div>
#*#Html.DropDownList("CategoryList",new SelectList(ViewBag.Categories))*#
#Html.DropDownList("ParentCategoryID", ViewBag.ParentCategoryID as SelectList)
#Html.ValidationMessageFor(model => model.ParentCategoryID)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
Problem:
When I click the create button without filling up the category-name field following exception is thrown:
This property cannot be set to a null value.
The exception is thrown only when visual studio is debugging mode and when I continue debugging then only error is shown in validation message. Here, What actually have to be is that Error should be shown without throwing exception which is alright while not in debugging mode. I have following category table column in database and use model first approach Entity framework:
ID -> primary key and identity , integer
CategoryName -> Non nullable, varchar(50)
ParentCategoryID -> Nullable
I have not good at asp.net mvc 3 and can not figured what might be the problems.
In your actions replace:
ViewBag.ParentCategoryID = items;
with:
ViewBag.Categories = items;
and in your view:
#Html.DropDownListFor(x => x.ParentCategoryID, ViewBag.Categories as SelectList)
The DropDownList helper needs 2 arguments: the first one represents a scalar property that will hold the selected value and the second argument a collection with the available items. They should be different.
Luckily I found solution for this. Actually, Problem was due to PreBinding validation. I was searching and found same issue at this link explained nicely.
I have made partial class for Category as below:
public partial class Category{
}
public class TestEntityValidation{
[Required]
[DisplayFormat(ConvertEmptyStringToNull = false)]
public String CategoryName { get; set; }
}
Here, Converting empty string to null is set to false which have solved my problem at DisplayFormat attributes.

Can't add file upload capability to generated MVC3 page

I'm new to MCV and I'm learning MVC3. I created a model and a controller and view was generated for me. The generated code makes perfect sense to me. I wanted to modify the generated view and controller so that I could upload a file when I "create" a new record. There is a lot of good information out there about how to do this. Specifically I tried this: http://haacked.com/archive/2010/07/16/uploading-files-with-aspnetmvc.aspx
The problem is that even when I select a file (not large) and submit, there are no files in the request. That is, Request.Files.Count is 0.
If I create the controller and and view from scratch, in the same project (no model), the example works just fine. I just can't add that functionality to the generated page. Basically, I'm trying get the Create action to also send the file. For example, create a new product entry and send the picture with it.
Example Create view:
#model Product.Models.Find
#{
ViewBag.Title = "Create";
}
<h2>Create</h2>
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
#using (Html.BeginForm("Create", "Find", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.ValidationSummary(true)
<fieldset>
<legend>Find</legend>
<input type="file" id="file" />
<div class="editor-label">
#Html.LabelFor(model => model.Title)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Title)
#Html.ValidationMessageFor(model => model.Title)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Description)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Description)
#Html.ValidationMessageFor(model => model.Description)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
Example Controller:
[HttpPost]
public ActionResult Create(Product product)
{
if (ModelState.IsValid)
{
if (Request.Files.Count > 0 && Request.Files[0] != null)
{
//Not getting here
}
db.Products.Add(product);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(find);
}
This will create the record just fine but there are not files associated with the Request.
I've also tried a controller action like this:
[HttpPost]
public ActionResult Create(HttpPostedFileBase file)
{
if (file.ContentLength > 0)
{
//Not getting here
}
return RedirectToAction("Index");
}
I'm wondering if maybe you can't post a file at the same time as posting form fields? If that is the case, what are some patterns for creating a new record and associating a picture (or other file) with it?
Thanks
Create a ViewModel which has properties to handle your image and Product deatils
public class ProductViewModel
{
public string ImageURL { set;get;}
public string Title { set;get;}
public string Description { set;get;}
}
And in your HTTPGET Action method, return this ViewModel object to your strongly typed view
public ActionResult Create()
{
ProductViewModel objVM = new ProductViewModel();
return View(objVM);
}
And in your View
#model ProductViewModel
<h2>Add Product</h2>
#using (Html.BeginForm("Create", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.TextBoxFor(m => m.Title) <br/>
#Html.TextBoxFor(m => m.Description ) <br/>
<input type="file" name="file" />
<input type="submit" value="Upload" />
#Html.HiddenFor(m => m.ImageURL )
}
Now in your HttpPost action method, accept this ViewModel and File
[HttpPost]
public ActionResult Create(HttpPostedFileBase file, ProductViewModel objVM)
{
if(file==null)
{
return View("Create",objVM);
}
else
{
//You can check ModeState.IsValid if you have to check any model validations and do further processing with the data here.
//Now you have everything here in your parameters, you can access those and save
}
}
You will have to create a ViewModel for Product (maybe ProductViewModel) and add a HttpPostedFileBase field with the same name as the field of the form and use that instead of the Product in the action of the controller.
A ViewModel is nothing but a model used for specific views. Most of the times, with extra data to generate the view or to decompose and form the model on the controller action.
public ProductViewModel
{
public string Cod { get; set; }
// All needed fields goes here
public HttpPostedFileBase File{ get; set; }
/// Empty constructor and so on ...
}

How i can submit multiple objects inside the form post values to be added

i have a create view to add answers to a question, currently the user can only add one answer at the same time when he clicks on the submit button, instead of this i want the user to be able to insert multiple answers objects into the same view and then the system to add all these new answer objects to the database after the user click on the submit button, my current view looks as the follow:-
#model Elearning.Models.Answer
#{
ViewBag.Title = "Create";
}
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
<div id = "remove">
#using (Ajax.BeginForm("Create", "Answer", new AjaxOptions
{
HttpMethod = "Post",
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "remove"
}))
{
<div id = "returnedquestion">
#Html.ValidationSummary(true)
<fieldset>
<legend>Answer</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Description)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Description)
#Html.ValidationMessageFor(model => model.Description)
</div>
</fieldset>
<input type= "hidden" name = "questionid" value = #ViewBag.questionid>
<input type= "hidden" name = "assessmentid" value = #ViewBag.assessmentid>
<input type="submit" value="Add answer" />
</div>
}
</div>
and the action methods look as the follow:-
public ActionResult Create(int questionid)//, int assessmentid)
{
ViewBag.questionid = questionid;
Answer answer = new Answer();
return PartialView("_answer",answer);
}
//
// POST: /Answer/Create
[HttpPost]
public ActionResult Create(int questionid, Answer a)
{
if (ModelState.IsValid)
{
repository.AddAnswer(a);
repository.Save();
return PartialView("_details",a);
}
return View(a);}
so how i can modify the above code to be able to insert multiple answer objects at the same view and then submit these answers objects at the same time when the user click on the submit button?
Try Post a List
Add input by javascript when user click "Add Answer".
And when submit the form ,it will post all answer data to binding to List
<script>
$(document).ready(function () {
var anwserCount = 1;
$("#addbutton").click(function () {
$("#AnwsersDiv")
.append("<input type='text' name='Anwsers[" + anwserCount + "]'/>");
anwserCount += 1;
});
});
</script>
#using (Html.BeginForm())
{
<div id="AnwsersDiv">
<input type="text" name="Anwsers[0]" />
</div>
<input id="addbutton" type="button" value="Add answer" />
<input type="submit" value="submit" />
}
Model
public class Answer
{
public List<String> Anwsers { get; set; }
}
When submit the form
I think this is what you are looking for
http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx
Conclusion: you should make the post action with ICollection<Answer> Parameter, then it will be easy to get them when you post your main form, and create the appropriate QUESTION object, then save them all with only one submit.

Resources