私はそれを実装するクラスで宣言されたモデルのインターフェースを持っています:
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 などの一部のメタデータ属性は考慮されません。