2

私が次のようなインターフェースを持っているとしましょう:

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フォームバインダーでそれを使用するにはどうすればよいですか?

ありがとう!

4

4 に答える 4

4

カスタムモデルバインダーを使用できます。ただし、msdnに関する記事はまったく役に立ちません。検索を使用して、より良いものを見つける方がよいでしょう。利用可能な記事の平面があります。

于 2009-07-03T21:40:12.477 に答える
3

私はこれに対して2つのアプローチを思いついた。

1つ目は、NHibernateリポジトリクラスにコードを追加して、MVCコントローラーで使用される単純なPOCOタイプ(SimpleThing)をNHibernateが必要とするエンティティのタイプ( RealThing )に変換することでした。

/// <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 item)を呼び出すことができ、渡されたアイテムのプロパティを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番目のアプローチが好きですが、依存性注入に関するもののほとんどはControllerクラスにあります。Global.asax.csにこれらすべてのModelBinderマッピングを追加する必要はありません。

于 2009-07-04T13:57:24.480 に答える
1

ここにいくつかの良い提案があり、私は実際に機能する解決策を思いつきました。しかし、私は完全に何かになってしまいました。投稿したフォームデータに固有のモデルを作成し、デフォルトのモデルバインダーを使用しました。

はるかに単純で、ドメインモデルの一部ではないデータ(つまり、「コメント」フィールドなど)をキャプチャできます。

于 2009-11-23T20:57:34.857 に答える
0

これはあなたの質問に正直な答えではありません。

私たちはあなたが持っている同じ問題に対処するためにわずかに異なるアプローチを使用します。私たちのコントローラーは、フィールドごとに永続エンティティに一致するDTOを受け入れます。次に、AutoMapperを使用して、データベースに移動する永続エンティティを作成します。これにより、不要なインターフェイスが排除され、公開されているAPIがロックダウンされます(つまり、永続オブジェクトのフィールドの名前を変更しても、クライアントコードが破損することはありません)。

于 2009-07-05T20:45:25.260 に答える