当json有效负载无效时,不会调用自定义ActionFilterAttribute

时间:2015-10-14 13:34:39

标签: c# asp.net asp.net-web-api asp.net-web-api2

当Json反序列化失败时,尝试返回正确的错误消息而不是WebAPI默认错误消息{"Message":"The request is invalid.","ModelState"

我实现了自定义ActionFilterAttribute:

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

}

我用这个属性修饰了我的Controller方法:

   [ValidateModelAttribute]
    public async Task<HttpResponseMessage> Put(string username, string serviceId, [FromBody] Dictionary<string, string> jsonData)
    {
      // code
    }

如果我在OnActionExecuting中设置了一个断点,那么只有当jsonData成功解析为json时它才会中断。如果json无效,它永远不会进入过滤器,并返回相同的错误消息。所以看起来这是在某个地方完成的,但我发现的所有帖子都说这应该是处理这个问题的地方。

知道什么是错的吗?

1 个答案:

答案 0 :(得分:1)

由于反序列化在调用方法之前失败,因此永远不会调用该属性,这意味着不会调用修饰方法的属性。您需要一个自定义转换器(处理文化的技术借鉴了this)。

public class Testee {}
public class Tester
{
    [JsonConverter(typeof(CustomMesssageConverter<Testee>), "Custom Error Message")]
    public Testee Testee { get; set; }
}

public class CustomMesssageConverter<T> : JsonConverter where T : new()
{
    private string _customErrorMessage;

    public CustomMesssageConverter(string customErrorMessage)
    {
        _customErrorMessage = customErrorMessage;
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
       serializer.Serialize(writer, value);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        try
        {
            if (reader.TokenType == JsonToken.Null)
                return null;

            // Load JObject from stream
            JObject jObject = JObject.Load(reader);

            // Create target object based on type
            var target = new T();

            //Create a new reader for this jObject, and set all properties to match the original reader.
            JsonReader jObjectReader = jObject.CreateReader();
            jObjectReader.Culture = reader.Culture;
            jObjectReader.DateParseHandling = reader.DateParseHandling;
            jObjectReader.DateTimeZoneHandling = reader.DateTimeZoneHandling;
            jObjectReader.FloatParseHandling = reader.FloatParseHandling;

            // Populate the object properties
            serializer.Populate(jObjectReader, target);

            return target;
        }
        catch(Exception ex)
        {
            // log ex here
            throw new Exception(_customErrorMessage);
        }
    }

    public override bool CanConvert(Type objectType)
    {
       return typeof(T).IsAssignableFrom(objectType);
    }
}