How to get property and object inside OData array JSON results - c#

I want to get entityObject using OData API logic, I was able to get id and name using this ${this.environment.url}/magic?$select=id,name} However when I say ${this.environment.url}/magic?$select=id,name,entityObject} it does not get entityObject. Result from api
[
{
"id":"someId",
"name":"some Name,",
"entityObject":{
"id":"someId",
"description":"some Description"
}
}
]

Related

CosmosDb. How to retrieve the _ts property from a Upsert operation

Using the .NET 3 SDK for CosmosDB my upsert operation on an existing document does not return any of the extra properties stored in the document E.G. the _ts property. I would like to use this property in my app. Do I have to include a _ts property in my model or is there a way to retrieve _ts from the document?
Do I have to include a _ts property in my model?
If you're working with a typed model, then the answer is yes. You will need to create a property corresponding to _ts property of the response otherwise the deserializer will not be able to deserialize this.
Another option would be to work with dynamic type and do the conversion into the model yourself. For example, you could do something like:
var model = new Model()
{
Id = "some id",//should serialize to "id",
//other properties of the model
}
var item = (await container.UpsertItemAsync<dynamic>(model)).Resource;
Console.WriteLine(item.ToString());
Above would print something like the following:
{
"id": "783cf82c-f24c-4031-971d-bd5f604724d5",
"_rid": "xxxx",
"_self": "dbs/xxxx/colls/xxxx/docs/xxxx/",
"_etag": "\"xxxx\"",
"_attachments": "attachments/",
"_ts": 1621597233,
//other model properties
}
You can now extract the "_ts" property from the JSON.

OData in ASP.NET Core, pagination with total number of records in a table (Metadat missing)

I'm using OData in my asp.net core3.1 app and what to delegate the pagination to the client. I'm stuck at how to return alog with the given number of entries, the total number of entries in a table. For example having a table with 100 entries, I want to be able to get this information to know exactly how to create my page component.
Service registration
services.AddOData();
Configuration
app.UseEndpoints(endpoints =>
{
endpoints.MapDefaultControllerRoute();
endpoints.EnableDependencyInjection();
endpoints.Expand().Select().Count().Filter().OrderBy().SkipToken().MaxTop(20);
});
This is the endpoint
[HttpGet]
[EnableQuery]
[Produces("application/json")]
public IActionResult Get()
{
var query = dbContext.Users;
return Ok(query);
}
I'm using this query -
https://localhost:1234/api/users?$count=true&$select=id,name,version&$skip=0&$top=5
outputs just a list of 5 objects, no extra metadata.
[
{
Id: "1",
Name: "a",
Version: "1"
},
... 4 more objects
]
$count=true means that the overall count will be in the response:
GET: ~/OData/Employees/Summaries?$count=true&$top=10&$skip=10
{
"#odata.context": "~/odata/$metadata#EmployeeSummaryDTOs(Contact())",
"#odata.count": 29,
"value": [
{
"Id": 15097,
"Title": "Miss Mavis MOPPIT",
...
We can actually cheat a little to prove this, if we take the $top 0 records, the count is still returned:
GET: ~/OData/Employees/Summaries?$count=true&$top=0
{
"#odata.context": "~/odata/$metadata#EmployeeSummaryDTOs(Contact())",
"#odata.count": 29,
"value": []
}
This of course relys on a default or pass through controller, your controller method will need to return an IQueryable expression for the $count to be resolved automatically.
The default implementation will apply the $filter to your expression, then resolve the $count as a separate DB query, then it applies the paging Take/Skip logic when it retrieves the final result.
If you are processing the request yourself, then you will need to manage that logic as well.

How post JSON array to ASP.Net Core app using Postman

I am new in ASP.Net Core development. I want to post array of custom class to ASP.Net controller. I can post object but not array.
Here is my InventoryItem class
public class InventoryItem
{
public int Id { get; set; }
public string ItemName { get; set; }
public double Price { get; set; }
}
Here is my method in InventoryController Class
public ActionResult<InventoryItem> AddInventoryItems([FromForm]InventoryItem[] items)
{
return Ok("Array Length " + items.Length);
}
I am getting Array Length as 0.
I am using Postman
Also I have tried Posting data as JSON and modifying [FromForm] to [FromBody] attribute:
Also I am getting 415 Unsupported Media Type error in Postman when changed to [FromBody].
You are trying in a wrong way. As you are trying to pass data to your controller which is a collection type. So you have to pass a Json array to meet your controller data type. You can do it in following way.
Select Body then Raw then Json If you want to pass Json data. your array
should look like this:
[
{
"id": 1,
"itemName": "A",
"price": 10.0
},
{
"id": 2,
"itemName": "B",
"price": 20.0
},
{
"id": 3,
"itemName": "C",
"price": 30.0
}
]
See the screen shot:
Test Result
I have tried as per your sample which works fine:
[HttpPost("[action]")]
[Route("AddInventoryItems")]
[ActionName("AddInventoryItems")]
public ActionResult<InventoryItem> AddInventoryItems([FromBody]InventoryItem [] items)
{
return Ok("Array Length " + items.Count());
}
Final Output:
I have tested many ways all works fine. I have attached code as well you could try.
But apart from your question I would suggest you to write your controller like below which mostly practice in C# and Web API
[HttpPost("[action]")]
[Route("AddInventoryItems")]
[ActionName("AddInventoryItems")]
public ActionResult<InventoryItem> AddInventoryItems([FromBody]List<InventoryItem> items)
{
return Ok("Array Length " + items.Count());
}
1.Get data in [FromForm] , you should pass the array data as below format in postman:
2.Pass the data as JSON, you should use [FromBody] attribute as Md Farid Uddin Kiron suggested above:
public ActionResult<InventoryItem> AddInventoryItems([FromBody]InventoryItem[] items)
{
return Ok("Array Length " + items.Length);
}
Answering my own question in detail how I solved the problem.
There was no problem in C# code, only method of posting data in Postman was wrong.
Refer to this answer if 415 Unsupported Media Type Error arises in Postman. C# code is same as in the Question above.
I am using two ways to post data. Firstly posting as Form-data, secondly posting in JSON format.
1] When posting Array of custom class using form data use Xueli Chen's method Select Body -> form-data in Postman and enter array items as items[index].key = value like items[0].id = 1001 and items[0].ItemName = "Biscuits"
2] When posting array of custom class in JSON format firstly select Body -> raw -> Select JSON in Languages. If there is warning sign when JSON is selected like
then Go To Headers -> Set Content-Type = application/json just like
Now Body -> raw JSON Array Data
[
{
"Id": 1,
"ItemName": "Biscuits",
"Price": 20
},
{
"Id": 1,
"ItemName": "Cakes",
"Price": 100
}
]
and in C# code in the project change [FromForm] to [FromBody] attribute
public ActionResult<InventoryItem> AddInventoryItems([FromBody]InventoryItem[] items)
and Send to the Server
In short for Posting Array as form-data use items[index].key = value like items[0].ItemName = Biscuits in Postman.
For Posting Array as JSON Data Enter JSON array and check if Content-Type = application/json in Headers in Postman.
Sorry for the long answer.
Actually you are using wrong way to send data as a POST request. You can use raw instead of form-data and post a json array of your InventoryItem.

Youtube Data v3 Api, Get Request sort

Hey everyone i'm trying to use the v3 Data Youtube API, already have the Request itself and the response looks like this
{
"items": [
{
"snippet": {
"publishedAt": "2016-12-07T16:04:40.472Z",
"displayMessage": "a"
}
}
]
}
The Problem is that i only want the last Comment and not the whole 200(cant be set lower) my first Idea was to Save the whole Response and Compare it to the next one so i know whats new, but that wont really work out
Ok, so from the comments, I gather you are talking about the Live Streaming API.
What you get back are messages, not comments. And yes, as the doc says, "Acceptable values are 200 to 2000, inclusive. The default value is 500." So, you could get the whole 200, and then sort on the timestamp to get the latest message.
How to do that?
As you are doing this in C#, once you have the json string, you need to use some library such as Json.NET. Once you add a NuGet package reference to this, you will need
using Newtonsoft.Json.Linq;
and say your json string is
var json = #"{
""items"": [
{
""snippet"": {
""publishedAt"": ""2016-12-07T16:04:40.472Z"",
""displayMessage"": ""a""
}
}
,
{
""snippet"": {
""publishedAt"": ""2016-12-12T16:04:40.472Z"",
""displayMessage"": ""b""
}
}
]
}";
Then, as described in this documentation, use JObject.Parse to use LINQ to JSON.
var parsedJson = JObject.Parse(json);
JArray items = parsedJson.SelectToken("items") as JArray;
var sortedItems = items.OrderByDescending(item => item["snippet"]["publishedAt"]);
// sortedItems.First() will give you the item with the newest timestamp
Have put all of this at https://dotnetfiddle.net/ubQAZV.
Alternately, you can use JsonConvert if you prefer to deserialize to strongly-typed code.
More about it here.

ASP.NET getting indexed values when deserializing JSON into a dynamic object

So I have a JSON string that I am passing from an AJAX call to my controller. I have a list of indexed values that I am passing into a dynamic object.
I deserialize the JSON with
JsonConvert.DeserializeObject<dynamic>(s)
This is the output from that dynamic object:
"RolePermissions[0].RolePermissionId": "269",
"RolePermissions[0].HasAccess": "false",
"RolePermissions[1].RolePermissionId": "270",
"RolePermissions[1].HasAccess": "false",
"RolePermissions[2].RolePermissionId": "271",
"RolePermissions[2].HasAccess": "true",
"RolePermissions[3].RolePermissionId": "272",
"RolePermissions[3].HasAccess": "false"
When I try to access the a property of the object with
ssObj.RolePermissions[0].RolePermissionId
I get a RuntimeBinderException. I have tried to use JObject.Parse, which works great, but for some reason, the values in the array become out of order.
Any help would be greatly appreciated. Thanks!
When you try to do RolePermissions[0].RolePermissionId you are trying to access a nested collection containing an object with a property RolePermissionId at index 0. But your JSON doesn't represent a hierarchy of objects, it represents a single flat object with key/value pairs whose keys contain periods and brackets. Since c# identifiers don't allow such characters so you have no way to access such property values using dynamic directly.
Instead, your options include:
Take advantage of the fact that JsonConvert.DeserializeObject<dynamic>(s) actually returns a JObject and use its dictionary indexer:
var ssObj = JsonConvert.DeserializeObject<dynamic>(s);
var rolePermissionId = (string)ssObj["RolePermissions[0].RolePermissionId"];
If you prefer a slightly more typed solution, you could deserialize to a Dictionary<string, dynamic>:
var ssDict = JsonConvert.DeserializeObject<Dictionary<string, dynamic>>(s);
var rolePermissionId = (string)ssDict["RolePermissions[0].RolePermissionId"];
Or for a much more statically typed solution, parse explicitly to a JObject and use LINQ to JSON:
var jObj = JObject.Parse(s);
var rolePermissionId = (string)jObj["RolePermissions[0].RolePermissionId"];
Sample fiddle showing the various options.
If you are in control of the data being sent via AJAX then make sure the data sent is properly formatted.
In order to be able to deserialize variable s like:
var ssObj = JsonConvert.DeserializeObject<dynamic>(s);
and access the resulting object in this manner:
ssObj.RolePermissions[0].RolePermissionId
then the JSON value in s, based on your sample and desired behavior, would have to look like this:
{
"RolePermissions": [
{
"RolePermissionId": "269",
"HasAccess": "false"
},
{
"RolePermissionId": "270",
"HasAccess": "false"
},
{
"RolePermissionId": "271",
"HasAccess": "true"
},
{
"RolePermissionId": "272",
"HasAccess": "false"
}
]
}
This quick unit test showed that it is possible to get indexed values when deserializing JSON into a dynamic object
[TestClass]
public class UnitTest1 {
[TestMethod]
public void GetIndexedValuesWhenDeserializingJSONIntoDynamicObject() {
var s = #"
{
'RolePermissions': [
{
'RolePermissionId': '269',
'HasAccess': 'false'
},
{
'RolePermissionId': '270',
'HasAccess': 'false'
},
{
'RolePermissionId': '271',
'HasAccess': 'true'
},
{
'RolePermissionId': '272',
'HasAccess': 'false'
}
]
}
";
var ssObj = JsonConvert.DeserializeObject<dynamic>(s);
var result = ssObj.RolePermissions[0].RolePermissionId;
Assert.AreEqual("269", (string)result);
}
}
So you need to make sure you are sending well formatted JSON to your controller to achieve desired behavior.

Categories