2012-01-11 11 views
3

私の理解では、ASP.NET MVCは、唯一のアクションの引数はコンクリートクラスとして掲示物を受け入れるコントローラ、でアクションにオブジェクトを投稿することができますということです。ASP.NET MVCは、インターフェースでアクションにモデルを投稿

これを回避する方法や良い方法はありますか?

public ActionResult SaveAdjustment(IModel model) 
{ 
    switch (model.SubsetType) 
    { 
     // factory like usage 
    } 
} 

そして、このアクションのために、私は数多くの景色を眺めることができ

は、すべて強くIModelをを実装するオブジェクトに入力された、私が望むすべて:私の場合は

、私は、引数としてインターフェイスを受け入れる作用を有しますこの1つの方法に投稿できるようにする。

もちろん、これは私にエラーを与えて実行している:

Cannot create an instance of an interface

はこれに周りの素敵な作品はありますか?あるいは、それぞれのアクションメソッドを作成し、このようなメソッドに送る必要がありますか?

答えて

1

私はこれを私の元の質問の可能な解決策と言いましたが、その解決策は私が最後に行ったものです。このように、私はモデルのデフォルトのバインディング実装に触れる必要はなく、このアプローチは当初求めていたものよりも読みやすく理解可能なアプローチだと私は考えています。

私がこのアプローチにしたい理由がわからない場合は、これをどのようにしてOOベネフィットに使用できるかの例を追加しました。

[HttpPost] 
    public ActionResult SaveModelA(ModelA model) 
    { 
     return SaveModel(model); 
    } 

    [HttpPost] 
    public ActionResult SaveModelB(ModelB model) 
    { 
     return SaveModel(model); 
    } 

    private ActionResult SaveModel(IModel model) 
    { 
     IExampleService exampleService; 
     IRequirements requirements; 

     switch (model.SubsetType) 
     { 
      case SubsetType.ModelA: 
       myService = new ModelAService(); 
       requirements = new ModelARequirements 
       { 
        ModelASpecificProperty = "example" 
       }; 
       break; 
      case SubsetType.ModelB: 
       myService = new ModelBService(); 
       requirements = new ModelBRequirements 
       { 
        ModelBSpecificProperty1 = "example", 
        ModelBSpecificProperty2 = "example2", 
        ModelBSpecificProperty3 = "example3" 
       }; 
       break;     
      default: 
       throw new InvalidEnumArgumentException(); 
     } 

     var serviceResonse = exampleService.ExecuteExample(model, requirements); 

     return RedirectToAction("Index", new 
     { 
      ExampleData = serviceResponse.ExampleDate 
     }); 
    } 

はケースでは、コード内で明確ではありません。アドバイス

ModelA : IModel 
ModelB : IModel 
ModelARequirements : IModelRequirements 
ModelBRequirements : IModelRequirements 
ModelAService : IExampleService 
ModelBService : IExampleService 

// and IModel defines a property SubsetType SubsetType { get; } 
3

MVCは、一般に、Request.Formからの投稿時にモデルをバインドします。つまり、名前=値のペアです。デフォルトの実装では、バインディングインタフェースや抽象クラスのサポートがないという理由は明らかです。mvcは、name = valueのペアからどの具体的なクラスを作成するかを判断できません。クライアントサイドに隠しフィールドがある場合や、作成する具体的なクラスの型を決定できる他のパラメータがある場合は、カスタムモデルバインダーを作成するだけで済みます。私は実際には、MVCのコントローラとアクションをすることを意図しているあなたはDefaultModelBinderCreateModelメソッドをオーバーライドし、Global.asaxの中の機能

public class IModelModelBinder : DefaultModelBinder 
{ 
    protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, System.Type modelType) 
    { 
     //Create and return concrete instance 
    } 
} 

とモデルバインダー登録

ModelBinders.Binders.Add(typeof(IModel?), new IModelModelBinder()); 

を結合して構築された他のすべてを再利用することができると信じて薄く、サービス層のいくつかの種類が厚くなければなりません。実装しようとしているアクションロジックがすぐに複雑になる可能性があるので、別のサービスに移行することをお勧めします。

+0

感謝。面白いことに、アクションがどのように薄くなければならないかについて言及しています。なぜなら、現在私はこれをここに置いています。私はそれを取り出し、それをあなたのようなサービスに入れて、非常に単純なアクションを残して、すべて同じ方法で実行します(別のモデルだけで)。今のところ、それぞれの具体的なクラスのアクションを作成して、メソッドのような抽象的なファクトリを実行するようにしました。今投稿されたオブジェクトがnullの新しい問題に直面しています... :( – Arkiliknam