C# MVC-多态视图绑定可能吗?

C# MVC-多态视图绑定可能吗?,c#,asp.net-mvc,C#,Asp.net Mvc,在处理多个派生的ViewModel类的MVC项目中,我可以拥有一个视图吗?我目前正在使用ASP Core RC1,目标是4.5.NET framework 我的衍生ViewModels使用数据注释实现了特定的验证。如果我将派生模型类对象传递给引用基本模型(@model Models.BaseModel)的视图,则所有数据注释都不会以html 5数据val标记呈现在客户端 如果我使用强类型视图(@model Models.ChildModel),它将按预期工作。我不能在视图中使用多个@model声

在处理多个派生的
ViewModel
类的MVC项目中,我可以拥有一个
视图吗?我目前正在使用ASP Core RC1,目标是4.5.NET framework

我的衍生
ViewModels
使用数据注释实现了特定的验证。如果我将派生模型类对象传递给引用基本模型(
@model Models.BaseModel
)的
视图,则所有数据注释都不会以html 5
数据val
标记呈现在客户端

如果我使用强类型视图(
@model Models.ChildModel
),它将按预期工作。我不能在
视图中使用多个
@model
声明,因此我无法在
视图中检查模型的类型并选择要渲染的模型的类型

但是,我希望使用共享视图,因为有许多字段,只有验证实现需要根据使用的派生类进行更改

下面是一个示例实现:

public abstract class BaseModel
{
    [Required]
    public abstract string FieldTest {get; set;}
}

public class ChildModel : BaseModel
{
    [Email]
    public override string FieldTest {get; set;}
}

public class AnotherChildModel : BaseModel
{
    [Phone]
    public override string FieldTest {get; set;}
}
以下是我试图在
视图中实现的目标:

@if(Model is ChildModel)
{
    @model Models.ChildModel
}
else
{
    @model Models.AnotherChildModel
}
目前,我最好的解决方案是为每个派生类视图模型提供一个单独的视图。问题在于,这些视图只是不同的
@model
引用的重复

目前,我的最佳解决方案是对每个问题都有一个单独的视图 派生类视图模型。问题是这些观点都是错误的 仅使用不同的@model引用进行复制

似乎根本的问题是您希望消除视图之间的重复代码

如果是这样,您可以创建局部视图,并在视图之间共享

比如说,

Edit.cshtml Create.cshtml _CreateOrUpdate.cshtml 更新 我只是注意到,您将同一财产用于不同的目的。请不要那样做它隐藏对属性的确认-在ViewModel类以外的任何类中。维护将成为噩梦。

从BaseViewModel继承ViewModel是可以的(我们都这样做),但不是以覆盖它的方式

我建议使用单独的属性-
publicstringemail{get;set;}
publicstringphone{get;set;}

public abstract class BaseModel
{
    [Required]
    public abstract string FieldTest {get; set;}
                            ^^^^^^^
}

public class ChildModel : BaseModel
{
    [Email]
    public override string FieldTest {get; set;}
                            ^^^^^^^
                          Store email
}

public class AnotherChildModel : BaseModel
{
    [Phone]
    public override string FieldTest {get; set;}
                            ^^^^^^^
                        Store phone number
}

使用接口而不是具体类型。一切都会好起来的

我的意思是

您可以有一个接口类型的模型, 比如说IBaseModel

@model IBaseModel
@using (Html.BeginForm("Create", "Users", FormMethod.Post))
{
    @Html.Partial("_CreateOrUpdate", IBaseModel)
}


// instead of this than all you need to do is cast to right model 
@if(Model is ChildModel)
{
    @model Models.ChildModel
}
else
{
    @model Models.AnotherChildModel
}

// in this case you will be able use both types and if your base class is implementing it you don't have to do much of refactoring.
IBaseModel as ChildModel.something 
IBaseModel as AnotherChildModel.something  
您可以使用基类型,因为子类型可以通过这种方式引用, 我以前使用动态对象自己做过这件事。我假设你在顶部的模型只是模型的一个例子,并不能真正代表最终产品

@model basetype

@{
  dynamic testModel;
  if(Model.GetType().Name == typeof(ChildModel).Name)
       testModel = new ChildModel();
  else if(Model.GetType().Name == typeof(AnotherChildModel).Name)
       testModel = new AnotherChildModel();
}
您还可以使用一个标志或枚举来指示它在整个页面中是哪个子级,以便可以在页面上更改详细信息

我尚未测试以下内容,但如果只有两个选项,您甚至可以使用以下内容:

var testModel = Model.getType().Name == typeof(ChildModel).Name ? new ChildModel() : new AnotherChildModel();

您可以保留视图以接受基本类型,即BaseModel

 @model Models.BaseModel
在动作方法中,可以将ChildModel或其他ChildModel类型的对象从动作发送到视图。由于两者都是BaseModel的派生类型,因此视图应该能够处理其中任何一种派生类型。你不必真的按照你正在做的方式来设置它。只需将其设置为基本类型就足够了

您还可以使用模板化的视图帮助器方法,如EditorFor(),这正适合于您希望在视图中保留一定数量多态性的情况


您可以看到此链接,它可能会帮助您-

模型是在控制器中设置的,因此理想情况下,只要模型是/继承自/实现
@model
,视图就不应该关心它获取的模型。为了根据模型处理要显示的视图,我发现最好的方法是使用基于模型名称显示的局部视图

使用非抽象的基本模型

@model MyApp.Models.BaseModel
@using (Html.BeginForm...
{
    @Html.DisplayFor(model => model.BaseProperty)

    @await Html.PartialAsync(String.Concat("_", Model.GetType().Name, "SomePartial"), Model);
}
这需要遵循模型的部分命名约定。因此,
SquirrelModel
将在
\u squirrelmodeldetailsparial.cshtml
中显示其独特的属性,以此类推。这样就不需要在视图中进行检查
ChipmunkModel
随后将触发
\u chipmunkModelDetailSpatial.cshtml
等等


我尝试了抽象/接口方法,但在测试发布数据的控制器操作时遇到了问题。

是接口而不是抽象类?然后,我必须正确实现每个派生ViewModel中的所有字段,这将导致ViewModels中的大量重复。如果我理解正确的话。我只是编辑了我的答案,让你更好地理解我的意思。看一看,希望这有助于感谢你的更新。当我这样做并试图访问一个视图时,我得到一个运行时异常——“一个文件中只允许有一个‘model’语句。”。因此,模型IBaseModel、model Models.ChildModel和Models.AnotherChildModel总共有3条“model”语句。但是,我没有尝试将model语句用于仅接口的抽象/派生类。如果要使用接口,则必须删除此if-else语句,但我猜您以前从未针对接口编程过?这将是一个很好的开始,看看一些针对接口编程的教程。我可以尝试一下,但我想知道PartialView的@model引用是什么,或者更好地说,是哪种模型类型?如果是基类的话,我也会遇到同样的情况。在我的情况下,所有字段都是相同的,但应用于每个字段的验证是不同的。因此,当视图被呈现时(或者之前?),它需要知道被呈现的模型属于哪个DerivedClass类型,以便应用验证规则。我更新了我的答案。请不要那样做。信息技术
var testModel = Model.getType().Name == typeof(ChildModel).Name ? new ChildModel() : new AnotherChildModel();
 @model Models.BaseModel
@model MyApp.Models.BaseModel
@using (Html.BeginForm...
{
    @Html.DisplayFor(model => model.BaseProperty)

    @await Html.PartialAsync(String.Concat("_", Model.GetType().Name, "SomePartial"), Model);
}