1

私が取り組んでいるプロジェクトの重要な機能の 1 つは、ユーザーが既存のフィールド タイプ (よく知られているタイプなど) のプールに基づいてフォームを構成できることです ("フォーム" のように)。 「ユーザー名」、「生年月日」などだけでなく、「文字列」、「DateTime」などの「ジェネリック型」もあります)。

以前は、「よく知られている」型に対して正常に機能する静的な ViewModel があり、次のように見えました。

public class UserInputModel
{
    [StringLength(200)]
    public string Name { get; set; }

    [Required(ErrorMessageResourceName = "BirthDateEmptyError", ErrorMessageResourceType = typeof(Resources.ErrorMessages))]
    public DateTime BirthDate { get; set; }

    //Here comes a lot of other properties
}

すべての既知のプロパティがリストされ、コンテキストに応じてそれらを表示または非表示にしていました。

しかし、最後の要件が来て、すべてが変わりました。ユーザーは、必要な数のジェネリック型フィールドを追加できるようになりました。これを行うために、この InputModel を完全に動的にすることにしました。次のようになります。

public class UserInputModel
{
    // Each ModelProperty has an "Id" and a "Value" property
    public ICollection<ModelProperty> Properties { get; set; }
}

これは魅力のように機能します。Razor ビューは、コレクションを反復処理し、コレクションの各プロパティに対応するコントロールを標準以上の方法で作成するだけで済みます。

@Html.TextBoxFor(m => m.Properties[index].Value);

...そして、入力されたフォームとしてデータをうまく取得します。

=> これは問題なく動作しますが、クライアント側の検証はありません。このためには、いくつかのメタデータが必要になります...モデルを動的に作成しているため、注釈を介してはもうありません。

これらの MetaData を提供するために、CustomModelMetadataProvider継承するを作成し、Global.asaxDataAnnotationsModelMetadataProviderに新規登録しました。ModelMetadataProviderこのCreateMetadata()関数は、ViewModel の作成時に呼び出され、ViewModel の各プロパティに対して呼び出されます。

問題の始まり: 現在のプロパティにいくつかのメタデータを追加するには、まず、現在見ているプロパティを特定する必要があります (「名前」の最大長は 200 ですが、「生年月日」はそうでないため、割り当てることができません)。デフォルトではすべてのプロパティに maxlength があります)。Valueそして、すべてのプロパティが同じ名前と同じコンテナタイプを持っているため、どういうわけかまだそれを行うことができませんでしたModelProperty

リフレクションを介してプロパティのコンテナーにアクセスしようとしましたが、ModelAccessor のターゲットは ViewModel 自体であるため (ラムダ式のためm => m.Properties)、次の構成により、ModelProperty だけでなく ViewModel 全体が得られます。

var container = modelAccessor.Target.GetType().GetField("container");
var containerObject = (UserInputModel)container.GetValue(modelAccessor.Target);

これを何度もめくっていますが、手元にある ModelProperty を特定する方法が見つかりません。これを行う方法はありますか?

更新:しばらくあらゆる方向にこれをひっくり返した後、最終的に別の方向に進みました。基本的に、控えめな JavaScript を使用して、属性やメタデータに触れることなく MVC の検証機能を使用しています。value-data="true"つまり、HTML 属性(および他のすべての必須属性) を@Html.TextBoxFor()ステートメントに追加します。これは、すべてのアトミック検証 (必須、文字列長など) でうまく機能します。

4

2 に答える 2

0

この記事が役立つかどうかを確認してください: AutoMapper を使用してメタデータをビュー モデルに運ぶためのテクニック

これもアイデアに使用します (カスタム モデル メタデータ プロバイダー):実行時にビューモデルの MetadataType 属性を変更する

流暢な検証はおそらくあなたにとって最良の選択肢だと思いますが、上記の中から最適なものを選択するのは明らかにあなた次第です。

アップデート

useModelMetadataと override を試してみてください: MVC ModelMetadataProvider: ModelMetadata と ModelMetadataProvider を深く掘り下げてください。このようにして、モデルのメタデータを完全にカスタマイズし (これによりデータ注釈が置き換えられます)、ASP.NET MVC に依存するのではなく、何が起こっているかを完全に制御できます。

別の参照先として、カスタム属性を処理するための独自の ModelMetadataProvider の作成があります。

これがすべてあなたのお役に立てば幸いです。

于 2012-09-14T15:35:16.527 に答える
0

Tim さん、プロパティのRemote 属性を使用して、Ajax を介してクライアント側の検証のように見えるものを活用できます。

基本的に、検証コントローラーをセットアップしてから、そのコントローラーにいくつかのスマートを書き込む必要があります。しかし、少なくともいくつかのヘルパー メソッドを記述して、すべてを 1 か所に保持することができます。エンド ユーザーに提示するメタ データに基づいて、一連のバリデーターを用意し、各バリデーター メソッドを特定のタイプに対して適切に再利用できます。

このアプローチの 1 つの落とし穴は、サポートする型と条件ごとに検証メソッドを作成する必要があることです。とにかく、あなたはその道を行かなければならないように聞こえます。

お役に立てれば。

于 2012-09-14T14:47:35.773 に答える