asp.net MVC 模型绑定错误"Cannot create an instance of Interface"

asp.net MVC model binding error "Cannot create an instance of Interface"

我有一个 ViewModel,其接口为 属性。当我提交页面时,出现 "Cannot create an instance of Interface" 错误。

ViewModel 是这样的:

public class PlanoPagamentoViewModel
{
     //some properties
     public IPlanoPagamentosParcelas PlanoPagamentosParcelas { get; set; }     
}

有两个 类 实现了这个接口。 根据所选的选项,相应的 ViewModel 会动态加载 PartialView。

public class PlanoPagamentoCartaoViewModel : IPlanoPagamentosParcelas
{
   //some properties
}

public class PlanoPagamentoCrediarioViewModel : IPlanoPagamentosParcelas
{
   //some properties
}

我进行了一项研究,发现需要创建自定义模型绑定,然后我就这样做了:

public class PlanoPagamentoParcelasBinder : DefaultModelBinder
{
    protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
    {
        var type = typeof(PlanoPagamentoCartaoViewModel);
        var model = Activator.CreateInstance(type);
        bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, type);

        return model;
    }
}

并在 Global.asax、Application_Start 方法中添加这个新的自定义绑定:

ModelBinders.Binders.Add(typeof(IPlanoPagamentosParcelas), new PlanoPagamentoParcelasBinder());  

它适用于 PlanoPagamentoCartaoViewModel,但我需要为 PlanoPagamentoCrediarioViewModel 设置另一个自定义绑定,但我不能只添加一个具有相同密钥的新 ModelBinders.Binders.Add (IPlanoPagamentosParcelas) 因为已经有一把这种类型的钥匙。

那么,是否有任何其他方法可以为实现相同接口的 ViewModel 创建自定义模型绑定?

我认为解决方案如下:

protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
{
        var typeValueProvider = bindingContext.ValueProvider.GetValue("Type");

        var type = (int)typeValueProvider.ConvertTo(typeof(int));

        Type instanceType = null;

        switch (type)
        {
            case 1:
                instanceType = typeof(PlanoPagamentoCartaoViewModel );
                break;

            case 2:
                instanceType = typeof(PlanoPagamentoCrediarioViewModel );
                break;
        }

        if (!typeof(IPlanoPagamentosParcelas).IsAssignableFrom(instanceType))
        {
            throw new InvalidOperationException("Bad Type");
        }
        var model = Activator.CreateInstance(instanceType);
        bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, instanceType);
        return model;
}

在上面的代码中,var typeValueProvider = bindingContext.ValueProvider.GetValue("Type"); Type 将决定实例化哪个具体 class。我测试了这个解决方案,它对我有用。它可以改进为更具可扩展性(也许删除其他东西的开关)但我只是试图让它工作。

这是我提出问题的依据(也许您可以从那里获得更多信息)Polymorphic model binding 下面是我为模拟这种情况而创建的代码(以防万一):

型号:

public class NewVehicleViewModel
{
    public string Type { get; set; }

    public VehicleViewModel Vehicle { get; set; }
}

public interface VehicleViewModel
{
    string Name { get; set; }
    string Color { get; set; }
}

public class CarViewModel : VehicleViewModel
{
    public string Color { get; set; }

    public string Name { get; set; }

    public string Brand { get; set; }
}

public class TankViewModel : VehicleViewModel
{
    public string Color { get; set; }

    public string Name { get; set; }

    public string Weapon { get; set; }
}

活页夹:

public class VehicleBinder : DefaultModelBinder
{
    protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
    {
        var typeValueProvider = bindingContext.ValueProvider.GetValue("Type");

        var type = (int)typeValueProvider.ConvertTo(typeof(int));

        Type instanceType = null;

        switch (type)
        {
            case 1:
                instanceType = typeof(CarViewModel);
                break;

            case 2:
                instanceType = typeof(TankViewModel);
                break;
        }

        if (!typeof(VehicleViewModel).IsAssignableFrom(instanceType))
        {
            throw new InvalidOperationException("Bad Type");
        }
        var model = Activator.CreateInstance(instanceType);
        bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, instanceType);
        return model;
    }
}

控制器:

public class VehiclesController : Controller
{
    // GET: Vehicles
    public ActionResult Index()
    {
        return View();
    }

    [HttpPost]
    public ActionResult Create(NewVehicleViewModel vm)
    {
        return View();
    }
}

GLOBAL.ASAX:

    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);
        ModelBinders.Binders.Add(typeof(VehicleViewModel), new VehicleBinder());
    }

VIEW (Index.cshtml):

@{
    ViewBag.Title = "New Vehicle";
}


@using (Html.BeginForm("Create", "Vehicles"))
{
    <label>Type</label>
    <input name="type" type="text" />

    <label >Name</label>
    <input name="Vehicle.Name" type="text"/>

    <label>Color</label>
    <input name="Vehicle.Color" type="text" />

    <label>Weapon</label>
    <input name="Vehicle.Weapon" type="text" />

    <label>Brand</label>
    <input name="Vehicle.Brand" type="text" />

    <input type="submit" />
}

此致。