Why is the object passed to Delete action empty? - asp.net-mvc-2

I've got a basic ASP.NET MVC 2 application. I've got adding and editing rows working just fine, but deleting won't work. The Delete view gets the correct record on the GET, but when posting back, the parameter that gets passed is empty, as in CategoryID = 0, all empty values. Because of that, no object is found to be deleted from the database and an exception is thrown. How can I get the correct Category to be passed to the HttpPost Delete action?
Here's what I've got in the controller:
public ActionResult Delete(int id)
{
return View(_categoryRespository.Get(id));
}
[HttpPost]
public ActionResult Delete(Category categoryToDelete)
{
try
{
_categoryRespository.Delete(categoryToDelete);
return RedirectToAction("Index");
}
catch
{
return View();
}
}
This is the Delete view, which as I said correctly displays the data on the GET:
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<MVCApp.Models.Category>" %>
<h2>Delete</h2>
<h3>Are you sure you want to delete this?</h3>
<fieldset>
<legend>Fields</legend>
<div class="display-label">CategoryID</div>
<div class="display-field"><%: Model.CategoryID %></div>
<div class="display-label">SectionName</div>
<div class="display-field"><%: Model.SectionName %></div>
<div class="display-label">CategoryName</div>
<div class="display-field"><%: Model.CategoryName %></div>
<div class="display-label">Content</div>
<div class="display-field"><%: Model.Content %></div>
</fieldset>
<% using (Html.BeginForm()) { %>
<p>
<input type="submit" value="Delete" /> |
<%: Html.ActionLink("Back to List", "Index") %>
</p>
<% } %>

Your form is not actually POSTing anything. You can add a hidden input with CategoryID, and then create a static Delete method in your repository that will accept CategoryID as a parameter (or instantiate a category by CategoryID and then call your existing Delete method).
Controller
public ActionResult Delete(int id)
{
return View(_categoryRespository.Get(id));
}
[HttpPost]
public ActionResult Delete(int categoryID)
{
try
{
_categoryRespository.Delete(categoryID);
return RedirectToAction("Index");
}
catch
{
return View();
}
}
View
<h2>Delete</h2>
<h3>Are you sure you want to delete this?</h3>
<fieldset>
<legend>Fields</legend>
<div class="display-label">CategoryID</div>
<div class="display-field"><%: Model.CategoryID %></div>
<div class="display-label">SectionName</div>
<div class="display-field"><%: Model.SectionName %></div>
<div class="display-label">CategoryName</div>
<div class="display-field"><%: Model.CategoryName %></div>
<div class="display-label">Content</div>
<div class="display-field"><%: Model.Content %></div>
</fieldset>
<% using (Html.BeginForm()) { %>
<p>
<input type="hidden" name="categoryID" value="<%: Model.CategoryID %>" />
<input type="submit" value="Delete" /> |
<%: Html.ActionLink("Back to List", "Index") %>
</p>
<% } %>

Related

asp.net-mvc2 - Strongly typed helpers not using Model?

When using strongly typed helpers in MVC2 the input field values aren't taken from the Model property when a post is made. Is this default behavior?
(strongly typed) view with strongly typed helpers:
<div class="editor-label">
<%: Html.LabelFor(model => model.Name) %>
</div>
<div class="editor-field">
<%: Html.TextBoxFor(model => model.Name) %>
<%: Html.ValidationMessageFor(model => model.Name) %>
</div>
<div class="editor-label">
<%: Html.LabelFor(model => model.Price) %>
</div>
<div class="editor-field">
<%: Html.TextBoxFor(model => model.Price) %>
<%: Html.ValidationMessageFor(model => model.Price) %>
</div>
Controller action for: /Product/Edit/5
public ActionResult Edit(int id)
{
var p = new Product();
p.Name = "product 1";
p.Price = "100";
return View(p);
}
Html output:
<div class="editor-label">
<label for="Name">Name</label>
</div>
<div class="editor-field">
<input id="Name" name="Name" type="text" value="product 1" />
</div>
<div class="editor-label">
<label for="Price">Price</label>
</div>
<div class="editor-field">
<input id="Price" name="Price" type="text" value="100" />
</div>
Controller action for: /Product/Edit/5
[HttpPost]
public ActionResult Edit(Product p)
{
p.Name = "prrrrrrd 2";
return View(p);
}
Html output after form post (below I would expect the value of the input with id="Name" to be "prrrrrrd 2. Where does the strongly typed helper get it's value from?):
<div class="editor-label">
<label for="Name">Name</label>
</div>
<div class="editor-field">
<input id="Name" name="Name" type="text" value="product 1" />
</div>
<div class="editor-label">
<label for="Price">Price</label>
</div>
<div class="editor-field">
<input id="Price" name="Price" type="text" value="100" />
</div>
When using strongly typed helpers in MVC2 the input field values
aren't taken from the Model property when a post is made. Is this
default behavior?
Yes, they are first taken from the ModelState and then from the Model. If you intend to perform some modifications on the model in your POST action you need to remove them from the ModelState first. For example:
[HttpPost]
public ActionResult Edit(Product p)
{
ModelState.Remove("Name");
p.Name = "prrrrrrd 2";
return View(p);
}

asp .net mvc change password issue firefox

//UPDATE : Described problem occurs only in Firefox Browser
I've written small app in mvc 2.0, which uses aspnetdb to manage users and standard Account controllers / views etc.
My problem is when i try to change password for user sometimes after typing old password and putting new password, another window opens where i can (?) choose user to change password.
It is very strange, it happens only to some users in application while for other it works quite fine.
Could anyone give me any suggestion what's going on ?
Update:
I don't know whats the difference at first I thought it depends on roles they have defined in application but then this pattern failed.
I don't use any js here
My controller actions looks like:
[Authorize]
public ActionResult ChangePassword()
{
ViewData["PasswordLength"] = this.MembershipService.MinPasswordLength;
return View();
}
[Authorize]
[HttpPost]
public ActionResult ChangePassword(ChangePasswordModel model)
{
if (ModelState.IsValid)
{
if (this.MembershipService.ChangePassword(User.Identity.Name, model.OldPassword, model.NewPassword))
{
return RedirectToAction("ChangePasswordSuccess");
}
else
{
ModelState.AddModelError(String.Empty, "Błędne hasło aktualne lub nowe nie spełnia wymagań.");
}
}
// If we got this far, something failed, redisplay form
ViewData["PasswordLength"] = this.MembershipService.MinPasswordLength;
return View(model);
}
And ChangePassword.aspx
<%# Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<TheApp.Web.Models.ChangePasswordModel>" %>
<asp:Content ID="changePasswordTitle" ContentPlaceHolderID="TitleContent" runat="server">
Change Password
</asp:Content>
<asp:Content ID="changePasswordContent" ContentPlaceHolderID="MainContent" runat="server">
<h2>Change Password</h2>
<p>
Min password length: <%= Html.Encode(ViewData["PasswordLength"]) %>.
</p>
<% using (Html.BeginForm()) { %>
<%= Html.ValidationSummary(true, "Message.") %>
<div>
<fieldset>
<legend>Account Information</legend>
<div class="editor-label">
<%= Html.LabelFor(m => m.OldPassword) %>
<%= Html.HiddenFor(m => m.UserName) %>
</div>
<div class="editor-field">
<%= Html.PasswordFor(m => m.OldPassword) %>
<%= Html.ValidationMessageFor(m => m.OldPassword) %>
</div>
<div class="editor-label">
<%= Html.LabelFor(m => m.NewPassword) %>
</div>
<div class="editor-field">
<%= Html.PasswordFor(m => m.NewPassword) %>
<%= Html.ValidationMessageFor(m => m.NewPassword) %>
</div>
<div class="editor-label">
<%= Html.LabelFor(m => m.ConfirmPassword) %>
</div>
<div class="editor-field">
<%= Html.PasswordFor(m => m.ConfirmPassword) %>
<%= Html.ValidationMessageFor(m => m.ConfirmPassword) %>
</div>
<p>
<input type="submit" value="Change Password" />
</p>
</fieldset>
</div>
<% } %>
</asp:Content>
... and weird window with users list (which is incomplete btw) shows even before
public ActionResult ChangePassword(ChangePasswordModel model)
invocation.
I've added in my view autocomplete="off" in all input fields and it helped :)

mvc-System.Web.Mvc.ViewUserControl

Hey...
How can I send submit buttons'id from ViewUserControl to controler on post action? When I had normal view I could write something like this:
[HttpPost]
public ActionResult KontaktIzabran(string myId)
{
//some code
}
Now myId is alwasy null....
Here is my UserControl
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<KontaktModel>" %>
<%# OutputCache Duration="1200" VaryByParam="*" %>
<div id="sign-in-pop" class="popup">
<div class="modal fat-form">
<div class="clipper">
<div class="left"></div>
<div class="content">Sign In</div>
<div class="right"></div>
</div>
<% Html.BeginForm("IzborKontaktaPopUp", "Kontakt"); %>
<%: Html.ValidationSummary(true) %>
<div class="editor-field">
<%: Html.TextBoxFor(model => model.Naziv)%>
<%: Html.ValidationMessageFor(model => model.Naziv) %>
<input type="submit" value="Traži" name="submitButton" id="submitButton" />
<input type="submit" value="Dodaj novi" name="noviKontakt" />
</div>
<% Html.EndForm(); %>
</div>
</div>
[HttpPost]
public ActionResult KontaktIzabran(string myId, string noviKontakt)
{
if (!string.IsNullOrEmpty(noviKontakt))
{
// <input type="submit" value="Dodaj novi" name="noviKontakt" />
// was used to submit the form
}
else
{
// <input type="submit" value="Traži" name="submitButton" id="submitButton" />
// was used to submit the form
}
...
}
Well it looks like you don't have a form field called "myId", so the submit can't send that back to the controller. Instead it will send back a FormCollection containing the current values of these:
<%: Html.TextBoxFor(model => model.Naziv)%>
<input type="submit" value="Traži" name="submitButton" id="submitButton" />
<input type="submit" value="Dodaj novi" name="noviKontakt" />

ASP.NET MVC 2 - First submit button on site doesn't work - rest is fine!

Sorry for unclear title - I don't know how to describe that problem in one sentence. Code sample will make it clear.
First UP button do nothing when clicked. Rest works like it should!
Below my view:
<%# Page Title="" Language="C#"
MasterPageFile="~/Views/Shared/Main.Master"
Inherits="System.Web.Mvc.ViewPage<GeekClick.ViewModels.HomeViewModel>" %>
<asp:Content ID="Content2" ContentPlaceHolderID="head" runat="server">
<title>Beta</title>
</asp:Content>
<asp:Content ID="Content1" ContentPlaceHolderID="MainPageLinks" runat="server">
<h2>Najlepsze linki w sieci</h2>
<div id="HomePageLinks">
<%foreach (var link in Model.Links) { %>
<b><%:link.Description %></b><br />
<%: Html.ActionLink("details", "Index", "Link", new {id = link.LinkID}, null) %>
<% using (Html.BeginForm("UpVote", "Home", new { linkId = link.LinkID }, FormMethod.Post)) {%>
<input type="submit" value="UP" /> <% } %>
<%: link.Votes %>
<% using (Html.BeginForm("DownVote", "Home", new { linkId = link.LinkID }, FormMethod.Post)) {%>
<input type="submit" value="DOWN" /> <% } %>
<% } %>
</div>
</asp:Content>
Controller:
[HttpPost]
public RedirectToRouteResult UpVote(int linkId)
{
var updateLink = _geekDb.Link.Single(a => a.LinkID == linkId);
updateLink.Votes++;
_geekDb.SaveChanges();
return RedirectToAction("Index");
}
[HttpPost]
public RedirectToRouteResult DownVote(int linkId)
{
var updateLink = _geekDb.Link.Single(a => a.LinkID == linkId);
updateLink.Votes--;
_geekDb.SaveChanges();
return RedirectToAction("Index");
}
And finally generated html:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1">
<title>Beta</title>
<title>
</title></head>
<body>
<form method="post" action="./" id="form1">
<div class="aspNetHidden">
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDwULLTE1NDk5OTQxMTBkZLMRoMOmMkoaJsHIkFWLWjn7HFSzna1LBeMqvRiCxdDQ" />
</div>
<div id ="mainPage" >
<h2>title</h2>
<div id="HomePageLinks">
<b>Something </b><br />
details
<form action="/Home/UpVote?linkId=1" method="post">
<input type="submit" value="UP" /> </form>3
<form action="/Home/DownVote?linkId=1" method="post">
<input type="submit" value="DOWN" /> </form>
<b>Somedesc </b><br />
details
<form action="/Home/UpVote?linkId=2" method="post">
<input type="submit" value="UP" /> </form>10
<form action="/Home/DownVote?linkId=2" method="post">
<input type="submit" value="DOWN" /> </form>
</div>
</div>
</form>
</body>
</html>
There shouldn't be viewstate, should be?
I can't see there any problem in code. Someone can?
Looks like somewhere (perhaps in your Main.Master) you have a <form runat="server" /> that's messing things up.
It makes sense why your first button does not work - notice <form method="post" action="./"> at the top of your output - it's clashing with your other form and posting to the wrong action.

How to update one to many relationship entity from same view?

Table Product
Product Id
Product Name
Table Supplier
SupplierId
ProductId
SupplierName
When I create a New Product, I want to have a textbox to enter a supplier as well on the same view. Is this a good practice? Since Product can have many Suppliers, I want to be able to add more Supplier records from the same view. How do I do that?
I am trying to figure out what do I put in the aspx page?
If I put something like <%= Html.TextBoxFor(model => model.Supplier) %> I see a textbox with System.Data.Objects.DataClasses.EntityCollection`1[MyProject.Mvc.Models.Supplier] in it.
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master"
Inherits="System.Web.Mvc.ViewPage<MyProject.Mvc.Models.ProductFormViewModel>" %>
<%= Html.ValidationSummary("Please correct the errors and try again.") %>
<% using (Html.BeginForm()) {%>
<fieldset>
<legend>Fields</legend>
<div class="editor-label">
<%= Html.LabelFor(model => model.Product.ProductId) %>
</div>
<div class="editor-field">
<%= Html.TextBoxFor(model => model.Product.ProductId) %>
<%= Html.ValidationMessageFor(model => model.Product.ProductId) %>
</div>
<div class="editor-label">
<%= Html.LabelFor(model => model.Product.ProductName) %>
</div>
<div class="editor-field">
<%= Html.TextBoxFor(model => model.Product.ProductName) %>
<%= Html.ValidationMessageFor(model => model.Product.ProductName) %>
</div>
<div class="editor-label">
<%= Html.LabelFor(model => model.Product.Description) %>
</div>
<div class="editor-field">
<%= Html.TextBoxFor(model => model.Product.Description) %>
<%= Html.ValidationMessageFor(model => model.Product.Description) %>
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
<% } %>
ProductViewModel
public class ProductFormViewModel
{
public Product Product{ get; private set; }
public IEnumerable<Supplier> Supplier { get; private set; }
public ProductFormViewModel()
{
Product = new Product();
}
public ProductFormViewModel(Product product)
{
Product = product;
Supplier = product.Supplier;
}
}
I think you will find Steven Sanderson's blogpost about editing variable length lists in ASP.NET MVC 2 really useful. He also has another blogpost about validating such a list.