A создал новый CustomModelBinder из уже работавшего. Почему новый никогда не вызывается для привязки?

Могу ли я сделать что-то подобное?

[HttpPost]
public ActionResult Index(WizardViewModel wizard, IStepViewModel step)
{

Где у меня есть следующее в моем global.asax.cs application_start

    ModelBinders.Binders.Add(typeof(IStepViewModel), new StepViewModelBinder());
    ModelBinders.Binders.Add(typeof(WizardViewModel), new WizardViewModelBinder());

Обновлять

Итак, я попытался увидеть, что не так. Вот мой новый код. Похоже, проблема в этой WizardViewModel и ее связующем. Что «сообщает» приложению, что следует ожидать и входящую модель Wizard?

[HttpPost]
public ActionResult Index(WizardViewModel wizard)
{

Где у меня есть следующее в моем global.asax.cs application_start

    ModelBinders.Binders.Add(typeof(WizardViewModel), new WizardViewModelBinder());

Полный код связующего

namespace Tangible.Binders
{
    public class StepViewModelBinder : DefaultModelBinder
    {
        protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
        {
            var stepTypeValue = bindingContext.ValueProvider.GetValue("StepType");
            var stepType = Type.GetType((string)stepTypeValue.ConvertTo(typeof(string)), true);
            var step = Activator.CreateInstance(stepType);

            bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => step, stepType); 
            return step; 
        }
    }

    public class WizardViewModelBinder : DefaultModelBinder
    {
        protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
        {
                var wizardValue = bindingContext.ValueProvider.GetValue("wizard");
                if (wizardValue != null)
                {
                    var wizardType = Type.GetType((string)wizardValue.ConvertTo(typeof(string)), true);
                    var wizard = Activator.CreateInstance(wizardType);

                    bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => wizard, wizardType);
                    return wizard;
                }
                else
                {
                    var wizard = new Tangible.Models.WizardViewModel();
                    wizard.Initialize();
                    return wizard;
                }
        }
    }
}

person Doug Chamberlain    schedule 26.07.2011    source источник
comment
Да, но у меня может быть много других проблем, из-за которых это не работает. Поэтому, прежде чем идти дальше, я решил проверить, возможно ли это.   -  person Doug Chamberlain    schedule 27.07.2011
comment
Даг, насколько я помню из вашего предыдущего вопроса в stackoverflow.com/questions/6834814/, WizardViewModel включил IList<IStepVIewModel> в качестве атрибута. Это все еще так? Если это так, то ваш WizardViewModelBinder, вероятно, также должен обрабатывать привязку для дочернего класса IStepViewModel. Как и другие, пожалуйста, опубликуйте код привязки модели.   -  person counsellorben    schedule 08.08.2011
comment
Обновил мой вопрос. Как и прежде, есть два биндера, один выполнять один не будет.   -  person Doug Chamberlain    schedule 08.08.2011
comment
Даг, не могли бы вы также показать упрощенные модели, простые действия контроллера GET и POST и представление? Когда я пробовал ваши связыватели, проблема, с которой я столкнулся, связана с StepViewModelBinder, а не с WizardViewModelBinder.   -  person counsellorben    schedule 09.08.2011


Ответы (4)


Ответ прост - Да! Это то, что вы ДОЛЖНЫ делать, когда у вас есть собственная логика для привязки значений к вашим параметрам. Вы даже можете сделать это с помощью ModelBinderAttribute, задается по каждому из параметров в отдельности.

    [HttpPost]
    public ActionResult Index([ModelBinder(typeof(WizardViewModelBinder))]WizardViewModel wizard, 
[ModelBinder(typeof(StepViewModelBinder))]IStepViewModel step)
    { }

И, как я вижу, ошибка в вашем коде связывателя модели. У меня нет времени проверять это, но насколько я помню, CreateModel используется связывателем модели для создания экземпляра модели, а затем возвращаемый экземпляр привязывается к модели. Итак, переопределите BindModel вместо CreateModel и напишите логику привязки модели в BindModel. Это определенно работает.

public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) 
{
//your model binding logic here
}
person archil    schedule 03.08.2011
comment
Теперь это очень вкусный хрустящий ответ. Я приму это, как только у меня будет возможность проверить это. Если вы нашли этот вопрос интересным, я был бы признателен за вопрос - person Doug Chamberlain; 04.08.2011
comment
К сожалению, это не привело к каким-либо изменениям. Мой CustomModelBinder для WizardViewModel по-прежнему не вызывается. - person Doug Chamberlain; 04.08.2011
comment
Оба пути - через Global.asax и через атрибуты параметров должны работать. Опубликуйте свой код ModelBinder, возможно, это поможет нам помочь вам - person archil; 05.08.2011
comment
Вы поняли, мистер. Это замечательно! Это добавляет простоты моему контроллеру. Просто передайте Модель и Vwwwwooop! - person Doug Chamberlain; 10.08.2011
comment
Если этот ответ был полезен, вы могли бы наградить его наградой за вопрос - person archil; 10.08.2011
comment
О, мой плохой, я думал, что это было автоматически. - person Doug Chamberlain; 10.08.2011

Я делал что-то подобное в прошлом, когда я передал строку, а затем разделил значение.

person Internet Engineer    schedule 26.07.2011
comment
Насколько я понимаю, вся цель ModelBinders состоит в том, чтобы позволить сложным объектам передаваться в действия контроллера в качестве параметров вместо простых типов данных. Это неправильно? - person Doug Chamberlain; 27.07.2011
comment
ModelBinders были представлены в версии 3.5. До этого мое решение было эффективным, но примитивным вариантом. - person Internet Engineer; 27.07.2011

Я бы сказал, что ответ просто: Да! В своем комментарии вы обеспокоены «многими другими проблемами», которые могут вызвать проблемы. Не зная, какие проблемы вы имеете в виду, трудно вам помочь. Но то, что вы сделали, это именно то, для чего предназначены папки для моделей. И нет причин, по которым у вас должен быть только один объект на действие.

person Achim    schedule 03.08.2011
comment
Я имел в виду, что, возможно, мой код в другом месте вызывает неожиданные результаты. Я бы предпочел увидеть реальный пример. Вместо восторженного да. Это ситуация, когда я не хотел бороться с кодом, который едва понимаю, без участия некоторых экспертов. - person Doug Chamberlain; 04.08.2011
comment
Я действительно не вижу вашей проблемы: вы используете связыватели моделей именно так, как они предназначены. На мой взгляд, использование атрибутов, предложенных archil, обычно является плохим выбором, но это зависит от вашего конкретного варианта использования. Если вы создадите странную иерархию типов, у вас тоже могут возникнуть проблемы. Но это все не зависит от связывателей моделей и (более или менее) совершенно другой темы. Так что мой ответ по-прежнему: да, вы правильно используете связующие модели! - person Achim; 04.08.2011
comment
Не уверен, что мне нужно переименовать свой вопрос, но мне действительно нужен пример нескольких связующих для действия. Что и предоставил Арчил. - person Doug Chamberlain; 04.08.2011
comment
В вашем исходном примере тоже используются несколько связующих!? - person Achim; 04.08.2011
comment
Когда я выполняю код, я ожидаю, что смогу установить точку останова для каждого настраиваемого связывателя модели, и во время вызова моего действия я вижу, что настраиваемые связыватели вызываются, но он пропускает сразу после второго ModelBinder. Это показало мне, что нужно сделать больше, чем просто заставить список параметров принимать модели вместо простых типов данных. - person Doug Chamberlain; 04.08.2011
comment
В вашем примере должны вызываться оба метода Bind ваших пользовательских привязок, и вы должны иметь возможность устанавливать точки останова в этих методах. Но ваши подшивки создаются только один раз, конечно. Где именно вы установили точки останова? - person Achim; 04.08.2011
comment
Я установил здесь точку останова protected override object CreateModel в каждом CustomModelBinder. - person Doug Chamberlain; 04.08.2011

Я был действительно разочарован теми обручами, которые ASP.NET MVC Model Binding требовал от меня пройти, чтобы получить некоторую базовую десериализацию.

Поскольку привязка модели была далеко не такой прозрачной, как я надеялся, для сложных Model/ViewModels, я просто создал собственный ActionFilter для разрешения типов [и ТОЛЬКО типов], которые я хочу десериализовать в методе действия, и использовать ServiceStack.Text для всех моих потребностей в сериализации/десериализации.

Посмотрите здесь:

https://gist.github.com/3b18a58922fdd8d5a963

person Anuj    schedule 07.08.2011