C#解析JSON查找属性:ASP.Net Web API可变Payload提取PersonId最优方案
ASP.NET Web API 跨结构Payload提取PersonId的优化方案
你当前使用SelectToken指定路径的方案本身可以满足需求,以下是3种适配不同场景的更优选择,可根据你的项目约束选用:
方案1:标记接口+显式实现(优先推荐)
这是性能最高、可维护性最好的方案,适合可以修改现有ViewModel代码的场景:
- 定义统一标记接口
IHasPersonId:
public interface IHasPersonId { int PersonId { get; } }
- 所有包含PersonId的ViewModel实现该接口,不管PersonId在结构的哪一层,都可以直接映射到该属性:
// 嵌套结构的ViewModel示例 public class CreateOrderViewModel : IHasPersonId { public UserInfo User { get; set; } // 直接映射嵌套的PersonId public int PersonId => User.Person.Id; }
- 在日志中间件/Action过滤器中,拿到模型绑定完成的对象后,直接判断是否实现
IHasPersonId接口即可取值,无需解析JSON,性能远高于字符串路径匹配,且修改ViewModel结构时编译器会自动校验取值逻辑。
方案2:递归JSON属性匹配(无侵入推荐)
如果不能修改现有ViewModel,且Payload中PersonId不会出现重名场景,可以用递归遍历JToken的方式自动查找取值,完全不需要维护任何路径配置:
public static bool TryExtractPersonId(JToken payload, out int personId) { personId = default; if (payload is JObject jObj) { foreach (var prop in jObj.Properties()) { if (prop.Name.Equals(nameof(PersonId), StringComparison.OrdinalIgnoreCase)) { return prop.Value.Type == JTokenType.Integer && int.TryParse(prop.Value.ToString(), out personId); } if (TryExtractPersonId(prop.Value, out personId)) { return true; } } } else if (payload is JArray jArr) { foreach (var item in jArr) { if (TryExtractPersonId(item, out personId)) { return true; } } } return false; }
该方案适配任意结构的Payload,只要存在符合命名要求的PersonId就可以自动提取,仅在单个Payload存在多个同名PersonId时可能出现取值偏差。
方案3:Action级路径标记
如果存在PersonId重名场景,不想在全局维护路径映射表,可以用自定义Attribute把路径和接口绑定在一起,降低维护成本:
- 定义路径标记Attribute:
[AttributeUsage(AttributeTargets.Method)] public class PersonIdPathAttribute : Attribute { public string Path { get; } public PersonIdPathAttribute(string path) => Path = path; }
- 在对应Action上标记路径:
[PersonIdPath("Order.SubmitUser.PersonId")] - 日志阶段先从当前Action的元数据中拿到路径,再调用
SelectToken取值即可。
内容的提问来源于stack exchange,提问作者Raghul Raman
相关产品推荐
相关产品推荐

