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。模型状态验证将在:
- RestaurantMenuNameId
- OwnerId
在 POST 请求期间,controller/Action 将需要字段的模型状态验证:
- RestaurantMenuNameId
- OwnerId
- 菜单名称类别
- 类别描述
这就是我所说的不一致问题,一种解决方案是对 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
更改默认错误消息并正确格式化的方法。
由于 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。模型状态验证将在:
- RestaurantMenuNameId
- OwnerId
在 POST 请求期间,controller/Action 将需要字段的模型状态验证:
- RestaurantMenuNameId
- OwnerId
- 菜单名称类别
- 类别描述
这就是我所说的不一致问题,一种解决方案是对 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
更改默认错误消息并正确格式化的方法。