id is null in mvc4 controller on form postback

I'm trying to send to the cart controller some values but when I'm trying to access them in the cart controller they are null in the controller, although I have them in hidden field in the view with correct value. That is happening when I'm trying to add item to a cart. This is what I have:

Razor view:

@using Solution.Order.Models
@model IEnumerable<CategoriesViewModel>

@{
    ViewBag.Title = "Categories";
}
@using (Html.BeginForm())
{
       <div class="panel-group">                   
    @foreach (var m in Model)
    {
        <div class="panel panel-default">
            <div class="panel-heading">
                <h4 class="panel-title">
                    <a data-toggle="collapse" id="#accordion" data-parent="#accordion" href="#@m.Categories.ID.ToString()">
                        @m.Categories.Name <span class="badge">@m.Categories.ItemCount</span>
                    </a>                     
                </h4>
            </div>
            <div id="@m.Categories.ID.ToString()" class="panel-collapse collapse">                
                <div class="panel-body">
                    <ul class="list-group">
                        @foreach (var i in m.Items)
                        {                            
                            <li class="list-group-item">
                                @i.Name | Price £@i.Price 

                                @using (Html.BeginForm("AddToCart", "Cart"))
                                {
                                    <div class="pull-right">
                                        @Html.HiddenFor(k => @i.Id)
                                        @Html.Hidden("returnUrl", Request.Url.PathAndQuery)
                                        <input type="submit" class="btn btn-success" value="Add"/>
                                    </div>
                                }
                            </li>                            
                        }
                    </ul>  
                </div>
            </div>
        </div>     
    }        
</div>                                  
}

<script>
    $(document).ready(function() {
        $('#accordion').on('click', function() {
            $('#accordion .in').collapse('hide');
        });
    });
</script>

Controller content:

public RedirectToRouteResult AddToCart(Guid? Id, string returnUrl)
    {
        RestItem itemSingle = restItem.Items.FirstOrDefault(p => p.Id == Id);
        if (itemSingle != null)
        {
            GetCart().AddItem(itemSingle, 1);
        }
        return RedirectToAction("Index", new {returnUrl});
    }

In the controller, the Id value is null, although when I view the source of the page I'm able to see the hidden value for the id:

Since I'm still trying to find the best ways to develop in MVC, the approach I'm taking might not be the best one, so every comment is greatly appreciated. Thanks in advance, Laziale

Answers


The input field you have in your form is having the name "i.Id" , but your action method expects parameter with name just Id.MVC model binding expects you to have the same name attribute values as your parameter name.

You may explicitly keep a hidden field with matching name

@foreach (var m in Model)
{
  <h4>Items</h4>
  <ul>
  @foreach(var i in m.Items)
  {
   <li>
     <h4>@i.Name | Price @i.Price</h4>
     @using(Html.BeginForm())
     {
       <div> 
          <input type="submit" class="btn btn-success" value="Add"/>
          @Html.Hidden("returnUrl", Request.Url.PathAndQuery)  

          <input type="hidden" name="Id" value="@m.Id" />   

       </div>
     }
    </li>
  }
}

This should work, Assuming the Id property of your Item is of type Guid.

Also, Your outer form tag is nolonger being used. You may remove it. Without seeing your viewmodel class, i won't be able to say you are doing it wrong /rite.

Few suggestions
  • If you are showing many items in a loop, Consider using EditorTemplates.
  • In this specific case, I prefer to avoid the multiple form tags in my razor view and catch the submit button click event in javascript and read the hidden variable values (For returnUrl and itemId) and redirect the user to the new action method (Since you are not worried about keeping the action method with HttpPost attribute.

You can't use the @Html.HiddenFor() helper in this context. You want the name of that field to end up being Id, but as you can see it's confused and the name is i.Id. You should use the @Html.Hidden() method like you do on the next line.


Need Your Help

Python : Importing modules

python module

What is the difference between

convert a string or byte to a hex decimal in c#

c# hex byte listener converter

I have a sensor that gets the request and gives me its value the request should be hex format in c# as you can see in the picture :