Asp.Net MVC 4 - привязка к сложному объекту, не работающему в POST

У меня есть модель вида, которая выглядит так:

 public class EventVm
    {
        public int Id { get; set; }
        public int GroupId { get; set; }
        public string Title { get; set; }       
        public EventLayout EventLayout { get; set; }
    }

EventLayout - это пользовательский объект, который выглядит следующим образом:

public class EventLayout
{
    private const string SingleColumnLayoutLocalKey = "MyOrg.SingleColumnLayout";
    ...
    //Removed for breviety

    public static EventLayout SingleColumnLayout = new EventLayout(SingleColumnLayoutLocalKey);
    ...
    //Removed for breviety

    public string Value
    {
        get { return _layoutLocalKey; }
    }

    private readonly string _layoutLocalKey;

    private EventLayout(string layoutLocalKey)
    {
        _layoutLocalKey = layoutLocalKey;
    }

    public static EventLayout LayoutFromLocalString(string localString)
    {
       ...
    }

    public override string ToString()
    {
        return _layoutLocalKey;
    }

    public override bool Equals(object obj)
    {
        if (obj.GetType() != this.GetType())
        {
            return false;
        }
        if (this._layoutLocalKey == obj.ToString())
        {
            return true;
        }
        return false;
    }

    public override int GetHashCode()
    {
        return this._layoutLocalKey.GetHashCode();
    }
}

По сути, EventLayout - это просто пользовательское перечисление, которое обеспечивает хранилище строк. EventLayout привязан к элементу управления формы Select (T() - просто метод расширения локализации):

<select id="eventLayoutSelect" name="EventVm.EventLayout">
    @foreach (var option in Model.EventLayoutOptions)
    {
        <option value="@option.Value" @((Model.EventLayout != null && Model.EventLayout.Equals(option))
                                            ? "selected=selected" 
                                            : string.Empty)>@T(option.Value)</option>
    }
</select>

Когда я отправляю эту форму на сервер, свойство EventVm.EventLayout становится пустым, когда действие пытается выполнить привязку. Однако я вижу, что экземпляр EventLayout размещен в данных формы:

Мое действие выглядит так:

 [HttpPost]
    public ActionResult Update(EventVm eventVm)
    {
        _eventService.UpdateEvent(eventVm);
        return RedirectToAction("Index", new { groupId = eventVm.GroupId }); 
    }

Может кто-нибудь сказать мне, что я сделал не так, пожалуйста?

2 ответа

Пользовательская привязка решила проблему. Спасибо всем за полезные комментарии.

Брэд Кристи отметил, что, поскольку объект, с которым мое действие пытается связать, имеет только частный конструктор, потребуется специальная привязка.

Пользовательская привязка:

public class EventVmBinder : IModelBinder
{
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {

        HttpRequestBase request = controllerContext.HttpContext.Request;

        var eventVm = new EventVm()
        {
            Id = Int32.Parse(request.Form.Get("Id")),
            GroupId = Int32.Parse(request.Form.Get("GroupId")),
            Title = request.Form.Get("Title"),
            HeaderMarkup = request.Form.Get("HeaderMarkup"),
            LeftNavigationMarkup = request.Form.Get("LeftNavigationMarkup"),
            CenterContentMarkup = request.Form.Get("CenterContentMarkup"),
            RightNavigationMarkup = request.Form.Get("RightNavigationMarkup"),
            EventLayout = EventLayout.LayoutFromLocalString(request.Form.Get("EventLayout")),
            DisplayOrder = Int32.Parse(request.Form.Get("DisplayOrder")),
            Active = request.Form.Get("Active").As<bool>(),
            CanEdit = request.Form.Get("CanEdit").As<bool>()
        };

        return eventVm;
    }

}

Связать это на действии:

 [HttpPost]
    public ActionResult Create([ModelBinder(typeof(EventVmBinder))]EventVm eventVm)
    {
        _groupService.AddEventToGroup(eventVm);
        return RedirectToAction("Index", new {groupId = eventVm.GroupId});
    }

Замените цикл foreach на цикл for, как показано ниже

@foreach (var option in Model.EventLayoutOptions)
{
<option value="@option.Value" @((Model.EventLayout != null && Model.EventLayout.Equals(option))
                                        ? "selected=selected" 
                                        : string.Empty)>@T(option.Value)</option>
}  

с

for(int i=0; i<Model.EventLayoutOptions.Count; i++ )
{
<option value="@Model.EventLayoutOptions[i].Value" @((Model.EventLayout != null &&      Model.EventLayout.Equals(Model.EventLayoutOptions[i]))
                                        ? "selected=selected" 
                                        :  string.Empty)>@T(Model.EventLayoutOptions[i].Value)</option>
}
Другие вопросы по тегам