Elasticsearch Nest C# -- ElasticProperty Analyzer causing dynamic mapping - c#

I am using ElasticProperty attributes to define my index type mapping. This works:
[ElasticProperty(Boost = 2)]
public string Title { get; set; }
[ElasticProperty(Index = FieldIndexOption.NotAnalyzed)]
public string ActivityType { get; set; }
I create my index and everything looks good (I'm just copying the affected props):
"properties": {
"activityType": {
"type": "string",
"index": "not_analyzed"
},
"title": {
"type": "string",
"boost": 2
}
}
BUT, when I drop the mapping, change the Analyzer and reindex watch what happens:
[ElasticProperty(Boost = 2, Analyzer = "keyword")]
public string Title { get; set; }
[ElasticProperty(Index = FieldIndexOption.NotAnalyzed)]
public string ActivityType { get; set; }
Result:
"properties": {
"activityType": {
"type": "string"
},
"title": {
"type": "string"
}
}
Can someone explain what's happening here? It seems that adding the Analyzer parameter forces the mapping to be generated dynamically. Why?

Make sure that on your application startup you're calling the following:
private readonly IElasticClient _client;
//initialize _client
_client.Map<YourTypeHere>(m => m.MapFromAttributes());
That code will apply any new mapping that you have.

Related

convert objects model to json in c#?

I have a object model I want to show as a json string, for example:
public class SectionD
{
public string InsertID { get; set; }
public int CaseReference { get; set; }
public string AdditionalInfo { get; set; }
public DateTime CreationDate { get; set; }
}
and I want to present this as a json object, like so:
{
"class": "SectionD",
"parameters": [
{
"key": "InsertID",
"type": "string"
},
{
"key": "CaseReference",
"type": "int"
},
{
"key": "AdditionalInfo",
"type": "string"
},
{
"key": "CreationDate",
"type": "DateTime"
}
]
}
The data is being stored as a json string in a database, and I want to provide a list of fields and types to someone who would be making database views on that data.
google provides a lot of hits for querying the contents on the model, but I can't find anything for looking at the object itself.
Thanks
How about something simple like:
public class ReflectedPropertyInfo
{
[JsonProperty("key")]
public string Key { get; set; }
[JsonProperty("type")]
public string Type { get; set; }
}
public class ReflectJson
{
public static string ReflectIntoJson<T>() where T : class
{
var type = typeof(T);
var className = type.Name;
var props = type.GetProperties(BindingFlags.Instance | BindingFlags.Public);
var propertyList = new List<ReflectedPropertyInfo>();
foreach (var prop in props)
{
propertyList.Add(new ReflectedPropertyInfo{Key =prop.Name, Type =prop.PropertyType.Name});
}
var result = JsonConvert.SerializeObject(new {#class = className, parameters = propertyList}, Formatting.Indented);
return result;
}
}
It uses Reflection, as suggested by #dbc. After getting the type name, it gets a collection of properties and then builds up a anonymous type containing the information in the correct format, and then serializes it. The result looks like:
{
"class": "SectionD",
"parameters": [
{
"key": "InsertID",
"type": "String"
},
{
"key": "CaseReference",
"type": "Int32"
},
{
"key": "AdditionalInfo",
"type": "String"
},
{
"key": "CreationDate",
"type": "DateTime"
}
]
}
The only difference (that I see) is that it uses the actual "Int32" as the type name for integers, rather than the C# alias "int".

Runtime objects from JSONSchema in C#

You can validate an object using a JSON Schema.
You can generate dynamic objects at runtime with dynamic and expanddo
What I would like to do, is generate objects at runtime from JSON Schemas, that can then be populated as necessary.
If this seems weird, the reason is the JSON Schema will define a template to be populated from another source, but the system allows you to create new templates.
Example as requested:
Parent Object
public class Parent
{
public Guid Id { get; set; }
public string Name { get; set; }
public int IntValue { get; set; }
public decimal DecimalValue { get; set; }
public double DoubleValue { get; set; }
public float FloatValue { get; set; }
public DateTime DateTimeValue { get; set; }
[EnumDataType(typeof(EnumData))]
public string EnumValue { get; set; }
public List<Child> children { get; set; }
}
public enum EnumData
{
Alpha,
Beta,
Charlie
}
Child Object
public class Child
{
public Guid ParentId { get; set; }
public string ChildName { get; set; }
public int ChildInt { get; set; }
}
Resulting JSON Schema
{
"type": "object",
"properties": {
"Id": {
"type": "string"
},
"Name": {
"type": [
"string",
"null"
]
},
"IntValue": {
"type": "integer"
},
"DecimalValue": {
"type": "number"
},
"DoubleValue": {
"type": "number"
},
"FloatValue": {
"type": "number"
},
"DateTimeValue": {
"type": "string",
"format": "date-time"
},
"EnumValue": {
"type": [
"string",
"null"
],
"enum": [
"Alpha",
"Beta",
"Charlie"
]
}
},
"required": [
"Id",
"Name",
"IntValue",
"DecimalValue",
"DoubleValue",
"FloatValue",
"DateTimeValue",
"EnumValue"
]
}
The schema is a definition of an object. If this definitions was created by a user choosing what properties they want, they type, acceptable values etc, then a schema could be generated.
If you could then create an instance of an object from this schema, the properties could be populated.
The point is the class won't be known at coding time.
The reason for this is we have a huge generic set of data that we need to create smaller sets from, that the user defines what these sets will be from inside the application. The definition they create can be stored and used again.
You can do this with my new library, JsonSchema.Net.Generation.
var schema = new JsonSchemaBuilder().FromType(myType);
You can read more about it in the docs.
I think #gregsdennis got the library right. If you look at the documentation it can be done.
The NJsonSchema.CodeGeneration can be used to generate C# or TypeScript code from a JSON schema:
var generator = new CSharpGenerator(schema);
var file = generator.GenerateFile();
The file variable now contains the C# code for all the classes defined in the JSON schema.

Deserializing JSON Class with multiple Objects with different types

I am trying to deserialize the following string output to json in csharp.
Now the Problem is, that there are multiple objects that i dont know how to access.
My endgoal would be to access for example just the twitch object.
How would my Jsonclass need to look like?
Thanks in advance.
[
{
"type": "battlenet",
"id": "zzzz#25589",
"name": "zzzz#25589",
"visibility": 1,
"friend_sync": false,
"show_activity": true,
"verified": true
},
{
"type": "steam",
"id": "45356364364564",
"name": "zzzz",
"visibility": 1,
"friend_sync": false,
"show_activity": true,
"verified": true
},
{
"type": "twitch",
"id": "4353454353453",
"name": "zzzzz",
"visibility": 1,
"friend_sync": false,
"show_activity": true,
"verified": true
},
{
"type": "youtube",
"id": "xxxxx-xxxxxx",
"name": "Salt",
"visibility": 1,
"friend_sync": false,
"show_activity": true,
"verified": true
}
]
What you have here is a JSON array of objects. You have to parse it to an array or List :
Your object :
public class SomeObject
{
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("visibility")]
public int Visibility { get; set; }
[JsonProperty("friend_sync")]
public bool FriendSync { get; set; }
[JsonProperty("show_activity")]
public bool ShowActivity { get; set; }
[JsonProperty("verified")]
public bool Verified { get; set; }
}
Parsing :
var resultList = JsonConvert.DeserializeObject<List<SomeObject>>(jsonstring);
Then, just search for the twitch object :
resultList.FirstOrDefault(x=>x.type == "twitch")
Maybe I'm on the wrong path right now,
but since they've got all the same attributes why don't you try implement an Interface/Superclass and use Reflection to get the correct Type according to the value in "type" ?
To get the instance:
public object GetInstance(string typeString)
{
Type t = Type.GetType(typeString);
return Activator.CreateInstance(t);
}

Serialize some relationships to JSON, but not all

I have the following problem: I am trying to serialize an object (object1) to Json using Newtonsoft.Json package. I need to be able to send it to a server. The problem is object1 has several referenced objects, some that should be created together with object1, but one of them is "read only" on the server, so it must be send as a relationship.
I am using string json = JsonConvert.SerializeObject
Example:
<code>
[DataContract]
public class Object1
{
// Simple Properties
[JsonProperty(PropertyName = "ext_ref", Order = 1)]
public string ExtRef { get; set; }
[JsonProperty(PropertyName = "external_comment", Order = 1)]
public string ExternalComment { get; set; }
[JsonProperty(PropertyName = "internal_comment", Order = 1)]
public string InternalComment { get; set; }
[JsonProperty(PropertyName = "object2")]
public Object2 Object2 { get; set; }
[JsonProperty(PropertyName = "object3")]
public Object3 Object3 { get; set; }
}
</code>
This is how I get it atm. This is fine for most of the objects, but not all:
{
"data": {
"attributes": {
"ext_ref": "2573421",
"external_comment": "Ext Comment",
"internal_comment": "Internal comment",
"object2": {
"data": {
"attributes": {
"xx":"XX",
"yy":"YY"
},
"id": "1",
"type": "object2s"
},
"object3": {
"data": {
"attributes": {
"xx":"XX",
"yy":"YY"
},
"id": "1",
"type": "object3s"
}
},
},
"type": "object1"
}
Because the object2 is a "special case", where it can only be understood by the server as a link, it needs to look like this:
{
"data": {
"attributes":{
"ext_ref": "2573421",
"external_comment": "Ext Comment",
"internal_comment": "Internal comment",
"object3": {
"data": {
"attributes": {
"xx":"XX",
"yy":"YY"
},
"id": "1",
"type": "object3s"
}
},
"type": "object1",
"relationships":{
"object2": {
"data": {
"id": "1",
"type": "object2s"
}
}
}
}
Now my question is this: Is there an easy way of doing this?
I have tried the following:
Using the Relationship attribute from JsonApiSerializer
Changing the JsonProperty settings for the object2.id property
Deleting the object2.id
I can't help thinking there must some attribute I can use to get the desired result, but atm. I am stuck
[EDIT]
I added an example object structure
Ok, I found the error. I am using Newtonsoft.Json to create the Json with this call:
string json = JsonConvert.SerializeObject(order, Format.None,
new JsonApiSerializerSettings {
NullValueHandling = NullValueHandling.Ignore
});
The part that caused the problem was the Format.None, which made the Json come out as basic Json, and not the usual format. I changed it to null, and I got the result I wanted. Big woop, wanna fight about it?

c# How do I parse a non array array

I need to parse a jsonfile that has a structure like this:
"number": {
"1": {
"branch": null,
"build": 1,
"files": [
[
"zip",
"client",
"4d96d6e8f1543c5fa1184f4771ce16e2"
],
[
"zip",
"src",
"fd397591148fac49a7d57aafdccac6a3"
],
[
"zip",
"server",
"d7e1df9a91ded33be81ee8226b027c2f"
],
[
"txt",
"changelog",
"df98aec1a868ce99532c64f246387d55"
]
],
"jobver": "1.3.2",
"mcversion": "1.1",
"modified": 1328269373.0,
"version": "1.3.2.01"
},
"2": {
"branch": null,
"build": 2,
"files": [
[
"zip",
"server",
"80fbd5d837a5867c2dd7b7967e3aa2a9"
],
[
"zip",
"client",
"0cedb5e9844e490f877b6cf04601f929"
],
[
"txt",
"changelog",
"87e9fba9322e9dbc2ea482a2c3edeec6"
],
[
"zip",
"src",
"292d5596879bd13c159a2afe571ec5eb"
]
],
"jobver": "1.3.2",
"mcversion": "1.1",
"modified": 1328613907.0,
"version": "1.3.2.2"
}
(The entire json file can be found here: http://files.minecraftforge.net/maven/net/minecraftforge/forge/json)
I have figure out the internals, in the "1" and the externals that leads to this code part, however using the Json.NET library I can't figure out how to deal with the "1" and "2"s without writing a seperate class for each. I have over 1000 of these to parse trough, so I need some way that can do it relatively simple.
My current class for parsing looks something like this:
public class forgemaven
{
public string homepage { get; set; }
public string name { get; set; }
public List<Number> number { get; set; }
public string webpath { get; set; }
}
public class Number
{
public string branch { get; set; }
public int build { get; set; }
public List<String> files { get; set; }
public string jobver { get; set; }
public string mcversion { get; set; }
public string modified { get; set; }
public string version { get; set; }
}
Note: I removed some of the things, like the first 1000 lines of version/build, since they aren't needed and json.net seems fine with that.
I have tried parsing it with http://json2csharp.com/ sadly that crashes my webbrowser. I also tried the desktop version of it, but that give me almost a MB of classes, which again isn't optimal, since new builds are constantly added to this file, so I would have to change my structure all the time, and it would be horrible to use the data from here.
So for my question: How do I do this in a maintainable way?
Your problem is that {"1" : something, "2" ; something} is not a json array, it's a json map.
In .net, you will want to deserialize that to a Dictionary<int,TObject>. Then you can process it afterwards if it really should be a `List' or an array, but you can't do that while deserializing: you got bad json in the first place, you have to deal with it.
Here is a fiddle demonstrating the thing (with the json you gave and your own classes only very slightly modified: the files property is a List<List<string>> instead of a List<String>) using Json.Net : https://dotnetfiddle.net/feqFZd
You must replace
public List<Number> number { get; set; }
with
public Dictionary<int,Number> number { get; set; }

Categories