asp.net MVC模型绑定错误“无法创建接口实例”

本文关键字:创建 接口 实例 MVC net 模型 绑定 错误 asp | 更新日期: 2023-09-27 18:16:16

我有一个ViewModel,它有一个接口作为属性。当我提交页面时,我得到了"Cannot create a instance of Interface"的错误。

ViewModel是这样的:

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

有两个类实现这个接口。相应的ViewModels动态地加载一个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有另一个自定义绑定,但我不能只是添加一个新的modelbinder . binder . add与相同的键(IPlanoPagamentosParcelas),因为已经有一个键与此类型。

那么,有没有其他的方法来为实现相同接口的ViewModels创建自定义模型绑定?

asp.net MVC模型绑定错误“无法创建接口实例”

我相信解决办法如下:

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将决定实例化哪个具体类。我已经测试了这个解决方案,它对我很有效。它可以改进为更具可扩展性(删除开关为其他东西可能),但我只是试图使它工作。

这里是我基于我的问题(也许你可以从那里得到更多的信息)多态模型绑定,下面是我创建的代码来模拟这个场景(只是在有疑问的情况下):

模型:

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();
    }
}

全球。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());
    }

视图(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" />
}

问候。