I have a problem; I have various (too many) classes, that are linked as Parent/Child
I populate initially my top class while instantiate the others, as follows (works):
TopClass MyClass = new TopClass()
{
Headers = new someHeaders()
{
CorrID = "1234567890",
RequestID = "1234567890",
L_Token = "abcdefghijklmnopqrstuvwxyz"
},
Body = new someBody()
{
access = new AccessHeaders()
{
allPs = "allAcc",
availableAcc = "all"
},
CombinedServiceIndicator = false,
FrequencyPerDay = 10,
ValidUntil = "2020-12-31"
},
ResponseAttributes = new ConsentResponse()
{
myId = String.Empty,
myStatus = String.Empty,
myName = String.Empty,
_links_self_href = String.Empty,
status_href = String.Empty
}
};
The initials values that I populate above rarely change, but the Classes' properties change as the project goes on, and each class ends up having many properties.
I need to parse the properties and set values to any properties that match their name, but I can't seem to figure out why despite following official examples.
(I read the input data from a JSON string I use Newtonsoft - have tried everything out there)
I can't find a way to deserialize the JSON and assign any values to my properties without using the name of the property, i.e. without saying
MyClass.Body.access.allPs = "Hello"
but something like
var json = response.Content.ReadAsStringAsync().Result.ToString();
var a = new { serverTime = "", data = new object[] { } };
var c = new JsonSerializer();
or
if (myresponse.Attributes.GetType().GetTypeInfo().GetDeclaredProperty(key) != null)
myresponse.GetType().GetTypeInfo().GetDeclaredProperty(key).SetValue(myresponse, entry.Value);
//and how do I read the value, parse my TopClass and assign the value to correct property?
Could someone help me?
Values for the properties will get automatically assigned if the JSON is having the correct structure as per the class mentioned above.
Something like:
{
"Body":
"access:
{
"allPs" = "required value"
}
}
Then you can use:
var result = JsonConvert.DeserializeObject < TopClass > (json );
Related
Is it possible to take a JSON object in C# that I read from from another source and convert the contents to files. The problem is I don't know the structure of the incoming objects.
So far I've got this:
var response = await client.GetAsync("https://blahblah/creds" +
"?ApiKey=" + textBox_password.Text +
"&deviceId=" + deviceId +
"&modelNum=" + modelNum);
var res = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
var resJson = JsonConvert.DeserializeObject(res);
this.textBox_Stream.AppendText("responseBody = " + resJson + "\r\n");
Which gives me:
responseBody = {
"statusCode": 200,
"body": {
"modelNum": "42",
"creds": "[{\"deviceid.txt\":\"4DA23E\",\"pac.txt\":\"580795498743\"}]",
"deviceId": "4DA23E"
}
}
What I want to do is create a folder called 4DA23E and place one file inside it for each entry in the creds object.
device.txt will contain 4DA23E
pac.tct will contain 580795498743
etc. I can't figure out a dynamic way to extract the stuff I need. Goes without saying, I am not a C# programmer! So, please be kind.
Don't use JsonConvert.DeserializeObject. That's best when you know the schema of the JSON object and you've made a corresponding C# model.
First, parse the outer response JSON
var res = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
JObject resJson = JObject.Parse(res);
Now pull out the value of the "creds" property and re-parse it.
var credsJsonRaw = resJson["body"]["creds"].Value<string>();
JArray credsJson = JArray.Parse(credsJsonRaw);
Now you can loop through each object in the array, and each property in each object.
foreach (JObject obj in credsJson)
{
foreach (JProperty prop in obj.Properties)
{
Console.WriteLine($"Name = {prop.Name}");
Console.WriteLine($"Value = {prop.Value.Value<string>()}");
}
}
For your example, this prints
Name = deviceid.txt
Value = 4DA23E
Name = pac.txt
Value = 580795498743
One way to deserialise the following json is in two stages. This is because 'creds' is a string.
{
"statusCode": 200,
"body": {
"modelNum": "42",
"creds": "[{\"deviceid.txt\":\"4DA23E\",\"pac.txt\":\"580795498743\"}]",
"deviceId": "4DA23E"
}
}
Here's an example of how to do it. If you're not .NET6 change 'record' to 'class' and if you don't use nullable reference types (on by default in .NET6) remove the appropriate question marks in property definitions.
using System.Text.Json;
using System.Text.Json.Serialization;
var json = File.ReadAllText("data.json");
var o = JsonSerializer.Deserialize<Outer>(json);
if(o?.Body?.Creds == null)
{
throw new Exception("Bad data");
}
var credList = JsonSerializer.Deserialize<List<Dictionary<string, string>>>(o.Body.Creds);
if(credList == null)
{
throw new Exception("Bad data");
}
foreach( var e in credList)
foreach( var kvp in e)
Console.WriteLine($"{kvp.Key} : {kvp.Value}");
record Outer {
[JsonPropertyName("staticCode")]
public int? StaticCode {get; set;}
[JsonPropertyName("body")]
public Body? Body {get; set;}
}
record Body {
[JsonPropertyName("creds")]
public string? Creds {get; set;}
}
This prints
deviceid.txt : 4DA23E
pac.txt : 580795498743
I'm trying to post two fields and a bundled object with two fields to Mailchimp's API endpoint.
var store_id = ConfigurationManager.AppSettings["MailChimpStoreID"];
var method = String.Format("ecommerce/stores/{0}/products?", store_id);
var id = "id123";
var title = "testproduct";
//var variants = new {id, title };
var productData = new { id, title, variants = new { id, title } };
var requestJson = JsonConvert.SerializeObject(productData);
When I POST my data and do a try-catch around my code to check, I see that my requestJson returns the following:
{
"id":"id123",
"title":"testproduct",
"variants":{"id":"id123","title":"testproduct"}
}
I know the issue is that the variants when serialized isn't returning as "variants":[{"foo":bar"}] but how do I resolve it so that my code bundles this as an object correctly?
Second theory: Since C# is a strongly-typed Object Oriented program, do I need to define the objects above with get:sets and then call them into my function?
you should write it like this,
var productData = new { id, title, variants = new[] {new { id, title }} };
Console.WriteLine(JsonConvert.SerializeObject(productData));
//Prints:
{"id":1,"title":"sodijf","variants":[{"id":1,"title":"sodijf"}]}
You can use either dynamic or an object as the type of list as well.
var productData = new { id, title, variants = new List<object>() {new { id, title }} };
When data from a device goes into the elastic there are duplicates. I like to avoid this duplicates. I'm using a object of IElasticClient, .NET and NEST to put data.
I searched for a method like ElasticClient.SetDocumentId(), but cant find.
_doc doc = (_doc)obj;
HashObject hashObject = new HashObject { DataRecordId = doc.DataRecordId, TimeStamp = doc.Timestamp };
// hashId should be the document ID.
int hashId = hashObject.GetHashCode();
ElasticClient.IndexDocumentAsync(doc);
I would like to update the data set inside the Elastic instead of adding one more same object right now.
Assuming the following set up
var pool = new SingleNodeConnectionPool(new Uri("http://localhost:9200"));
var settings = new ConnectionSettings(pool)
.DefaultIndex("example")
.DefaultTypeName("_doc");
var client = new ElasticClient(settings);
public class HashObject
{
public int DataRecordId { get; set; }
public DateTime TimeStamp { get; set; }
}
If you want to set the Id for a document explicitly on the request, you can do so with
Fluent syntax
var indexResponse = client.Index(new HashObject(), i => i.Id("your_id"));
Object initializer syntax
var indexRequest = new IndexRequest<HashObject>(new HashObject(), id: "your_id");
var indexResponse = client.Index(indexRequest);
both result in a request
PUT http://localhost:9200/example/_doc/your_id
{
"dataRecordId": 0,
"timeStamp": "0001-01-01T00:00:00"
}
As Rob pointed out in the question comments, NEST has a convention whereby it can infer the Id from the document itself, by looking for a property on the CLR POCO named Id. If it finds one, it will use that as the Id for the document. This does mean that an Id value ends up being stored in _source (and indexed, but you can disable this in the mappings), but it is useful because the Id value is automatically associated with the document and used when needed.
If HashObject is updated to have an Id value, now we can just do
Fluent syntax
var indexResponse = client.IndexDocument(new HashObject { Id = 1 });
Object initializer syntax
var indexRequest = new IndexRequest<HashObject>(new HashObject { Id = 1});
var indexResponse = client.Index(indexRequest);
which will send the request
PUT http://localhost:9200/example/_doc/1
{
"id": 1,
"dataRecordId": 0,
"timeStamp": "0001-01-01T00:00:00"
}
If your documents do not have an id field in the _source, you'll need to handle the _id values from the hits metadata from each hit yourself. For example
var searchResponse = client.Search<HashObject>(s => s
.MatchAll()
);
foreach (var hit in searchResponse.Hits)
{
var id = hit.Id;
var document = hit.Source;
// do something with them
}
Thank you very much Russ for this detailed and easy to understand description! :-)
The HashObject should be just a helper to get a unique ID from my real _doc object. Now I add a Id property to my _doc class and the rest I will show with my code below. I get now duplicates any more into the Elastic.
public void Create(object obj)
{
_doc doc = (_doc)obj;
string idAsString = doc.DataRecordId.ToString() + doc.Timestamp.ToString();
int hashId = idAsString.GetHashCode();
doc.Id = hashId;
ElasticClient.IndexDocumentAsync(doc);
}
Currently what I'm doing is serializing the JsonResult.Data then Deserialized into dynamic variable before looping in each row and get the Document. Is there any way to handle this? Thanks
if (string.IsNullOrWhiteSpace(searchTerm_))
searchTerm_ = "*";
_azureSearch = new AzureSearchService("afindexdev");
JsonResult result = new JsonResult
{
JsonRequestBehavior = JsonRequestBehavior.AllowGet,
Data = _azureSearch.SearchAssetFactory(searchTerm_).Results
};
string json = JsonConvert.SerializeObject(result.Data);
var resultJsonString = Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(json);
foreach (dynamic row in resultJsonString)
{
var associatemItem = new AssociatedItem();
associatemItem.Id = row.Document.Id;
associatemItem.Title = row.Document.Title;
associatemItem.Type = row.Document.Type;
searcResult.AssociatedItems.Add(associatemItem);
}
What about this?
var associatedItem = Newtonsoft.Json.JsonConvert.DeserializeObject< List < AssociatedItem > >(json);
That way you don't have to make your object yourself.
You can define your model with properties which you want to deserialize with attribute [SerializePropertyNamesAsCamelCase]. This attribute is included to Microsoft.Azure.Search library. After that, all you need to do is to define your model in search generic - like this Hotel class
var sp = new SearchParameters();
if (!String.IsNullOrEmpty(filter))
{
sp.Filter = filter;
}
DocumentSearchResult<Hotel> response = indexClient.Documents.Search<Hotel>(searchText, sp);
You can find more info here
This is my case, I want to pull the Vendor Credit that have ApplyList.apply.doc (this is Vendor Bill ID) in a List of Vendor Bill ID.
I have to create a TransactionSearch, but I don't know how to apply a condition for this.
For now, I just know to create a search with Status, Type, but that's not enough.
Here is my code :
var transactionsSearch = new TransactionSearch
{
basic = new TransactionSearchBasic
{
//we only want credits with an "Open" status
billingStatus = new SearchBooleanField
{
searchValue = isOpen,
searchValueSpecified = true
},
//only search for those with a type of "_vendorCredit"
type = new SearchEnumMultiSelectField
{
#operator = SearchEnumMultiSelectFieldOperator.anyOf,
operatorSpecified = true,
searchValue = new[] { "_vendorCredit" }
},
}
};
I figured out the answer.
I have to use property Applied To Transaction in TransactionSearchBasic, that will be an array of Record Ref.