new object with brackets as property name - c#

How could I produce this JSON:
{"{}":""}
From this code:
JsonConvert.SerializeObject(new
{
brackets = ""
})
brackets should be replaced by {}

"{}" is a string, just like any other string, so you can use it as a key like you usually do.
There are two ways to achieve this.
Use a dictionary of string-to-string with custom name:
var dict = new Dictionary<string, string>
{
["{}"] = ""
};
string result = JsonConvert.SerializeObject(dict);
Use a class with custom property name:
public class MyClass
{
[JsonProperty(PropertyName = "{}")]
public string Brackets { get; set; }
}
// Usage:
var obj = new MyClass { Brackets = "" };
string result = JsonConvert.SerializeObject(obj);

Create a class that sets the property name using JsonProperty:
public class Foo
{
[JsonProperty("{}")]
public string Value { get; set; }
}
And deserialise like this:
var json = JsonConvert.SerializeObject(new Foo { Value = "" } );

Related

How can i add a property to object during the a run time at C#?

I have two different lists. I want to combine these list in an object. I don't know the property names in these lists, which is why I cannot create a class in advance.
public class exampleConfigProperty
{
public string PropertName { get; set; };
public string PropertValue { get; set; };
}
public class exampleFile
{
public string config1 { get; set; };
}
List<exampleConfigProperty> myList = new List<exampleConfigProperty>();
myList.add(new exampleConfigProperty {
PropertName = "Config_Property_Name",
PropertValue = "Config Property Value"
});
List<exampleFile> myListTwo = new List<exampleFile>();
myListTwo.add(new exampleFile {
config1 = "Config Value"
});
I tried to figure out if is there any way I can use the code below:
var obj = new object();
foreach(var item in myList)
{
obj.addProperty(item.PropertName, item.PropertValue );
}
foreach(var item in myListTwo)
{
obj.addProperty(nameof(item.config1), item.config1 );
}
In conclusion I try to create an object instance by using two lists,
for example:
var resut = new {
Config_Property_Name = "Config Property Value",
config1 ="Config Value"
}
dynamic type does not work so what should I do to get an object instance by using two lists?
Since you just want to make a JSON I think would fit your criteria:
var test = new Dictionary<string, string>(); //<string, object> for mixed types of values
test["key1"] = "value1";
test["key2"] = "value2";
var result = JsonConvert.SerializeObject(test); //indented for readability of result
// result:
// {
// "key1": "value1",
// "key2": "value2"
// }

how to string.join object array parameters with customize output

I have an object like that
public class MyModel
{
public int Key { get; set; }
public string Value { get; set; }
}
And I have model like List<MyModel>
model[0]=new MyModel(){Key = 1,Value ="Something"};
model[1]=new MyModel(){Key = 3,Value ="Something else"};
I want this output :
1. Value is = Something //there is \n here
3. Value is = Something else
So the seperator is \n and while string.join(" \n ", ? ) what should I do?
Is that possible or not? I did it like that but I want to learn can I string.join() do that:
var newArray = model.Select(x => ((x.Key)+". Value is ="+x.Value));
string.join(" \n ",newArray );
Sorry for my bad english...
var modelList = new List<MyModel>(){
new MyModel(){ Key = 1, Value = "Value 1"},
new MyModel(){ Key = 3, Value = "Value 2 with Key3"}
};
var stringArray = modelList.Select(model=> $"{model.Key}. Value={model.Value}");
var finalString = String.Join('\n', stringArray);
Console.Write(finalString);
https://dotnetfiddle.net/buCe8P
You did well. There are other ways but they are no more correct (in some cases at least).
Example with custom ToString method:
var all = string.Join("\n", model);
public class MyModel
{
public int Key { get; set; }
public string Value { get; set; }
public override string ToString() => $"{Key}. Value Is: {Value}";
}
Or directly with project array:
var all = string.Concat(model.Select(x => $"{x.Key}. Value Is: {x.Value}\n"));
but there's an unnecessary line brake at the end.

Creating an anonymous object who must have the dot in Key name and put it inside another anonymous object

I'm making a JSON body for an elasticsearch query.
I have this dynamic:
var hlBodyText = new
{
bodyText = new { }
};
But there's a case in which the name must be bodyText.exact = new { }, but obviously I'm not allowed to do it and return the error message:
Invalid anonymous type member declarator. Anonymous type members must be declared with a member assignment, simple name or member access.
There's a way to make that value name with the dot char?
EDIT
Furthermore, I have to put this object inside another object, like this:
var fieldsInner = new
{
hlBodyText.bodyText
};
What could be the best way to get this result but with the property name set with the dot?
EDIT #2
I created a class with all my parameters beacause I thought the JsonProperty attribute could help me.
internal class ElasticSearchHighlightsModel
{
[JsonProperty("bodyText")]
public object bodyText { get; set; }
[JsonProperty("title")]
public object title { get; set; }
[JsonProperty("shortDescription")]
public object shortDescription { get; set; }
[JsonProperty("bodyText.exact")]
public object bodyTextExact { get; set; }
[JsonProperty("title.exact")]
public object titleExact { get; set; }
[JsonProperty("shortDescription.exact")]
public object shortDescriptionExact { get; set; }
}
then in my method i have a condition for which I have to use some params or others.
// ...some code...
else
{
var hlBodyText = new ElasticSearchHighlightsModel() { bodyTextExact = new { } };
var hlTitle = new ElasticSearchHighlightsModel() { titleExact = new { } };
var hlShortDescription = new ElasticSearchHighlightsModel() { shortDescriptionExact = new { } };
var fieldsInner = new
{
hlBodyText.bodyTextExact,
hlTitle.titleExact,
hlShortDescription.shortDescriptionExact,
};
var fieldsContainer = new
{
pre_tags = preTags,
post_tags = postTags,
fields = fieldsInner,
};
return fieldsContainer;
}
But the fieldsInner object have the parameter names (bodyTextExact, titleExact etc...), not the JsonProperty attribute ones.
It seems this you are looking for,later u convert dictionary to json
Dictionary<string,object> obj=new Dictionary<string,object>();
obj["bodyText.exact"]=new object{};
Solved using Dictionary, then passed it inside an anonymous type obj:
IDictionary highlitsFieldsContainer = new Dictionary<string, object>();
// ... some code
highlitsFieldsContainer["bodyText.exact"] = new { };
highlitsFieldsContainer["title.exact"] = new { };
var fieldsContainer = new
{
fields = highlitsFieldsContainer,
};
// OUTPUT: fieldsContainer = { fields = { bodyText.exact = {}, title.exact = {} } }
And used a RouteValueDictionary class to read that values when elasticsearch send his response.
RouteValueDictionary _res = new RouteValueDictionary(dynamicResponse.highlights);
if (_res["shortDescription.exact"] != null)
{
// ...
}
You seem to be creating an anonymous type (not "dynamic") and wanting to serialize it with a different name that is not valid in C#. To do that you'll need to use a named type and use the JsonProperty
attribute:
internal class HlBodyText
{
[JsonProperty("bodyText.exact")]
public DateTime bodyText { get; set; }
}
and create an instance of it:
var hlBodyText = new HlBodyText()
{
bodyText = new { }
};

Converting JSON array

I am attempting to use the Newtonsoft JSON library to parse a JSON string dynamically using C#. In the JSON is a named array. I would like to remove the square brackets from this array and then write out the modified JSON.
The JSON now looks like the following. I would like to remove the square bracket from the ProductDescription array.
{
"Product": "123",
"to_Description": [
{
"ProductDescription": "Product 1"
}
]
}
Desired result
{
"Product": "123",
"to_Description":
{
"ProductDescription": "Product 1"
}
}
I believe I can use the code below to parse the JSON. I just need some help with making the modification.
JObject o1 = JObject.Parse(File.ReadAllText(#"output.json"));
The to_Description property starts off as List<Dictionary<string,string>> and you want to take the first element from the List.
So, given 2 classes
public class Source
{
public string Product {get;set;}
public List<Dictionary<string,string>> To_Description{get;set;}
}
public class Destination
{
public string Product {get;set;}
public Dictionary<string,string> To_Description{get;set;}
}
You could do it like this:
var src = JsonConvert.DeserializeObject<Source>(jsonString);
var dest = new Destination
{
Product = src.Product,
To_Description = src.To_Description[0]
};
var newJson = JsonConvert.SerializeObject(dest);
Note: You might want to check there really is just 1 item in the list!
Live example: https://dotnetfiddle.net/vxqumd
You do not need to create classes for this task. You can modify your object like this:
// Load the JSON from a file into a JObject
JObject o1 = JObject.Parse(File.ReadAllText(#"output.json"));
// Get the desired property whose value is to be replaced
var prop = o1.Property("to_Description");
// Replace the property value with the first child JObject of the existing value
prop.Value = prop.Value.Children<JObject>().FirstOrDefault();
// write the changed JSON back to the original file
File.WriteAllText(#"output.json", o1.ToString());
Fiddle: https://dotnetfiddle.net/M83zv3
I have used json2csharp to convert the actual and desired output to classes and manipulated the input json.. this will help in the maintenance in future
First defined the model
public class ToDescription
{
public string ProductDescription { get; set; }
}
public class ActualObject
{
public string Product { get; set; }
public List<ToDescription> to_Description { get; set; }
}
public class ChangedObject
{
public string Product { get; set; }
public ToDescription to_Description { get; set; }
}
Inject the logic
static void Main(string[] args)
{
string json = "{\"Product\": \"123\", \"to_Description\": [ { \"ProductDescription\": \"Product 1\" } ]} ";
ActualObject actualObject = JsonConvert.DeserializeObject<ActualObject>(json);
ChangedObject changedObject = new ChangedObject();
changedObject.Product = actualObject.Product;
changedObject.to_Description = actualObject.to_Description[0];
string formattedjson = JsonConvert.SerializeObject(changedObject);
Console.WriteLine(formattedjson);
}
Why not:
public class EntityDescription
{
public string ProductDescription { get; set; }
}
public class Entity
{
public string Product { get; set; }
}
public class Source : Entity
{
[JsonProperty("to_Description")]
public EntityDescription[] Description { get; set; }
}
public class Target : Entity
{
[JsonProperty("to_Description")]
public EntityDescription Description { get; set; }
}
var raw = File.ReadAllText(#"output.json");
var source = JsonConvert.DeserializeObject<Source>(raw);
var target = new Target { Product = source.Product, Description = source.Description.FirstOrDefault() };
var rawResult = JsonConvert.SerializeObject(target);
Update For dynamic JSON
var jObject = JObject.Parse(File.ReadAllText(#"output.json"));
var newjObject = new JObject();
foreach(var jToken in jObject) {
if(jToken.Value is JArray) {
List<JToken> l = jToken.Value.ToObject<List<JToken>>();
if(l != null && l.Count > 0) {
newjObject.Add(jToken.Key, l.First());
}
} else {
newjObject.Add(jToken.Key, jToken.Value);
}
}
var newTxt = newjObject.ToString();

Get attribute arguments with roslyn

I try to get the named arguments for MyAttribute with Roslyn.
var sourceCode = (#"
public class MyAttribute : Attribute
{
public string Test { get; set; }
}
[MyAttribute(Test = ""Hello"")]
public class MyClass { }
");
var syntaxTree = CSharpSyntaxTree.ParseText(sourceCode);
var mscorlib = MetadataReference.CreateFromFile(typeof(object).Assembly.Location);
var compilation = CSharpCompilation.Create("MyCompilation", new[] { syntaxTree }, new[] { mscorlib });
var semanticModel = compilation.GetSemanticModel(syntaxTree);
var syntaxRoot = syntaxTree.GetRoot();
var classNode = syntaxRoot.DescendantNodes().OfType<ClassDeclarationSyntax>().Skip(1).First();
var classModel = (ITypeSymbol)semanticModel.GetDeclaredSymbol(classNode);
var firstAttribute = classModel.GetAttributes().First();
However firstAttribute.AttributeClass.Kind equals to ErrorType and consequently firstAttribute.NamedArguments contains no elements.
The code isn't an anlyzer or something I have more complete context like a solution.
I can't see roslyn is missing any references or something else. What can I do to fully analyze the attribute?
You need to fully qualify Attribute type name:
var sourceCode = (#"
public class MyAttribute : System.Attribute // < here
{
public string Test { get; set; }
}
[MyAttribute(Test = ""Hello"")]
public class MyClass { }
");
Then it will work as you expect:
var firstNamedArg = firstAttribute.NamedArguments[0];
var key = firstNamedArg.Key; // "Test"
var value = firstNamedArg.Value.Value; // "Hello"
Alternatively, you can add using System; at the top:
var sourceCode = (#"
using System;
public class MyAttribute : Attribute
{
public string Test { get; set; }
}
[MyAttribute(Test = ""Hello"")]
public class MyClass { }
");
Instead of using the Roslyn's SemanticModel you can also simply use the Syntax API to get the atttribute's argument info:
var firstAttribute = classNode.AttributeLists.First().Attributes.First();
var attributeName = firstAttribute.Name.NormalizeWhitespace().ToFullString();
Console.WriteLine(attributeName);
// prints --> "MyAttribute"
var firstArgument = firstAttribute.ArgumentList.Arguments.First();
var argumentFullString = firstArgument.NormalizeWhitespace().ToFullString();
Console.WriteLine(argumentFullString);
// prints --> Test = "Hello"
var argumentName = firstArgument.NameEquals.Name.Identifier.ValueText;
Console.WriteLine(argumentName);
// prints --> Test
var argumentExpression = firstArgument.Expression.NormalizeWhitespace().ToFullString();
Console.WriteLine(argumentExpression);
// prints --> "Hello"
Once you have your xxxDeclaredSymbol you can get all attributes like so
var attributes = methodSymbol.GetAttributes().ToArray();
You can then loop over each AttributeData in the array and use this extension I wrote, which will give you a list of all names + values passed to the attribute's constructor whether they were named or not...
// Used as a 3 value tuple for Name + TypeName + actual value
public class NameTypeAndValue
{
public string Name { get; private set; }
public string TypeFullName { get; private set; }
public object Value { get; private set; }
public NameTypeAndValue(string name, string typeFullName, object value)
{
Name = name;
TypeFullName = typeFullName;
Value = value;
}
}
public static class ITypeSymbolExtensions
{
// Converts names like `string` to `System.String`
public static string GetTypeFullName(this ITypeSymbol typeSymbol) =>
typeSymbol.SpecialType == SpecialType.None
? typeSymbol.ToDisplayString()
: typeSymbol.SpecialType.ToString().Replace("_", ".");
}
public static bool TryGetAttributeAndValues(
this AttributeData attributeData,
string attributeFullName,
SemanticModel model,
out IEnumerable<NameTypeAndValue> attributeValues)
{
var attributeValuesList = new List<NameTypeAndValue>();
var constructorParams = attributeData.AttributeConstructor.Parameters;
// Start with an indexed list of names for mandatory args
var argumentNames = constructorParams.Select(x => x.Name).ToArray();
var allArguments = attributeData.ConstructorArguments
// For unnamed args, we get the name from the array we just made
.Select((info, index) => new KeyValuePair<string, TypedConstant>(argumentNames[index], info))
// Then we use name + value from the named values
.Union(attributeData.NamedArguments.Select(x => new KeyValuePair<string, TypedConstant>(x.Key, x.Value)))
.Distinct();
foreach(var argument in allArguments)
{
attributeValuesList.Add(
new NameTypeAndValue(
name: argument.Key,
typeFullName: argument.Value.Type.GetTypeFullName(),
value: argument.Value.Value));
}
attributeValues = attributeValuesList.ToArray();
return true;
}

Categories