问题
I have a simple model that I used as a request payload
public class CommandRequest
{
public CommandType Type { get; set; }
public dynamic Attributes { get; set; }
}
In controller action I need to read some property from dynamic Attributes
public async Task<IActionResult> Commands([FromBody] CommandRequest requestBody)
{
string name = requestBody.Attributes.Name;
...
}
Got the following exception:
Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: 'System.Text.Json.JsonElement' does not contain a definition for 'Name'
How can I read that property?
回答1:
Simply declaring something as dynamic
doesn't guarantee that the resulting concrete object implements IDynamicMetaObjectProvider and allows for runtime definition of properties. Rather, dynamic
simply means an object
to which all compile-time checking has been turned off, and so all method and member references to it will be resolved in runtime. See:
- What Is Dynamic?
- What is the 'dynamic' type in C# 4.0 used for?
Now, when you deserialize a JSON object to a member declared as dynamic
with Json.NET, Newtonsoft will chose JObject as the concrete type to which to deserialize. As its base type JToken implements IDynamicMetaObjectProvider
you can do things like requestBody.Attributes.Name
and the .Net runtime will forward the property resolution to the JObject
which will look the property up inside its list of properties. However, this doesn't happen automatically, Newtonsoft had to enhance JToken
to make dynamic property access possible.
System.Text.Json
, however, does not have built-in support for deserializing free-form JSON to some custom type implementing IDynamicMetaObjectProvider
, so you will need to use the compile-time methods of the actual type returned, viz. JsonElement, to access the JSON data contained therein:
var name = requestBody.Attributes.GetProperty("Name").ToString();
Or, you could cast it for clarity:
var name = ((JsonElement)requestBody.Attributes).GetProperty("Name").ToString();
Demo fiddle here.
回答2:
- You can use the GetProperty method on the JsonElement to get the property you desire.
- You can deserialize with JsonConvert.Deseralize("jsonpayload") to the model of Attributes and get Name directly with the "." notation.
- You can deserialize to Dictionary<string,string> and get the property name as Dict["Name"].
来源:https://stackoverflow.com/questions/64036207/read-value-from-dynamic-property-from-json-payload