I'm using RestSharp 106.6.10. I expect the response to return a simple object with four string properties. I've defined the object's class in C# with the correct property types, spelling, and capitalization.
I'm posting a request and getting a response with no errors. The response's Content appears to be clean JSON, with a Data object that includes good values for my "TransactionAcknowledgement" object. But here's my problem: the Data object returned by RestSharp has null values for the deserialized properties.
I've tried several suggestions from SO and other sites: Adding "DeserializeAs" hints on the class properties; using OnBeforeDeserialization to set ContentType = "application/json"; and a few other ideas others have suggested. Nothing seems to help.
Here is the class definition:
public class TransactionAcknowledgement
{
[DeserializeAs(Name = "BusinessEntityID")] // These hints don't seem to help.
public string BusinessEntityID { get; set; }
[DeserializeAs(Name = "BusinessEntityMedicaidIdentifier")]
public string BusinessEntityMedicaidIdentifier { get; set; }/
[DeserializeAs(Name = "TransactionID")]
public string TransactionID { get; set; }
[DeserializeAs(Name = "Reason")]
public string Reason { get; set; }
}
And a C# code snippet:
RestClient restClient;
RestRequest restRequest;
IRestResponse<TransactionAcknowledgement> restResponse;
restClient = new RestClient(MyBaseUrl);
restClient.Authenticator = new HttpBasicAuthenticator(evvCompanyAggregator.EffectiveUserID, evvCompanyAggregator.EffectiveUserPassword);
restRequest = new RestRequest("MyResource", Method.POST, DataFormat.Json);
restRequest.AddJsonBody(myData);
restRequest.OnBeforeDeserialization = r => { r.ContentType = "application/json"; }; // This doesn't seem to help.
restResponse = restClient.Execute<TransactionAcknowledgement>(restRequest);
The restResponse.Content looks good, including good values in the "Data" object within the raw restResponse.Content string.
The restResponse.Content.Data object is also the correct class, TransactionAcknowledgement.
However, the property values within restResponse.Content.Data are all null.
Here is the raw restResponse.Content string:
"{\n \"id\": \"1de51d1a-8086-4ba7-8aa6-2d1431986a99\",\n \"status\": null,\n \"token\": null,\n \"messageSummary\": \"Transaction Received.\",\n \"messageDetail\": null,\n \"errorMessage\": null,\n \"failedCount\": 0,\n \"succeededCount\": 0,\n \"cached\": false,\n \"cachedDate\": null,\n \"totalRows\": 0,\n \"page\": 0,\n \"pageSize\": 0,\n \"orderByColumn\": null,\n \"orderByDirection\": null,\n \"data\": {\n \"BusinessEntityID\": \"200248\",\n \"BusinessEntityMedicaidIdentifier\": \"8471209\",\n \"TransactionID\": \"1de51d1a-8086-4ba7-8aa6-2d1431986a99\",\n \"Reason\": \"Transaction Received.\"\n }\n}"
And here is the same restResponse.Content nicely formatted for readability:
{
"id": "bf0606a3-f21d-4d51-980c-bee407adc561",
"status": null,
"token": null,
"messageSummary": "Transaction Received.",
"messageDetail": null,
"errorMessage": null,
"failedCount": 0,
"succeededCount": 0,
"cached": false,
"cachedDate": null,
"totalRows": 0,
"page": 0,
"pageSize": 0,
"orderByColumn": null,
"orderByDirection": null,
"data": {
"BusinessEntityID": "200248",
"BusinessEntityMedicaidIdentifier": "8471209",
"TransactionID": "bf0606a3-f21d-4d51-980c-bee407adc561",
"Reason": "Transaction Received."
}
}
And here is the object in the debugger, showing null property values:
I've spent a couple of days on this. I'm sure this works for most people, so I'm probably just missing something simple. Any suggestions?
Update:
To prove that the data coming in with the response is ok and matches my class definition, I deserialized the response content directly. I created a new wrapper class:
public class HttpRestRootObject
{
public TransactionAcknowledgement data { get; set; }
}
Then, I deserialized the the restResponse.Content string without RestSharp:
HttpRestRootObject testRoot = javaScriptSerializer.Deserialize<HttpRestRootObject>(restResponse.Content);
TransactionAcknowledgement transactionAcknowledgement = testRoot.data;
So, everything works except RestSharp's deserialization. Am I using RestSharp wrong somehow? Any suggestions?
I have the exact same problem. The only fix I've found is to revert back to RestSharp 106.10.1. All 106.11.x have the same problem. It's also possible to declare your own custom serializer, which could be simply NewtonSoft, however, depending on the complexity of what you are serializing/deserializing this could be more headache than it's worth.
Related
I am learning Flutter. This is the string that I need to call and I don't know how to call this type of string.
{
"Info":[
{
"c_type_id":"1",
"cleaning type":"Washroom Cleaning"
},
{
"c_type_id":"2",
"cleaning type":"Garden\/Lawn Cleaning"
}
]
}
My code
class Album {
final String title;
Album({
this.title,
});
factory Album.fromJson(Map<String, dynamic> json) {
return Album(
title: json['title'],
);
}
}
As I am following my code like this https://flutter.dev/docs/cookbook/networking/fetch-data
and got this error "A non-null String must be provided to a Text widget." because they are following this type of string and my string type is different. Help!
{
"userId": 1,
"id": 1,
"title": "quidem molestiae enim"
}
Your given data (API response) seems to have a list of maps, so you should get the data first (use async function):
var response = await http.get("Your Url")
then you should extract the given map list as follow:
var temp = json.decode(response);
List<dynamic> result = temp['Info']); // it is the described list
now, you can use your data (extract each parameter):
String c_type_id = result[0]['c_type_id'];
// and so on...
Your question is not clear at all but I can show you an example how to reach an element in a json.
Your json consists a list that contains string keys. To reach first element of list;
json["Info"][0]
Then pass the key you want to get its value;
json["Info"][0]["c_type_id"]
http_requests All type of http requests are mentioned in this post. If you have any further problem kindly make comment.
I have the following JSON configuration
"Configurations": {
"KeyA": {
"Ids": []
},
"KeyB": {
"Ids": [1, 2, 3]
},
"KeyC": {
"Ids": [1, 2, 3],
"OptionalData": "asdf"
}
}
This is then read into the following object
public class AppConfiguration
{
public Dictionary<ConfigType, ConfigurationData> Configurations {get; set;} = new Dictionary<ConfigType, ConfigurationData>();
}
public class ConfigurationData
{
public HashSet<int> Ids {get;set;} = new HashSet<int>();
public string OptionalData = "";
}
public Enum ConfigType
{
KeyA = 1,
KeyB = 2,
KeyC = 3
}
I then bind this in ConfigureServices(IServiceCollection services) method using
services.Configure<AppConfiguration>(this.Configuration);
However, I notied that the configuration binding produces my AppConfiguration's dictionary with only the KeyB and KeyC keys, skipping KeyA, because its Ids array is empty. I read up on the behaviour of the configuration binding online, but as far as I saw it should bind the Ids to null, but here it just does not generate a key value pair in the dictionary altogether.
I tried removing the "Ids" property, leaving my config like "KeyA": {}", but this still did not work. The only way I can get it to parse is if I put in some numbers in the array, but this obviously not what I want.
I would like to know if there is anyway I can bind such a key-value pair, where I don't have any Ids in my array. This seems like it should be somehow supported out of the box, but I'm not sure why it's not working and how could I resolve it, without implementing some hacky custom configuration loader/binder.
For anyone who stumbles upon this in the future, I managed to solve this by setting my array to null, instead of an empty array like so.
"Configurations": {
"KeyA": {
"Ids": null
}
}
I'm using Helidon 2.0.0-M2.
When I run the query below I get back a list of JSON objects.
dbClient.execute(exec -> exec.createNamedQuery("select-dsitem-by-id")
.addParam("userId", dataItemId)
.execute())
.thenAccept(response::send)
.exceptionally(throwable -> sendError(throwable, response));
Returned list
[
{
"data": "qwerty",
"user_id": "12345"
},
{
"data": "qwerty123",
"user_id": "22345"
}
]
The attribute names seem to be taken directly from the database column name. e.g. one attribute name returned is "user_id". However, I want it to be "userId". I also want to create a parent wrapper for this list like:
{
"userList": [
{
"data": "qwerty",
"user_id": "12345"
},
{
"data": "qwerty123",
"user_id": "22345"
}
]
}
What is the best way to do this with the dbclient?
Thanks
Simple approach:
Change your SQL statement to return the correct name, such as:
SELECT data, user_id as userId FROM mytable
Complicated approach:
We are working on a better support to map to a JSON stream.
Currently there is only one (a bit complicated) way to achieve this:
You can create a custom mapper from a DbRow to JsonObject. This mapper needs to be a general one (it must work for any DbRow of any query).
The built-in mapper uses metadata provided on the columns. I have prepared a simple example (that just expects to have a single type of statements):
class DbRecordMapperProvider implements DbMapperProvider {
private static final DbMapper<JsonObject> MAPPER = new DbRecordMapper();
#SuppressWarnings("unchecked")
#Override
public <T> Optional<DbMapper<T>> mapper(Class<T> aClass) {
if (JsonObject.class.equals(aClass)) {
return Optional.of((DbMapper<T>)MAPPER);
}
return Optional.empty();
}
}
class DbRecordMapper implements DbMapper<JsonObject> {
#Override
public JsonObject read(DbRow dbRow) {
return Json.createObjectBuilder()
.add("name", dbRow.column("FIRSTPART").as(String.class))
.add("message", dbRow.column("SECONDPART").as(String.class))
.build();
}
#Override
public Map<String, ?> toNamedParameters(JsonObject dbRecord) {
return dbRecord;
}
#Override
public List<?> toIndexedParameters(JsonObject dbRecord) {
throw new IllegalStateException("Cannot convert json object to indexed parameters");
}
}
The important method is public JsonObject read(DbRow dbRow).
Once you have such a DbMapperProvider, you register it with the DbClient:
dbClient = DbClient.builder()
.config(config.get("db"))
.mapperProvider(new DbRecordMapperProvider())
.build();
I have this provider dictionary in appsetting.json
"AppSettings": {
"Providers": {
"http://localhost:5001": "Provider1",
"http://localhost:5002": "Provider2"
},
"ArrayWorks": [
"http://localhost:5001",
"http://localhost:5002"
],
"SoDoesColonInDictionaryValue": {
"Provider1": "http://localhost:5001",
"Provider2": "http://localhost:5002"
}
}
And the following throw exception because there's colon in the dictionary key.
Configuration.GetSection("AppSettings").Get<AppSettings>()
However, colon works fine as dictionary value, or array, just not dictionary key.
I read colon has special meaning in config, but there seems no way to escape. Why?
Edit:
public class AppSettings
{
public string ApplicationName { get; set; }
public IDictionary<string, string> Providers { get; set; }
}
When debugging Configuration.GetSection("AppSettings"), you get this
Key AppSettings:Providers:http://localhost:5000
Value Provider1
It was intended to be something like this
Key AppSettings:Providers:http_//localhost_5000
But there seems no way to control how Configuration treat the :::
Edit:
According to aspnet/Configuration#792
Colons are reserved for special meaning in the keys, so they shouldn't
be used as part of normal key values.
This isn't supported and issue was closed.
Not yet, Until now there is no escape colon character, Accourding to Microsoft Asp.net repository on github, but there is an open issue with #782 on the github repository which move it to this backlog
As a workaround you can reverse the key with the value in appsetting:AppSettings and correct it in code like the below:
"AppSettings": {
"Providers": {
"Provider1":"http://localhost:5001",
"Provider2":"http://localhost:5002"
},
"ArrayWorks": [
"http://localhost:5001",
"http://localhost:5002"
],
"SoDoesColonInDictionaryValue": {
"Provider1": "http://localhost:5001",
"Provider2": "http://localhost:5002"
}
}
And in code make sure to reverse dictionary key and value as the below
var result = _configuration.GetSection("AppSettings:Providers")
.GetChildren().ToDictionary(i=>i.Value,i=>i.Key);
// result["http://localhost:5001"] return Provider1
// result["http://localhost:5002"] return Provider2
I'm trying to validate filter generation logic, so I have an instance of SearchRequest, but how to get a String representation of it ?
I don't have SearchResponse, only SearchRequest since I'm simply capturing it in my test.
This doesn't compile "Can't convert from NestSearchRequest" to byte[].
This doesn't work either, there is no Client class in Nest and ElasticClient doesn't have Serializer property (Nest 1.6.0/Elasticsearch 1.6.1).
Here's a complete example for how to get the json representation of a query, using NEST 1.6.0
void Main()
{
var client = new ElasticClient(connection: new InMemoryConnection());
var query = Query<Document>.Match(m => m
.OnField(f => f.Name)
.Query("Match This Name")
);
var json = Encoding.UTF8.GetString(client.Serializer.Serialize(query));
Console.WriteLine(json);
}
public class Document
{
public string Name { get; set; }
}
which prints the following to the console
{
"match": {
"name": {
"query": "Match This Name"
}
}
}