CslaModelBinder not binding child list

2019-08-10 01:14发布

问题:

I have the following business classes

public class EditableRoot:Csla.BusinessBase<EditableRoot>
{
    public string Name { get; private set; }
    public int Id { get; private set; }

    public static EditableRoot New() {
        return DataPortal.Create<EditableRoot>();
    }

    public static readonly PropertyInfo<EditableChildList> ChildListProperty = RegisterProperty<EditableChildList>(c => c.ChildList, RelationshipTypes.Child);
    public EditableChildList ChildList
    {
        get { return GetProperty(ChildListProperty); }
        private set { SetProperty(ChildListProperty, value); }
    }
    protected override void DataPortal_Create()
    {
        ChildList = EditableChildList.New();
    }

}
public class EditableChildList : Csla.BusinessListBase<EditableChildList,EditableChild>
{
    public static EditableChildList New() { return DataPortal.CreateChild<EditableChildList>(); }
}
public class EditableChild : Csla.BusinessBase<EditableChild>
{
    public static readonly PropertyInfo<string> AssignedByProperty = RegisterProperty<string>(c => c.AssignedBy);
    public string AssignedBy
    {
        get { return GetProperty(AssignedByProperty); }
        private set { LoadProperty(AssignedByProperty, value); }
    }
    public static readonly PropertyInfo<int> DocTypeIDProperty = RegisterProperty<int>(c => c.DocTypeID);
    public int DocTypeID
    {
        get { return GetProperty(DocTypeIDProperty); }
        set { SetProperty(DocTypeIDProperty, value); }
    }
    public static EditableChild New(int docTypeId) { return DataPortal.CreateChild<EditableChild>(docTypeId); }
    void Child_Create(int docTypeId)
    {
        DocTypeID = docTypeId;
        AssignedBy = "AssignedBy" + docTypeId;
    }

}

And I have controller

 public class ComplexTypeController : Csla.Web.Mvc.Controller, Csla.Web.Mvc.IModelCreator
{
    //
    // GET: /ComplexType/
    public ActionResult Create()
    {
        EditableRoot type = EditableRoot.New();
        ViewData.Model = type;
        return View();
    }

    [HttpPost]
    public ActionResult Create(EditableRoot complexType, FormCollection collection, string submit)
    {
        if (submit != "Create")
        {
            Random rand = new Random();

            complexType.ChildList.Add(EditableChild.New(rand.Next()));

        }
        ViewData.Model = complexType;
        return View();
    }

    public object CreateModel(Type modelType)
    {
        if (modelType == typeof(EditableRoot))
            return EditableRoot.New();
        else if (modelType == typeof(EditableChildList))
            return EditableChildList.New();
        else if (modelType == typeof(EditableChild))
            return EditableChild.New(0);
        else
            return Activator.CreateInstance(modelType);
    }
}

And I have view

 @model EditableRoot

 @{
     ViewBag.Title = "Create";
 }

 <h2>Create</h2>
 @using (Html.BeginForm())
 {
     @Html.DisplayFor(m => m.Name);
     @Html.HiddenFor(m => m.Id);
     <table>
         <thead>
             <tr>
                 <th>Child Type Name</th>
                 <td>Child Type Id</td>
             </tr>
         </thead>


    <tbody>
            @for (int i = 0; i < Model.ChildList.Count(); i++)
            {
                <tr>
                    <td>
                        @Html.TextBoxFor(a => Model.ChildListIdea.AssignedBy)
                    </td>
                    <td>
                        @Html.TextBoxFor(a => Model.ChildListIdea.DocTypeID)
                    </td>
                </tr>
            }
        </tbody>
    </table>
   <input name="submit" type="submit" id="submit" value="Create" />
    <input name="submit" type="submit" id="process" value="Add Child" />                       
}

When I add an EditableChild by clicking the "Add Child" button then click the "Create" button the ChildList property of the EditableRoot object in the public ActionResult Create(EditableRoot complexType, FormCollection collection, string submit) call is not bound.

In other words the child list EditableRoot.ChildList is not bound, no items in the list, even though the html in the view follows the conventions for binding lists of complex types. And when I view the actual html in the browser the rows emitted for the items in EditableRoot.ChildList are present and correctly named.

However, I got the CslaModelBinder from github and put it into my project and wired up the mvc default modelbinder to use it. Then I changed the CslaModelBinder method

public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)

to look like this

public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
            {
                //if (typeof(Csla.Core.IEditableCollection).IsAssignableFrom((bindingContext.ModelType)))
                //    return BindCslaCollection(controllerContext, bindingContext);

                var suppress = bindingContext.Model as Csla.Core.ICheckRules;
                if (suppress != null)
                    suppress.SuppressRuleChecking();
                var result = base.BindModel(controllerContext, bindingContext);
                return result;
            }

Everything worked. The EditableRoot.ChildList property is bound, the expected items are in the list.

Ultimately my modification of the CslaModelBinder method

public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)

comments out the handling of binding Csla IEditableCollection and so the method ultimately calls the BindModel method on the base class, DefaultModelBinder. Which works.

But, if I use my modified CslaModelBinder will I run into problems elsewhere?

If DefaultModelBinder can handle binding of Csla.Core.IEditableCollection types then why

if (typeof(Csla.Core.IEditableCollection).IsAssignableFrom((bindingContext.ModelType))) return BindCslaCollection(controllerContext, bindingContext);

???

回答1:

There are known issues around binding against child collections, with an open ticket to resolve the issues.

See https://github.com/MarimerLLC/csla/issues/19