Saving forms in mvc - asp.net-mvc

I'm completely new to MVC having made the decision to try make the switch from aspx WebForms.
I have created a view using the MVC view creator wizard and selected a strongly typed class and an edit Scaffold template.
I got the following
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>Company</legend>
#Html.HiddenFor(model => model.Id)
<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.PhoneNumber)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.PhoneNumber)
#Html.ValidationMessageFor(model => model.PhoneNumber)
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
In the Controller I have the following to get the model details
[System.Web.Http.HttpGet]
public ActionResult Edit(int id)
{
var uow = new BlogUow();
var company = uow.Companies.GetById(id);
return View(company);
}
This works fine but the problem is, I'm stumped on how I actually save the newly entered details.
I relied too much on how the web forms handle post backs.

You must write a post action for your edit in the controller:
[System.Web.Http.HttpPost]
public ActionResult Edit(Companies company)
{
var uow = new BlogUow();
if (ModelState.IsValid)
{
uow.Entry(company).State = EntityState.Modified;
return RedirectToAction("Index");
}
return View(company);
}

note Companies overload
[HttpPost]
public ActionResult Edit(Companies company)
{
var uow = new BlogUow();
if (ModelState.IsValid)
{
Edit here
}
return View(company);
}

Related

Form submit using partail View error

I have created a form for add comment. I have created it in main View called Index in Home controller. bellow is Index View
private projectDBEntities db = new projectDBEntities();
public ActionResult Index()
{
ViewBag.Message = "Modify this template to jump-start your ASP.NET MVC application.";
return View();
}
public ActionResult AddComment()
{
return PartialView("_Comment");
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult AddComment(comment cmt)
{
if (ModelState.IsValid)
{
db.comments.Add(cmt);
db.SaveChanges();
return RedirectToAction("Index", "Home");
}
return PartialView("_Comment", cmt);
}
below is _Comment Partial View
#using (Html.BeginForm()) {#Html.AntiForgeryToken()#Html.ValidationSummary(true)
<fieldset>
<legend>comment</legend>
<div class="editor-label">
#Html.LabelFor(model => model.cmd_content)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.cmd_content)
#Html.ValidationMessageFor(model => model.cmd_content)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.t_email)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.t_email)
#Html.ValidationMessageFor(model => model.t_email)
</div>
<p>
<input type="submit" value="Comment" />
</p>
</fieldset>}
System.Web.HttpException was occuerd. I want to know What is the reason behind this error and what is the best method to form submit using partail View.
Id have to agree with Sandip's answer here, but to elaborate ..
#using (Html.BeginForm("AddComment", "Home"))
{
//Content to send to the server-side
}
As long as your model in your partial view points to your 'Comment' object, then this should work fine when using #Html.EditorFor(). In your controller, your already waiting for your 'Comment' object to be populated. So on Post, when the submit is clicked, it will populate that object.
Hope this helps.
#using (Html.BeginForm("AddComment", "Home"))
{
}

Why would Entity Framework carry out update when RowVersion has changed?

I'm having a problem trying to catch a DbUpdateConcurrencyException using Entity Framework 5. The problem that I'm having is that EF is updating the record, even though the RowVersion (Timestamp) property has changed since the row was retrieved from the database. The HttpGet Edit action gets a user profile from the database and I pass the values to a ViewModel, including a list of checkboxes for the user to select the roles and pass this to the view.
public ActionResult Edit(int id = 0)
{
UserProfile userProfile = unitOfWork.UserProfileRepository.GetUserProfileById(id);
UserProfileEditViewModel viewModel = new UserProfileEditViewModel
{
UserId = userProfile.UserId,
UserName = userProfile.UserName,
FirstName = userProfile.FirstName,
LastName = userProfile.LastName,
Email = userProfile.Email,
RowVersion = userProfile.RowVersion,
};
var allRoles = unitOfWork.RoleRepository.GetAllRoles();
var userProfileRoles = userProfile.Roles;
foreach (var role in allRoles)
{
if (userProfileRoles.Contains(role))
{
viewModel.Roles.Add(new RoleViewModel
{
RoleId = role.RoleId,
RoleName = role.RoleName,
Assigned = true,
});
}
else
{
viewModel.Roles.Add(new RoleViewModel
{
RoleId = role.RoleId,
RoleName = role.RoleName,
Assigned = false,
});
}
}
return View(viewModel);
}
I then have a basic edit view that has a HiddenFor for the RowVersion property.
#model MvcWebsite.ViewModels.UserProfileEditViewModel
#{
ViewBag.Title = "Edit";
}
<h2>Edit</h2>
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>UserProfile</legend>
#Html.HiddenFor(model => model.UserId)
#Html.HiddenFor(model => model.UserName)
#Html.HiddenFor(model => model.RowVersion)
<div class="editor-label">
#Html.LabelFor(model => model.UserName)
</div>
<div class="editor-field">
#Html.DisplayFor(model => model.UserName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.FirstName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.FirstName)
#Html.ValidationMessageFor(model => model.FirstName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.LastName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.LastName)
#Html.ValidationMessageFor(model => model.LastName)
</div>
<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-field">
<table>
<tr>
#Html.EditorFor(model => model.Roles)
#Html.ValidationMessageFor(model => model.Roles)
</tr>
</table>
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
I then have a HttpPost Edit action that takes the data from the viewModel and adds it to a user profile that I've retrieved from the database. I then change the properties of this profile to those that were retrieved from the client, including the RowVersion (changing the RowVersion back to its original state)
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(UserProfileEditViewModel model)
{
try
{
if (ModelState.IsValid)
{
var userProfile = unitOfWork.UserProfileRepository.GetUserProfileById(model.UserId);
userProfile.UserName = model.UserName;
userProfile.FirstName = model.FirstName;
userProfile.LastName = model.LastName;
userProfile.Email = model.Email;
userProfile.RowVersion = model.RowVersion;
var roleAssignments = model.Roles;
foreach (var roleAssignment in roleAssignments)
{
if (roleAssignment.Assigned)
{
userProfile.Roles.Add(unitOfWork.RoleRepository.GetRoleById(roleAssignment.RoleId));
}
else
{
userProfile.Roles.Remove(unitOfWork.RoleRepository.GetRoleById(roleAssignment.RoleId));
}
}
unitOfWork.UserProfileRepository.UpdateUserProfile(userProfile);
unitOfWork.Save();
return RedirectToAction("Details", new { id = userProfile.UserId });
}
}
catch (DbUpdateConcurrencyException ex)
{
... Code omitted for brevity
}
}
return View(model);
}
I test this by opening the edit page twice. I then update the second page and click save, which commits the changes to the database. The database shows that the row version has in fact been changed to reflect the update. When I change the second page and click save, even though the row version of this profile is different from the row version that was created when the first profile was saved, the changes are saved to the database also. I've checked that indeed, the row version in the database is actually changed twice.
I have a funny feeling that I'm missing the obvious here, but any help would be greatly appreciated.
typically you don't change the row version explicitly. this would be handled by the ORM itself. What you would do is compare the view model version to the domain version. if they do not match you then need to handle that scenario.
if(viewmodel.RowVersion != domainModel.RowVersion)
{
//model has changed, notify user...
}
else
{
//update domain model
//save changes
}
You could further prevent this by making RowVersion immutable
class domainmodel
{
...
public int RowVersion {get; private set;}
}

MVC4 Pass custom view Model back to Controller Action

I have a custom class
public class BloggerViewModel
{
public Person Blogger;
public List<BloggerWebsite> BloggerWebsites;
}
That I pass into a view
[HttpGet]
public ActionResult Edit(int id)
{
blogger = GetById(id);
var WebSites = GetBloggersWebsites(Id);
var BloggerViewModel = new BloggerViewModel();
BloggerViewModel.Blogger = blogger;
BloggerViewModel.BloggerWebsites = WebSites;
return View(BloggerViewModel);
}
Then when I post back to the edit action
[HttpPost]
public ActionResult Edit(BloggerViewModel entity)
{
return View(entity);
}
entity is null.
My view is something like this ( I took out allot of the code that you didn't need to see. Such as most of the text box bindings)
#model Bloginect.Model.Models.BloggerViewModel
<h2>Edit</h2>
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>Person</legend>
#Html.HiddenFor(model => model.Blogger.Id)
<div class="editor-label">
#Html.LabelFor(model => model.Blogger.FirstName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Blogger.FirstName)
#Html.ValidationMessageFor(model => model.Blogger.FirstName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Blogger.LastName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Blogger.LastName)
#Html.ValidationMessageFor(model => model.Blogger.LastName)
</div>
<div class="editor-field">
#if (Model.BloggerWebsites[0].Website != null)
{
Html.EditorFor(model => model.BloggerWebsites[0].Website);
}
else
{
#Html.TextBox("Website1")
}
</div>
<div class="editor-field">
#if (Model.BloggerWebsites[1].Website != null)
{
Html.EditorFor(model => model.BloggerWebsites[0].Website);
}
else
{
#Html.TextBox("Website2")
}
</div>
<div class="editor-field">
#if (Model.BloggerWebsites[2].Website != null)
{
Html.EditorFor(model => model.BloggerWebsites[0].Website);
}
else
{
#Html.TextBox("Website3")
}
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
Is there something I am doing wrong? I have checked out some of the other replies to similar questions on this and they did not answer my question.
You must use editors to handle the bindings to your nested model properties, a good example on how to do it can be found here.

adding new comment in database for a post

I am creating a forum application in mvc3...
I have a link called Add New Comment on Post page where user can add the comments for that post... for creating new comment i have written following code....
public ActionResult Addnew(int id)
{
Answer ans = new Answer();
ans.QuestionQId = id;
return View();
}
[HttpPost]
public ActionResult Addnew(Answer ans,int id)
{
_db.Answers.Add(ans);
_db.SaveChanges();
return View("Details");
}
but it is giving mean error whenever i try to save the code as follows:
Value cannot be null.
Parameter name: entity
I have two different table Question{id(pk), Question} and Answer{id(pk), ans, Qid(fk)}
All i want to do is While adding the comment for a perticular question, its Qid will be stored in answer database .....
Help me!!
View Related --
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
<fieldset>
<legend>Answer</legend>
<div class="editor-label">
#Html.LabelFor(model => model.AId)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.AId)
#Html.ValidationMessageFor(model => model.AId)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Ans)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Ans)
#Html.ValidationMessageFor(model => model.Ans)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.QuestionQId)
</div> <div class="display-field">
#Html.DisplayFor(modelItem => modelItem.QuestionQId)
</div>
}
I think you are not passing the Answer object to the view, may caused the problem. have you tried following
public ActionResult Addnew(int id)
{
Answer ans = new Answer();
ans.QuestionQId = id;
return View(ans);
}
is it in your route define parameter for your controller?
may be this is your problem!

How do I call submit in mvc app?

I have mvc3 web app.
inside that I have one Enquiry form once I submit that form it should save all data into database for that I have used Entity Framework.
EnquiryController.cs
public class EnquiryController : Controller
{
aspnetdbEntities dbEntities = new aspnetdbEntities();
//
// GET: /Enquiry/
public ActionResult Index()
{
return View();
}
//
// GET: /Enquiry/
public ActionResult Enquiry()
{
return View();
}
//
//POST: /Enquiry/
[HttpPost]
public ActionResult Enquiry(Enquiry enquiry)
{
if (ModelState.IsValid)
{
dbEntities.Enquiries.AddObject(enquiry);
dbEntities.SaveChanges();
return RedirectToAction("Index");
}
return View(enquiry);
}
}
Enquiry.cshtml
#model MyWeb.Models.Enquiry
#{
ViewBag.Title = "Enquiry";
}
<h2>Enquiry</h2>
<div>
<fieldset>
<legend>Enquiry Form</legend>
<div class="editor-label">
#Html.LabelFor(m => m.FirstName)
</div>
<div class="editor-field">
#Html.TextBoxFor(m => m.FirstName)
#Html.ValidationMessageFor(m => m.FirstName)
</div>
<div class="editor-label">
#Html.LabelFor(m => m.LastName)
</div>
<div class="editor-field">
#Html.TextBoxFor(m => m.LastName)
#Html.ValidationMessageFor(m => m.LastName)
</div>
<p>
<input type="submit" value="Submit" />
</p>
</fieldset>
</div>
But when I clicked on Submit button it is not working no round rip no refresh
please help me where i go wrong i'm newbie.
ashuthinks,
just add the htmlHelper (for forms) to your view:
#using(Html.BeginForm()){
// exisiting fieldset stuff
<fieldset>... bla</fieldset>
}
around your fieldset and you're good to go

Resources