带接口的ASP.NET MVC UpdateModel

Bri*_*nga 6 asp.net-mvc defaultmodelbinder modelbinders

我试图让UpdateModel填充一个在编译时设置为只有接口的模型.例如,我有:

// View Model
public class AccountViewModel {
  public string Email { get; set; }
  public IProfile Profile { get; set; }
}

// Interface
public interface IProfile {
  // Empty
}

// Actual profile instance used
public class StandardProfile : IProfile {
  public string FavoriteFood { get; set; }
  public string FavoriteMusic { get; set; }
}

// Controller action
public ActionResult AddAccount(AccountViewModel viewModel) {
  // viewModel is populated already
  UpdateModel(viewModel.Profile, "Profile"); // This isn't working.
}

// Form
<form ... >
  <input name='Email' />
  <input name='Profile.FavoriteFood' />
  <input name='Profile.FavoriteMusic' />
  <button type='submit'></button>
</form>
Run Code Online (Sandbox Code Playgroud)

另请注意,我有一个自定义模型绑定器,它继承自正在使用的DefaultModelBinder,它在重写的CreateModel方法中使用StandardProfile实例填充IProfile.

问题是从不填充FavoriteFood和FavoriteMusic.有任何想法吗?理想情况下,这一切都将在模型绑定器中完成,但我不确定如果不编写完全自定义的实现.

谢谢,Brian

ano*_*ous 2

我必须检查 ASP.NET MVC 代码 (DefaultModelBinder),但我猜测它反映的是 IProfile 类型,而不是实例 StandardProfile。

因此它会查找可以尝试绑定的任何 IProfile 成员,但它是一个空接口,因此它认为自己已完成。

您可以尝试更新 BindingContext 并将 ModelType 更改为 StandardProfile,然后调用

bindingContext.ModelType = typeof(StandardProfile);
IProfile profile = base.BindModel(controllerContext, bindingContext);
Run Code Online (Sandbox Code Playgroud)

无论如何,有一个空的界面很奇怪~


编辑:只想添加上面的代码只是伪代码,您需要检查 DefaultModelBinder 以准确了解您想要编写的内容。


编辑#2:

你可以做:

public class ProfileModelBinder : DefaultModelBinder
{
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) {
    {
        bindingContext.ModelType = typeof(StandardProfile);
        return base.BindModel(controllerContext, bindingContext);
    }
}
Run Code Online (Sandbox Code Playgroud)

无需为 AccountView 制作模型绑定器,该绑定器就可以正常工作。


编辑#3

测试了一下,上面的binder可以用,只需要添加:

ModelBinders.Binders[typeof(IProfile)] = new ProfileModelBinder();
Run Code Online (Sandbox Code Playgroud)

你的动作看起来像:

public ActionResult AddAccount(AccountViewModel viewModel) {
    // viewModel is fully populated, including profile, don't call UpdateModel
}
Run Code Online (Sandbox Code Playgroud)

您可以在设置模型绑定器时使用 IOC(例如注入类型构造函数)。

  • 简单说一下:在版本 2 中,ModelType setter 现已过时。如果您尝试设置它,您将收到此消息:“此属性设置器已过时,因为它的值现在是从 ModelMetadata.Model 派生的。” (2认同)