JSON.当为对象传递无效值时,网络反序列化程序不会生成异常

本文关键字:程序 反序列化 网络 异常 对象 无效 JSON | 更新日期: 2023-09-27 18:12:28

我有以下结构:

public class SampleEntity{
    public string Name { get; set; }
    public OtherEntity Relation { get; set; }
}
public class OtherEntity {
    public string Name { get; set; }
}

当我调用更新web中的对象时。具有以下请求体的API:

"{'Name':'Nome', 'Relation':''}"

反序列化器用空值填充对象,但我认为正确的操作是抛出异常,如"字段关系的无效值",我可以返回状态码400。

我试图使自定义转换器做到这一点,但我不满意的解决方案,我很关心这个性能。

 public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.StartObject)
        {
            var @object = JObject.Load(reader);
            var target = Activator.CreateInstance(objectType);
            var objectProperties = target.GetType().GetProperties().Where(x => x.PropertyType.IsPrimitive == false && x.PropertyType != typeof(string));
            foreach (var prop in objectProperties)
            {
                var value = @object[prop.Name];
                if (value != null && value.ToString() == string.Empty)
                    throw new Exception();
            }
            serializer.Populate(@object.CreateReader(), target);
            return target;
        }
        return reader.Value;
    }

JSON.当为对象传递无效值时,网络反序列化程序不会生成异常

当验证失败时,Web API不会自动返回错误给客户端。由控制器动作来检查模型状态并作出适当的响应。虽然@loop的答案可以工作,但您可能需要考虑另一个选项,这样您甚至不必输入控制器的动作方法。

为此,您可以创建一个动作过滤器,以便在调用控制器动作之前检查模型状态。

例如:

public class ValidateModelAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(HttpActionContext actionContext)
    {
        if (actionContext.ModelState.IsValid == false)
        {
            actionContext.Response = actionContext.Request.CreateErrorResponse(
                HttpStatusCode.BadRequest, actionContext.ModelState);
        }
    }
}

注意,您将仍然需要用描述验证规则的属性来修饰您的模型。这将类似于@loop所建议的。

如果模型验证失败,这个过滤器返回一个包含验证错误的HTTP响应。在这种情况下,控制器动作不会被调用。

要将此过滤器应用于所有Web API控制器,请在HttpConfiguration中添加该过滤器的实例。配置期间的过滤器收集:

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        config.Filters.Add(new ValidateModelAttribute());
        // ...
    }
}

另一个选择是将过滤器设置为单个控制器或控制器动作的属性:

public class EntitiesController : ApiController
{
    [ValidateModel]
    public HttpResponseMessage Post(SampleEntity entity)
    {
        // ...
    }
}

有关更详细的解释,请查看本文。要了解可以用来定义验证规则的各种模型注释,例如[Required]等,请查看MSDN页面