views:

75

answers:

2

Hey all I am attempting to learn MVC 2 and ASP etc through the MVC Music Store. At the same time I am attempting to conform what it is doing to a solution I am developing at work. The overall structure is an IT Help Desk ticket system and I am working on the very broad admin functions of creating, editing, and deleting tickets. I have followed the tutorial very closely but have hit a brick wall, when attempting to use values that should be getting posted to controller methods, and theyre not getting there.

For the create section my create.aspx looks like

<h2>Create</h2>
<% Html.EnableClientValidation(); %>
<% using (Html.BeginForm()) {%>
    <%: Html.ValidationSummary(true) %>

    <fieldset>
        <legend>Create New Request</legend>
        <%: Html.EditorFor(model => model.request,
               new {Softwares = Model.SoftwareName, Systems = Model.SystemIDNo}) %>

        <p>
            <input type="submit" value="Create" />
        </p>
    </fieldset>

<% } %>

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

the partial view its calling is workRequest.ascx

<p> 
    <%= Html.LabelFor(model => model.Medium)%> 
    <%= Html.TextBoxFor(model => model.Medium)%>
    <%= Html.ValidationMessageFor(model => model.Medium)%> 
</p> 
<p> 
    <%= Html.LabelFor(model => model.Summary)%> 
    <%= Html.TextBoxFor(model => model.Summary)%> 
    <%= Html.ValidationMessageFor(model => model.Summary)%> 
</p> 
<p> 
    <%= Html.LabelFor(model => model.Details)%> 
    <%= Html.TextAreaFor(model => model.Details)%> 
    <%= Html.ValidationMessageFor(model => model.Details)%> 
</p>
<p> 
    <%= Html.LabelFor(model => model.WorkHalted)%> 
    <%= Html.TextBoxFor(model => model.WorkHalted)%>  
    <%= Html.ValidationMessageFor(model => model.WorkHalted)%> 
</p>
<p> 
    <%= Html.LabelFor(model => model.Frequency)%> 
    <%= Html.TextBoxFor(model => model.Frequency)%>
    <%= Html.ValidationMessageFor(model => model.Frequency)%> 
</p>
<p> 
    <%= Html.LabelFor(model => model.StartDate)%> 
    <%= Html.TextBoxFor(model => model.StartDate, String.Format("{0:g}", Model.StartDate))%> 
    <%= Html.ValidationMessageFor(model => model.StartDate)%> 
</p>
<p>
    <%= Html.LabelFor(model => model.SoftwareID) %>
    <%= Html.DropDownList("SoftwareID", new SelectList(ViewData["Softwares"] as IEnumerable, Model.SoftwareID)) %>
</p>
<p>
    <%= Html.LabelFor(model => model.SystemID) %>
    <%= Html.DropDownList("SystemID", new SelectList(ViewData["Systems"] as IEnumerable, Model.SystemID)) %>
</p>

and the post create controller looks like

[HttpPost]
    public ActionResult Create(WorkRequest newRequest)
    {
        try
        {
            storeDB.AddToWorkRequests(newRequest);
            storeDB.SaveChanges();

            return RedirectToAction("Index");
        }
        catch
        {
            return View();
        }

    }

I put a break point in the try and checked the values coming into newRequest and everything in newRequest is null, like nothing is getting passed.

A similar situation occurs on the edit side of things as well, nothing is getting sent from the partial view to the controller at all.

Anyways I am sure its something fairly simple, I am new to MVC, ASP, C#, pretty much all of it. I dont normally ask other people for much, but I have been looking at this problem for quite some time and could use some fresh eyes on this one.

Thanks in advance!

A: 

Try using the same view model type as parameter that you used to render the view and to which it is strongly typed:

[HttpPost]
public ActionResult Create(ViewModelUsedToStronglyTypeTheView model)
{
    //model.request should be properly bound here
    try
    {
        storeDB.AddToWorkRequests(model.request);
        storeDB.SaveChanges();
        return RedirectToAction("Index");
    }
    catch
    {
        return View(model);
    }
}

Or using a prefix:

[HttpPost]
public ActionResult Create([Bind(Prefix = "request")] WorkRequest newRequest)
{
    //model.request should be properly bound here
    try
    {
        storeDB.AddToWorkRequests(newRequest);
        storeDB.SaveChanges();
        return RedirectToAction("Index");
    }
    catch
    {
        return View();
    }
}
Darin Dimitrov
Hey adding a prefix worked. In order to learn more I just wanted to ask what does adding that do that I wasnt before, or what was I doing wrong?Just trying to figure everything out.
Mark
Look at the posted values using FireBug. You will notice that all of them are prefixed with `request`. This is how the strongly typed helpers in editor template work: they generate input fields based on the lambda expression you are providing and the context. Because you are working in the context of the `request` property everything is prefixed with it. The default model binder will then try to bind to request but it couldn't find any POST parameter which is named like the properties of this object because all of them are prefixed. Be careful with this because if you rename your property.
Darin Dimitrov
Oh okay, I see what I was doing, thanks for the quick answer!!
Mark
A: 

I believe you just need to change your action signature to look like this..

public ActionResult Create(WorkRequest request)

The reason for this is the name of the values being posted. They look something like RequestViewModel.Request.Summary so the name of the request object is actually Request. There is no Request property on a WorkRequest object so nothing binds.

You can bind to the object your view is tied to, RequestViewModel, as Darin Dimitrov suggested.

Alternatively, you can just bind to the request as you intended, you just need to ensure MVC knows how to bind the values. It only knows these things via naming convention so if you are binding a sub-object you need to ensure your param for the action is named the same as the property of it's parent object.

Jab