Я не уверен, ожидается ли это поведение или нет, но кажется, что пользовательская образцовая привязка не работает, когда привязка присвоена интерфейсному типу. Кто-либо экспериментировал с этим?
public interface ISomeModel {}
public class SomeModel : ISomeModel {}
public class MvcApplication : HttpApplication {
protected void Application_Start(object sender, EventArgs e) {
ModelBinders.Binders[typeof(ISomeModel)] = new MyCustomModelBinder();
}
}
С вышеупомянутым кодом, когда я связываю с моделью типа SomeModel, никогда не поражается MyCustomModelBinder; однако, если я изменяю вышеупомянутый код и замену typeof(ISomeModel)
для typeof(SomeModel)
и отправьте ту же самую форму, которой MyCustomModelBinder называют как ожидалось. Это кажется правильным?
Править
Я оказался назад в этом затруднительном положении спустя более чем год после того, как я первоначально задал этот вопрос, и теперь у меня есть решение, которое работает. Спасибо Matt Hidinger!
Я не уверен, связано ли это напрямую, но да, есть вещи, о которых вам нужно подумать при использовании привязки модели и интерфейсы ... Я столкнулся с аналогичными проблемами со связывателем модели по умолчанию, но это может не иметь прямого отношения в зависимости от того, как вы что-то делаете ...
Взгляните на следующее: ASP.net MVC v2 - Проблемы с привязкой модели отладки - ОШИБКА? ASP.net MVC v2 - Проблемы с привязкой модели отладки - ОШИБКА?
Я экспериментировал с этой проблемой и пришел к своеобразному решению. Я создал класс под названием InterfaceModelBinder:
public class InterfaceModelBinder : DefaultModelBinder
{
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
ModelBindingContext context = new ModelBindingContext(bindingContext);
var item = Activator.CreateInstance(
Type.GetType(controllerContext.RequestContext.HttpContext.Request.Form["AssemblyQualifiedName"]));
Func<object> modelAccessor = () => item;
context.ModelMetadata = new ModelMetadata(new DataAnnotationsModelMetadataProvider(),
bindingContext.ModelMetadata.ContainerType, modelAccessor, item.GetType(), bindingContext.ModelName);
return base.BindModel(controllerContext, context);
}
}
Который я зарегистрировал в Application_Start следующим образом:
ModelBinders.Binders.Add(typeof(IFormSubmission), new InterfaceModelBinder.Models.InterfaceModelBinder());
Интерфейс и конкретная реализация выглядят так:
public interface IFormSubmission
{
}
public class ContactForm : IFormSubmission
{
public string Name
{
get;
set;
}
public string Email
{
get;
set;
}
public string Comments
{
get;
set;
}
}
Единственным недостатком всего этого подхода (как вы, возможно, уже поняли) является то, что мне нужно откуда-то получить AssemblyQualifiedName, и в этом примере оно хранится как скрытое поле на стороне клиента, вот так:
<%=Html.HiddenFor(m => m.GetType().AssemblyQualifiedName) %>
Однако я не уверен, что недостатки раскрытия имени Type клиенту стоят потери преимуществ этого подхода. Action, подобный этому, может обрабатывать все отправленные формы:
[HttpPost]
public ActionResult Process(IFormSubmission form)
{
if (ModelState.IsValid)
{
FormManager manager = new FormManager();
manager.Process(form);
}
//do whatever you want
}
Есть мысли по поводу этого подхода?