Отправка исключений с моделью представления со свойством словаря, с указанием enum, со значением class в качестве значений

редактировать: я не уверен, как я пропустил это ранее, но это может быть дубликат Binding словарь, содержащий список в MVC4.

Я использую ASP.NET MVC4, и у меня есть свойство словаря, которое имеет ключ для перечисления и имеет класс в качестве типа значения. я использую Html.TextBoxFor сгенерировать HTML для формы для действия контроллера, которое принимает один из них в качестве модели представления. Я получаю InvalidCastException во время связывания, когда я отправляю форму через мой браузер.

Вот модель представления:

public class MyViewModel
{
    public virtual IDictionary<MyEnumType, IList<MySubViewModel>> Subs { get; set; }

    public class MySubViewModel
    {
        public virtual String Name { get; set; }
   }
}

В контроллере у меня есть:

[HttpGet]
public ActionResult EditPage(Int32? id)
{
    MyViewModel testViewModel = new MyViewModel
        {
            Subs = new Dictionary<MyEnumType, IList<MyViewModel.MySubViewModel>>() {
                {
                    MyEnumType.MySubViewModel
                  , new List<MyViewModel.MySubViewModel> {
                        new MyViewModel.MySubViewModel {
                            Name = "Foo-Bar"
                        }
                    }
                }
            }
        };
    return View(testViewModel);
}

[HttpPost]
public ActionResult EditPage(MyViewModel model)
{
    return View(model);
}

У меня есть на мой взгляд (с помощью двигателя Spark View):

<tbody each="var enumValue in Html.EnumValues<MyEnumType>()">
    <tr each="var sub in Model.Subs[enumValue]" class="DataRow">
        <td>
            ${Html.TextBoxFor(m => m.Subs[enumValue][subIndex].Name, new { @class="SubName" })}
        </td>
    </tr>
</tbody>

Это отображается как:

<tbody>
    <tr>
        <td>
            <input id="Subs_EnumValueOne__0__Name" type="text" value="Foo-Bar" name="Subs[EnumValueOne][0].Name">
        </td>
    </tr>
</tbody>

Когда я отправляю страницу, я получаю InvalidCastException: {"Specified cast is not valid."},

at System.Web.Mvc.DefaultModelBinder.CollectionHelpers.ReplaceDictionaryImpl[TKey,TValue](IDictionary`2 dictionary, IEnumerable`1 newContents)

Вот трассировка стека. (У меня есть связыватель модели для другого типа, но для этого свойства словаря он просто проходит через base.BindModel.)

[InvalidCastException: Specified cast is not valid.]
   System.Web.Mvc.CollectionHelpers.ReplaceDictionaryImpl(IDictionary`2 dictionary, IEnumerable`1 newContents) +131

[TargetInvocationException: Exception has been thrown by the target of an invocation.]
   System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor) +0
   System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments) +92
   System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture) +108
   System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters) +19
   System.Web.Mvc.CollectionHelpers.ReplaceDictionary(Type keyType, Type valueType, Object dictionary, Object newContents) +178
   System.Web.Mvc.DefaultModelBinder.UpdateDictionary(ControllerContext controllerContext, ModelBindingContext bindingContext, Type keyType, Type valueType) +1211
   System.Web.Mvc.DefaultModelBinder.BindComplexModel(ControllerContext controllerContext, ModelBindingContext bindingContext) +921
   System.Web.Mvc.DefaultModelBinder.BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) +416
   Namespace.For.MyBinder.BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) +1195
   System.Web.Mvc.DefaultModelBinder.GetPropertyValue(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor, IModelBinder propertyBinder) +17
   System.Web.Mvc.DefaultModelBinder.BindProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor) +384
   System.Web.Mvc.DefaultModelBinder.BindProperties(ControllerContext controllerContext, ModelBindingContext bindingContext) +88
   System.Web.Mvc.DefaultModelBinder.BindComplexElementalModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Object model) +53
   System.Web.Mvc.DefaultModelBinder.BindComplexModel(ControllerContext controllerContext, ModelBindingContext bindingContext) +1314
   System.Web.Mvc.DefaultModelBinder.BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) +416
   Namespace.For.MyBinder.BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) +1195
   System.Web.Mvc.ControllerActionInvoker.GetParameterValue(ControllerContext controllerContext, ParameterDescriptor parameterDescriptor) +317
   System.Web.Mvc.ControllerActionInvoker.GetParameterValues(ControllerContext controllerContext, ActionDescriptor actionDescriptor) +117
   System.Web.Mvc.Async.<>c__DisplayClass25.<BeginInvokeAction>b__1e(AsyncCallback asyncCallback, Object asyncState) +446
   System.Web.Mvc.Async.WrappedAsyncResult`1.Begin(AsyncCallback callback, Object state, Int32 timeout) +130
   System.Web.Mvc.Async.AsyncControllerActionInvoker.BeginInvokeAction(ControllerContext controllerContext, String actionName, AsyncCallback callback, Object state) +302
   System.Web.Mvc.<>c__DisplayClass1d.<BeginExecuteCore>b__17(AsyncCallback asyncCallback, Object asyncState) +30
   System.Web.Mvc.Async.WrappedAsyncResult`1.Begin(AsyncCallback callback, Object state, Int32 timeout) +130
   System.Web.Mvc.Controller.BeginExecuteCore(AsyncCallback callback, Object state) +382
   System.Web.Mvc.Async.WrappedAsyncResult`1.Begin(AsyncCallback callback, Object state, Int32 timeout) +130
   System.Web.Mvc.Controller.BeginExecute(RequestContext requestContext, AsyncCallback callback, Object state) +317
   System.Web.Mvc.Controller.System.Web.Mvc.Async.IAsyncController.BeginExecute(RequestContext requestContext, AsyncCallback callback, Object state) +15
   System.Web.Mvc.<>c__DisplayClass8.<BeginProcessRequest>b__2(AsyncCallback asyncCallback, Object asyncState) +71
   System.Web.Mvc.Async.WrappedAsyncResult`1.Begin(AsyncCallback callback, Object state, Int32 timeout) +130
   System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, Object state) +249
   System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContext httpContext, AsyncCallback callback, Object state) +50
   System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, Object extraData) +16
   System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +301
   System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +155

1 ответ

Похоже, вы забыли повторно заполнить Subs собственность вашего MyViewModel в POST действие. Вы должны сделать это в обоих GET а также POST запрос.

Вы можете рефакторировать его в метод и вызывать его в обоих действиях:

private Dictionary<MyEnumType, IList<MyViewModel.MySubViewModel>> GetSubsDict()
{
    return new Dictionary<MyEnumType, IList<MyViewModel.MySubViewModel>>() 
                {
                    {
                        MyEnumType.MySubViewModel, 
                        new List<MyViewModel.MySubViewModel>
                        {
                            new MyViewModel.MySubViewModel
                            {
                                Name = "Foo-Bar"
                            }
                        }
                    }
                }
}

Действие GET:

public ActionResult EditPage(Int32? id)
{
    MyViewModel testViewModel = new MyViewModel
                                    {
                                        Subs = GetSubsDict();
                                    }
    return View(testViewModel);
}

И снова в действии POST:

public ActionResult EditPage(MyViewModel model)
{
    model.Subs = GetSubsDict();
    return View(model);
}
Другие вопросы по тегам