Не связывайте один параметр действия - PullRequest
0 голосов
/ 30 июня 2011

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

[Post]
[PopulateModelFromId]
public ActionResult ChangeName( string name, MyModel model )
{
    try
    {
        model.changeName
        return JSONSuccess();
    }
    catch( ModelUpdateException )
    {
        return JSONFail();
    }
}

Имя и идентификатор модели отправляются с помощью ajax POST, а модель заполняется фильтром настраиваемых действий, который принимает идентификатор и извлекает модель из базы данных.

Фильтр действий выглядит следующим образом:

...
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
    // parse the id from the request
    MyModel model = getModelFromDataStoreById( id );
    filterContext.ActionParameters["model"] = model;
}
...

Проблема в том, что объект MyModel не имеет конструктора без параметров, и MVC пытается создать и привязать объект MyModel до того, как даже вызывается ActionFilter, но выдает исключение, поскольку он не может создать экземпляр объекта MyModel.

Мой первый вопрос: правильно ли я это делаю или я должен использовать что-то вроде HttpContext.Items для передачи данных между фильтром и действием? Во-вторых, есть ли способ сказать MVC не пытаться связывать объект MyModel, потому что он будет создан позже?

1 Ответ

2 голосов
/ 30 июня 2011

Пользовательское связующее модель кажется более подходящим для этой задачи, чем фильтр настраиваемого действия:

public class MyModelBinder : DefaultModelBinder
{
    protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
    {
        var id = bindingContext.ValueProvider.GetValue("id");
        if (id != null)
        {
            return GetModelFromDataStoreById(id.AttemptedValue);
        }
        return base.CreateModel(controllerContext, bindingContext, modelType);
    }
}

который будет зарегистрирован в Application_Start:

ModelBinders.Binders.Add(typeof(MyModel), new MyModelBinder());

Теперь действие вашего контроллера может выглядеть так:

[HttpPost]
public ActionResult ChangeName(string name, MyModel model)
{
    try
    {
        model.ChangeName();
        return JSONSuccess();
    }
    catch (ModelUpdateException)
    {
        return JSONFail();
    }
}
...