public ObjectTreeAnalysisResult(object objectToSearch, string propertyPath , IContractResolver contractResolver) { // construct the analysis result. // split the propertypath, and if necessary, remove the first // empty item (that's the case when it starts with a "/") var propertyPathTree = propertyPath.Split( new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries).ToList(); object targetObject = objectToSearch; // we've now got a split up property tree "base/property/otherproperty/..." int lastPosition = 0; for (int i = 0; i < propertyPathTree.Count; i++) { // if the current target object is an ExpandoObject (IDictionary<string, object>), // we cannot use the ContractResolver. lastPosition = i; // if the current part of the path is numeric, this means we're trying // to get the propertyInfo of a specific object in an array. To allow // for this, the previous value (targetObject) must be an IEnumerable, and // the position must exist. int numericValue = -1; if (int.TryParse(propertyPathTree[i], out numericValue)) { var element = GetElementAtFromObject(targetObject, numericValue); if (element != null) { targetObject = element; } else { break; } } else { var jsonContract = (JsonObjectContract)contractResolver .ResolveContract(targetObject.GetType()); // does the property exist? var attemptedProperty = jsonContract.Properties.FirstOrDefault (p => string.Equals(p.PropertyName, propertyPathTree[i] , StringComparison.OrdinalIgnoreCase)); if (attemptedProperty != null) { // unless we're at the last item, we should continue searching. // If we're at the last item, we need to stop if (!(i == propertyPathTree.Count - 1)) { targetObject = attemptedProperty.ValueProvider.GetValue(targetObject); } } else { // property cannot be found // Stop, and return invalid path. break; } } } var leftOverPath = propertyPathTree .GetRange(lastPosition, propertyPathTree.Count - lastPosition); if (leftOverPath.Count == 1) { var jsonContract = (JsonObjectContract)contractResolver .ResolveContract(targetObject.GetType()); var attemptedProperty = jsonContract.Properties.FirstOrDefault (p => string.Equals(p.PropertyName, leftOverPath.Last() , StringComparison.OrdinalIgnoreCase)); if (attemptedProperty == null) { IsValidPathForAdd = false; IsValidPathForRemove = false; } else { IsValidPathForAdd = true; IsValidPathForRemove = true; JsonPatchProperty = new Helpers.JsonPatchProperty(attemptedProperty, targetObject); PropertyPathInParent = leftOverPath.Last(); } } else { IsValidPathForAdd = false; IsValidPathForRemove = false; } }
public ObjectTreeAnalysisResult(object objectToSearch, string propertyPath , IContractResolver contractResolver) { // construct the analysis result. // split the propertypath, and if necessary, remove the first // empty item (that's the case when it starts with a "/") var propertyPathTree = propertyPath.Split( new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries).ToList(); object targetObject = objectToSearch; // we've now got a split up property tree "base/property/otherproperty/..." int lastPosition = 0; for (int i = 0; i < propertyPathTree.Count; i++) { // if the current target object is an ExpandoObject (IDictionary<string, object>), // we cannot use the ContractResolver. lastPosition = i; // if the current part of the path is numeric, this means we're trying // to get the propertyInfo of a specific object in an array. To allow // for this, the previous value (targetObject) must be an IEnumerable, and // the position must exist. int numericValue = -1; if (int.TryParse(propertyPathTree[i], out numericValue)) { var element = GetElementAtFromObject(targetObject, numericValue); if (element != null) { targetObject = element; } else { break; } } else if (propertyPathTree[i].StartsWith("[") && propertyPathTree[i].EndsWith("]")) { // we are going to try a bit of bullshittery here. // i would use something like dynamic linq, but this is a portable library. When i have time, i will split this out. Until then: string exprString = propertyPathTree[i].Substring(1, propertyPathTree[i].Length - 2); var element = ExpressionHelpers.GetElementAtFromObjectExpression(targetObject, exprString); if (element != null) { targetObject = element; } else { break; } } else { var jsonContract = (JsonObjectContract)contractResolver .ResolveContract(targetObject.GetType()); // does the property exist? var attemptedProperty = jsonContract.Properties.FirstOrDefault (p => string.Equals(p.PropertyName, propertyPathTree[i] , StringComparison.OrdinalIgnoreCase)); if (attemptedProperty != null) { // unless we're at the last item, we should continue searching. // If we're at the last item, we need to stop if (!(i == propertyPathTree.Count - 1)) { targetObject = attemptedProperty.ValueProvider.GetValue(targetObject); if (targetObject == null) { throw new Exception($"Attempted to walk path '/{string.Join("/", propertyPathTree.GetRange(0, i + 1))}' on given '{objectToSearch.GetType().Name}' but encountered null"); } } } else { // property cannot be found // Stop, and return invalid path. break; } } } var leftOverPath = propertyPathTree .GetRange(lastPosition, propertyPathTree.Count - lastPosition); if (leftOverPath.Count == 1) { var jsonContract = (JsonObjectContract)contractResolver .ResolveContract(targetObject.GetType()); var attemptedProperty = jsonContract.Properties.FirstOrDefault (p => string.Equals(p.PropertyName, leftOverPath.Last() , StringComparison.OrdinalIgnoreCase)); if (attemptedProperty == null) { if (leftOverPath.Last().StartsWith("[") && leftOverPath.Last().EndsWith("]")) { attemptedProperty = jsonContract.Properties.FirstOrDefault(p => string.Equals(p.PropertyName, propertyPathTree[lastPosition - 1], StringComparison.OrdinalIgnoreCase)); if (attemptedProperty != null) { IsValidPathForAdd = false; IsValidPathForRemove = true; JsonPatchProperty = new Helpers.JsonPatchProperty(attemptedProperty, targetObject); PropertyPathInParent = leftOverPath.Last(); } else { IsValidPathForAdd = false; IsValidPathForRemove = false; } } else { IsValidPathForAdd = false; IsValidPathForRemove = false; } } else { IsValidPathForAdd = true; IsValidPathForRemove = true; JsonPatchProperty = new Helpers.JsonPatchProperty(attemptedProperty, targetObject); PropertyPathInParent = leftOverPath.Last(); } } else { IsValidPathForAdd = false; IsValidPathForRemove = false; } }