我有一个APIController和一个输入类。
POST处理程序:
public void Post([FromBody]NRCSSoilInput input)
{
new NRCSSoilWebService().SendRequest(input.box.west, input.box.north, input.box.east, input.box.south);
}
输入类:
public class NRCSSoilInput
{
public class BBox
{
public double north { get; set; }
public double south { get; set; }
public double east { get; set; }
public double west { get; set; }
}
private BBox _box;
public BBox box
{
get { return _box; }
set { Validate(value); _box = value; }
}
public void Validate(BBox value)
{
if (value.west > value.east)
throw new ArgumentOutOfRangeException("west", value.west, "West cannot be bigger than east coordinate.");
... etc ...
}
}
所发生的事情是,当遇到异常时,不会创建对象(如预期的那样),但是代码会继续并在Post中命中SendRequest,然后在input.box.west处作为输入失败。一片空白。这就是Post调用返回前端的内容。我希望它返回的是ArgumentOutOfRangeException,但我会停止代码。
ExceptionMessage:"Object reference not set to an instance of an object."
ExceptionType:"System.NullReferenceException"
Message:"An error has occurred."
我想一个简单的解决方案就是将验证移到帖子中,我不是那个想法的粉丝,尽管在我看来验证应该在创建Input对象时发生。
有几个侧面问题:
将验证放入Post的另一个好处是我可以将它放入try catch块然后返回OK响应{status:error,message:"错误消息" },而不是500响应。
输入json必须将east,west等作为整数,但它应该真正接受它们作为字符串然后转换它们。
有没有任何巧妙的方法来做上述事情?
答案 0 :(得分:2)
最好的方法是通过数据注释(开箱即用或FluentValidations)和过滤器属性,如下所示。
第1步 - 构建自定义属性。 (我在本例中使用了开箱即用的数据注释)
[AttributeUsage(AttributeTargets.Property)]
public class DoubleGreaterThanAttribute : ValidationAttribute
{
public DoubleGreaterThanAttribute(string doubleToCompareToFieldName)
{
DoubleToCompareToFieldName = doubleToCompareToFieldName;
}
private string DoubleToCompareToFieldName { get; set; }
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
double west = (double)value;
double east = (double)validationContext.ObjectType.GetProperty(DoubleToCompareToFieldName).GetValue(validationContext.ObjectInstance, null);
if (east > west)
{
return ValidationResult.Success;
}
else
{
return new ValidationResult("West cannot be bigger than east coordinate.");
}
}
}
步骤-2使用自定义属性
注释属性public class NRCSSoilInput
{
public class BBox
{
public double north { get; set; }
public double south { get; set; }
[Required]
public double east { get; set; }
[Required]
[DoubleGreaterThan("east")]
public double west { get; set; }
}
public BBox box { get; set; }
}
步骤3-添加如下所示的过滤器属性类(最好在Filters文件夹中)
[AttributeUsage(AttributeTargets.Method, Inherited = true)]
public class ValidateModelAttribute : ActionFilterAttribute
{
private readonly Func<Dictionary<string, object>, bool> _validate;
public ValidateModelAttribute()
: this(arguments =>
arguments.ContainsValue(null))
{ }
public ValidateModelAttribute(Func<Dictionary<string, object>, bool> checkCondition)
{
_validate = checkCondition;
}
public override void OnActionExecuting(HttpActionContext actionContext)
{
var modelState = actionContext.ModelState;
if (!modelState.IsValid)
actionContext.Response = actionContext.Request
.CreateErrorResponse(HttpStatusCode.BadRequest, modelState);
}
}
步骤4 - 在控制器上注释过滤器属性
[HttpPost]
[ValidateModel]
public Void Post(NRCSSoilInput model)
{
return Ok();
}
这样,只有当模型通过所有验证时,才会触发您的方法。希望这会有所帮助。