C# 为HttpGet和HttpPost设计包含显示数据和绑定数据的ViewModel的最佳实践

C# 为HttpGet和HttpPost设计包含显示数据和绑定数据的ViewModel的最佳实践,c#,asp.net-core,C#,Asp.net Core,我已经阅读StackOverflow有一段时间了,现在是我的第一篇文章的时间了: 我目前正在使用C#/ASP.NET Core 3.1。为HttpGet和HttpPost设计包含显示数据和绑定数据的ViewModel的最佳实践是什么。我发现了一些关于保持显示和绑定数据分离或不分离的讨论,但没有任何示例。在HttpPost上使用相同的ViewModel(没有绑定属性)的问题是,显示数据引用会获得无效的modelstate,因为它们在传入模型中当然为null 我通常倾向于使用以下精简的代码。继承是要

我已经阅读StackOverflow有一段时间了,现在是我的第一篇文章的时间了:

我目前正在使用C#/ASP.NET Core 3.1。为HttpGet和HttpPost设计包含显示数据和绑定数据的ViewModel的最佳实践是什么。我发现了一些关于保持显示和绑定数据分离或不分离的讨论,但没有任何示例。在HttpPost上使用相同的ViewModel(没有绑定属性)的问题是,显示数据引用会获得无效的modelstate,因为它们在传入模型中当然为null

我通常倾向于使用以下精简的代码。继承是要走的路还是其他模式?或者,对于非绑定数据,最好将所有内容都放在具有绑定属性的视图模型中

谢谢大家

public class CMyBindModel
{
  public int ProductQuantity ( get; set; }    // Binding Data

  // Other Binding properties ...
}

public class CMyViewModel : CMyBindModel
{
  public string ProductName ( get; set; }    // Display Data

  // Other Display properties ...
}


Cart.cshtml
@模型CMyViewModel
@Model.ProductName
更新
在HttpPost上使用相同的ViewModel(不带绑定属性)的问题是,显示数据引用获得无效的modelstate,因为它们在传入模型中当然为null

通过使用相同的视图模型(这里是
CMyViewModel
),您可以通过在判断
ModelState.IsValid
之前从
ModelState
中删除字段来克服验证错误

请参阅我的简单演示:

型号:

public class CMyViewModel 
{
    [Required]
    public int ProductQuantity { get; set; }  // Binding Data

    // Other Binding properties ...

    [Required]
    public string ProductName{get; set; }    // Display Data

    // Other Displaying properties ...
}
行动:

public void RemoveDisplayingDataValidation()
{
    ModelState.Remove("ProductName");
    //remove other Displaying properties' validation
}

[HttpPost]
public IActionResult Cart(CMyViewModel viewModel)
{
    RemoveDisplayingDataValidation();
    if (ModelState.IsValid)
    {
        SetProductQuantity (viewModel.ProductQuantity) ;
        return RedirectToAction("Cart");
    }

    CMyViewModel viewModel = BuildViewModel () ;
    return View(viewModel);
}

此外,克里斯托夫·吕特仁(Christoph Lütjen)提出的分别使用两种模型的建议也会奏效

在HttpPost上使用相同的ViewModel(不带绑定属性)的问题是,显示数据引用获得无效的modelstate,因为它们在传入模型中当然为null

通过使用相同的视图模型(这里是
CMyViewModel
),您可以通过在判断
ModelState.IsValid
之前从
ModelState
中删除字段来克服验证错误

请参阅我的简单演示:

型号:

public class CMyViewModel 
{
    [Required]
    public int ProductQuantity { get; set; }  // Binding Data

    // Other Binding properties ...

    [Required]
    public string ProductName{get; set; }    // Display Data

    // Other Displaying properties ...
}
行动:

public void RemoveDisplayingDataValidation()
{
    ModelState.Remove("ProductName");
    //remove other Displaying properties' validation
}

[HttpPost]
public IActionResult Cart(CMyViewModel viewModel)
{
    RemoveDisplayingDataValidation();
    if (ModelState.IsValid)
    {
        SetProductQuantity (viewModel.ProductQuantity) ;
        return RedirectToAction("Cart");
    }

    CMyViewModel viewModel = BuildViewModel () ;
    return View(viewModel);
}


此外,Christoph Lütjen关于分别使用两个模型的建议也会起作用。

您的第一个模型描述了请求的外观。视图模型描述了渲染视图所需的内容。两者看起来可能相似,但它们显然负责不同的事情。也就是说:我将使用两个类。没有继承权。如果您需要视图中请求的零件,请复制属性。-只有我的5美分。这里有一些策略。我经常使用您概述的继承方法,尤其是当每个视图模型特定于底层绑定模型时。例如,如果一个
用户
实体有一个只读的
DateJoined
属性,应该显示该属性,这是
用户视图模型
的一个很好的用例。对于视图模型具有跨绑定模型使用的一组公共属性的区域,我使用具有通用绑定模型属性的通用视图模型。它包含常见的只读元数据和共享用户界面元素,如
PageTitle
LastModified
。非常感谢大家的建议。是的,我想不同的策略在不同的情况下是有用的(继承、单独的模型、ModelState.Remove等等)。纯粹主义者可能不同意继承解决方案,因为大多数情况下,它不是isA关系。我很少使用两个单独的模型,但最近我有一个模型,其中包含一个商店类列表,其中包含一个要显示的产品类列表,每个类中都有一些绑定属性—两个单独的视图和绑定模型解决了我的问题。干杯。您的第一个模型描述了请求的外观。视图模型描述了渲染视图所需的内容。两者看起来可能相似,但它们显然负责不同的事情。也就是说:我将使用两个类。没有继承权。如果您需要视图中请求的零件,请复制属性。-只有我的5美分。这里有一些策略。我经常使用您概述的继承方法,尤其是当每个视图模型特定于底层绑定模型时。例如,如果一个
用户
实体有一个只读的
DateJoined
属性,应该显示该属性,这是
用户视图模型
的一个很好的用例。对于视图模型具有跨绑定模型使用的一组公共属性的区域,我使用具有通用绑定模型属性的通用视图模型。它包含常见的只读元数据和共享用户界面元素,如
PageTitle
LastModified
。非常感谢大家的建议。是的,我想不同的策略在不同的情况下是有用的(继承、单独的模型、ModelState.Remove等等)。纯粹主义者可能不同意继承解决方案,因为大多数情况下,它不是isA关系。我很少使用两个单独的模型,但最近我有一个模型,其中包含一个商店类列表,其中包含一个要显示的产品类列表,每个类中都有一些绑定属性—两个单独的视图和绑定模型解决了我的问题。干杯