MVC ViewModel,使用带有一些标记为必需的属性的 VM,具体取决于它是 GET 还是 POST

MVC ViewModel, using a VM with some properies marked required, depending if its a GET or POST

由于 post 和 get 期间视图模型中所需的某些字段不一致,我经常发现自己手动修复模型状态的验证。

假设我有这个视图模型:

public class RestaurantMenuName_ViewModel
{        
    public Int64 RestaurantMenuNameId { get; set; }

    public Int64 OwnerId{ get; set; }

    public string MenuNameCategory { get; set; }

    public string CategoryDescription { get; set; }

    public bool IsFormSaved { get; set; }
} 

GET 请求期间,controller/Action 只需要验证字段 RestaurantMenuNameId 和 OwnerId。调用 RestaurantMenuName 操作时,查询字符串值为 RestaurantMenuNameId 和 OwnerId。模型状态验证将在:

POST 请求期间,controller/Action 将需要字段的模型状态验证:

这就是我所说的不一致问题,一种解决方案是对 Get 请求使用 ViewModel,对 Post 使用一个 ViewModel,但这可能真的很浪费时间而且容易出错。使用 ViewBag 不在讨论之列。

问题: 有没有办法告诉 MVC 我们想要 GET 的一些字段 [required] 和 POST 的其他字段?

以下是我所说内容的伪代码:

 public class RestaurantMenuName_ViewModel
{   
    [Required: in GET, POST]  //<--Pseudo code
    public Int64 RestaurantMenuNameId { get; set; }

    [Required: in GET, POST]  //<--Pseudo code
    public Int64 OwnerId { get; set; }

    [Required: in POST]       //<--Pseudo code
    public string MenuNameCategory { get; set; }

    [Required: in POST]       //<--Pseudo code
    public string CategoryDescription { get; set; }

    public bool IsFormSaved { get; set; }
} 

当您只需要很少的属性时,传递复杂的对象不是一个很好的做法(并且在您的情况下会造成混淆)。最好只将所需的 ID 作为原语传递。

如果情况特殊,确实需要复杂的对象,最好为每个请求创建两个不同的视图模型,并相应地装饰所需的属性。

但是,您可以创建自己的要求验证属性,该属性将根据当前请求验证属性。

public class MyRequiredAttribute : ValidationAttribute
{
    private string httpVerb;

    public MyRequiredAttribute(string httpVerb)
    {
        this.httpVerb = httpVerb;
    }

    public override bool IsValid(object value)
    {
        if(HttpContext.Current.Request.HttpMethod == this.httpVerb)
        {
            return value != null;
        }

        return true;
    }
}

// Usage
public class MyViewModel
{
    [MyRequired("GET")]
    public string A { get; set; }

    [MyRequired("POST")]
    public string B { get; set; }
}

注意:您可以使用枚举来避免一些困难(例如大写、小写、拼写错误等),您也可以覆盖 FormatErrorMessage更改默认错误消息并正确格式化的方法。