/// <summary> /// Reads the JSON representation of the object. /// </summary> /// <param name="reader">The <see cref="JsonReader"/> to read from.</param> /// <param name="objectType">Type of the object.</param> /// <param name="existingValue">The existing value of object being read.</param> /// <param name="serializer">The calling serializer.</param> /// <returns>The object value.</returns> public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { var(jToken, range) = SourceScope.ReadTokenRange(reader, sourceContext); using (new SourceScope(sourceContext, range)) { string refDialogName = null; if (resourceExplorer.IsRef(jToken)) { refDialogName = jToken.Value <string>(); // We can't do this asynchronously as the Json.NET interface is synchronous var reference = resourceExplorer.ResolveRefInternalAsync(jToken, sourceContext).GetAwaiter().GetResult(); jToken = reference.token; if (!rangeReferences.ContainsKey(jToken)) { rangeReferences.Add(jToken, reference.range); } } var kind = (string)jToken["$kind"]; if (kind == null) { // see if there is jObject resolver var unKnownResult = ResolveUnknownObject(jToken); if (unKnownResult != null) { return(unKnownResult); } throw new ArgumentNullException($"$kind was not found: {JsonConvert.SerializeObject(jToken)}"); } // if reference resolution made a source context available for the JToken, then add it to the context stack var found = rangeReferences.TryGetValue(jToken, out var rangeResolved); using (var newScope = found ? new SourceScope(sourceContext, rangeResolved) : null) { var passTwo = false; foreach (var observer in this.observers) { if (observer is CycleDetectionObserver cycDetectObserver && cycDetectObserver.CycleDetectionPass == CycleDetectionPasses.PassTwo) { passTwo = true; } if (observer.OnBeforeLoadToken(sourceContext, rangeResolved ?? range, jToken, out T interceptResult)) { return(interceptResult); } } var tokenToBuild = TryAssignId(jToken, sourceContext); T result; if (passTwo && refDialogName != null && cachedRefDialogs.ContainsKey(refDialogName)) { result = cachedRefDialogs[refDialogName]; } else { result = BuildOrGetType(kind, tokenToBuild, serializer, passTwo, (rangeResolved ?? range).ToString()); if (passTwo && refDialogName != null) { cachedRefDialogs[refDialogName] = result; resourceExplorer.UpdateResourceTokenCache(refDialogName, tokenToBuild, range); } } // Associate the most specific source context information with this item if (sourceContext.CallStack.Count > 0) { range = sourceContext.CallStack.Peek().DeepClone(); if (!DebugSupport.SourceMap.TryGetValue(result, out var _)) { DebugSupport.SourceMap.Add(result, range); } } foreach (var observer in this.observers) { if (observer.OnAfterLoadToken(sourceContext, range, jToken, result, out T interceptedResult)) { return(interceptedResult); } } return(result); } } }