I want to bind the configuration from a JSON file to an instance of HttpApiClientOptions
. However, I encountered some issues when binding the Body
property. After defining it as Dictionary<string, object>?
, the Body
property correctly contains the model
and temperature
key-value pairs, but the value of messages
is empty, and I’m unable to retrieve {"role":"user", "content":"hello!"}
from it.
C# Code:
var config = new ConfigurationBuilder()
.AddJsonFile(configFilePath, false, false)
.Build();
//...
config.GetSection("apiClientOptions").GetSection(apiClientName).Bind(apiClientOptions);
HttpApiClientOptions Class:
public class HttpApiClientOptions : BaseApiClientOptions
{
public string Url { get; set; }
public Dictionary<string, string>? Headers { get; set; }
public Dictionary<string, string>? Params { get; set; }
public Dictionary<string, object>? Body { get; set; }
}
JSON Configuration:
{
"url": "https://example.com",
"headers": {
"Authorization": "Bearer sk-"
},
"params": {},
"body": {"model": "gpt-3.5-turbo", "messages": [{"role":"user", "content":"hello!"}], "temperature": 0.7}
}
I attempted to define Body
as JObject
or JsonElement
, but this approach also failed to retrieve values from the first level of nesting.
The reason I did not map the entire Body
node to a specific type is that the contents and nesting depth under the Body
node are uncertain. Is there any way to make the program read all the information inside the body
node from the JSON file during configuration?
2
Answers
Now, I've also defined Body as
Dictionary<string, string>
, where the value contains the original content that was under theBody
node. However, this approach becomes very cumbersome when filling out the JSON configuration file. Is there a better way to do this?Example of the "body" field in the JSON configuration file:
You should understand one thing, configuration is not JSON, it is collection of key-value pairs, JSON files are not a single source of config. From the docs:
So
Dictionary<string, object>
does not make much sense to binder. One option – provide actual types for all levels:Another way would be to exclude
Body
from the model and dynamically read config viaGetChildren
from some point and process results:And