0

I have a page in which I am maintaining a list as shown below.

 @for (int i = 0; i < Model.RuleDetails.Rules.AssociatedRules.Count; i++)
 {
    <div class="checkbox">
        <label><input type="checkbox" checked="true" value="true" />
                   @Model.RuleDetails.Rules.AssociatedRules[i].Rule_Name 
            </label>
             @Html.HiddenFor(x => x.RuleDetails.Rules.AssociatedRules[i].Rule_Id)
             @Html.HiddenFor(x => x.RuleDetails.Rules.AssociatedRules[i].State)
        </div>
  }

when I click on the save button I can see data going to the server in network monitor ..

enter image description here

but when I see the model in action parameter I am getting RuleDetails.Rules.AssociatedRules as null.

I investigated the HttpRequest Object in Controller and I can see my values in the request params

enter image description here

I don't know what is happening in the server and what I am missing . is there any way to control the model binding.

This is the model of the view

enter image description here

and Controller has only action methods which will basically fetch and save mode.

Sujith Kp
  • 1,075
  • 3
  • 14
  • 27
  • Refer `Prefer Binding Over Request.Form` in http://odetocode.com/blogs/scott/archive/2009/04/27/6-tips-for-asp-net-mvc-model-binding.aspx – Earth Jul 28 '14 at 10:48
  • 1
    Whats the code in the controller? And what is the viewmodel? – user1666620 Jul 28 '14 at 10:48
  • @user1666620 I have updated the question with model of the page. – Sujith Kp Jul 28 '14 at 11:33
  • do you have the actual code? what are the data types etc? Screenshots aren't much good, Nobody wants to have to type out a load of somebody else's code if they want to try to reproduce the problem. If it's prorietary, then obfuscate the code - just allow us the minimum amount to reproduce the behaviour. – user1666620 Jul 28 '14 at 11:38
  • My first guess would be that the model is just not binding due to some type binding error. Check the `ModelState.IsValid` property, it's probably false and you will have an error in the model state values. See this answer for a quick example on reading the errors from the property. http://stackoverflow.com/a/22305555/426894 – asawyer Jul 28 '14 at 13:16
  • I can see ModelState.IsValid as true in the action method. @asawyer – Sujith Kp Jul 28 '14 at 14:36
  • Darn, well it was just a guess. Next suggestion is to download the debug symbols and step through the model binder until you find the issue. – asawyer Jul 28 '14 at 15:05
  • @asawyer I end up writing my own model binder.. now it is working. – Sujith Kp Jul 29 '14 at 21:31
  • @SujithKp I'd write up what you did as an answer and accept it then. – asawyer Jul 30 '14 at 11:55
  • @asawyer I have added the code as answer. – Sujith Kp Jul 31 '14 at 09:57

1 Answers1

0

Here is the model binder that I wrote. I know this is not the solution that I was looking but I have already spent lot of time looking the cause of the issue. Will investigate in more detail after meeting the deadlines ;)

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Web.Mvc;

namespace ModelBinderPoc
{
public class MyModelBinder : IModelBinder
{
    private bool IsPropertyClrObject(PropertyInfo obj)
    {
        var type = obj.PropertyType;

        return (type.Equals(typeof(Boolean)) || type.Equals(typeof(string)) || type.Equals(typeof(Int32)) || type.Equals(typeof(decimal))
            || type.Equals(typeof(DateTime)) || type.Equals(typeof(DateTime?)));
    }

    private void SetClrObjectValue(PropertyInfo pinfo, object model, object pvalue)
    {
        pinfo.SetValue(model, pvalue, null);
    }

    private object CreateCollection(object obj, string propertyPart)
    {
        var propertyLength = propertyPart.IndexOf('[');
        var propertyName = propertyPart.Substring(0, propertyLength);
        var index = propertyPart.Substring(propertyLength + 1, propertyPart.Length - (propertyLength + 2));

        var property = obj.GetType().GetProperty(propertyName);
        var propertyValue = property.GetValue(obj, null);
        if (propertyValue == null)
        {
            var ctype = property.PropertyType.GetGenericTypeDefinition();
            if (ctype.FullName.Contains("System.Collections.Generic.IList"))
            {
                var gptype = property.PropertyType.GetGenericArguments().First();
                var listInstance = (IList)typeof(List<>).MakeGenericType(gptype).GetConstructor(Type.EmptyTypes).Invoke(null);
                property.SetValue(obj, listInstance, null);
                propertyValue = listInstance;
            }
        }

        int count = (int)propertyValue.GetType().GetProperty("Count").GetValue(propertyValue, null);
        var gtype = propertyValue.GetType().GetGenericArguments().First();
        object listItem = null;

        if (int.Parse(index) + 1 > count)
        {
            ((IList)propertyValue).Add(listItem = gtype.GetConstructor(Type.EmptyTypes).Invoke(null));
        }
        else
        {
            listItem = propertyValue.GetType().GetMethod("get_Item").Invoke(propertyValue, new object[] { int.Parse(index) });
        }

        return listItem;
    }


    private void setPropertyValue(object model, string propertyName, string value)
    {
        var objectValue = model;

        foreach (var propertyPart in propertyName.Split('.'))
        {
            var propertyLength = propertyPart.Length;

            if ((propertyLength = propertyPart.IndexOf('[')) != -1)
            {
                objectValue = CreateCollection(objectValue, propertyPart);
                continue;
            }

            var property = GetProperty(objectValue, propertyPart);

            if (property == null)
                return; // invalid property

            if (IsPropertyClrObject(property))
            {
                SetValue(objectValue, property, value);
                return;
            }

            var propertyValue = GetValueOf(objectValue, property);
            if (propertyValue == null)
            {
                var newObjValue = GetNewValueFor(property);
                SetObjValue(objectValue, property, newObjValue);
                propertyValue = newObjValue;
            }

            objectValue = propertyValue;
        }
    }

    private void SetValue(object obj, PropertyInfo pinfo, object value)
    {
        if (pinfo.PropertyType.Equals(typeof(DateTime?)))
        {
            DateTime date = DateTime.Now;
            if (DateTime.TryParse(value as string, out date))
                pinfo.SetValue(obj, date, null);
            else
                pinfo.SetValue(obj, null, null);
            return;
        }

        if (value.ToString().Length != 0) 
            pinfo.SetValue(obj, Convert.ChangeType(value, pinfo.PropertyType), null);
    }

    private void SetObjValue(object obj, PropertyInfo pinfo, object value)
    {
        pinfo.SetValue(obj, value, null);
    }

    private object GetValueOf(object obj, PropertyInfo pinfo)
    {
        return pinfo.GetValue(obj, null);
    }

    private object GetNewValueFor(PropertyInfo pinfo)
    {
        return Instantiate(pinfo.PropertyType);
    }

    private object Instantiate(Type type)
    {
        return type.GetConstructor(Type.EmptyTypes).Invoke(null); ;
    }

    private PropertyInfo GetProperty(object obj, string property)
    {
        return obj.GetType().GetProperty(property);
    }

    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var model = Instantiate(bindingContext.ModelType);
        var parameters = controllerContext.HttpContext.Request.Params;

        foreach (var key in parameters.AllKeys)
        {
            var value = parameters.GetValues(key);
            setPropertyValue(model, key, value.First());
        }

        return model;
    }
}
}`    
Sujith Kp
  • 1,075
  • 3
  • 14
  • 27