I am getting a 500 error when I post my AJAX form via clicking the submit button. The controller that handles the AJAX post is getting the data fine but when I return the Partial View, via this line, I am getting the 500:
return PartialView("_SiteSurveyNewClubTeam", model);
The reason I am returning the partial back instead of a HTTP status code is because if I don't, one of my dynamic dropdowns comes back unpopulated. Maybe I am pinting myself into a corner, here.
The data types supplied in the offending DropDownListFor() I believe are correct and in the right order: (string, IList<SelectListItem>)
Error
The ViewData item that has the key 'DistrictSelected' is of type 'System.String'
but must be of type 'IEnumerable<SelectListItem>'.
View Model Declarations
public IList<SelectListItem> DistrictSelect { get; set; }
public string DistrictSelected { get; set; }
Source of the Error is this line in my View
<span class="formColumn2">#Html.DropDownListFor(model => model.DistrictSelected, Model.DistrictSelect)</span>
Not sure why I am getting this. Any ideas?
Thanks
Here is the code that processes the AJAX form post
[HttpPost]
public ActionResult ProcessFormANewClubTeam(FormANewClubTeamViewModel model)
{
var httpStatus = HttpStatusCode.BadRequest;
var cosponsors = new List<NewClubSponsor>();
var errorMessages = new StringBuilder();
var tasks = new NewClubBuilderTasks();
var clubKeyNumber = tasks.GetClubKeyNumber();
var masterCustomerId = tasks.GetMasterCustomerId();
bool exceptionRaised = false;
if (ModelState.IsValid)
{
if (model.NewClub_Id > 0)
{
//Load the entity to be partially-updated
NewClub newClub = db.NewClubs.Single(nc => nc.Id == model.NewClub_Id);
//Set the values for the fields to be updated
newClub.District = model.DistrictSelected;
newClub.Division = model.DivisionSelected;
newClub.Region = Utility.Personify.GetRegionFromDistrict(newClub.District);
newClub.ClubCounselorMasterCustomerId = model.ClubCounselorMasterCustomerId;
newClub.ClubCounselorContact = model.ClubCounselorContact;
newClub.ClubCounselorEmail = model.ClubCounselorEmail;
newClub.ClubCounselorPhone = model.ClubCounselorPhone;
newClub.DateUpdated = DateTime.Now;
try
{
//Execute the UPDATE
var dbResult = db.SaveChanges() > 0;
httpStatus = HttpStatusCode.OK;
}
catch (SqlException ex)
{
//Catch exceptions here
}
// return new HttpStatusCodeResult((int) httpStatus);
return PartialView("_SiteSurveyNewClubTeam", model);
} else {
var errors = ModelState
.Where(x => x.Value.Errors.Count > 0)
.Select(x => new {x.Key, x.Value.Errors})
.ToArray();
return new HttpStatusCodeResult((int) httpStatus);
}
}
You have to repopulate your select list items in your DistrictSelect list in the post action. Your viewmodel that was posted has DistrictSelect as null, this is why you are getting that exception when you render your partial.
Related
I am checking to see if a user has payment data associated with them and to display that data if so.
I've tried redefining 'paymentMessage' in various ways to no avail. I am getting the error that paymentMessage must have a value.
public ActionResult Index() {
string paymentMessage = (string)TempData["payment_result"];
PublicBasicDetailsViewModel viewModel = new PublicBasicDetailsViewModel();
viewModel.Patron = Datasource.GetPatron(CurrentUser.PatronId.Value);
viewModel.Transactions = Datasource.GetPatronTransactionList(viewModel.Patron.PatronID);
viewModel.IsFirstLogin = CurrentUser.IsFirstLogin;
if (CurrentUser.IsFirstLogin) {
string userIdent = HttpContext.User.Identity.GetUserId();
Datasource.SetFirstLogin(userIdent);
}
if (paymentMessage == null) {
viewModel.HasPaymentResult = false;
return View(viewModel);
}
else if (paymentMessage == "SUCCESS") {
viewModel.HasPaymentResult = true;
return View(viewModel);
}
else {
viewModel.HasPaymentResult = true;
viewModel.Errors = paymentMessage;
return View(viewModel);
}
}
This is the error message appearing when I log in as a user
Exception Details: System.InvalidOperationException: Nullable object
must have a value.
Source Error: Line 57: string paymentMessage =
(string)TempData["payment_result"];
Tempdata has a lifetime of two actions.
https://www.codeproject.com/Tips/827059/Data-Passing-Mechanism-in-MVC-Architecture
The problem is basically the Save changes method is not working (updating), the method should receive 3 parameters, item id, user id and the object which contains the updated information from the UI, however the code seems to be something bad because the saveChanges() method is not working.
This is my code:
[HttpPost]
[AllowAnonymous]
public JsonResult UpdatePersonalData(int ItemId, int UserId, CND_PersonalData Item)
{
try
{
if (ModelState.IsValid)
{
using (var context = new DexusEntities())
{
CND_PersonalData PersonalData = context.CND_PersonalData.Where(d => d.Id == ItemId && d.UserId == UserId).SingleOrDefault();
if (PersonalData == null)
{
/// Display bad request
/// User does not exist and/or is not activated
List<RootObject> rootObj = new List<RootObject>();
rootObj.Add(new RootObject
{
msg = "User/Item not found in our DB",
code = "error_07"
});
HttpContext.Response.StatusCode = 404;
HttpContext.Response.TrySkipIisCustomErrors = true;
JsonRes.Message = rootObj;
return Json(JsonRes, JsonRequestBehavior.AllowGet);
}
else
{
PersonalData = Item;
context.SaveChanges();
context.ChangeTracker.DetectChanges();
List<RootObject> rootObj = new List<RootObject>();
rootObj.Add(new RootObject
{
msg = "Information stored/updated successfully",
code = "success_05"
});
HttpContext.Response.StatusCode = 200;
JsonRes.Message = rootObj;
return Json(JsonRes, JsonRequestBehavior.AllowGet);
}
}
}
else
{
List<RootObject> rootObj = new List<RootObject>();
JsonRes.Issue = "The model is not correct";
rootObj.Add(new RootObject
{
msg = "Model is not valid",
code = "error_03"
});
HttpContext.Response.StatusCode = 403;
HttpContext.Response.TrySkipIisCustomErrors = true;// Avoid issues in the HTTP methods
JsonRes.Message = rootObj;
return Json(JsonRes, JsonRequestBehavior.AllowGet);
}
}
catch (Exception ex)
{
string err = ex.ToString();
List<RootObject> rootObj = new List<RootObject>();
JsonRes.Issue = err;
rootObj.Add(new RootObject
{
msg = "Conflict with method, see issue description.",
code = "error_08"
});
HttpContext.Response.StatusCode = 400;// Bad request
HttpContext.Response.TrySkipIisCustomErrors = true;
JsonRes.Message = rootObj;
return Json(JsonRes, JsonRequestBehavior.AllowGet);
}
}
What's wrong with my code?
Thanks in advance.
As I can see you are not adding an item into the DbSet and calling SaveChanges after:
When adding an item you should put it into DbSet
context.CND_PersonalData.Add(item);
context.SaveChanges();
when you want to update just call SaveChanges after you update loaded object
var PersonalData= context.CND_PersonalData.Where(d => d.Id == ItemId && d.UserId == UserId).SingleOrDefault();
PersonalData.Name = item.Name;
PersonalData.Title = item.Title;
context.SaveChanges();
You can't just assign passed object to an entity you got from the DB, you need to change properties. If you do it as you did you didn't change values in the loaded object. So when you call SaveChanges nothing is changed. You need to change properties one by one.
If you don't want to do that then you can attach your item into the db by using Attach method on context.
context.Attach(item);
context.SaveChanges();
but you should be careful because if you load and track item with the same id as you are doing before checking if it is null:
CND_PersonalData PersonalData = context.CND_PersonalData.Where(d => d.Id == ItemId && d.UserId == UserId).SingleOrDefault();
if (PersonalData == null)
{
then you will get an error during the save because the context is already tracking item with the same ID, so you can remove that check and just check if it exists:
if (context.CND_PersonalData.Any(d => d.Id == ItemId && d.UserId == UserId))
{
and then execute your code
I'm creating an application that books Guests in hotelrooms. In the HttpGet I pass a ReservationViewModel from my Controller to the View. This VM contains all the reservationdetails and 2 empty Guest objects (or however many). For each Guest object I show a form where the user needs to enter information about the Guest. However when I try to submit it only returns the info of one Guest. I've tried looking for a way to pass an array or multiple guests, but that doesn't seem to be possible, only sending one Guest object with parameters seems to work..
Here is the code for my GET:
[HttpGet]
public ActionResult Edit2(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Reservation reservation = resRepo.GetReservationByID(id);
ReservationVM reservationVM = new ReservationVM(0);
for (int i = 0; i < reservation.amount_people; i++)
{
reservationVM.guests.Add(new Guest());
}
foreach(Guest guest in reservationVM.guests)
{
guest.name = " ";
guest.zipcode = " ";
guest.housenumber = 0;
guest.suffix = "";
guest.email = " ";
guestRepo.AddGuest(guest);
}
guestRepo.Save();
reservationVM.date = (DateTime)reservation.date;
reservationVM.amount_people = (int)reservation.amount_people;
reservationVM.ID = reservation.ID;
reservationVM.room_ID = (int)reservation.room_ID;
if (reservation == null)
{
return HttpNotFound();
}
return View(reservationVM);
}
And my POST:
[HttpPost]
public ActionResult Edit2([Bind(Include = "room_ID,date,amount_people,ID")]Reservation reservation, [Bind(Include = "ID,name,zipcode,housenumber,suffix,email")]Guest guest)
{
if (ModelState.IsValid)
{
resRepo.UpdateReservation(reservation);
resRepo.Save();
guestRepo.UpdateGuest(guest);
guestRepo.Save();
Reservation r = new Reservation { ID = reservation.ID };
db.Reservations.Add(r);
db.Reservations.Attach(r);
Guest g = new Guest { ID = guest.ID };
db.Guests.Add(g);
db.Guests.Attach(g);
r.Guests.Add(g);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(reservation);
}
and my form for completion:
Form
Now I was wondering how to pass all the forminfo to my Controller and use that information to save the Reservation and each Guest, so I can write that to my db.
Thanks!
EDIT: I tried the solution given, but I can't seem to get the Guest information in my database. Problem seems to be that when it reaches the foreach loop to get the guests out of reservationVM it's empty. Tried writing to Debug output whenever it entered the loop but it never does. Here's my code
[HttpPost]
public ActionResult Edit2(ReservationVM reservationVM)
{
if (ModelState.IsValid)
{
//Get reservation
Reservation reservation = resRepo.GetReservationByID(reservationVM.ID);
//Update values in model
reservation.date = reservationVM.date;
reservation.amount_people = reservationVM.amount_people;
reservation.ID = reservationVM.ID;
reservation.room_ID = reservationVM.room_ID;
//Update to DB and save changes
resRepo.UpdateReservation(reservation);
resRepo.Save();
foreach (Guest guest in reservationVM.guests)
{
Guest temp = guestRepo.GetGuestByID(guest.ID);
temp.name = guest.name;
temp.zipcode = guest.zipcode;
temp.housenumber = guest.housenumber;
temp.suffix = guest.suffix;
temp.email = guest.email;
temp.ID = guest.ID;
guestRepo.UpdateGuest(temp);
reservation.Guests.Add(temp);
}
guestRepo.Save();
//Reservation r = new Reservation { ID = reservation.ID };
//db.Reservations.Add(r);
//db.Reservations.Attach(r);
//Guest g = new Guest { ID = guest.ID };
//db.Guests.Add(g);
//db.Guests.Attach(g);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(reservationVM);
}
You are passing ReservationVM from view to the post method. So write your post method as follows:
[HttpPost]
public ActionResult Edit2(ReservationVM reservationVM)
{
if (ModelState.IsValid)
{
// Here access the necessary values you need from `reservationVM` and do your necessary stuffs
return RedirectToAction("Index");
}
return View(reservation);
}
To get your guest information in you post action, you need to make the guest fields as follow:
#for(var i = 0; i < Model.guests.count; i++)
{
Your editor will be like below
#Html.EditorFor(model => model.guests[i].ID)
#Html.EditorFor(model => model.guests[i].name)
}
try making the fields in razor view like the above code .. it’ll work.
well i m having 2 hyperlinks :
Fr
|
Ang
in my controller i used this to change the current langage
[HttpPost]
public ActionResult Fr()
{
ContentModelView CMV = new ContentModelView();
//Langue:
int CurrentLanguageid = db.Langues.FirstOrDefault(x => x.active_langue == "true").id_langue;
Langues LangueA = db.Langues.Find(CurrentLanguageid);
LangueA.active_langue = "false";
db.SaveChanges();
int NextLanguage = db.Langues.FirstOrDefault(x => x.txt_langue == "fr").id_langue;
Langues LangueB = db.Langues.Find(CurrentLanguageid);
LangueB.active_langue = "true";
db.SaveChanges();
return (RedirectToAction("../Home/Index"));
}
[HttpPost]
public ActionResult Ang()
{
ContentModelView CMV = new ContentModelView();
//Langue:
int CurrentLanguageid = db.Langues.FirstOrDefault(x => x.active_langue == "true").id_langue;
Langues LangueA = db.Langues.Find(CurrentLanguageid);
LangueA.active_langue = "false";
db.SaveChanges();
int NextLanguage = db.Langues.FirstOrDefault(x => x.txt_langue == "en").id_langue;
Langues LangueB = db.Langues.Find(CurrentLanguageid);
LangueB.active_langue = "true";
db.SaveChanges();
return (RedirectToAction("../Home/Index"));
}
but i don t know if i m obliged to use a parametre in my methode because it s an httpost and it send me to /Home/Fr not the index even after forcing the method no change in database i m struggling with this problem
Clicking on the link element(anchor tag) will issue a GET request.Your action methods are marked with HttpPost and it will not be hit from your GET action request generated by clicking in the link. You have 2 options
Change remove the [HttpPost] decorator from the action method
Hijack the click event on the link and make an http post ajax call.
Also i notice that you have duplicate code in the two methods except the language code you use in your where clause. Why not use a single method with a parameter where you can pass the language code ?
public ActionResult UpdateLanguage(string id)
{
//This is your existing code. I did not verify the correctness of this!
var CMV = new ContentModelView();
//Langue:
int CurrentLanguageid = db.Langues.FirstOrDefault(x => x.active_langue == "true")
.id_langue;
Langues LangueA = db.Langues.Find(CurrentLanguageid);
LangueA.active_langue = "false";
db.SaveChanges();
int NextLanguage = db.Langues.FirstOrDefault(x => x.txt_langue == id).id_langue;
Langues LangueB = db.Langues.Find(CurrentLanguageid);
LangueB.active_langue = "true";
db.SaveChanges();
if(Request.IsAjaxRequest())
return Json(new { status="success"},JsonRequestBehavior.AllowGet);
return RedirectToAction("Index","Home");
}
Now, to make the ajax call, you may simply add a css class to the links
<a class="languageLink" href="#Url.Action("UpdateLanguage", "Home",new {id="fr"})">Fr</a>
<a class="languageLink" href="#Url.Action("UpdateLanguage", "Home",new {id="en"})">En</a>
Now the js code to hijack the link click event and make an ajax call
$(function(){
$("a.languageLink").click(function(){
$.post($(this).attr("href"),function(data){
window.location.href="#Url.Action("Index","Home")";
});
});
});
I have a form where the user can edit their user account information and then save the new changes.
The problem I'm getting happens when I save the modified changes to the database.
On the line context.SaveChanges(), I get a DbUpdateConcurrencyException exception thrown. It says, "Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. Refresh ObjectStateManager entries."
I have no idea why.
Here's what I have done:
public ActionResult EditUserAccount()
{
UserAccountViewModel editUserAccountViewModel = new UserAccountViewModel();
editUserAccountViewModel.UserName = UserSession.GetValue(StateNameEnum.UserName, StateNameEnum.UserName.ToString()) as string;
int UserId = WebSecurity.GetUserId(editUserAccountViewModel.UserName);
var userInfo = context.db_user.First(x => x.UserId == UserId);
editUserAccountViewModel.Title = userInfo.Title;
editUserAccountViewModel.FirstName = userInfo.FirstName;
editUserAccountViewModel.LastName = userInfo.LastName;
editUserAccountViewModel.PhoneNumber = userInfo.PhoneNumber;
editUserAccountViewModel.AltPhoneNumber = userInfo.AltPhoneNumber;
editUserAccountViewModel.EmailAddress = userInfo.EmailAddress;
editUserAccountViewModel.UserAccountState = UserAccountViewModel.AccountState.EDIT;
return (PartialView("~/Views/Account/UserAccount.cshtml", editUserAccountViewModel));
}
[HttpPost]
public ActionResult EditUserAccount_Save(UserAccountViewModel editUserAccountViewModel)
{
try
{
if (ModelState.IsValid)
{
editUserAccountViewModel.UserName = UserSession.GetValue(StateNameEnum.UserName, StateNameEnum.UserName.ToString()) as string;
db_user user = new db_user();
user.Title = editUserAccountViewModel.Title;
user.FirstName = editUserAccountViewModel.FirstName;
user.LastName = editUserAccountViewModel.LastName;
user.PhoneNumber = editUserAccountViewModel.PhoneNumber;
user.AltPhoneNumber = editUserAccountViewModel.AltPhoneNumber;
user.EmailAddress = editUserAccountViewModel.EmailAddress;
user.LanguageId = context.languages.Where(t => t.Code == editUserAccountViewModel.Language).Select(t => t.Id).SingleOrDefault();
user.CreatedDate = DateTime.Now;
user.UserId = WebSecurity.GetUserId(editUserAccountViewModel.UserName);
context.Entry(user).State = EntityState.Modified;
context.SaveChanges();
JsonResult res = Json(new { Success = true, data = "", Message = "" });
return res;
}
else
{
JsonResult res2 = Json(new { Success = false, data = "", Message = "" });
return res2;
}
}
return null;
}
You are not creating an instance of context within the controller action, which would imply that it is at the class level. That means that context is shared with every other web request processed by that controller. This part of the error message Entities may have been modified or deleted since entities were loaded seems to confirm that hypothesis.
Instead, create an instance of context in your controller action.
Since you are editing an existing user in this action, you will first need to load the existing user into the context from the database, rather than instantiating a new one as you are now.
I strongly suspect that this change will resolve your issue.
UPDATE
Here's a code example. I don't know what your context class is called, so you might have to change that part. I assume that the user must already exist when this controller is called (based on the name of the method). I removed the try because you are not catching anything. If there is something useful you can do when an exception is thrown, go ahead and put that back in.
[HttpPost]
public ActionResult EditUserAccount_Save(UserAccountViewModel editUserAccountViewModel)
{
if (ModelState.IsValid)
{
using (MyContext context = new MyContext())
{
int userId = WebSecurity.GetUserId(editUserAccountViewModel.UserName);
db_user user = context.DbUsers.Where(u => u.Id == userId).Single();
editUserAccountViewModel.UserName = UserSession.GetValue(StateNameEnum.UserName, StateNameEnum.UserName.ToString()) as string;
user.Title = editUserAccountViewModel.Title;
user.FirstName = editUserAccountViewModel.FirstName;
user.LastName = editUserAccountViewModel.LastName;
user.PhoneNumber = editUserAccountViewModel.PhoneNumber;
user.AltPhoneNumber = editUserAccountViewModel.AltPhoneNumber;
user.EmailAddress = editUserAccountViewModel.EmailAddress;
user.LanguageId = context.languages.Where(t => t.Code == editUserAccountViewModel.Language).Select(t => t.Id).SingleOrDefault();
user.CreatedDate = DateTime.Now;
context.SaveChanges();
JsonResult res = Json(new { Success = true, data = "", Message = "" });
return res;
}
}
else
{
JsonResult res2 = Json(new { Success = false, data = "", Message = "" });
return res2;
}
}