3

私はそれを実装するクラスで宣言されたモデルのインターフェースを持っています:

public interface IMyModel
{
    [Range(1, 1000)]
    [Display(Name = "ModelProp From Interface")]
    int MyIntProperty { get; set; }
    IMySubModel SubModel { get; }
}

public interface IMySubModel
{
    [Range(1,1000)]
    [Display(Name = "SubModelProp From Interface")]
    int MyIntSubProperty { get; set; }
}

異なるメタデータを使用したモデルの実装もあります。

public class MyModelImplementation:IMyModel
{
    [Display(Name = "ModelProp From Class")]
    [Range(1, 15)]
    public int MyIntProperty
    {
        get;
        set;
    }
    public IMySubModel SubModel { get; set; }
    public MyModelImplementation()
    {
        SubModel = new MySubModelImplementation();
    }
}

public class MySubModelImplementation: IMySubModel
{
    [Display(Name = "SubModelProp From Class")]
    [Range(1, 15)]
    public int MyIntSubProperty
    {
        get;
        set;
    }
}

このモデル インターフェイスを使用するビューがあります。

@model MvcApplicationModelInterface.Models.IMyModel
@using (Html.BeginForm())
{
    <p>Using Lambda Expression:</p>

    @Html.DisplayNameFor(m=>m.MyIntProperty)
    @Html.EditorFor(m=>m.MyIntProperty)
    @Html.ValidationMessageFor(m=>m.MyIntProperty)
    <br/>
    @Html.DisplayNameFor(m=>m.SubModel.MyIntSubProperty)
    @Html.EditorFor(m=>m.SubModel.MyIntSubProperty)
    @Html.ValidationMessageFor(m=>m.SubModel.MyIntSubProperty)
    <br/>

    <p>Using String Expression:</p>

    @Html.DisplayName("MyIntProperty")
    @Html.Editor("MyIntProperty")
    @Html.ValidationMessage("MyIntProperty")
    <br/>
    @Html.DisplayName("SubModel.MyIntSubProperty")
    @Html.Editor("SubModel.MyIntSubProperty")
    @Html.ValidationMessage("SubModel.MyIntSubProperty")
    <br/>
    @Html.ValidationSummary(true)
    <br/>
    <input type="submit" name="btnSubmit" value="btnSubmit" />
}

そして、モデルの適切なバインドと初期化を行うコントローラーがあります。

    [HttpGet]
    public ActionResult Index()
    {
        ViewBag.Message = "Modify this template to jump-start your ASP.NET MVC application.";
        var model = new MyModelImplementation();
        model.MyIntProperty = 111;
        model.SubModel.MyIntSubProperty = 222;
        return View(model);
    }

    [ActionName("Index"), HttpPost]
    public ActionResult Save([ModelBinder(typeof(MyModelBinder))]IMyModel model)
    {
        return View(model);
    }

    public class MyModelBinder : DefaultModelBinder
    {
        protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
        {
            return new MyModelImplementation();
        }
    }

問題:

コントローラーのアクションで NOT NULL モデルのビューを返す場合 ( return View(new MyModelImplementation(){...}); )、画面に表示される結果は次のとおりです。

ここに画像の説明を入力

ただし、コントローラーのアクションが null モデルの結果を返す場合 ( return View(null); )、結果は次のようになります。

ここに画像の説明を入力

ご覧のとおり、Lambda html ヘルパーと文字列式ヘルパーの動作は異なります。これらはまったく一貫しておらず、一部の動作はバグのように見えます。

  • (予想) Lambda ヘルパーの場合、DisplayName は IMyModel から取得されます
  • (予期しない)文字列式の場合、すべてのメタデータは MyModelImplementation クラスから取得されます (別の言い方をすると、Html.DisplayNameFor(m=>m.MyIntProperty) を使用する場合 - インターフェイス (ビューで宣言されたモデル タイプ) からのメタデータが表示されます)。ただし、Html を使用する場合.DisplayName("MyIntProperty") model.GetType()) のメタデータを使用します。
  • (予想外)すべての検証規則と文字列は、宣言されたモデル タイプ (IMyModel) ではなく、常に MyModelImplementation (model.GetType()) メタデータから取得されます。
  • (予想)文字列式ヘルパーの場合 モデルのプロパティは、ビューに渡されたモデルが NULL の場合にのみインターフェイスから取得されます
  • (予期しない)ビューに渡されたモデルが NULL の場合、文字列式ヘルパーのサブモデルのプロパティ メタデータがまったく取得/尊重されない

質問:

この ASP.NET MVC のバグ/機能に対する最善の回避策は何ですか? デフォルトでHtml拡張機能がビューで宣言されたモデルタイプのメタデータを常に使用するように強制する方法は? MetadataTypeAttribute を使用しようとしましたが、この場合、モデルを実装する人は、許可したくないインターフェイスで指定された元のメタデータを上書きする自由を取得します。だから私はカスタム ModelMetadataProvider 実装を探しています。また、MetadataType の場合、RequiredAttribute などの一部のメタデータ属性は考慮されません。

4

1 に答える 1

0

と の違いはバグだEditor()とは思いません。EditorFor()これは、厳密に型指定されたモデルの型情報にアクセスできるためだと思いますがEditorFor()、エディターはリフレクションを使用して型を取得する必要があり、使用されているインターフェイスの型ではなく、実際の型を返します。

あなたが見ているのは、強く型付けされたバージョンにはより多くのコンテキストがあり、単に呼び出す必要があるのではなく、インターフェイス情報を取得できることだと思いますGetType()

MyModelImplementation にバインドする MyModelBinder にバインドするようにモデル バインダーに指示したため、検証は正しく機能しています。検証は、投稿先のメソッドとそれが取る引数に基づいています。

于 2013-04-12T22:45:11.470 に答える