Web API动作过滤器中如何在运行时处理未知类型?
解决方案
你遇到的问题是因为Json.NET的DeserializeObject<dynamic>返回的是JObject实例,而非与原对象同类型的实例,后续Web API序列化时会因类型不匹配导致输出异常。下面是两种无需反射、也不需要提前知道具体类型的实现方式:
方法一:直接操作JObject(推荐,更安全)
通过将原对象序列化为JObject,直接修改其属性值后再转换回原类型,既避免了字符串替换的误操作,也能保证返回对象类型与原类型一致:
public class MyFilterAttribute : ActionFilterAttribute { public override void OnActionExecuted(ActionExecutedContext context) { var okResult = context.Result as OkObjectResult; if (okResult?.Value == null) return; // 将原对象转换为JObject,方便直接操作属性 var jObject = JObject.FromObject(okResult.Value); // 场景1:修改指定字段(比如name字段) if (jObject.TryGetValue("name", out JToken nameToken) && nameToken.Type == JTokenType.String) { string updatedName = nameToken.ToString().Replace("John", "John Smith"); jObject["name"] = updatedName; } // 场景2:全局替换所有字符串字段中的"John"(按需使用) foreach (var stringToken in jObject.Descendants() .OfType<JValue>() .Where(t => t.Type == JTokenType.String)) { stringToken.Value = stringToken.Value.ToString().Replace("John", "John Smith"); } // 转换回原对象类型,确保后续序列化正常 var modifiedValue = jObject.ToObject(okResult.Value.GetType()); okResult.Value = modifiedValue; } }
方法二:改进字符串替换+动态类型转换
如果你坚持使用字符串替换的方式,需要确保反序列化时使用原对象的类型,而非dynamic:
public class MyFilterAttribute : ActionFilterAttribute { public override void OnActionExecuted(ActionExecutedContext context) { var okResult = context.Result as OkObjectResult; if (okResult?.Value == null) return; string json = JsonConvert.SerializeObject(okResult.Value); json = json.Replace("John", "John Smith"); // 使用原对象的类型进行反序列化,而非dynamic var targetType = okResult.Value.GetType(); var modifiedResultValue = JsonConvert.DeserializeObject(json, targetType); okResult.Value = modifiedResultValue; } }
关键说明
- 方法一中的
JObject操作更精准,不会误替换其他字段中包含的"John"(比如字段值为"JohnDoe"不会被改成"John SmithDoe")。 - 两种方法都通过
okResult.Value.GetType()获取运行时类型,无需提前指定具体类型,也不需要反射。 - 避免直接使用
dynamic是因为Json.NET的dynamic本质是JObject,Web API默认序列化器处理JObject时可能出现字段名大小写不匹配、值格式异常等问题。
内容的提问来源于stack exchange,提问作者MVCKarl
相关产品推荐
相关产品推荐

