まず、大きな投稿(最初にいくつかの調査を試みました)と同じ質問に関するテクノロジの組み合わせ(ASP.NET MVC 3、Ninject、およびMvcContrib)について申し訳ありません。
一部のクライアントの注文を処理するために、ASP.NETMVC3を使用してプロジェクトを開発しています。
つまり、抽象クラスから継承されたオブジェクトがいくつかOrder
あり、コントローラーに対してPOSTリクエストが行われたときにそれらを解析する必要があります。正しいタイプを解決するにはどうすればよいですか?クラスをオーバーライドする必要がありますDefaultModelBinder
か、それともこれを行う他の方法がありますか?誰かが私にこれを行う方法に関するいくつかのコードまたは他のリンクを提供できますか?どんな助けでも素晴らしいでしょう!投稿がわかりにくい場合は、明確にするために変更を加えることができます。
したがって、処理する必要のある注文に対して、次の継承ツリーがあります。
public abstract partial class Order {
public Int32 OrderTypeId {get; set; }
/* rest of the implementation ommited */
}
public class OrderBottling : Order { /* implementation ommited */ }
public class OrderFinishing : Order { /* implementation ommited */ }
このクラスはすべてEntityFrameworkによって生成されるため、モデルを更新する必要があるため、変更しません(拡張できることはわかっています)。また、より多くの注文がありますが、すべてがから派生していOrder
ます。
注文を作成するための汎用ビュー( )があり、このビューは、継承された注文(この場合はと)Create.aspx
ごとに強く型付けされた部分ビューを呼び出します。クラスでGETリクエスト用のメソッドとPOSTリクエスト用のメソッドを定義しました。2番目は次のようなものです。OrderBottling
OrderFinishing
Create()
OrderController
public class OrderController : Controller
{
/* rest of the implementation ommited */
[HttpPost]
public ActionResult Create(Order order) { /* implementation ommited */ }
}
ここで問題があります。フォームからのデータを含むPOSTリクエストを受信すると、MVCのデフォルトのバインダーがオブジェクトをインスタンス化しようとしますOrder
。これは、メソッドのタイプがそれであるため問題ありません。しかし、Order
は抽象的であるため、インスタンス化することはできません。
質問:Order
ビューによって送信された具体的なタイプをどのように見つけることができますか?
私はすでにStackOverflowでここを検索し、これについて多くのことをグーグルで検索し(私はこの問題に約3日間取り組んでいます!)、いくつかの同様の問題を解決するいくつかの方法を見つけましたが、私の本当のようなものは見つかりませんでした問題。これを解決するための2つのオプション:
- ASP.NET MVC
DefaultModelBinder
をオーバーライドし、ダイレクトインジェクションを使用してOrder
;がどのタイプであるかを検出します。 - 注文ごとにメソッドを作成します(美しくなく、維持するのに問題があります)。
問題を解決する正しい方法ではないと思うので、2番目のオプションは試していません。最初のオプションでは、注文のタイプを解決してインスタンス化するためにNinjectを試しました。私のNinjectモジュールは次のようなものです。
private class OrdersService : NinjectModule
{
public override void Load()
{
Bind<Order>().To<OrderBottling>();
Bind<Order>().To<OrderFinishing>();
}
}
NinjectのGet<>()
メソッドを使用して、タイプの1つを取得しようとしましたが、タイプを解決する方法は1つではないことがわかります。そのため、モジュールが適切に実装されていないことを理解しています。私も両方のタイプにこのように実装しようとしました:Bind<Order>().To<OrderBottling>().WithPropertyInject("OrderTypeId", 2);
、しかしそれは同じ問題を抱えています...このモジュールを実装する正しい方法は何でしょうか?
また、MvcContribモデルバインダーを使用してみました。私はこれをしました:
[DerivedTypeBinderAware(typeof(OrderBottling))]
[DerivedTypeBinderAware(typeof(OrderFinishing))]
public abstract partial class Order { }
そしてGlobal.asax.cs
私はこれをしました:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
ModelBinders.Binders.Add(typeof(Order), new DerivedTypeModelBinder());
}
ただし、これにより例外がスローされます。System.MissingMethodException:抽象クラスを作成できません。したがって、バインダーが正しいタイプに解決されないか、解決できないと思います。
よろしくお願いします!
編集:まず第一に、あなたの答えをマーティンとジェイソンに感謝し、遅れて申し訳ありません!私は両方のアプローチを試しましたが、両方ともうまくいきました!マーティンの答えはより柔軟で、私のプロジェクトのニーズのいくつかを満たしているので、正しいとマークしました。具体的には、各リクエストのIDはデータベースに保存されており、IDを1か所(データベースまたはクラス)でのみ変更すると、それらをクラスに配置するとソフトウェアが破損する可能性があります。マーティンのアプローチは、その点で非常に柔軟です。
@Martin:私のコードで行を変更しました
var concreteType = Assembly.GetExecutingAssembly().GetType(concreteTypeValue.AttemptedValue);
に
var concreteType = Assembly.GetAssembly(typeof(Order)).GetType(concreteTypeValue.AttemptedValue);
私のクラスは別のプロジェクト(そして別のアセンブリ)にあるからです。これを共有しているのは、外部アセンブリの型を解決できない実行中のアセンブリのみを取得するよりも柔軟性があるように見えるためです。私の場合、すべての注文クラスは同じアセンブリにあります。それは良くも魔法の公式でもありませんが、これを共有するのは面白いと思います;)