ValidationMessage in MVC View not displaying - asp.net-mvc

I have a custom date validation and I have done as explained in
this link. Below is my Model code:
[DisplayFormat(DataFormatString = "{0:dd/MM/yyyy}",ApplyFormatInEditMode=true)]
[DisplayName("Sch.Start Date:")]
[DataType(DataType.Date)]
[ValidProjectDate(ErrorMessage="Project Start Date cannot be greater than Project End Date.")]
public DateTime? ProjectScheduleStartDate { get; set; }
[DisplayFormat(DataFormatString = "{0:dd/MM/yyyy}", ApplyFormatInEditMode = true)]
[DisplayName("Sch.End Date:")]
[DataType(DataType.Date)]
[ValidProjectDate(ErrorMessage = "Project End Date cannot be less than or Equal to Current Date.")]
public DateTime? ProjectScheduleEndDate { get; set; }
`
Below is my code in View:
<div class="form-group">
#Html.LabelFor(model => model.ProjectScheduleStartDate, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.ProjectScheduleStartDate, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.ProjectScheduleStartDate, "*", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.ProjectScheduleEndDate, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.ProjectScheduleEndDate, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.ProjectScheduleEndDate, "*", new { #class = "text-danger" })
</div>
</div>
<hr/>
#Html.ValidationSummary(true, "Please correct below errors", new { #class = "text-danger" })
Below is my code in Controller:
if (ModelState.IsValid)
{
ProjectManager pm = new ProjectManager();
pm.AddProjects(prj);
ViewBag.Result = "Record Inserted Successfully.";
ModelState.Clear();
}
else
{
ModelState.AddModelError(string.Empty, "An Error has happened");
}
return View("AddNewProject");
Even though I tried to display the validation message as mentioned in the model class, I am getting only star images instead of the validation messages. However, the Error messsages specified inside the validation summary is getting displayed. But I want to display the messages in the model class. Any clue?

I removed the star symbol on the ValidationMessageFor in View. It started working.. May be helpful for someone.

Your attribute's ValidationResult does not have a key associated with a field, which prevents ValidationMessageFor from working.
I would suggest using implementing the IValidatable interface on your ViewModel instead of your custom data validation attribute, unless there are many places in your application where this type of validation is required.
You will notice that it provides the name of the property as the key to associate the error with the field:
public class TestViewModel : IValidatableObject
{
public DateTime? ProjectStartDate { get; set; }
public DateTime? ProjectEndDate { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (ProjectStartDate > ProjectEndDate)
yield return new ValidationResult("The Project Start Date cannot be after the Project End Date.", new List<string>() { nameof(ProjectStartDate) });
if (ProjectEndDate < DateTime.Now)
yield return new ValidationResult("Project End Date cannot be less than or Equal to Current Date.", new List<string>() { nameof(ProjectEndDate) });
}
}

Related

Receiving "SqlException: Cannot insert explicit value for identity column in table ' ' when IDENTITY_INSERT is set to OFF" When not submitting Id

I am using ASP.Net MVC 5 with EF6
I have a model called DoodleBug (dont ask). When I try to create and save a new entry of this entity to the database I get the following exception, even though i am not inputting an Id value?
SqlException: Cannot insert explicit value for identity column in table
'DoodleBugs' when IDENTITY_INSERT is set to OFF.
Here is my model
public class DoodleBug
{
public int Id { get; set; }
public string Sentence { get; set; }
public DateTime Adate { get; set; }
public Boolean TrueFalse { get; set; }
public int DoodleId { get; set; }
public int BugId { get; set; }
public virtual Doodle Doodle { get; set; }
public virtual Bug Bug { get; set; }
}
Here is the controller
// GET: DoodleBugs/Create
public ActionResult Create()
{
ViewBag.Id = new SelectList(db.Bug, "Id", "BugString");
ViewBag.Id = new SelectList(db.Doodle, "Id", "DoodleString");
return View();
}
// POST: DoodleBugs/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see https://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "Sentence,Adate,TrueFalse,DoodleId,BugId")] DoodleBug doodleBug) // Edited FROM [Bind(Include = "Id,Sentence,Adate,TrueFalse,DoodleId,BugId")] ---- removed Id from bind list
{
if (ModelState.IsValid)
{
db.DoodleBug.Add(doodleBug);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.Id = new SelectList(db.Bug, "Id", "BugString", doodleBug.Id);
ViewBag.Id = new SelectList(db.Doodle, "Id", "DoodleString", doodleBug.Id);
return View(doodleBug);
}
and here is the view
<div class="form-horizontal">
<h4>DoodleBug</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#*<div class="form-group">
#Html.LabelFor(model => model.Id, "Id", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("Id", null, htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.Id, "", new { #class = "text-danger" })
</div>
</div>*#
<div class="form-group">
#Html.LabelFor(model => model.Sentence, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Sentence, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Sentence, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Adate, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Adate, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Adate, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.TrueFalse, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
<div class="checkbox">
#Html.EditorFor(model => model.TrueFalse)
#Html.ValidationMessageFor(model => model.TrueFalse, "", new { #class = "text-danger" })
</div>
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.DoodleId, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.DoodleId, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.DoodleId, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.BugId, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.BugId, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.BugId, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
In case it helps, here is the EF generated migration code for the DoodleBug Entity. I manually changed some of the codelines, as noted by the comments next to them, to create a Foreign Key relationship between the DoodleBug entity and two other entities (Doodle and Bug)
CreateTable(
"dbo.DoodleBugs",
c => new
{
Id = c.Int(nullable: false, identity: true), // Edited FROM 'Id = c.Int(nullable: false)'
Sentence = c.String(),
Adate = c.DateTime(),
TrueFalse = c.Boolean(),
DoodleId = c.Int(nullable: false),
BugId = c.Int(nullable: false),
})
.PrimaryKey(t => t.Id)
.ForeignKey("dbo.Bugs", t => t.BugId) // Edited FROM 'ForeignKey("dbo.Bugs", t => t.Id)'
.ForeignKey("dbo.Doodles", t => t.DoodleId) // Edited FROM 'ForeignKey("dbo.Doodles", t => t.Id)'
.Index(t => t.Id)
.Index(t => t.BugId) // Added
.Index(t => t.DoodleId); // Added
NB the controller and the view were scaffolded by EF which added both a Bind attribute for the ID in the create() method and a SelectList of items for the Id in the controllers ViewBag, as well as a form control in the view to utilise the SelectList from the controller to create a dropdown list of option to input into the Id value.
I have deleted the Id from the Bind attribute in the controllers Create() method and have commented out the form control in the View relating to the Id value (as seen by the #* - *# from lines 5 - 11 in the View)
Despite this when I run the code and try to submit the form I get the above error?
When I run the app in debug mode the properties box for the doodleBug variable has an Id value of 0 (Int). I'm not sure where this is coming from or if it a default value?
In response to questions below are the Doodle and Bug Models
public class Doodle
{
public int Id { get; set; }
public string DoodleString { get; set; }
public DateTime DoodleTime { get; set; }
public Boolean DoodleBool { get; set; }
public virtual DoodleBug DoodleBUg { get; set; }
}
public class Bug
{
public int Id { get; set; }
public string BugString { get; set; }
public DateTime BugTime { get; set; }
public Boolean BugBool { get; set; }
public virtual DoodleBug DoodleBug { get; set; }
}
I also have some fluent API attempting to create a 1 - to - 0/1 relationship, the DoodleBug Entity being the optional entity to both.
// 1 - 2 - 0/1
modelBuilder.Entity<DoodleBug>()
.HasRequired(db => db.Doodle)
.WithOptional(d => d.DoodleBUg);
modelBuilder.Entity<DoodleBug>()
.HasRequired(db => db.Bug)
.WithOptional(b => b.DoodleBug);
Not sure if this is what you mean by asking what my DB structure is but copied this from opening up sqlexpress;
dbo.DoodlBugs
Columns:
Id (PK, int, not null)
Sentence (nvarchar(max), null)
Adate (datetime, null)
TrueFalse (bit, null)
DoodleId (FK, int, not null)
BugId (FK, int, not null)
Keys
PK_dbo.DoodleBugs
FK_dbo.DoodleBugs_dbo.Bugs_BugId
FK_dbo.DoodleBugs_dbo.Doodles_DoodleId
As I mentioned in the comments, the fact that you had to modify manually the generated migration is indication of a problem in the model.
For instance this edit
Id = c.Int(nullable: false, identity: true), // Edited FROM 'Id = c.Int(nullable: false)'
The migration is generated based on the model. The important thing to notice here is that from EF point of view, the Id field is not identity. Although your edit fixed the database field, still for EF this field is not identity, hence EF does not treat it as identity and associated behaviors like not passing a value when doing INSERT, but like regular int field and passes its value (even it's 0 by default) to INSERT command, which leads to the exception you are getting.
Similar, the following edits
.ForeignKey("dbo.Bugs", t => t.BugId) // Edited FROM 'ForeignKey("dbo.Bugs", t => t.Id)'
.ForeignKey("dbo.Doodles", t => t.DoodleId) // Edited FROM 'ForeignKey("dbo.Doodles", t => t.Id)'
indicate that for EF DoodleId and BugId are not FKs (instead, Id is), so all the behavior and generated SQL joins will be based on that.
With that being said, never edit migrations manually to "fix" model issues, but fix the model.
The root of the problem in your case are the two one-to-one relationships. By default, EF uses so called Shared Primary Key Associations for such relationships, where the PK of the dependent table is also a FK to the principal table. And of course the PK of the dependent table is no more identity.
How to fix it? The problem is that one-to-one FK associations have limited support. More specifically, explicit FK properties are not supported. So you have to remove them from the model and keep only the navigation properties:
public class DoodleBug
{
public int Id { get; set; }
public string Sentence { get; set; }
public DateTime Adate { get; set; }
public Boolean TrueFalse { get; set; }
public virtual Doodle Doodle { get; set; }
public virtual Bug Bug { get; set; }
}
and change the configuration as follows:
modelBuilder.Entity<DoodleBug>()
.HasRequired(db => db.Doodle)
.WithOptional(d => d.DoodleBUg)
.Map(c => c.MapKey("DoodleId"));
modelBuilder.Entity<DoodleBug>()
.HasRequired(db => db.Bug)
.WithOptional(b => b.DoodleBug)
.Map(c => c.MapKey("BugId"));
Now the generated migration (w/o edits!) is:
CreateTable(
"dbo.DoodleBug",
c => new
{
Id = c.Int(nullable: false, identity: true),
Sentence = c.String(),
Adate = c.DateTime(nullable: false),
TrueFalse = c.Boolean(nullable: false),
BugId = c.Int(nullable: false),
DoodleId = c.Int(nullable: false),
})
.PrimaryKey(t => t.Id)
.ForeignKey("dbo.Bug", t => t.BugId)
.ForeignKey("dbo.Doodle", t => t.DoodleId)
.Index(t => t.BugId)
.Index(t => t.DoodleId);
I was receiving this error. In my case I changed the column on database (setting Identity) after I created with scaffolding the context in the MVC app. So I needed to remove this line from the DataContext class
entity.Property(e => e.Id).ValueGeneratedNever();
And this solve my problem! Good luck!

DataAnnotation and value by default

I have a property in view model:
[Display(Name = "Date")]
[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:MM/dd/yyyy}")]
public System.DateTime DateTime { get; set; }
and view:
<div class="form-group">
#Html.LabelFor(model => model.DateTime, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.DateTime, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.DateTime, "", new { #class = "text-danger" })
</div>
</div>
and page shows default value as 01/01/0001 on form:
I want have not any default value (user should specify correct value and can't send form without it). How to remove default value?
You have to make public System.DateTime DateTime { get; set; } a nullable DateTime.

Why always in the database, the DateTime property is null?

i 'm beginner in programming with MVC5.
I am working with MVC5 and Entity framework 6.
I have a class and a DateTime property like this:
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}",ApplyFormatInEditMode = true)]
[Column(TypeName = "datetime2")]
public DateTime? BirthDay { get; set; }
my controller:
public ActionResult Create([Bind(Include = "MelliCode,EnCode,grade,quota,password,FName,Lname,shenasname,FatehrName,sex,tel,mobile,ResAddress,WorkAddress")] Expert expert)
{
if (ModelState.IsValid)
{
db.Experts.Add(expert);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(expert);
}
and my view like this:
<div class="form-group">
#Html.LabelFor(model => model.BirthDay, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.BirthDay, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.BirthDay, "", new { #class = "text-danger" })
</div>
However, after the run of the page and enter personal information in the database is inserted to null for Birthday!!!why?
I found my problem
I had forgotten Birthday in [Bind] attribute
public ActionResult Create([Bind(Include = "BirthDay,MelliCode,EnCode,grade,quota,password,FName,Lname,shenasname,FatehrName,sex,tel,mobile,ResAddress,WorkAddress")] Expert expert)
{
if (ModelState.IsValid)
{
db.Experts.Add(expert);
db.SaveChanges();
return RedirectToAction("Index");
}

I can not save date in MVC

I've this model which has a couple of columns and one of them is date, but on post I get nothing of date, only in case if I give it the value of DateTime.Now then it will save the current date but If had selected some other date in the datepicker it will not save that as it should, so How can I pass the date to the view model on post, I can pass all the date from dropdown and textboxes but date is no where to found. Here is the code
My view model
[Display(Name = "Requested Date")]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
[DataType(DataType.Date)]
public DateTime? RequestDate { get; set; }
[Display(Name = "Job Number")]
public string JobNo { get; set; }
Here is the Post Create method code
if (ModelState.IsValid)
{
var model = new PECEquipmentRequest()
{
ProjectId = pecEquipmentRequest.ProjectId,
JobNo = pecEquipmentRequest.JobNo,
RequestDate = pecEquipmentRequest.RequestDate
};
db.PECEquipmentRequests.Add(model);
db.SaveChanges();
}
and here is the my razor syntax
<div class="form-group">
#Html.LabelFor(model => model.RequestDate, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.RequestDate, new { htmlAttributes = new { #Value = DateTime.Now,#class = "form-control datepicker" } })
#Html.ValidationMessageFor(model => model.RequestDate, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.JobNo, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.JobNo, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.JobNo, "", new { #class = "text-danger" })
</div>
</div>
and here is the kendo date picker that I'm using
$(document).ready(function () {
$(".datepicker").kendoDatePicker();
});
You can parse the date to the required format in the server side.
DateTime.ParseExact(str, "yyyyMMddHHmmss", CultureInfo.InvariantCulture);

How to save dropdownlist selected value to the database int asp.net MVC 5

I am currently new to Asp.net MVC .In one of the view I add a dropdownlist and I bind this dropdownlist with my database like this
Controller CollegeController
[HttpGet]
public ActionResult Create()
{
IEnumerable<SelectListItem> items = db.College_Names.Select(c => new SelectListItem { Value = c.id.ToString(), Text = c.Name });
IEnumerable<SelectListItem> item = db.Stream_Names.Select(c => new SelectListItem { Value = c.id.ToString(), Text = c.Stream });
ViewBag.CollName=items;
ViewBag.StreamName = item;
return View();
}
[HttpPost]
public ActionResult Create(College college)
{
try
{
if(ModelState.IsValid)
{
db.Colleges.Add(college);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.CollName = db.Colleges;
return View(college);
}
catch
{
return View();
}
}
This is my model
public class College
{
[Required]
public int Id { get; set; }
[Required]
[Display(Name="College Name")]
public int CollegeName { get; set; }
[Required]
public int Stream { get; set; }
[Required]
[Column(TypeName="varchar")]
public string Name { get; set; }
....
public virtual College_Name College_Name { get; set; }
public virtual Stream_Name Stream_Name { get; set; }
}
This is My View
<div class="form-group">
#Html.LabelFor(model => model.CollegeName, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("CollName", (IEnumerable<SelectListItem>)ViewBag.CollName, "Select College", new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.CollegeName, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Stream, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("StreamName", (IEnumerable<SelectListItem>)ViewBag.StreamName, "Select Stream", new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.Stream, "", new { #class = "text-danger" })
</div>
</div>
Now when I check my database after I save the CollegeName and Stream in the database is zero from the dropdownlist.
You have multiple problems with your code. Firstly you dropdownlists are binding to a properties named CollName and StreamName which do not even exist in your model.
Next you cannot name the property your binding to the same as the ViewBag property.
Your view code would need to be (and always use the strongly typed xxxFor() HtmHelper methods
#Html.DropDownListFor(m => m.CollegeName, (IEnumerable<SelectListItem>)ViewBag.CollName, "Select College", new { #class = "form-control" })
....
#Html.DropDownListFor(m => m.Stream, (IEnumerable<SelectListItem>)ViewBag.StreamName, "Select Stream", new { #class = "form-control" }
and in your POST method, the values of college.CollegeName and college.Stream will contain the ID's of the selected options.
You also need to repopulate the ViewBag properties when you return the view in the POST method (as you did in the GET method) or an exception will be thrown (and note that your current use of ViewBag.CollName = db.Colleges; will also throw an exception)
I also strongly suggest you start learning to use view models (views for editing should not use data models - refer What is ViewModel in MVC?) - and use naming conventions that reflect what your properties are, for example CollegeNameList, or CollegeNames, not CollName

Resources