.NET Core get array in array from config.json - .net-core

I have an issue where an array object in my config.json is coming back as empty. In the following code, gridFields will come back as empty.
{"grids": [{
"name": "Grid1"
"gridFields": [
{
"Name": "Something",
"Label": "Something"
},
{
"Name": "SomethingElse",
"Label": "SomethingElse"
}]
},
{"name": "Grid2"
"gridFields": [
{
"Name": "Something",
"Label": "Something"
}]
}]
}
I have matching POCOs and made sure the names match up as follows.
public class Grid
{
public string name { get; set; }
public gridFields gridFields {get; set;}
}
public class gridFields
{
public List<gridField> GridFields { get; set; } = new List<gridField>();
public int Count => GridFields.Count();
public IEnumerator GetEnumerator()
{
return GridFields.GetEnumerator();
}
}
public class gridField
{
public string Name { get; set; }
public string Label { get; set; }
}
In my startup I have the following
public void ConfigureServices(IServiceCollection services)
{ services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
var config = new List<Grid>();
Configuration.Bind("grids", config);
services.AddSingleton(config);
}
The config.gridFields ends up holding no values. I have values for name, but not gridFields. Even if I make gridFields List it comes back null.
My question is if there is someway following this current code that I can get the data out of this array in array, or do I need to do something completely different. Why isn't .net core able to bind every object it comes across underneath the parent?

The example json misses a , after the name of each grid.
{
"name": "Grid2",
"gridFields":
[{
"Name": "Something",
"Label": "Something"
}]
}
You have a list of gridField directly under the Grid in the Json.
In the Code however you use another object, GridFields.
You should remove the gridfiels class and use a list of gridField in the Grid class:
public class Grid
{
public string name { get; set; }
public List<gridField> gridFields {get; set;}
}

Related

Swagger / Swashbuckle string property options

We have an API in our .Net Core 3.1 project that has a controller which returns a model that is documented by Swagger (Generated by Swashbuckle).
The consumer of the endpoint would like to see the options that a given property may return. For several reasons this for now at least is not just an Enum which would make the process a lot easier. It is a string that can return two different values.
Is there any way to decorate the property so that the options are available in Swagger just as if it had been an Enum? For Enums we can use the MapType on startup, but this is just a string so it's not a type we can map perse.
This is how we have done it with Enums previously:
c.MapType<PaginationSessionType>(() => new OpenApiSchema
{
Type = "string",
Enum = typeof(PaginationSessionType).GetEnumNames()
.Select(name => new OpenApiString(name)).Cast<IOpenApiAny>().ToList()
});
http://swagger-net-test.azurewebsites.net/swagger/ui/index#/TestStringEnum/TestStringEnum_Post
I was able to do what you need with "swagger": "2.0" not 100% sure with the version you are using... At that time I got what I needed with the RegularExpression decorator.
here is the code that generates that:
https://github.com/heldersepu/Swagger-Net-Test/blob/master/Swagger_Test/Controllers/TestStringEnumController.cs
using System.Web.Http;
using System.ComponentModel.DataAnnotations;
namespace Swagger_Test.Controllers
{
public class MyEndpointRequestClass
{
[RegularExpression("^(dark-blue|dark-red|light-blue|light-red)")]
public string StringEnumColor { get; set; }
[RegularExpression("^(high|medium|low)")]
public string Transparency { get; set; }
public string Name { get; set; }
}
public class TestStringEnumController : ApiController
{
public string Post([FromUri] MyEndpointRequestClass r)
{
return r.StringEnumColor;
}
public string Get([RegularExpression("^(uno|due)")]string x)
{
return x;
}
}
}
the relevant swagger.json from that is:
...
"MyEndpointRequestClass": {
"properties": {
"StringEnumColor": {
"type": "string",
"pattern": "^(dark-blue|dark-red|light-blue|light-red)"
},
"Transparency": {
"type": "string",
"pattern": "^(high|medium|low)"
},
"Name": {
"type": "string"
}
},
"xml": {
"name": "MyEndpointRequestClass"
},
"type": "object"
},
...
This might not answer you question but hopefully it sends you on the right direction

Working with restricted string field values in .NET Core WebAPI 3.1

I'm working on a webapi project using .netcore.
I have a model with the following properties:
public class Criterial {
[Required]
public string Field { get; set; }
[Required]
public Operator Operator { get; set; }
[Required]
public string Value { get; set; }
public bool Result { get; set; }
}
public enum Operator {
greater_than,
equal_to,
lower_than
}
I'm trying to use enum to restrict the values that the Operator propertie can receive, but when I make a POST request to the API I got the following scenario:
POST Request Body:
"criterials": [
{
"field": "amount",
"operator": "greater_than",
"value": "50"
}
]
Response from the API:
{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"traceId": "|7e53377-444fa4a723ac655c.",
"errors": {
"$.criterials[0].operator": [
"The JSON value could not be converted to LeagueOfFateApi.Models.Operator. Path: $.criterials[0].operator | LineNumber: 5 | BytePositionInLine: 26."
]
}
}
Searching about the issue on the internet I found the [JsonConverter(typeof(JsonStringEnumConverter))] Data Annotation.
So I added it to my code and the issue was "solved":
[Required]
[JsonConverter(typeof(JsonStringEnumConverter))]
public Operator Operator { get; set; }
New response from the API:
"criterials": [
{
"field": "amount",
"operator": "greater_than",
"value": "50",
"result": false
}
]
The problem is: in my MongoDB collection a new document was saved with the int value 0 of the enums, and not the string value "greater_than":
"Criterials" : [
{
"Field" : "amount",
"Operator" : 0,
"Value" : "50",
"Result" : false
}
]
Besides, another problem is that the "criterial" field can receive any int value with no restrictions.
Is there any other practical way to restrict a string's options without using enums? Or is there anything I can add to this solution using enums?
Thank you very much for your attention and your time!
According to your description, I suggest you could write custom set and get method for the Operator property.
You could set the Operator's type is string and use Enum.IsDefined to check the Operator value is enum Operator or not.
More details, you could refer to below codes:
public class Criterial
{
[Required]
public string Field { get; set; }
private string _Operator;
[Required]
public string Operator {
get {
return this._Operator;
}
set {
if (Enum.IsDefined(typeof(Operator), value))
{
this._Operator = value;
}
else
{
this._Operator = "Error you used wrong string";
}
}
}
[Required]
public string Value { get; set; }
public bool Result { get; set; }
}
public enum Operator
{
greater_than,
equal_to,
lower_than
}
Result:

POST request using JSON and Web API?

I have two models: Child and Location. They have a relationship. This is what Location looks like:
public class Location {
[Key]
public int Id { get; set; }
public float Latitude { get; set; }
public float Longitude { get; set; }
public float Accuracy { get; set; }
public DateTime ReportTime { get; set; }
[JsonIgnore]
public virtual Child Child { get; set; }
}
`
The Child model looks along those lines (FirstName, LastName, etc.) and has a reference to ICollection<Location> Locations.
My controller looks like this:
[ResponseType(typeof(Location))]
public IHttpActionResult PostLocation([FromBody] Location location)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
db.Locations.Add(location);
db.SaveChanges();
return CreatedAtRoute("DefaultApi", new { id = location.Id }, location);
}
When POSTing data using JSON from a mobile device, ideally I would like to pass the Child's ID value instead of the entire Child object. However, every time when inspecting the incoming Location object, the child property is set to null. I have tried the following JSONs:
{
"Latitude": 43.63434,
"Longitude": -92.12345,
"Accuracy": 13,
"ReportTime": "2016-05-11T23:29:30.87",
"Child": {
"Id": 3
}
}
and
{
"Latitude": 43.63434,
"Longitude": -92.12345,
"Accuracy": 13,
"ReportTime": "2016-05-11T23:29:30.87",
"Child": 3
}
I have even tried to pass an entire Child object (copy/pasted what I got from my own details GET ApiController), but the child is still set to null.
I am pretty new to ASP.NET and especially Web API so I'd appreciate any help. How can I instruct the WebAPI to at least parse the ID part of the Child object?
I know that technically I could solve this by adding another property to the Location model, int ChildId - but I was wondering if there was a more elegant solution (there are quite a few models associated with Child).
Thank you!
Change the property name of Child to other name. eg.
public virtual Child ChildProp { get; set; }
And your Json data:
{
"Latitude": 43.63434,
"Longitude": -92.12345,
"Accuracy": 13,
"ReportTime": "2016-05-11T23:29:30.87",
"ChildProp": {
"Id": 3
}
}

Prevent eager loading from including children of included entities (stop self-referencing loop)

I have two entities that have a many-to-many relationship. When I eager load one entity using Include() it loads the children and ALSO includes the children of the children. I do not want the grandchildren.
I turned off lazy loading: LazyLoadingEnabled = false; and am ignoring self referencing loops:
config.Formatters.JsonFormatter.SerializerSettings
.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling
.Ignore;
To better explain things:
public class A
{
public int Id { get; set; }
public ICollection<B> Bs { get; set; }
}
public class B
{
public int Id { get; set; }
public ICollection<A> As { get; set; }
}
I'm using the IUnitOfWork pattern (see Creating a Generic Repository) so load the entities thus:
return unitOfWork.ARepository.Get(a => a.Id == Id, null, "Bs");
I get back JSON that looks something like this:
[
{
"Id": 1,
"Bs": [
{
"Id": 1,
"As": [
{
"Id": 2,
"Bs": [
...
},
{
"Id": 2,
"Bs": [
{
"Id": 1,
"As": [
{
"Id": 1,
"Bs": [
...
Passing the self-referenced entities seems really wasteful. Is there any way to prevent this?
I added the Newtonsoft.Json.JsonIgnoreAttribute to the As property in class B.
public class B
{
public int Id { get; set; }
[JsonIgnore]
public ICollection<A> As { get; set; }
}
I believe it is safe to do this because I will not reference Class A through B. That relationship is present for EF Code First.
To use [JsonIgnore] install it using Nuget (https://nuget.org/packages/newtonsoft.json/):
PM> Install-Package Newtonsoft.Json

Parsing device listing from Urban Airship with JSON.Net

For the life of me, I can't figure out how to parse the collection of device_tokens out of this using JSON.Net. I can parse out the top level collection fine, but am bombing on parsing out the device tokens in any way shape or form. Anyone have any ideas?
{
"next_page": "https://go.urbanairship.com/api/device_tokens/?start=<MY_TOKEN>&limit=2",
"device_tokens_count": 87,
"device_tokens": [
{
"device_token": "<MY_TOKEN>",
"active": false,
"alias": null,
"tags": []
},
{
"device_token": "<MY_TOKEN>",
"active": true,
"alias": null,
"tags": ["tag1", "tag2"]
}
],
"active_device_tokens_count": 37
}
Heres how you can do it using Json.NET
First create a class to represent a single device_token:
public class DeviceToken
{
public string device_token { get; set; }
public bool active { get; set; }
public object alias { get; set; }
public List<object> tags { get; set; }
}
Then using the JsonConvert class you can deserialize the json device_token array to a list of DeviceToken objects.
string json = "{\"next_page\": \"https://go.urbanairship.com/api/device_tokens/?start=07AAFE44CD82C2F4E3FBAB8962A95B95F90A54857FB8532A155DE3510B481C13&limit=2\",\"device_tokens_count\": 87,\"device_tokens\": [{\"device_token\": \"0101F9929660BAD9FFF31A0B5FA32620FA988507DFFA52BD6C1C1F4783EDA2DB\",\"active\": false,\"alias\": null,\"tags\": []},{\"device_token\": \"07AAFE44CD82C2F4E3FBAB8962A95B95F90A54857FB8532A155DE3510B481C13\",\"active\": true,\"alias\": null,\"tags\": [\"tag1\", \"tag2\"] }],\"active_device_tokens_count\": 37}";
JObject obj = JObject.Parse(json);
var deviceTokens = JsonConvert.DeserializeObject<List<DeviceToken>>(obj["device_tokens"].ToString());

Resources