2016-11-04 20 views
1

Iインターフェイスをプロパティとして持つViewModelがあります。私がページを提出すると、「インターフェイスのインスタンスを作成できません」というエラーが表示されます。asp.net MVCモデルバインディングエラー "インターフェイスのインスタンスを作成できません"

ViewModelには、このようなものです:

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

このインタフェースを実装する2つのクラスがあります。 対応する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)にはこのタイプのキーがすでに1つあります。

したがって、同じインタフェースを実装するViewModelsのカスタムモデルバインディングを作成する方法はありますか?

+0

typeof(IPlanoPagamentosParcelas)からtypeof(PlanoPagamentoParcelasBinder)またはtypeof(DefaultModelBinder)への変更 –

+0

@viveknuna同じエラーが発生しました。 2つのViewModelのIPlanoPagamentosParcelasを追加する必要がありますが、それは辞書であるため、 – Maturano

答えて

2

私は解決策は以下の通りであると信じています:上記のコードvar typeValueProvider = bindingContext.ValueProvider.GetValue("Type");Type

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

は、具体的なクラスをインスタンス化するかを決定するものになるだろう。私はこのソリューションをテストして、それは私のために働いた。それはより拡張可能になるように改善することができます(スイッチを他の何かのために削除するかもしれませんが)私はそれを機能させるように試みました。

MODELS:ここ

は、私は私の質問に(多分あなたはそこからより多くの情報を得ることができます)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; } 
} 

BINDER:

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

CONTROLLER:

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" /> 
} 

よろしく。

+0

という非常に興味深いアプローチですが、不可能ですが、NullRecerenceExceptionが発生しています: var typeValueProvider = bindingContext.ValueProvider.GetValue( "Type"); 初心者の質問には申し訳ありませんが、「タイプ」を別のものに変更する必要がありますか? – Maturano

+0

また、 "Type"をbindingContext.ModelNameに変更しようとしましたが、nullも返されます。 – Maturano

+0

タイプはインスタンス化するクラスを決定するために使用されるプロパティです。それは別のものかもしれませんが、具体的なクラスを何らかの形でインスタンス化する必要があります。 booleanプロパティ、おそらく 'IsPlanoPagamentoCartao'を使用してビューの隠しフィールドとして配置し、モデルバインダーでこのプロパティ' bindingContext.ValueProvider.GetValue( "IsPlanoPagamentoCartao");を使用して、作成するインスタントを決定することができます。 – dime2lo

関連する問題