ASP.NET MVC:パラメータにフォームのPOSTをバインドするときに密結合を避けます
-
22-08-2019 - |
質問
のは、私のようなインターフェースを持っているとしましょう
interface IThing {
int Id { get; set; }
string Title { get; set; }
}
また、ASP.NET MVCで私はフォームを持っている。このようなコントローラのアクションにポストます:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult NewThing([Bind(Exclude = "Id")] SimpleThing thing) {
// code to validate and persist the thing can go here
}
ここで、のSimpleThing のぎりぎりのIThing の実装具象クラスです。
しかし、私はすべてのメソッドがインターフェイスに対処したいと思います。私はNHiberateと、独自ののIThing の実装(のは、のRealThing のそれを呼びましょう)を使用したデータのアセンブリを持っています。それは「未知の実体」について文句を言うだろうので、私はそれにSimpleThingを渡すことはできません。
誰もがこれを行うためのクリーンな方法についてのアイデアを持っていますか?私は、ファクトリクラスを使用しての線に沿って何かを考えていました。しかし、どのように私はMVCのフォームバインダーは、それを使用することになるだろう?
ありがとうございます。
解決 3
があり、いくつかの良い提案はここにいたと私は実際に機能するソリューションを思いつきました。しかし、私は完全に何かになってしまいました。私はちょうど私が投稿されたフォームデータのための特定のモデルを作成し、デフォルトのモデルバインダーを使用します。
はるかに簡単、それは私が私のドメインモデル(すなわち。「コメント」フィールドのような)の一部ではないデータをキャプチャすることができます。
他のヒント
カスタムモデルバインダーを使用することができます。しかし、MSDNの記事は全く役に立ちません。だから、より良い検索を利用して、より良いものを見つけることができます。利用できる記事のplanatyがあります。
私はこれには、2つの方法を思い付きました。
最初は、MVCコントローラで使用される単純なPOCOのタイプを変換するために私のNHibernateのリポジトリクラスにコードを追加することでした(のSimpleThing の)NHibernateのは、(のRealThing たかったエンティティのタイプにEM>):
/// <summary>
/// A NHibernate generic repository. Provides base of common
/// methods to retrieve and update data.
/// </summary>
/// <typeparam name="T">The base type to expose
/// repository methods for.</typeparam>
/// <typeparam name="K">The concrete type used by NHibernate</typeparam>
public class NHRepositoryBase<T, K>
: IRepository<T>
where T : class
where K : T, new()
{
// repository methods ...
/// <summary>
/// Return T item as a type of K, converting it if necessary
/// </summary>
protected static K GetKnownEntity(T item) {
if (typeof(T) != typeof(K)) {
K knownEntity = new K();
foreach (var prop in typeof(T).GetProperties()) {
object value = prop.GetValue(item, null);
prop.SetValue(knownEntity, value, null);
}
return knownEntity;
} else {
return (K)item;
}
}
だから、リポジトリ内の任意の方法は、GetKnownEntity(Tアイテム)を呼び出すことができますし、それはあなたがNHibernateのを望んでいるタイプに渡すアイテムのプロパティをコピーします。明らかにこれは少し不格好なと感じたので、私はカスタムモデルバインダーに見えます。
<時間>第2のアプローチでは、私はこのようなカスタムモデルバインダーを作成しました
public class FactoryModelBinder<T>
: DefaultModelBinder
where T : new()
{
protected override object CreateModel(ControllerContext controllerContext,
ModelBindingContext bindingContext,
Type modelType) {
return new T();
}
}
そして、私はGlobal.asax.csのそれを登録しました
ModelBinders.Binders.Add(typeof(IThing),
new FactoryModelBinder<RealThing>());
そして、それはこのようになりますコントローラのアクションで正常に動作します:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult NewThing([Bind(Exclude = "Id")] IThing thing) {
// code to process the thing goes here
}
<時間>
私は2番目のアプローチを好むが、私の依存性注入のもののほとんどは、コントローラクラスです。私は、Global.asax.csのすべてのこれらのModelBinderマッピングを追加する必要が好きではありません。
これは、あなたの質問にunswer dirrectされていません。
私たちは、あなたが持っている同じ問題に対処するために、わずかに異なるアプローチを使用します。当社のコントローラは、フィールドで永続エンティティのフィールドに一致するのDTOを受け入れます。その後、我々は、ユーザーの AutoMapper のデータベースに移動しますpersistenエンティティを作成します。これはunnesseseryインターフェースを排除し、公共の対面APIをロックダウン(持続性オブジェクトのフィールドの名前を変更することは、当社のクライアントコードを壊さないことを意味します)。