Пользовательская модель Binder не срабатывает
Я зарегистрировал собственное связующее устройство для MyList в global.asax. Однако модельное связующее не срабатывает для вложенных свойств, для простых типов оно отлично работает. В приведенном ниже примере он запускается для Index(), но не запускается для Index2()
Global.asax
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
ModelBinders.Binders.Add(typeof(MyList), new MyListBinder());
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
}
Код:
public class MyListBinder : IModelBinder
{
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
return new MyList();
}
}
public class MyList
{
public List<int> items { get; set; }
}
public class MyListWrapper
{
public MyList listItems { get; set; }
}
public class TestController : Controller
{
public ActionResult Index(MyList list) // ModelBinder fires :-)
{
return View();
}
public ActionResult Index2(MyListWrapper wrapper) // ModelBinder does not fire! :-(
{
return View();
}
}
Ответы
Ответ 1
Взаимодействия с образцами используются, чтобы позволить действиям принимать сложные типы объектов в качестве параметров. Эти сложные типы должны генерироваться посредством запросов POST, например, путем отправки формы. Если у вас есть очень сложный объект, который не может быть привязан связующим устройством по умолчанию (или он не будет эффективным), вы можете использовать пользовательские привязки модели.
Чтобы ответить на ваш вопрос:
если вы не добавите настраиваемое связующее устройство для класса MyListWrapper
, BindModel (из MyListBinder)
не будет вызываться в запросе GET, так работает ASP.NET MVC.
Однако, если вы измените свой код, добавив действие POST с параметром MyListWrapper
, вы увидите, что метод BindModel вызывается правильно.
[HttpGet]
public ActionResult Index2() // ModelBinder doesn't fire
{
return View();
}
[HttpPost]
public ActionResult Index2(MyListWrapper wrapper) // ModelBinder fires
{
return View();
}
И представление Index2
@model fun.web.MyListWrapper
@using (Html.BeginForm())
{
@Html.HiddenFor(m => m.listItems)
<input type="submit" value="Submit" />
}
Если вы хотите "контролировать" параметры действия в запросе GET, вы должны использовать фильтры действий.
Ответ 2
Добавьте это в свой мир:
ModelBinders.Binders.Add(typeof(MyListWrapper), new MyListWrapperBinder());
И затем создайте MyListWrapperBinder, который может обрабатывать привязку.
Ответ 3
Вы определили связующее для MyList
, поэтому он запускается только тогда, когда параметр ввода метода действия имеет тип MyList
.
ModelBinders.Binders.Add(typeof(MyList), new MyListBinder());
Если вы хотите, чтобы связующее устройство было запущено, даже если ваш MyList
вложен в другую модель, вы должны сделать это:
[ModelBinder(typeof(MyListBinder))]
public class MyList
{
public List<int> items { get; set; }
}
Затем, связывание модели запускается всякий раз, когда встречается тип MyList
, даже когда он вложен.
Ответ 4
Ваше связующее устройство соответствует вашему классу MyList, а не MyListWrapper. MyListBinder используется только с классом MyList или классом, который унаследован от MyClass.