【问题标题】:MVC - Nested models with interfaces and annotationsMVC - 具有接口和注释的嵌套模型
【发布时间】:2015-08-28 16:45:07
【问题描述】:

我有基础课:

public abstract class AbstractBaseModel : IModel
{
    [Display(Name = "Some Name")]
    [DisplayFormat(DataFormatString = "{0:d0}")]
    [RegularExpression(@"[0-9]{1,10}", ErrorMessage = "error")]
    public virtual string SomeName{ get; set; }
}

IModel 接口只是简单的属性声明:

public interface IModel
{
    string SomeName{ get; set; }
}

从基本模型我有 2 个派生模型

public class ClientModel : AbstractBaseModel
{
    [Required(ErrorMessage = "Some error message for customer only")]
    public override string SomeName{ get; set; }
}

public class PowerUserModel : AbstractBaseModel
{
    [Required(ErrorMessage = "Different message for the admin")]
    public override string SomeName{ get; set; }
}

这个模型,或者更确切地说是接口是组合多个模型的另一个模型的一部分:

public class ComboEndModel
{
     public IModel Model { get; set; }
     public IDifferentModel DifferentModel { get; set; }
}

根据当前使用的View/Controler,我将新的ClientModelPowerUserModel 作为模型传递给ComboEndModel

当视图被渲染时,我只从基本的抽象模型中获取注释,而不是在派生类型中添加的注释。我怀疑这是因为我将接口用作嵌套模型属性而不是类型。

实现这种关系的正确方法是什么,或者解决注释不正确的问题?我应该尝试自定义绑定吗?

【问题讨论】:

  • 已编辑 以为你有 dup。标签;我的错误(喝咖啡
  • 您能否分享您的视图代码中会导致模型注释重要的部分?例如,您是否使用@Html.EditorFor()
  • 您注意到的是预期的行为,更重要的是,当您提交到 POST 方法时,您将无法绑定到您的模型,因为DefaultModelBinder 无法初始化接口。使用具体的实现。

标签: c# asp.net asp.net-mvc asp.net-mvc-4 razor


【解决方案1】:

可能对您有用的一件事是为每个派生模型创建编辑器模板。

如果你像这样定义你的 ComboEndModel

var model = new ComboEndModel() { Model = new PowerUserModel() };
return View(model);

在您看来,您使用 EditorFor

@model WebApplication.Models.ComboEndModel
@Html.EditorFor(m => m.Model)

根据Model 是什么类型,它将选择关联的编辑器模板并应用该派生类型的注释。在这种情况下,您需要在名为 PowerUserModel.cshtmlEditorTemplates 文件夹中使用模型类型为 PowerUserModel 的局部视图

【讨论】:

  • 您实际上根本不需要编辑器模板,除非您想自定义标记。默认的编辑器模板可以很好地应对这种情况。
  • 那里没有我的论据。 ;-)
【解决方案2】:

好的,我也有一些问题,到目前为止我的理解是(如果我错了,请有人纠正我):

为什么会出现这个问题?

因为检索到的DataAnnotation 是从模型的类型中检索的。让我给你看一些样本:

如果您的.cshtml 文件中有:

样本 1:

@model AbstractBaseModel
// The type that will be retrived is `AbstractBaseModel`.

示例 2:

@model IModel
// The type that will be retrived is `IModel`.

或者在其他情况下,如果您有操作:

public ActionResult SomeAction(AbstractBaseModel model) { /* ... */ }

示例 2:

public ActionResult SomeAction(IModel model) { /* ... */ }

所以重要的是您在 @model 或 action 参数中指定的类型。不管是接口、抽象类、基类还是其他类型的类,只管你在使用中描述的类型。

在您的示例中,您特别写道:

public class ComboEndModel
{
    public IModel Model { get; set; }
    // ...
}

因此 DataAnnotation 将从 IModel 中检索,但 IModel 没有定义 RequiredAttribute,因此您在继承/实现链中更进一步并获得 AbstractBaseModel。 (试试这个来确认我在写什么:在 IModel.SomeName 中添加一个 required 和不同的消息,看看会得到什么消息)。

解决方案/建议

如果我是对的,如果不改变策略,就无法解决您的问题。所以这里有一些关于你可以做什么的建议:

  • 删除“必需”属性并自己进行验证(在操作或 javascript 中,具体取决于您使用的验证类型)。
  • 验证发生后替换错误消息,(我的例子是这样做的)。
  • 放弃这种继承,建立独立的模型。
  • 【讨论】:

    • 你在谈论的是一个不同的问题。 EditorTemplates 根本不支持接口。最重要的是,接口和属性存在更深层次的问题,您暗示建议将其作为修复。从这个link 中,开发团队讨论了为什么数据注释和接口不能很好地结合在一起的原因。请参阅那里接受的答案以获取解释。
    猜你喜欢
    • 2011-07-09
    • 2013-02-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-08-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多