convert dynamic object to C# object - c#

I’m looking to take a dynamic object from a third party API & convert to my C# object with minimal code.
Sort of like what Dapper does with a SQL statement results to a C# object. Is there a library that would do this?
I can do it manually like below, but it seems like alot of code to write everytime I want to retrieve from this API.
public IEnumerable<Requirement> Get()
{
dynamic requirementsSelect;
requirementsSelect = _RequirementsRepository.GetRequirements();
IList<Requirement> Requirements = new List<Requirement>();
foreach (var req in requirementsSelect)
{
Requirement requirement = new Requirement();
requirement.Text = req.Text;
requirement.Number = req.Number;
Requirements.Add(requirement);
foreach (var node in req.Phrases)
{
Requirement reqNode = new Requirement();
reqNode.Text = node.Text;
reqNode.Number = node.Number;
requirement.Nodes.Add(reqNode);
}
return Requirements;
}
Thanks

I ended up returning the third party as JSON as follows. In my specific case the JSON wasn't showing the properties. I resolved by changing the dynamic object to IEnumerable and I was then able to specify which properties I wanted to retrieve using .Select.
IEnumerable<dynamic> requirements = _RequirementsRepository.GetRequirements();
return JsonConvert.SerializeObject(new
{
Requirement = requirements.Select(x => x.Text),
Number = requirements.Select(x => x.Number),
});
Thanks!

Related

C# Extracting Data from API Response where response seems to be an Object vs XML

I'm calling an API the same way I always have called APIs. The response is what I would expect except with every other API I've used it's returned an XML string which is easy to get data out of. This one particular API seems to return the response and place the response data into an object. Here is how I'm calling the API in C#...
KeyFieldsAPI.PS_API_KeyFields_V2 KeyFieldsAPI = new KeyFieldsAPI.PS_API_KeyFields_V2();
object KFAPI = KeyFieldsAPI.GetKeyFields(KAccount_Number, KCourier, KService, "", InventoryCodeList);
I can loop through the KFAPI object and place the upper level field responses into variables by using:
foreach (PropertyInfo property in KFAPI.GetType().GetProperties())
{
PropName = property.Name.ToString();
PropType = property.GetType().ToString();
PropValue = property.GetValue(KFAPI, null).ToString();
DataRow dr = ITAB_KFHEADER.NewRow();
dr["Name"] = PropName;
dr["Value"] = PropValue;
ITAB_KFHEADER.Rows.Add(dr);
}
However two of the fields seem to be arrays as seen here...
image of watch values box
I need to extract data from the NeedDate_Item field which seems to be an array with 3 index lines of data as part of this object. Can anyone suggest how I can extract data from this API response object that is part of an embedded array? Thanks to everyone in advance.
I figured it out. If I change the line of code to call the API from object to var like this:
var KFAPI = KeyFieldsAPI.GetKeyFields(KAccount_Number, KCourier, KService, "", InventoryCodeList);
Then it allows me to grab the data like this:
foreach (var NDdate in KFAPI.NeedDate_Item)
{ *** do work here***
}
Calling the API with "object" did not allow me to select and use the embedded arrays but changing the call to "var" did. Maybe this might help someone else in the future.

How to dynamically pass object type to <>?

I want to use a method to create an empty document in a collection and get its id from MongoDB. I was thinking about using same method for 2 different types of object types. For example:
public async Task<string> CreateObject (object x)
{
Type objectType = x.GetType();
_context.Database.
GetCollection<objectType>("CollectionName").
InsertOneAsync(x);
return x;
}
But this doesn't work as GetCollection<> will work only with entities or models thats defined already in the application and refusing to take object type dynamically according to my code. I dunno if its bad programming but is it possible to attain this or just stupid to try this?
Thanks :)
Well am not exactly sure what you are trying to achieve but what if you make your method a generic one like
public async Task<string> CreateObject<T> (T x)
{
_context.Database.
GetCollection<T>(nameof(T)).InsertOneAsync(x);
return x;
}
Why can't you use something like dynamic type?
_context.Database.
GetCollection<dynamic>("CollectionName").
InsertOneAsync(x);
Or you can use the BsonDocument class as well.
If you just want to add an empty document into a collection and get back an id in which the database server assigned it you can do the following:
var client = new MongoClient();
var database = client.GetDatabase("test");
await client.DropDatabaseAsync(database.DatabaseNamespace.DatabaseName);
var collection = database.GetCollection<BsonDocument>("collection");
var newDocument = new BsonDocument();
await collection.InsertOneAsync(newDocument);
var id = newDocument["_id"].AsObjectId;
Console.WriteLine($"_id is '{id}'");

Converting json string into list of existing object in C#

I work with an api, that returns a json formatted resultset of a database query.
I have an equivalent object or "model" for the results.
What is the best way to convert the json string into a list of this object?
Of course there are many threads about this, but no one fits my needs properly.
One of the solutions I've found was this:
var jobj = (JObject)JsonConvert.DeserializeObject(json);
var items = jobj.Children()
.Cast<JProperty>()
.Select(j => new
{
ID = j.Name,
Topic = (string)j.Value["Topic_ID"],
Moved = (string)j.Value["Moved_ID"],
Subject = (string)j.Value["subject"],
})
.ToList();
This seems pretty close to what I need. I need to be able to map the keys/values to the appropriate object attributes, which DOES already exist. So maybe you only need to change a few things to make it work for my object?
PS: I'm using Newtonsoft. Any solution for .NET or Newtonsoft or if needed any other library would be great!
I have recently been consuming data from a WebApi and i have been using the following code to convert the json object to an object to work with:
using (var client = new HttpClient())
{
var response = client.GetAsync(apiUri).Result;
// For single objects.
MyObject data = response.Content.ReadAsAsync<MyObject>().Result;
// For an array of objects
IEnumerable<MyObject> data = response.Content.ReadAsAsync<IEnumerable<MyObject>>().Result;
}
Hope this helps.
OK, so you have something like this:
public class MyObject
{
public int ID {get; set;}
public string Topic {get; set;}
public string Subject {get; set;}
}
And you want to instantiate an array of MyObjects with the properties coming from your JSON?
In that case you're just a bout there - you're currently creating a dynamic object with the same properties as MyObject, right? So all you need to do is create an actual MyObject instead:
.Select(j => new **MyObject()**
{
ID = j.Name,
Topic = (string)j.Value["Topic_ID"],
Moved = (string)j.Value["Moved_ID"],
Subject = (string)j.Value["subject"]
})
Note that if your json property names exactly match your C# ones (including case), you can do this as a one-liner with NewtonSoft: http://www.newtonsoft.com/json/help/html/SerializingJSON.htm. But to use that method you'd have to have an intermediate C# class to match your JSON, and then automap (or manually convert) those to MyObjects. Or you'd have to make sure your json and c# properties match exactly. But you're already very close to a quicker (though some would argue less elegant) solution.
Why aren't you deserializing the json into the object type directly? you can do it like this...
var obj = (YourType)JsonConvert.DeserializeObject(
json,
typeof(YourType),
new JsonSerializerSettings()
{
TypeNameHandling = TypeNameHandling.Auto,
MissingMemberHandling=MissingMemberHandling.Ignore
});
or am I missing something in the question?

How to add a parent to every child in a json array?

I'm working on a Web Service in ASP.NET that has two methods, what I want to do is to return the data in JSON format, I'm usin JSON.NET library.
This is one of the methods:
[WebMethod]
public string GetReservas()
{
var json = "";
var data = from result in DCHotel.visHTLReservaciones select result;
json = JsonConvert.SerializeObject(data);
return json;
}
When I run the web service, this is the output in my browser:
[{"id":1,"name":"jose","age":22},{"id":2,"name":"john","age":21}]
And what I need is something like this:
["person":[{"id":1,"name":"jose","age":22}],"person":[{"id":2,"name":"john","age":21}]]
I need to add parents to every child in the array, I don't know how to do it, and I searched a lot and can't find the solution to this, hope you can help me.
Thanks.
It's very easy, change your linq query to this:
var data = from result in DCHotel.visHTLReservaciones select new { person = result };
Instead of taking just the result you encapsulate it on an anonymous class.
Cheers.

Creating a completely dynamic query with RavenDB using LuceneQuery

I want one method that can query my entire RavenDB database.
My method signature looks like this:
public static DataTable GetData(string className, int amount, string orderByProperty, string filterByProperty, string filterByOperator, string filterCompare)
I figured I can accomplish all of the above with a dynamic LuceneQuery.
session.Advanced.LuceneQuery<dynamic>();
The problem is: Since I'm using dynamic in the type given, how do I ensure that the query only includes the types matching the className?
I'm looking for something like .WhereType(className) or .Where("type: " + className).
Solution
This returns the results of the correct type:
var type = Type.GetType("Business.Data.DTO." + className);
var tagName = RavenDb.GetTypeTagName(type);
using (var session = RavenDb.OpenSession())
{
var result = session.Advanced
.LuceneQuery<object, RavenDocumentsByEntityName>()
.WhereEquals("Tag", tagName)
.ToList();
}
Note, it is not possible to add additional "WhereEquals" or other filters to this. This is because nothing specific to that document type is included in the "RavenDocumentByEntityName" index.
This means that this solution cannot be used for what I wanted to accomplish.
What I ended up doing
Although it doesn't fulfill my requirement completely, this is what I ended up doing:
public static List<T> GetData<T>(DataQuery query)
{
using (var session = RavenDb.OpenSession())
{
var result = session.Advanced.LuceneQuery<T>();
if (!string.IsNullOrEmpty(query.FilterByProperty))
{
if (query.FilterByOperator == "=")
{
result = result.WhereEquals(query.FilterByProperty, query.FilterCompare);
}
else if (query.FilterByOperator == "StartsWith")
{
result = result.WhereStartsWith(query.FilterByProperty, query.FilterCompare);
}
else if (query.FilterByOperator == "EndsWith")
{
result = result.WhereEndsWith(query.FilterByProperty, query.FilterCompare);
}
}
if (!string.IsNullOrEmpty(query.OrderByProperty))
{
if (query.Descending)
{
result = result.OrderBy(query.OrderByProperty);
}
else
{
result = result.OrderByDescending(query.OrderByProperty);
}
}
result = result.Skip(query.Skip).Take(query.Amount);
return result.ToList();
}
}
Although this is most certainly an anti-pattern, it's a neat way to just look at some data, if that's what you want. It's called very easily like this:
DataQuery query = new DataQuery
{
Amount = int.Parse(txtAmount.Text),
Skip = 0,
FilterByProperty = ddlFilterBy.SelectedValue,
FilterByOperator = ddlOperator.SelectedValue,
FilterCompare = txtCompare.Text,
OrderByProperty = ddlOrderBy.SelectedValue,
Descending = chkDescending.Checked
};
grdData.DataSource = DataService.GetData<Server>(query);
grdData.DataBind();
"Server" is one of the classes/document types I'm working with, so the downside, where it isn't completely dynamic, is that I would have to define a call like that for each type.
I strongly suggest you don't go down this road. You are essentially attempting to hide the RavenDB Session object, which is very powerful and intended to be used directly.
Just looking at the signature of the method you want to create, the parameters are all very restrictive and make a lot of assumptions that might not be true for the data you're working on. And the return type - why would you return a DataTable? Maybe return an object or a dynamic, but nothing in Raven is structured in tables, so DataTable is a bad idea.
To answer the specific question, the type name comes from the Raven-Entity-Name metadata, which you would need to build an index over. This happens automatically when you index using the from docs.YourEntity syntax in an index. Raven does this behind the scenes when you use a dynamic index such as .Query<YourEntity> or .Advanced.LuceneQuery<YourEntity>.
Still, you shouldn't do this.

Categories

Resources