using System.Collections;
using System.Collections.Generic;
using System.Runtime.Serialization.Formatters;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.Collections.ObjectModel;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CSharp.Scripting;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Scripting;
using Microsoft.CSharp.RuntimeBinder;
using System.Text.Json.Serialization;
public class EvaluationContext { public dynamic Payload { get; set; } }
public async Task Should_Evaluate_Dynamic_Payload_Using_SystemTextJson()
const string jsonPayload = """
var jsonOptions = new JsonSerializerOptions
Converters = { new ObjectAsPrimitiveConverter(objectFormat : ObjectFormat.Expando,
floatFormat : FloatFormat.Double, unknownNumberFormat : UnknownNumberFormat.Error) },
var evaluationContext = new EvaluationContext
Payload = JsonSerializer.Deserialize<dynamic>(jsonPayload, jsonOptions),
const string expression = @"Payload.dog.name == ""Slayer""";
var options = ScriptOptions.Default;
options = options.AddReferences(typeof(CSharpArgumentInfo).Assembly);
var script = CSharpScript.Create<bool>(expression, options, globalsType: typeof(EvaluationContext));
var scriptRunner = script.CreateDelegate();
var result = await scriptRunner(evaluationContext);
Assert.AreEqual(true, result);
Console.WriteLine("Result = {0}", result);
string name = ((dynamic)evaluationContext.Payload).dog.name;
public class ObjectAsPrimitiveConverter : JsonConverter<object>
FloatFormat FloatFormat { get; init; }
UnknownNumberFormat UnknownNumberFormat { get; init; }
ObjectFormat ObjectFormat { get; init; }
public ObjectAsPrimitiveConverter() : this(FloatFormat.Double, UnknownNumberFormat.Error, ObjectFormat.Expando) { }
public ObjectAsPrimitiveConverter(FloatFormat floatFormat, UnknownNumberFormat unknownNumberFormat, ObjectFormat objectFormat)
this.FloatFormat = floatFormat;
this.UnknownNumberFormat = unknownNumberFormat;
this.ObjectFormat = objectFormat;
public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options)
if (value.GetType() == typeof(object))
writer.WriteStartObject();
JsonSerializer.Serialize(writer, value, value.GetType(), options);
public override object Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
switch (reader.TokenType)
case JsonTokenType.False:
case JsonTokenType.String:
return reader.GetString();
case JsonTokenType.Number:
if (reader.TryGetInt32(out var i))
if (reader.TryGetInt64(out var l))
if (FloatFormat == FloatFormat.Decimal && reader.TryGetDecimal(out var m))
else if (FloatFormat == FloatFormat.Double && reader.TryGetDouble(out var d))
using var doc = JsonDocument.ParseValue(ref reader);
if (UnknownNumberFormat == UnknownNumberFormat.JsonElement)
return doc.RootElement.Clone();
throw new JsonException(string.Format("Cannot parse number {0}", doc.RootElement.ToString()));
case JsonTokenType.StartArray:
var list = new List<object>();
switch (reader.TokenType)
list.Add(Read(ref reader, typeof(object), options));
case JsonTokenType.EndArray:
throw new JsonException();
case JsonTokenType.StartObject:
var dict = CreateDictionary();
switch (reader.TokenType)
case JsonTokenType.EndObject:
case JsonTokenType.PropertyName:
var key = reader.GetString();
dict.Add(key, Read(ref reader, typeof(object), options));
throw new JsonException();
throw new JsonException();
throw new JsonException(string.Format("Unknown token {0}", reader.TokenType));
protected virtual IDictionary<string, object> CreateDictionary() =>
ObjectFormat == ObjectFormat.Expando ? new ExpandoObject() : new Dictionary<string, object>();
public enum UnknownNumberFormat
public static async Task Test()
await new TestClass().Should_Evaluate_Dynamic_Payload_Using_SystemTextJson();
public static async Task Main(string[] args)
Console.WriteLine("Environment version: {0} ({1})", System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription , Environment.Version);
Console.WriteLine("{0} version: {1}", typeof(JsonSerializer).Assembly.GetName().Name, typeof(JsonSerializer).Assembly.FullName);
Console.WriteLine("{0} version: {1}", typeof(CSharpScript).Assembly.GetName().Name, typeof(CSharpScript).Assembly.FullName);
Console.WriteLine("Failed with unhandled exception: ");