1

formCollectionが渡されたときにオブジェクトがUpdateModelで更新されないという ASP.NET MVC で奇妙な問題が発生しています。更新中のオブジェクトがリフレクションによって作成されている場合、 UpdateModelが正しく機能していないように見えます。

シナリオ: 約 50 のルックアップ テーブルを持つアプリケーションがあります。各ルックアップ テーブルには、id、title、description、isactive、createdon などの典型的なフィールドを含むまったく同じスキーマが含まれています。50 個のビューを作成するのではなく、すべてのルックアップ テーブルのデータを表示できる単一のビューが必要でした。IReferenceEntity というインターフェイスを作成し、ルックアップ テーブルを表す各 POCO に実装しました。

このインターフェイスを使用すると、ルックアップ テーブルのレコードをビューに簡単に取り込むことができます。(次の方法でアイテムをビューに渡します。)

System.Web.Mvc.ViewPage<MyNamespece.IReferenceEntity> 

データベースからビューまで、すべてが完璧に機能します。

ただし、投稿時にモデルを更新しようとすると、いくつかの問題が発生します。

次のようにオブジェクト参照を明示的に宣言すると、すべてが完全に機能し、オブジェクトの値がフォームの値で更新されます。したがって、データベースを更新できます。

AccountStatus a = new AccountStatus();

UpdateModel(a, formCollection.ToValueProvider());

残念ながら、オブジェクト タイプをハード コーディングすると、インターフェイスを使用する理由が完全に無効になります。

(アプリケーションの主な目的は、「特別な」ことを何もせずにルックアップ テーブルなどの新しいテーブルを動的に追加できるようにすることです。これは、読み込まれたアセンブリを反映し、特定のインターフェイスまたは基本クラスを実装するクラスを見つけることによって達成されます。 )

私の戦略は、ポストバック時にオブジェクトの具体的な型を決定し、リフレクションによってその型のインスタンスを作成することです。(型を決定するために私が使用するメカニズムはやや原始的です。フォーム内の非表示フィールドとして含めています。より良いアイデアを歓迎します。)

次のいずれかの方法でリフレクションを使用してオブジェクトのインスタンスを作成すると、UpdateModel によって更新されるオブジェクトはありません。

Type t = {Magically Determined Type}

object b = Activator.CreatorInstance(t);

UpdateModel(b, formCollection.ToValueProvider());


Type t = {Magically Determined Type}

var c = Activator.CreatorInstance(t);

UpdateModel(c, formCollection.ToValueProvider());


Type t = {Magically Determined Type}

IReferenceEntity d = Activator.CreatorInstance(t);

UpdateModel(d, formCollection.ToValueProvider());

注: リフレクションによって作成されるオブジェクトがすべて適切なタイプであることを確認しました。

なぜこれが起こっているのか誰にも分かりますか?私はやや困惑しています。

私が本当に「苦労した」場合は、これらの参照エンティティ/ルックアップ オブジェクトのいずれかをインスタンス化するファクトリ オブジェクトを作成できます。ただし、これにより、新しいルックアップ テーブルを透過的に追加および検出できるようにするアプリケーションの機能が損なわれ、それほどクリーンではありません。

また、インターフェイスではなく、実際の ReferenceEntity 基本クラスから派生させることもできますが、これが違いを生むかどうかは疑問です。この問題は、リフレクションによって作成されたオブジェクトをモデル バインダーで使用する場合に発生するようです。

どんな助けでも大歓迎です。

アンソニー

4

3 に答える 3

1

Augi は ASP.NET フォーラムでこれに答えました。いくつかのマイナーな変更だけで機能しました。オージーありがとう。


問題は、[Try]UpdateModel メソッドではジェネリック パラメーターのみを使用してモデル タイプを指定できるため、動的なモデル タイプを指定できないことです。このための問題チケットを作成しました。

ここで TryModelUpdate メソッドの実装を確認できます。したがって、独自のオーバーロードを作成することは難しくありません。

public virtual bool TryUpdateModelDynamic<TModel>(TModel model, string prefix, string[] includeProperties, string[] excludeProperties, IDictionary<string, ValueProviderResult> valueProvider) where TModel : class
{
    if (model == null)
    {
        throw new ArgumentNullException("model");
    }
    if (valueProvider == null)
    {
        throw new ArgumentNullException("valueProvider");
    }


    //Predicate<string> propertyFilter = propertyName => BindAttribute.IsPropertyAllowed(propertyName, includeProperties, excludeProperties);  
    IModelBinder binder = Binders.GetBinder( /*typeof(TModel)*/model.GetType());

    ModelBindingContext bindingContext = new ModelBindingContext()
                                             {
                                                 Model = model,
                                                 ModelName = prefix,
                                                 ModelState = ModelState,
                                                 //ModelType = typeof(TModel), // old  
                                                 ModelType = model.GetType(),
                                                 // new  
                                                 //PropertyFilter = propertyFilter,  
                                                 ValueProvider = valueProvider
                                             };
    binder.BindModel(ControllerContext, bindingContext);
    return ModelState.IsValid;
}
于 2009-09-29T14:41:31.337 に答える
0

IReferenceEntity には、プロパティのセッターとゲッターが含まれていますか? インターフェイスにプロパティ セッターがある場合、最後のサンプルは機能すると思いますが、コンパイルするにはキャストする必要があります。

Type t = {Magically Determined Type}

IReferenceEntity d = Activator.CreatorInstance(t) as IReferenceEntity;

UpdateModel(d, formCollection.ToValueProvider());

通常、クラスにプロパティを設定しない理由は、リフレクションを介して使用できるパブリック セッター メソッドが見つからないためです。

于 2009-09-24T01:51:51.170 に答える
0

簡単な「もう1つのこと」:

UpdateModel(d as IReferenceEntity, formCollection.ToValueProvider());

それがうまくいくかどうかはわかりませんし、自分で試したこともありませんが、最初に頭に浮かんだことです.

後で機会があれば、Default Model Binder のコードを調べて、そこに明らかな何かがあるかどうかを確認します...

于 2009-09-24T01:51:59.837 に答える