-1
<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<NerdDinner.Models.Dinner>" %>

<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
    Details
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
    <h2>
        <%:Model.Title %></h2>
    <fieldset>
        <legend>
            <%: Model.HostedBy %></legend>
        <p>
            <strong>When: </strong>
            <%: Model.EventDate.ToShortDateString() %>
            <strong>at: </strong>
            <%: Model.EventDate.ToShortTimeString() %>
        </p>
        <p>
            <strong>Description: </strong>
            <%: Model.Description %>
        </p>
    </fieldset>
    <p>
        <%: Html.ActionLink("Edit Dinner", "Edit", new { dinner=Model }) %>
        |
        <%: Html.ActionLink("Delete Dinner", "Delete", new { id=Model.DinnerId }) %>
        |
        <%: Html.ActionLink("Back to Dinner list", "Index") %>
    </p>
</asp:Content>

public ActionResult Edit(Dinner dinner)
{
    //Dinner dinner = dinnerRepository.GetDinnerById(id);

    if (dinner == null)
        return View("NotFound");
    else
        return View(dinner);
}

[HttpPost]
public ActionResult Edit(Dinner dinner, object dummy)
{
    Dinner temp = dinnerRepository.GetDinnerById(dinner.DinnerId);

    if (TryUpdateModel(temp))
    {
        dinnerRepository.Save();

        return RedirectToAction("Details", new { id = dinner.DinnerId });
    }
    else
        return View(temp);
}
Iain Galloway
  • 18,669
  • 6
  • 52
  • 73
Second Person Shooter
  • 14,188
  • 21
  • 90
  • 165
  • 1
    Smells like a possible dupe of http://stackoverflow.com/questions/369102/using-a-strongly-typed-actionlink-when-the-action-method-doesnt-take-a-primitive. – Dan Atkinson Dec 20 '10 at 16:51
  • 1
    I am pretty sure the routing system can only accept simple types. If you wanted to take a Dinner in, you could change <%: Html.ActionLink("Edit Dinner", "Edit", new { dinner=Model.DinnerId }) %> and then create a custom Model binder that would look for DinnerId, query for it, and if found, it would pass the Dinner object to your Action Method. Good article here: http://www.lostechies.com/blogs/jimmy_bogard/archive/2010/07/23/mvcconf-slides-and-code-posted.aspx – Paul Dec 20 '10 at 17:20

3 Answers3

4

What would you expect the output HTML to look like?

Ultimately, whatever data you shove in your RouteValues dictionary needs to be rendered as part of the (text) href for the hyperlink:-

<a href="Dinners/Edit/<!-- We can't put a Dinner in here!! -->">Edit Dinner</a>

Edit:

In fact, if you look at your controller code, you're grabbing the id of the model that gets passed in and looking it up from the database again anyway!

If having action methods take id parameters offends you, you can have a look at using the ModelBinder framework to do the database lookup for you. That's a bit controversial though. I'd just go with how the examples do it until you've got a feel for the framework.

Iain Galloway
  • 18,669
  • 6
  • 52
  • 73
2

If you did that then the entire Dinner object and all of its properties would have to be passed in the URL. I find that less desirable than passing in a simple ID and obtaining the Dinner object from that.

Jamie Dixon
  • 53,019
  • 19
  • 125
  • 162
  • can we pass the model as form field instead of url? – Second Person Shooter Dec 20 '10 at 16:46
  • 1
    You can post the object to the server if you're using a form or some kind of ajax however the ActionLink is a different thing. – Jamie Dixon Dec 20 '10 at 16:48
  • 2
    You can e.g. serialise the entire model and pass it in the form, but really don't. You're much much better doing like the examples do and passing either the model's ID, or some other unique data you can use to pull the model out of the database on the server. – Iain Galloway Dec 20 '10 at 16:48
  • 1
    I agree with Iain. Retrieving by the id in a `GET` request means that you'll be helping to protect your app from being tampered with by malicious users and co-workers disgruntled at having to work with your crazy model-url abomination. :) – Dan Atkinson Dec 20 '10 at 16:55
  • 1
    Agreed. You should most certainly obtain the dinner object in your controller at the other end of the link. Passing an entire object either in the URL or form post is much less secure and is pretty bad practice. – Jamie Dixon Dec 20 '10 at 16:57
  • @Dan, your answer makes sense. – Second Person Shooter Dec 20 '10 at 17:25
0

Alternatively you can do as explained in Microsoft MSDN.

public class PersonController : Controller
{
    static List<Person> people = new List<Person>();

    //
    // GET: /Person/
    public ActionResult Index()
    {
        return View(people);
    }

    //
    // GET: /Person/Details/5
    public ActionResult Details(Person person)
    {
        return View(person);
    }

    //
    // GET: /Person/Create
    public ActionResult Create()
    {
        return View();
    } 

    //
    // POST: /Person/Create
    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Create(Person person)
    {
        if (!ModelState.IsValid)
        {
            return View("Create", person);
        }

        people.Add(person);

        return RedirectToAction("Index");
    }
}

Index.aspx

<h2>Index</h2>

<table>
    <tr>
        <th></th>
        <th>
            Id
        </th>
        <th>
            Name
        </th>
    </tr>

<% foreach (var person in Model) { %>

    <tr>
        <td>
            <%= Html.ActionLink("Details", "Details", person )%>
        </td>
        <td>
            <%= Html.Encode(person.Id) %>
        </td>
        <td>
            <%= Html.Encode(person.Name) %>
        </td>
    </tr>

<% } %>

</table>

<p>
    <%= Html.ActionLink("Create New", "Create") %>
</p>

Create.aspx

<h2>Create</h2>

<%= Html.ValidationSummary("Create was unsuccessful. Please correct the errors and try again.") %>

<% using (Html.BeginForm()) {%>

    <fieldset>
        <legend>Fields</legend>
        <p>
            <label for="Id">Id:</label>
            <%= Html.TextBox("Id") %>
            <%= Html.ValidationMessage("Id", "*") %>
        </p>
        <p>
            <label for="Name">Name:</label>
            <%= Html.TextBox("Name") %>
            <%= Html.ValidationMessage("Name", "*") %>
        </p>
        <p>
            <label for="Age">Age:</label>
            <%= Html.TextBox("Age") %>
            <%= Html.ValidationMessage("Age", "*") %>
        </p>
        <p>
            <label for="Street">Street:</label>
            <%= Html.TextBox("Street") %>
            <%= Html.ValidationMessage("Street", "*") %>
        </p>
        <p>
            <label for="City">City:</label>
            <%= Html.TextBox("City") %>
            <%= Html.ValidationMessage("City", "*") %>
        </p>
        <p>
            <label for="State">State:</label>
            <%= Html.TextBox("State") %>
            <%= Html.ValidationMessage("State", "*") %>
        </p>
        <p>
            <label for="Zipcode">Zipcode:</label>
            <%= Html.TextBox("Zipcode") %>
            <%= Html.ValidationMessage("Zipcode", "*") %>
        </p>
        <p>
            <input type="submit" value="Create" />
        </p>
    </fieldset>

<% } %>

<div>
    <%=Html.ActionLink("Back to List", "Index") %>
</div>

Details.aspx

<h2>Details</h2>

<fieldset>
    <legend>Fields</legend>
    <p>
        Id:
        <%= Html.Encode(Model.Id) %>
    </p>
    <p>
        Name:
        <%= Html.Encode(Model.Name) %>
    </p>
    <p>
        Age:
        <%= Html.Encode(Model.Age) %>
    </p>
    <p>
        Street:
        <%= Html.Encode(Model.Street) %>
    </p>
    <p>
        City:
        <%= Html.Encode(Model.City) %>
    </p>
    <p>
        State:
        <%= Html.Encode(Model.State) %>
    </p>
    <p>
        Zipcode:
        <%= Html.Encode(Model.Zipcode) %>
    </p>
</fieldset>
<p>
    <%=Html.ActionLink("Back to List", "Index") %>
</p>
Second Person Shooter
  • 14,188
  • 21
  • 90
  • 165