NEST mapping of Dictionary<string,List<string>> - dictionary

I have a class with Dictionary<string, List<string>> as one of the members. I'm able to insert the data with automap, but unable to query the documents with the keys and/or values in the dictionary. If I use match query, it returns everything in the index. I tried using Terms, Nested/non-nested query, and QueryString query, but none of them returns any document.
class ESSchema
{
[String(Index = FieldIndexOption.NotAnalyzed, Store = false)]
public string Machine { get; set; }
[String(Index = FieldIndexOption.NotAnalyzed, Store = false)]
public string Filename { get; set; }
[Number(NumberType.Long, Store = false)]
public long BatchNumber { get; set; }
[String(Index = FieldIndexOption.NotAnalyzed, Store = false)]
public string Environment { get; set; } = null;
[Nested]
//[Object(Store = false)]
public Dictionary<string, List<string>> KeysValues { get; set; }
}
Automap converts the dictionary to the following mapping which I'm not sure is the correct representation of what I'm looking for.
"keysValues": {
"type": "nested",
"properties": {
"comparer": {
"properties": {
},
"type": "object"
},
"count": {
"type": "integer"
},
"keys": {
"properties": {
"count": {
"type": "integer"
}
},
"type": "object"
},
"values": {
"properties": {
"count": {
"type": "integer"
}
},
"type": "object"
},
"item": {
"type": "string"
}
}
},

When Automapping, NEST by default will map one level down in the object graph. In the case of your Dictionary<string, List<string>> property, the public properties of the dictionary end up being mapped, which is undesirable.
There are a couple of ways this can be controlled
1.Passing -1 for maxRecursion to AutoMap()
class ESSchema
{
[String(Index = FieldIndexOption.NotAnalyzed, Store = false)]
public string Machine { get; set; }
[String(Index = FieldIndexOption.NotAnalyzed, Store = false)]
public string Filename { get; set; }
[Number(NumberType.Long, Store = false)]
public long BatchNumber { get; set; }
[String(Index = FieldIndexOption.NotAnalyzed, Store = false)]
public string Environment { get; set; } = null;
[Object(Store = false)]
public Dictionary<string, List<string>> KeysValues { get; set; }
}
client.Map<ESSchema>(m => m
.AutoMap(-1)
);
which results in
{
"properties": {
"machine": {
"type": "string",
"store": false,
"index": "not_analyzed"
},
"filename": {
"type": "string",
"store": false,
"index": "not_analyzed"
},
"batchNumber": {
"type": "long",
"store": false
},
"environment": {
"type": "string",
"store": false,
"index": "not_analyzed"
},
"keysValues": {
"type": "object",
"store": false,
"properties": {}
}
}
}
2.Controlling the mapping through fluent mapping overrides
client.Map<ESSchema>(m => m
.AutoMap()
.Properties(p => p
.Object<Dictionary<string, List<string>>>(o => o
.Name(n => n.KeysValues)
.Store(false)
)
)
);
Using .Properties() overrides any inferred mapping from Automapping.

Related

.Net Core - NSwag multipart/form-data required fields

I'm using the [FromForm] annotation to bind a multipart/form-data model.
But when swagger generates swagger.json it skips the required fields.
This causes it to misgenerate the interface in the typescript, putting optional properties that should be required.
Anyone helps?
Class:
[Required]
public string Name { get; set; }
[Required]
public string Abbreviation { get; set; }
[Required]
public DateTime DateOfFundation { get; set; }
Swagger.json:
"content": {
"multipart/form-data": {
"schema": {
"type": "object",
"properties": {
"Name": {
"type": "string",
"nullable": true
},
"Abbreviation": {
"type": "string",
"nullable": true
},
"DateOfFundation": {
"type": "string",
"format": "date-time"
}
...

Get value from appsettings.json from array of objects

We know that we can get values from json with the IConfiguration class with the GetSection method or simply with configuration["Serilog:Properties:ApplicationName"]; in case of array with configuration.GetSection("Serilog.Enrich").Get<string[]>()
But I don't know how to retrieve the value of "serverUrl" key that is nested in the first node of the WriteTo array
"Serilog": {
"MinimumLevel": {
"Default": "Information",
"Override": {
"Microsoft": "Warning",
"System": "Warning",
"Serilog": "Warning"
}
},
"Enrich": [ "FromLogContext", "WithMachineName", "WithProcessId", "WithThreadId" ],
"Properties": {
"ApplicationName": "MyApp"
},
"WriteTo": [
{
"Name": "Seq",
"Args": {
"serverUrl": "http://localhost:5341"
}
}
]
}
Any suggestion?
try this
var serverUrl = configuration.GetSection("Serilog").GetSection("WriteTo")
.Get<Dictionary<string,Dictionary<string,string>>[]>()[0]["Args"]["serverUrl"];
or using c# classes
var serverUrl = configuration.GetSection("Serilog").GetSection("WriteTo")
.Get<WriteTo[]>()[0].Args.serverUrl;
classes
public partial class WriteTo
{
public string Name { get; set; }
public Args Args { get; set; }
}
public partial class Args
{
public Uri serverUrl { get; set; }
}

ServiceStack: OpenApi import in Azure Api Management Gateway

We are running a Dotnet Core 2.2 service using ServiceStack 5.7, and need to throttle it. So we want to put it behind a Azure Api Management Gateway (apim) - it runs in a Azure App Service.
We have enabled OpenApi feature using
self.Plugins.Add(new OpenApiFeature());
When we export our OpenApi definition we get the following:
"paths": {
...
"/api/search": {
"post": {
"tags": [
"api"
],
"operationId": "SearchRequestsearch_Post",
"consumes": [
"application/x-www-form-urlencoded"
],
"produces": [
"application/json"
],
"parameters": [
{
"name": "Filters",
"in": "formData",
"type": "array",
"items": {
"$ref": "#/definitions/FilterDto"
},
"collectionFormat": "multi",
"required": false
}
],
"responses": {
"200": {
"description": "Success",
"schema": {
"$ref": "#/definitions/SearchResponse"
}
}
},
"deprecated": false,
"security": [
{
"Bearer": []
}
]
},
"parameters": [
{
"$ref": "#/parameters/Accept"
}
]
}
}
...
"definitions": {
"FilterDto": {
"title": "FilterDto",
"properties": {
"Field": {
"description": "The field to filter on",
"type": "string",
"enum": [
"None",
"DestinationName",
"DocumentId"
]
},
"Values": {
type": "array",
"items": {
"type": "string"
}
},
"Type": {
"type": "string",
"enum": [
"Equals",
"NotEquals",
"RangeNumeric",
"RangeDate"
]
}
},
"description": "FilterDto",
"type": "object"
}
...
}
The problem is that it is not supported to have a parameter with an array of a type (defined in #/definitions/FilterDto). And it fails with:
Parsing error(s): JSON is valid against no schemas from 'oneOf'. Path 'paths['/api/search'].post.parameters[1]', line 1, position 666.
Parsing error(s): The input OpenAPI file is not valid for the OpenAPI specificate https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md (schema https://github.com/OAI/OpenAPI-Specification/blob/master/schemas/v2.0/schema.json).
In the Azure portal.
In c# (ServiceStack) we have defined the following:
public class SearchRequest : SearchRequestBase, IReturn<SearchResponse>
{
public SearchRequest()
{
Filters = new List<FilterDto>();
}
[ApiMember(Name = "Filters"]
public List<FilterDto> Filters { get; set; }
}
public class FilterDto
{
[ApiMember(Name = "Field"]
[ApiAllowableValues("Field", typeof(FilterAndFacetField))]
public FilterAndFacetField Field { get; set; }
[ApiMember(Name = "Values")]
public List<string> Values { get; set; }
[ApiMember(Name = "Type")]
[ApiAllowableValues("Type", typeof(FilterType))]
public FilterType Type { get; set; }
public FilterDto()
{
Values = new List<string>();
}
}
Have anyone successfully managed to import a OpenApi using array of $ref in the parameters from ServiceStack into a Api Management?

JSON.NET - Getting nested values

I have a JSON something like this:
{
"key": "Target",
"value": {
"__type": "Entity:http://schemas.microsoft.com/xrm/2011/Contracts",
"Attributes": [
{
"key": "prioritycode",
"value": {
"__type": "OptionSetValue:http://schemas.microsoft.com/xrm/2011/Contracts",
"Value": 1
}
},
{
"key": "completeinternalreview",
"value": false
},
{
"key": "stepname",
"value": "10-Lead"
},
{
"key": "createdby",
"value": {
"__type": "EntityReference:http://schemas.microsoft.com/xrm/2011/Contracts",
"Id": "ca2ead0c-8786-e511-80f9-3863bb347b18",
"KeyAttributes": [],
"LogicalName": "systemuser",
"Name": null,
"RowVersion": null
}
}
]
}
}
How do the toke for the key/values by searching for the value of the key?
Eg I want to get the key value pair 'completeinternalreview'
Assuming you have a C# class like this to represent that attributes object from your JSON:
public class MyValue
{
[JsonProperty("Attributes")]
public List<KeyValuePair<string, object>> Attributes { get; set; }
}
you can simply deserialize the string:
var result = JsonConvert.DeserializeObject<KeyValuePair<string, MyValue>>(jsonString);
and then find the correct key-value pair with:
var kvp = result.Value.Attributes.Find(a => a.Value == "completeinternalreview");

JSON DeserializeObject error for a string and an object (array)

This is my JSON value
{ "spatialReference":
{ "wkid": 4326, "latestWkid": 4326 },
"candidates":
[
{ "address": "380 New York St, Redlands, California, 92373", "location": { "x": -117.19564110200449, "y": 34.057084093752607 }, "score": 99.890000000000001, "attributes": { } },
{ "address": "380 New York St, Redlands, California, 92373", "location": { "x": -117.19564235064003, "y": 34.057118309276547 }, "score": 99.890000000000001, "attributes": { } },
{ "address": "381 New York St, Redlands, California, 92373", "location": { "x": -117.19570747666533, "y": 34.057117640108572 }, "score": 78.890000000000001, "attributes": { } },
{ "address": "New York St, Redlands, California, 92373", "location": { "x": -117.19564313410432, "y": 34.054959327808675 }, "score": 99.890000000000001, "attributes": { } },
{ "address": "92373, Redlands, California", "location": { "x": -117.18448413080158, "y": 34.042938592774277 }, "score": 100, "attributes": { } },
{ "address": "Redlands, California", "location": { "x": -117.18259971082223, "y": 34.055564407815503 }, "score": 98.780000000000001, "attributes": { } }
]
}
This is code:
public class CanAttributes
{
public string StreetName { get; set; }
public string StreetType { get; set; }
}
public class Candidates
{
[JsonProperty("address")]
public string Address { get; set; }
[JsonProperty("location")]
public GeoLocation Location { get; set; }
[JsonProperty("score")]
public decimal Score { get; set; }
[JsonProperty("attributes")]
public CanAttributes Attributes { get; set; }
}
public class jsCandidates
{
[JsonProperty("spatialReference")]
public string spatialReference { get; set; }
[JsonProperty("candidates")]
public Candidates[] candidates { get; set; }
}
public class GeoLocation
{
[JsonProperty("x")]
public decimal X { get; set; }
[JsonProperty("y")]
public decimal Y { get; set; }
}
jsCandidates canArray = JsonConvert.DeserializeObject<jsCandidates>(str);
It gives me "Error reading string. Unexpected token: StartObject. Path 'spatialReference', line 2, position 23" when I tried to deserialized the above json value.
Any help would be appreciated.
Not string, you should change to object.
public string spatialReference { get; set; }
Or this instead:
public class SpatialReference
{
public int wkid { get; set; }
public int latestWkid { get; set; }
}

Resources