当JSON负载无效时,自定义ActionFilterAttribute不会被调用
问题描述:
当Json反序列化失败时,尝试返回正确的错误消息而不是WebAPI默认的错误消息{"Message":"The request is invalid.","ModelState"
。当JSON负载无效时,自定义ActionFilterAttribute不会被调用
我实现我的自定义ActionFilterAttribute:
internal class ValidateModelAttribute : ActionFilterAttribute {
public override void OnActionExecuting(HttpActionContext actionContext) {
if (!actionContext.ModelState.IsValid) {
actionContext.Response = actionContext.Request.CreateErrorResponse(HttpStatusCode.BadRequest, actionContext.ModelState);
}
}
}
}
我饰我的控制器方法与此属性:
[ValidateModelAttribute]
public async Task<HttpResponseMessage> Put(string username, string serviceId, [FromBody] Dictionary<string, string> jsonData)
{
// code
}
如果我在OnActionExecuting
设置断点只休息时jsonData
作为json被成功解析。如果json无效,它永远不会进入过滤器,并返回相同的错误消息。所以看起来这是在之前的某个地方完成的,但是我发现的所有帖子都说这应该是处理这个问题的地方。
任何想法有什么不对?
答
该属性将永远不会被调用,因为反序列化在该方法被调用之前失败,这意味着装饰该方法的属性不会被调用。你需要一个自定义的转换器(处理文化的技术是从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);
}
}