Save newly created object ASP.NET MVC - c#

I'm using EF Code First and here is my class which references a Professor object.
public class Mark
{
public int MarkId { get; set; }
[Required(ErrorMessage = "Please provide Grade")]
[Display(Name = "Grade Value")]
public int MarkValue { get; set; }
[Required(ErrorMessage = "Please provide grade type")]
[Display(Name = "Grade Type")]
public string Type { get; set; }
[Required(ErrorMessage = "Please provide Subject")]
[Display(Name = "Subject")]
public virtual Subject Subject { get; set; }
public virtual User User { get; set; }
public virtual Professor Professor { get; set; }
}
In my view I have a dropdown to select a professor who put the mark.
I implemented it like this:
//controller
public MarksController() : this(new MarkRepository())
{
IProfessorRepository professorsRepo = new ProfessorRepository();
List<Professor> professors = professorsRepo.All.ToList<Professor>();
List<SelectListItem> items = new List<SelectListItem>();
foreach (Professor p in professors)
{
items.Add(new SelectListItem
{
Text = String.Concat(p.FirstName, " ", p.LastName), Value = p.ProfessorId.ToString()
});
}
items.Add(new SelectListItem
{
Text = "Please select Professor", Value = "0", Selected = true
});
ViewBag.Professors = items;
}
//view create or edit
<div class="editor-label">
#Html.LabelFor(model => model.MarkValue)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.MarkValue)
#Html.ValidationMessageFor(model => model.MarkValue)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Type)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Type)
#Html.ValidationMessageFor(model => model.Type)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Professor)
</div>
<div class="editor-field">
#Html.DropDownList("Professors");
</div>
Yes, I know that there is is a metod in Controller called Create which appeals repository method InsertOrUpdate.
[HttpPost]
public ActionResult Create(Mark mark)
{
if (ModelState.IsValid) {
markRepository.InsertOrUpdate(mark);
markRepository.Save();
return RedirectToAction("Index");
} else {
return View();
}
}
public void InsertOrUpdate(Mark mark)
{
if (mark.MarkId == default(int)) {
// New entity
context.Marks.Add(mark);
} else {
// Existing entity
context.Entry(mark).State = EntityState.Modified;
}
}
Everything seems logic, but how can I save a newly created Mark object with the professor selected? How does ASP.NET arranges the object which is passed to Create method on Controller? How should I match the selected professor with the mark I am creating?

Take a look at this, you need a ProfessorId in the model.
Model binding dropdown selected value
public class Mark
{
// this will hold the selected value
public string ProfessorID { get; set; }
public IEnumerable<SelectListItem> Professors
{
get
{
return Proffessors
.Select(x => new SelectListItem {
Value = x.ProfessorId.ToString(),
Text = String.Concat(p.FirstName, " ", p.LastName)
});
}
}
public IEnumerable<Professor> Proffessors
{
get
{
IProfessorRepository professorsRepo = new ProfessorRepository();
return professorsRepo.All;
}
}
//the rest of your code
}
in the view do
#Html.DropDownListFor(
x => x.ProfessorId,
new SelectList(Model.Professors, "Value", "Text")
)

Related

Why is this web http exception happening when I am populating a drop down list?

Model
League and LeagueDivision are two model classes
public class League
{
public int Id { get; set; }
public string League1 { get; set; }
public string Icon { get; set; }
public virtual ICollection<LeagueDivision> LeagueDivisions { get; set; }
}
public class LeagueDivision
{
public int Id { get; set; }
public Nullable<int> LeagueId { get; set; }
public string Name { get; set; }
public string Icon { get; set; }
public virtual League League { get; set; }
}
public class ViewModelForHostBooster
{
[Required(ErrorMessage = "Please enter price")]
[Display(Name = "Price")]
public decimal Price { get; set; }
[Required(ErrorMessage = "Please select a league")]
[Display(Name = "League")]
public int? SelectedLeague { get; set; }
[Required(ErrorMessage = "Please select a league division")]
[Display(Name = "League Division")]
public int? SelectedLeagueDivision { get; set; }
public SelectList LeagueList { get; set; }
public SelectList LeagueDivisionList { get; set; }
}
Controller
In IndexDropdown action I am just populating view with model and validating if
the model is validated then populate the view otherwise return the view. In FetchLeagueDivision action I am selecting Id and Name properties of model class based on passed argument ID.
Can anybody guide me why a WebHttpException is happening when I run this piece of code? Here is a link of exception Http Exception Image
public class DropDownController : Controller
{
[HttpGet]
public ActionResult IndexDropDown()
{
ViewModelForHostBooster model = new ViewModelForHostBooster();
ConfigureViewModel(model);
return View(model);
}
[HttpPost]
public ActionResult IndexDropDown(ViewModelForHostBooster model)
{
if (!ModelState.IsValid)
{
ConfigureViewModel(model);
return View(model);
}
// save and redirect
return RedirectToAction("Somewhere");
}
private void ConfigureViewModel(ViewModelForHostBooster model)
{
HostBoostersDBEntities db = new HostBoostersDBEntities();
var leagues = db.Leagues.Select(x => new { Value = x.Id, Text = x.League1 }).ToList();
model.LeagueList = new SelectList(leagues, "Id", "League1");
if (model.SelectedLeague.HasValue)
{
IEnumerable<LeagueDivision> leaguedivisions = db.LeagueDivisions.Where(l => l.LeagueId == model.SelectedLeague.Value);
model.LeagueDivisionList = new SelectList(leaguedivisions, "Id", "Name");
}
else
{
model.LeagueDivisionList = new SelectList(Enumerable.Empty<SelectListItem>());
}
}
}
View
#model HostBooster.Models.ViewModelForHostBooster
#using (Html.BeginForm())
{
<div>
#Html.LabelFor(m => m.Price)
#Html.TextBoxFor(m => m.Price)
#Html.ValidationMessageFor(m => m.Price)
</div>
<div>
#Html.LabelFor(m => m.SelectedLeague)
exception is occurring here #Html.DropDownListFor(m => m.SelectedLeague, Model.LeagueList)
#Html.DropDownListFor(m => m.SelectedLeague, Model.LeagueList)
#Html.ValidationMessageFor(m => m.SelectedLeague)
</div>
<div>
#Html.LabelFor(m => m.SelectedLeagueDivision)
#Html.DropDownListFor(m => m.SelectedLeagueDivision, Model.LeagueDivisionList)
#Html.ValidationMessageFor(m => m.SelectedLeagueDivision)
</div>
<input type="submit" value="save" />
}
In view Model.LeagueList is null. It should not be null.
if edit view code like this(for example), Works well:
<body>
#using (Html.BeginForm())
{
List<SelectListItem> listItems = new List<SelectListItem>();
listItems.Add(new SelectListItem
{
Text = "Example1",
Value = "Example1"
});
listItems.Add(new SelectListItem
{
Text = "Example2",
Value = "Example2",
Selected = true
});
listItems.Add(new SelectListItem
{
Text = "Example3",
Value = "Example3"
});
<div>
#Html.LabelFor(m => m.Price)
#Html.TextBoxFor(m => m.Price)
#Html.ValidationMessageFor(m => m.Price)
</div>
<div>
#Html.LabelFor(m => m.SelectedLeague)
#Html.DropDownListFor(m => m.SelectedLeague, listItems)
#Html.ValidationMessageFor(m => m.SelectedLeague)
</div>
<div>
#Html.LabelFor(m => m.SelectedLeagueDivision)
#Html.DropDownListFor(m => m.SelectedLeagueDivision, Model.LeagueDivisionList)
#Html.ValidationMessageFor(m => m.SelectedLeagueDivision)
</div>
<input type="submit" value="save" />
}

Binding complex model and DropDownListFor

My entities:
public class Meal
{
[HiddenInput(DisplayValue = false)]
public int Id { get; set; }
[Required(ErrorMessage = "Proszę podać nazwę posiłku")]
public string Name { get; set; }
[Required(ErrorMessage = "Proszę podać ilość białka")]
[Range(0.00, double.MaxValue, ErrorMessage = "Proszę podać dodatnią ilość.")]
public double Protein { get; set; }
[Required(ErrorMessage = "Proszę podać ilość węglowodanów")]
[Range(0.00, double.MaxValue, ErrorMessage = "Proszę podać dodatnią ilość.")]
public double Carbohydrates { get; set; }
[Required(ErrorMessage = "Proszę podać ilość tłuszczy")]
[Range(0.00, double.MaxValue, ErrorMessage = "Proszę podać dodatnią ilość.")]
public double Fat { get; set; }
[Required(ErrorMessage = "Proszę podać ilość kalorii")]
[Range(0.00, double.MaxValue, ErrorMessage = "Proszę podać dodatnią ilość.")]
public double Calories { get; set; }
}
public class EatenMeal
{
public int Id { get; set; }
public virtual Meal Meal { get; set; }
public virtual MealType MealType { get; set; }
public double Serving { get; set; }
public string Username { get; set; }
public DateTime Date { get; set; }
}
public class MealType
{
public int Id { get; set; }
public string Name { get; set; }
}
In MealController's view MealList which displays meals from datebase. And there is a button "Add" which refers to action AddEatenMeal in EatenMealController.
public ActionResult AddEatenMeal(int id)
{
var meal = mealRepository.GetMeal(id);
EatenMeal eatenMeal = new EatenMeal() { Meal = meal, Username = User.Identity.Name };
return View(eatenMeal);
}
[HttpPost]
public ActionResult AddEatenMeal(EatenMeal eatenMeal)
{
if(ModelState.IsValid)
{
eatenMealRepository.AddEatenMeal(eatenMeal);
RedirectToAction("Index", "Home");
}
return RedirectToAction("Index", "Home");
}
I am creating there object EatenMeal and partially initializing this object. Then I am passing this object to View to further initializing.
#model Domain.Entities.EatenMeal
#{
ViewBag.Title = "Dodawanie posiłku do dziennika";
}
#using (Html.BeginForm("AddEatenMeal","EatenMeal", FormMethod.Post, new {#class = "form"}))
{
#Html.HiddenFor(x => x.Meal.Name)
#Html.HiddenFor(x => x.Username)
#Html.HiddenFor(x => x.Meal.Calories)
#Html.HiddenFor(x => x.Meal.Carbohydrates)
#Html.HiddenFor(x => x.Meal.Fat)
#Html.HiddenFor(x => x..Meal.Protein)
#Html.HiddenFor(x => x.Meal.Id)
#Html.HiddenFor(x=>x.Username)
<div class="form-group">
#Html.Label("Nazwa posiłku")
#Html.Label(Model.Meal.Name, new { #class = "form-control" })
</div>
<div class="form-group">
#Html.Label("Porcja (g)")
#Html.TextBoxFor(x => x.Serving, new { #class = "form-control" })
</div>
<div class="form-group">
#Html.Label("Typ posiłku")
#Html.DropDownListFor(x=>x.MealType)????
</div>
<div class="form-group">
#Html.Label("Data spożycia")
#Html.TextBoxFor(x => x.Date, new { #class = "form-control", #id="date-eaten", #Value=DateTime.Today.ToShortDateString()})
</div>
<input type="submit" class="btn btn-info" value="Dodaj" />
}
Now I have a question. Is it correct to hiding fields? I don't know how I can save data from first controller to second in other way.
And is a second question. How I can make DropDownListFor for property MealTye in EatenMeal?
Rather than sending and receiving a whole lot of unused data across the wire and opening yourself to over posting attack, create a view model that represents what you want to display and edit. See What is a view model in MVC?
View model
public class EatenMealVM
{
public int MealID { get; set; }
[Display(Name="Nazwa posiłku")]
public string MealName { get; set; }
[Display(Name = "Typ posiłku")]
[Required(ErrorMessage = "Please select a meal")]
public int? MealTypeID { get; set; }
[Display(Name = "Porcja (g)")]
public double Serving { get; set; } // is this really double?
[Display(Name = "Data spożycia")]
[DataType(DataType.Date)]
public DateTime Date { get; set; }
public SelectList MealTypeList { get; set; }
}
Controller
public ActionResult AddEatenMeal(int id)
{
var meal = mealRepository.GetMeal(id);
var mealTypes = // get the list of meal types from the database
EatenMealVM model = new EatenMealVM()
{
MealID = meal.Id,
MealName = meal.Name,
MealTypeList = new SelectList(mealTypes, "ID", "Name")
};
return View(model);
}
View
#model EatenMealVM
....
#using (Html.BeginForm())
{
#Html.HiddenFor(m => m.MealID)
#Html.DisplayNameFor(m => m.MealName)
#Html.DisplayFor(m => m.MealName)
#Html.LabelFor(m => m.MealTypeID)
#Html.DropDownListFor(m => m.MealTypeID, Model.MealTypeList, "--Please select--")
#Html.ValidationMessageFor(m => m.MealTypeID)
#Html.LabelFor(m => m.Serving)
#Html.TextBoxFor(m => m.Serving, new { #class = "form-control")
#Html.ValidationMessageFor(m => m.Serving)
#Html.LabelFor(m => m.Date)
#Html.TextBoxFor(m => m.Date)
#Html.ValidationMessageFor(m => m.Date, new { #class = "form-control" })
<input type="submit" class="btn btn-info" value="Dodaj" />
}
Post method
[HttpPost]
public ActionResult AddEatenMeal(EatenMealVM model)
{
if (!ModelState.IsValid)
{
var mealTypes = // get the list of meal types from the database
model.MealTypeList = new SelectList(mealTypes, "ID", "Name");
return View(model);
}
// Initialize new EatenMeal class
// Map properties from view model (including setting user name)
// Save and redirect
}
Note also the use of [Display] attribute and #Html.LabelFor(). Currently you not creating 'real' labels (they are not associated with the corresponding control)

The data has been cleared after post

I have edit page and controller that creates new model object and fills some data from db into this object then send a model object to view. When I click the submit button, some fields in this object have been cleared.
For example:
Before:
user_id
name
birth_date
username
password
id_role
email
After (Fields that are not null or empty):
name
username
birth_date
The model:
public partial class Users
{
public Users()
{
this.Albums = new HashSet<Albums>();
this.History = new HashSet<History>();
this.Country = new HashSet<Country>();
this.Artists = new HashSet<Artists>();
this.SelectedCountries = new List<string>();
}
[DisplayName("User ID")]
public System.Guid user_id { get; set; }
[DisplayName("Name")]
public string name { get; set; }
[DisplayName("Birth date")]
public Nullable<System.DateTime> birth_date { get; set; }
[DisplayName("Username")]
public string username { get; set; }
[DisplayName("Password")]
public string password { get; set; }
[DisplayName("Rights")]
public System.Guid id_role { get; set; }
[DisplayName("User Email")]
public string email { get; set; }
public bool isRemember { get; set; }
public virtual ICollection<Albums> Albums { get; set; }
public virtual ICollection<History> History { get; set; }
public virtual Role Role { get; set; }
public virtual ICollection<Country> Country { get; set; }
public virtual ICollection<Artists> Artists { get; set; }
public virtual List<string> SelectedCountries { get; set; }
}
Edit method:
public ActionResult Edit()
{
if (HttpContext.User.Identity.IsAuthenticated)
{
var userName = HttpContext.User.Identity.Name;
var user = db.Users.Where(x => x.username == userName).FirstOrDefault();
ViewBag.Countries = new MultiSelectList(db.Country, "id_country", "name", user.SelectedCountries);
return View(user);
}
return HttpNotFound();
}
Edit method for handling post request:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(Users users)
{
if (ModelState.IsValid)
{
foreach (var country in users.SelectedCountries)
{
var dbCountry = db.Country.Find(new Guid(country));
if (dbCountry != null)
users.Country.Add(dbCountry);
}
db.Entry(users).State = System.Data.Entity.EntityState.Modified;
//There handle of string array goes
db.SaveChanges();
return RedirectToAction("Index");
}
return View(users);
}
View:
<h2>Edit</h2>
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>Users</legend>
<div class="editor-label">
#Html.LabelFor(model => model.name)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.name)
#Html.ValidationMessageFor(model => model.name)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.birth_date)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.birth_date)
#Html.ValidationMessageFor(model => model.birth_date)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.username)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.username)
#Html.ValidationMessageFor(model => model.username)
</div>
<div class="editor-label">
#Html.Label("Country")
</div>
<div class="editor-field">
#Html.DropDownList("SelectedCountries", (ViewBag.Countries as MultiSelectList), new { multiple = "multiple", #class = "chosen", style = "width: 350px;"})
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
Thanks in advance :)
You will only receive values that are in your form. Http is stateless..
What you need to do.. is create a ViewModel. That ViewModel is the subset of properties from your domain model that are displayed in the view. Like this:
public class UserViewModel {
public string Name { get; set; }
public string Username { get; set; }
public DateTime? DateofBirth { get; set; }
}
Use this model in your view. Then, in your controller.. get the user and update the appropriate fields:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(UserViewModel viewModel) {
var user = db.Users.Where(x => x.username == viewModel.Username).FirstOrDefault();
user.Name = viewModel.Name;
user.Username = viewModel.Username;
// .. etc.
db.SaveChanges();
}
If you are worried about all of the manual mapping involved in this, there exists frameworks to help you with that:
Automapper
ValueInjector
You are heading down a very very daunting path if you start adding hidden fields into your view. Its a maintenance nightmare and very error prone.
The post operation only collects the values you have in the form.
If you want the other values to proceed in your controllers post-method, you can for example, add hidden fields.
#Html.HiddenFor(x => x.HiddenPostBack)

MVC client-side validation for multiple models

I have three models: VehicleType, VehicleModel, and VehicleManufacturer.
Both VehicleType and VehicleManufacturer point to VehicleModel in the model, like so:
public class VehicleModel
{
[Key]
public int ModelId { get; set; }
[Required(ErrorMessage = "Field is Required")]
public int TypeId { get; set; }
[Required(ErrorMessage = "Field is Required")]
public int ManufacturerId { get; set; }
public string ModelName { get; set; }
public VehicleType VehicleType { get; set; }
public VehicleManufacturer Manufacturer { get; set; }
}
From there, VehicleModel points to the InventoryModel:
public class Inventory
{
[Key]
public int InventoryId { get; set; }
public int Price { get; set; }
public int Mileage { get; set; }
public int Year { get; set; }
public int ModelId { get; set; }
public VehicleModel VehicleModel { get; set; }
}
My problem is when I try to get client-side validation working on all three dropdownlists (VehicleType, VehicleManufacturer, VehicleModel), it only works with VehicleModel.
What needs to be done to validate these two dropdownlists using these models?
Here is my controller (fyi):
// GET: /Inventory/Create
public ActionResult Create()
{
ViewBag.TypeId = new SelectList(db.Types, "TypeId", "TypeName"); //(Object List, Value Field (usually Id), Column)
ViewBag.ModelId = new SelectList(db.Models, "ModelId", "ModelName"); //(Object List, Value Field (usually Id), Column)
ViewBag.ManufacturerId = new SelectList(db.Manufacturers, "ManufacturerId", "ManufacturerName"); //(Object List, Value Field (usually Id), Column)
return View();
}
// POST: /Inventory/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(Inventory inventory, VehicleManufacturer VehicleManufacturer, VehicleType VehicleType)
{
if (ModelState.IsValid)
{
db.Inventorys.Add(inventory);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.TypeId = new SelectList(db.Types, "TypeId", "TypeName");
ViewBag.ModelId = new SelectList(db.Models, "ModelId", "ModelName");
ViewBag.ManufacturerId = new SelectList(db.Manufacturers, "ManufacturerId", "ManufacturerName");
return View(inventory);
}
View:
<div class="editor-label">
#Html.LabelFor(model => model.VehicleModel.TypeId, "Some name for column")
</div>
<div class="editor-field">
#Html.DropDownList("TypeId", String.Empty)
#Html.ValidationMessageFor(model => model.VehicleModel.TypeId)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.ModelId, "Some name for column")
</div>
<div class="editor-field">
#Html.DropDownList("ModelId", String.Empty)
#Html.ValidationMessageFor(model => model.ModelId)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.VehicleModel.ManufacturerId, "Some name for column")
</div>
<div class="editor-field">
#Html.DropDownList("ManufacturerId", String.Empty)
#Html.ValidationMessageFor(model => model.VehicleModel.ManufacturerId)
</div>
Please someone help. I've been on this for many, many hours!
There are actually two problems That I see above
1) That you're not mapping the DropDownList and the ValidationMessageFor to the same model attribute.
#Html.ValidationMessageFor(model => model.VehicleModel.ManufacturerId)
The above is binding it to VehicleModel_ManufacturerId where as:
#Html.DropDownList("ManufacturerId", String.Empty)
the above is mapping the DropDown to just ManufacturerId
You need to change one or the other to match each other.
2) In the above code, I don't see any Validation Attributes. did you forgot them when you copied the code over here?
Hope this helps, Let me know if you needed more details.

MVC4 Validation DataAnnotations not working (not validating)

I have a pretty complex model and a view (below). I only have ONE of my fields as Required (Key Active Mg). When I mark this [Required(ErrorMessage="Key Active Mg is required")] and set the #Html.ValidationMessageFor for that field, my app will let me enter nothing and click Save. Of course, Model.IsValid will return false. It doesn't come back and outline the field in red indicating it's required. Does anyone know why?
My model:
public class RawValues
{
[Key]
public int Pk { get; set; }
public int? FillerFk { get; set; }
[Display(Name = "Filler")]
[ForeignKey("FillerFk")]
public virtual Filler Filler { get; set; }
public int? CapsuleFk { get; set; }
[Display(Name = "Capsule")]
[ForeignKey("CapsuleFk")]
public virtual Capsule Capsule { get; set; }
public int? KeyActiveFk { get; set; }
[Display(Name = "Key Active")]
[ForeignKey("KeyActiveFk")]
public virtual KeyActive KeyActive { get; set; }
[Display(Name="API #1")]
public int? Active1 { get; set; }
[Display(Name = "API #2")]
public int? Active2 { get; set; }
[Display(Name = "API #3")]
public int? Active3 { get; set; }
[Display(Name = "API #4")]
public int? Active4 { get; set; }
[Display(Name = "API #5")]
public int? Active5 { get; set; }
[Display(Name = "Key Active Mg")]
[Required(ErrorMessage="Key Active Mg is required.")]
public int KeyActiveMg { get; set; }
[Display(Name = "E4M")]
public bool E4M { get; set; }
[Display(Name = "K100M")]
public bool K100M { get; set; }
public int TimeReleaseFillerFk { get; set; }
public int NumberCapsules { get; set; }
public string CreatedBy { get; set; }
public DateTime CreatedDate { get; set; }
}
My View:
#model CapWorx.QuikCap.Models.RawValues
#* This partial view defines form fields that will appear when creating and editing entities *#
<div data-role="fieldcontain">
#Html.LabelFor(model => model.Capsule, new { #class = "ui-input-text" })
#Html.DropDownListFor(m => m.Capsule.Pk, new SelectList(ViewBag.Capsules, "Pk", "Name", "Pk"))
</div>
<div data-role="fieldcontain">
#Html.LabelFor(model => model.Active1)
#Html.EditorFor(model => model.Active1)
</div>
<div data-role="fieldcontain">
#Html.LabelFor(model => model.Active2)
#Html.EditorFor(model => model.Active2)
</div>
<div data-role="fieldcontain">
#Html.LabelFor(model => model.Active3)
#Html.EditorFor(model => model.Active3)
</div>
<div data-role="fieldcontain">
#Html.LabelFor(model => model.Active4)
#Html.EditorFor(model => model.Active4)
</div>
<div data-role="fieldcontain">
#Html.LabelFor(model => model.Active5)
#Html.EditorFor(model => model.Active5)
</div>
<div data-role="fieldcontain">
#Html.LabelFor(model => model.KeyActive, new { #class = "ui-input-text" })
#Html.DropDownListFor(m => m.KeyActive.Pk, new SelectList(ViewBag.KeyActives, "Pk", "Name", "Pk"))
</div>
<div data-role="fieldcontain">
#Html.LabelFor(model => model.KeyActiveMg)
#Html.EditorFor(model => model.KeyActiveMg)
#Html.ValidationMessageFor(model => model.KeyActiveMg)
</div>
<div data-role="fieldcontain">
#Html.LabelFor(model => model.E4M)
#Html.DropDownListFor(x => x.E4M,
new[] {
new SelectListItem() { Text = "Off", Value = "False", Selected = true },
new SelectListItem() { Text = "On", Value = "True" } },
new { data_role = "slider" })
</div>
<div data-role="fieldcontain">
#Html.LabelFor(model => model.K100M)
#Html.DropDownListFor(x => x.K100M,
new[] {
new SelectListItem() { Text = "Off", Value = "False", Selected = true },
new SelectListItem() { Text = "On", Value = "True" } },
new { data_role = "slider" })
</div>
<div data-role="fieldcontain">
#Html.LabelFor(model => model.Filler, new { #class = "ui-input-text" })
#Html.DropDownListFor(m => m.Filler.Pk, new SelectList(ViewBag.Fillers, "Pk", "Name", "Pk"))
#Html.ValidationMessage("FillerName", "Filler is required")
</div>
My Controller:
[HttpPost]
public ActionResult Create(RawValues rawvalues)
{
rawvalues.CreatedBy = User.Identity.Name;
rawvalues.CreatedDate = DateTime.Now;
rawvalues.TimeReleaseFillerFk = Helpers.OperationContext.GetTimeReleaseFillerFk(rawvalues.E4M, rawvalues.K100M);
rawvalues.CapsuleFk = rawvalues.Capsule.Pk;
rawvalues.FillerFk = rawvalues.Filler.Pk;
rawvalues.KeyActiveFk = rawvalues.KeyActive.Pk;
rawvalues.Filler = Helpers.OperationContext.GetFiller(rawvalues.Filler.Pk);
rawvalues.Capsule = Helpers.OperationContext.GetCapsule(rawvalues.Capsule.Pk);
rawvalues.KeyActive = Helpers.OperationContext.GetKeyActive(rawvalues.KeyActive.Pk);
rawvalues.NumberCapsules = 100;
var errors = ModelState.Values.SelectMany(v => v.Errors);
if (ModelState.IsValid) {
rawvaluesRepository.InsertOrUpdate(rawvalues);
rawvaluesRepository.Save();
List<Results> results = Helpers.OperationContext.CallCalculate(rawvalues);
return View("Results", results);
} else {
ViewBag.Error = "Model State was not valid.";
return View("Error");
}
}
My screenshot:
UPDATE
I've updated my controller code to be the following:
if (ModelState.IsValid) {
rawvaluesRepository.InsertOrUpdate(rawvalues);
rawvaluesRepository.Save();
List<Results> results = Helpers.OperationContext.CallCalculate(rawvalues);
return View("Results", results);
} else {
ViewBag.Capsules = Helpers.OperationContext.GetCapsules();
ViewBag.Fillers = Helpers.OperationContext.GetFillers();
ViewBag.KeyActives = Helpers.OperationContext.GetKeyActives();
return View();
}
This resolves my issue. I needed to return the same View to display the errors on the screen. With DataAnnotations Validation, the form does in fact hit the HttpPost method of Create, and if there are errors (validation errors) the ModelState.IsValid will return false, in which case I need to return the same view. See screenshot below!
Looks like you are returning another view (Error) if ModelState.IsValid is false. You should return the posted viewmodel to the same create view.
public ActionResult Create(RawValues model)
{
if(ModelState.IsValid)
{
//everything is good. Lets save and redirect
}
return View(model);
}
My guess is that you are not including 'jquery.unobtrusive-ajax.min.js' and/or 'jquery.validate.unobtrusive.min.js'. I believe these are required to interpret the metadata added by DataAnnotations and supply the validation methods your looking for.
When your model is invalid, you don't actually return it with it's validation errors. Then, you do this:
#Html.ValidationMessageFor(model => model.KeyActiveMg)
but there is no Validation Message for anything. You returned a brand new view with a blank Model. Instead, you should return your invalid model to the view, like such:
return View(rawvalues);
UPDATE
Your controller should look like this:
public ActionResult Create()
{
return View(new RawValues());
}
[HttpPost]
public ActionResult Create(RawValues model)
{
if (ModelState.IsValid)
{
// Do stuff
}
else
{
return View(model);
}
}
Your view seems fine, so it should work from here.
If you're talking about client side validation, you need to reference the necessary JS files. They should be already preconfigured in your Bundle config. You just need to add to your view:
#Scripts.Render("~/bundles/jquery")
#Scripts.Render("~/bundles/jqueryui")
#Scripts.Render("~/bundles/jqueryval")
Just to make sure, your BundleConfig class that sits in the App_Start folder should have these:
bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
"~/Scripts/jquery-{version}.js"));
bundles.Add(new ScriptBundle("~/bundles/jqueryui").Include(
"~/Scripts/jquery-ui-{version}.js"));
bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include(
"~/Scripts/jquery.unobtrusive*",
"~/Scripts/jquery.validate*"));
I think you need this
[HttpPost]
public ActionResultCreate(RawValues model)
{
....
if (!ModelState.IsValid)
{
ModelState.AddModelError("KeyActiveMg", "KeyActiveMg field is required");
var model = new GetModel();
return View("Results", model);
}
rawvaluesRepository.InsertOrUpdate(rawvalues);
rawvaluesRepository.Save();
List<Results> results = Helpers.OperationContext.CallCalculate(rawvalues);
return View("Results", results);
}

Categories

Resources