I want to post the following DTO to a .NET Core API:
{
"Name": "Foo",
"Street": "Bar",
"DynamicInfo": {
"MetadataAsString": "23423",
"MetadataAsInt": 2,
"MetadataAsBool": true,
"SomeOtherValues": "blub"
}
}
The class I want to map this in C# looks like this:
public class Foo
{
public string Name { get; set; }
public string Street { get; set; }
public Dictionary<string, object> DynamicInfo { get; set; }
}
You can see that I am using two static properties (Name and Street), but I also want to post some dynamic data.
I expect the dynamic data to be written in a dictionary, but unfortunately this does not work.
The result I am getting in my debugger is a little confusing:
So the values arrive successful, but are in a strange format... I dont know how to even access the values.
How can I convert this to just a normal dictionary, containing objects?
For a solution that would not depend on your use case, I would use 2 objects. 1 for client input and 1 that has validated input. The client input object would contain a Dictionary<string,string>. And the validated input can contain your Dictionary<string,object> if its still something you intend to use.
If you use this approach. During validation of the client input, you could use bool.TryParse(DynamicInfo["MetadataAsBool"], out YourBoolean). Then simply add the YourBoolean to your new Dictionary<string,object> objectDictionary like objectDictionary.Add("BoolMetadata", YourBoolean)
I found a solution. The resulting object (ValueKind=String: 23423) is nothing else than a JSONElement. I did not understand this before.
This JSONElement has an enum that tells me what datatype I have, so I can use this to map my Dictionary of JSONElements to another dictionary of "real" objects.
var newDic = new Dictionary<string, object>();
foreach (var d in obj.DynamicInfo)
{
object obt;
string key = d.Key;
var a = enterprise.BasicInformation.TryGetValue(key, out obt);
if (obt == null) continue;
var doc = (JsonElement)obt;
string myString = null;
bool? myBool = null;
int? myInteger = null;
double? myFloatNumber = null;
if (doc.ValueKind == JsonValueKind.String)
{
myString = doc.ToString();
}
if (doc.ValueKind == JsonValueKind.True)
{
myBool = true;
}
if (doc.ValueKind == JsonValueKind.False)
{
myBool = false;
}
if (doc.ValueKind == JsonValueKind.Number)
{
double floatNumber;
doc.TryGetDouble(out floatNumber);
if ((floatNumber % 1) == 0)
{
myInteger = (int)floatNumber;
}
else
{
myFloatNumber = floatNumber;
}
}
if (myString != null)
{
newDic.Add(key, myString);
}
if (myBool != null)
{
newDic.Add(key, myBool);
}
if (myInteger != null)
{
newDic.Add(key, myInteger);
}
if (myFloatNumber != null)
{
newDic.Add(key, myFloatNumber);
}
}
The code might not be perfect - I will try to optimize it. But it does what it should.
Related
I have List of class as :-
public class Requirement
{
public string Id { get; set; }
public string desc { get; set; }
}
List lstRequirement
I have 3 records in this list for Id and desc.
I wanted to check if any of item is not remaining null.
For that I used below :-
bool IsHavingValidTags = lstRequirement.All(_=> _.Id!=null && _.desc!=null);
This condition is working fine with above Linq.
But I wanted to make it as Generic.
Eg. In future there may get added 5 more properties in Requirement class.
After addition of properties I also have to make changes in Linq.
How can I make this Linq condition generic for all properties?
I want to check any of the property is not remaining null in List.
Please help..!!!
I tried With =>
bool IsHavingValidTags = lstRequirement.All(_ => _ != null);
But not giving desired result.
EDIT 1 :
You can write an extension method that uses reflection like the following:
public static class Extensions
{
public static bool AreAllPropertiesNotNullForAllItems<T>(this IEnumerable<T> items)
{
var properties = typeof(T).GetProperties();
return items.All(x => properties.All(p => p.GetValue(x) != null));
}
}
then use like this:
bool IsHavingValidTags = lstRequirement.AreAllPropertiesNotNullForAllItems();
EDIT:
PropertyInfo.GetValue(object obj) method overload was introduced in .NET Framework 4.5. If you are using .NET Framework 4.0 you need to call p.GetValue(x, null)
Instead of this you should make those field not null. this will never allow those field inserted null. keep validations. like bellow.
[Required(ErrorMessage = "First name is required")]
public string first_name { get; set; }
[Required(ErrorMessage = "Last name is required")]
public string last_name { get; set; }
You can use foreach loop to loop through all the object in the list. Then use reflection to get all the properties in each item in the list, then you can loop through those properties to perform your null check.
Foreach (var x in lstRequirement){
List prop = x.GetType().GetProperties();
Foreach (var y in prop){
If (y == null){
IsHavingValidTag = true;
//Then you can return you method here or throw an Exception
}
}
Hope this helps.
You should add an static method to check the Properties of the Class. I will show you the following example.
Instead of your code :
bool IsHavingValidTags = lstRequirement.All(_ => _ != null);
use the following codes:
bool flg = list.All(m => CheckProperties(m));
public static bool CheckProperties<T>(T source)
{
bool rtnFlg = true;
Type t = typeof(T);
var properties = t.GetProperties();
foreach (var prop in properties)
{
var value = prop.GetValue(source, null);
if (value == null)
{
return false;
}
}
return rtnFlg;
}
I have two lists of object
[Serializable]
private class MemorySet
{
public Dictionary<string, object> _Map;
public List<object> _Results;
public List<object> _Storage;
}
MemorySet Memory = new MemorySet();
I can have keys assigned for an object, for example
_Map.Add("someKey", _Results[_Results.Count - 1]);
I have a method
private object Mapper(string key)
{
if (Memory._Map.ContainsKey(key))
{
return Memory._Map[key];
}
else if (key.ToLower() == "result")
{
return Memory._Results[Memory._Results.Count - 1];
}
else if (key.ToLower() == "storage")
{
return Memory._Storage[Memory._Storage.Count - 1];
}
else if (key.ToLower().Contains("result"))
{
int n = Convert.ToInt32(key.ToLower().Split(new string[] { "result" }, StringSplitOptions.None)[1]);
return Memory._Results[n];
}
else if (key.ToLower().Contains("storage"))
{
int n = Convert.ToInt32(key.ToLower().Split(new string[] { "storage" }, StringSplitOptions.None)[1]);
return Memory._Storage[n];
}
else return null;
}
Now I must assign to an object from _Storage or _Results like that:
object obj = key != "" ? Mapper(key) : Memory._Storage[Memory._Storage.Count - 1];
if(obj is string) obj as string = "test";
this will change obj to reference some new string in memory. But I want to change the object that obj references to instead.
In other words obj will become "test", but the underlying object won't be changed.
I understand why that happends, though I didn't imagine it that way when writing the whole engine, and now I have big trouble with that one. In C++ we have pointers, but in C# I don't want to use GCHandles or unmanaged code for that trivial stuff, would be extremely ugly.
So, how to assign to the object that object points to, instead assigning to the object itself?
Try this
[Serializable]
private class MemorySet
{
public Dictionary<string, object> _Map = new Dictionary<string,object>();
public List<object> _Results = new List<object>();
public List<object> _Storage = new List<object>)_;
}
If you don't want to mess with your current design, you could just add a method that would update your data structures on the same template as your Mapper method. This is what it would look like:
private void Update(string key, object value)
{
if (Memory._Map.ContainsKey(key))
{
Memory._Map[key] = value;
}
else if (key.ToLower() == "result")
{
Memory._Results[Memory._Results.Count - 1] = value;
}
else if (key.ToLower() == "storage")
{
Memory._Storage[Memory._Storage.Count - 1] = value;
}
else if (key.ToLower().Contains("result"))
{
int n = Convert.ToInt32(key.ToLower().Split(new string[] { "result" }, StringSplitOptions.None)[1]);
Memory._Results[n] = value;
}
else if (key.ToLower().Contains("storage"))
{
int n = Convert.ToInt32(key.ToLower().Split(new string[] { "storage" }, StringSplitOptions.None)[1]);
Memory._Storage[n] = value;
}
else
{
throw new ArgumentException("Failed to compute valid mapping", nameof(key));
}
}
Maybe you could also add the key == "" pattern in there, I'm not sure to understand how this would be used exactly, but hopefully you get the idea.
EDIT: OK, so references to the same object are used in different structures. You should consider to design a MemorySet that avoids this. If you still think this is the proper design considering your needs, you have a simple solution: wrap your target objects in other objects.
public class ObjectWrapper
{
public object ObjectOfInterest { get; set; }
}
Now you store ObjectWrapper objects. Then you can update the property ObjectOfInterest and this change will be reflected to all structures that contain this ObjectWrapper:
ObjectWrapper wrapper = Mapper(key);
wrapper.ObjectOfInterest = "test";
problably I'm not experienced enought and my question is kind of dumb:
For learning purposes I'm trying to connect to a REST-Service, which delivers JSON-Data.
From what I've learned, the purpose of JSON is to deliver the same data to any possible client without having a State of itself.
My code is looking like this:
public static void DoSomething()
{
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("SomeUrl"));
// Add an Accept header for JSON format.
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
// List data response.
HttpResponseMessage response = client.GetAsync("").Result;
if (response.IsSuccessStatusCode)
{
Task<Stream> readTask = response.Content.ReadAsStreamAsync();
readTask.ContinueWith(task =>
{
DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(RootObject));
using (Stream result = task.Result)
{
result.Position = 0;
RootObject obj = (RootObject)ser.ReadObject(result);
}
});
}
else
{
Console.WriteLine("{0} ({1})", (int)response.StatusCode, response.ReasonPhrase);
}
}
public class Sum
{
public int id { get; set; }
public string name { get; set; }
public int profileIconId { get; set; }
public int summonerLevel { get; set; }
public long revisionDate { get; set; }
}
public class RootObject
{
public Sum khalgor { get; set; }
}
But here's my Problem: I've created this classes "Sum" and "RootObject" by using the Website http://json2csharp.com/, the JSON-String is looking like this:
{"khalgor":{"id":23801741,"name":"Khalgor","profileIconId":7,"summonerLevel":30,"revisionDate":1396876104000}}
The Problem: The Name "Khalgor" seems to be used as a Root-Object, but it's a Name. So if I'd like to user for another Name, I'd have to user another RootObject.
It does not make that much sense to create such a Structure, so my question: What's the best practice here? Do I map this RootObject/Property to another object manually? Do I use some Reflection to dynamically create an Property or rename it?
As usual, thanks a lot for all Responses
Matthias
Edit:
I tinkered arround a bit and that's my first idea of a solution:
public static class LOLObjectFactory
{
public static ILOLObject Create(string jsonString)
{
JavaScriptSerializer jss = new JavaScriptSerializer();
Dictionary<String, object> entry = (jss.Deserialize<dynamic>(jsonString) as Dictionary<string, object>).First().Value as Dictionary<String, object>;
Type selectedType = null;
List<string> fieldNames = entry.Select(f => f.Key).OrderBy(f => f).ToList();
Type[] types = typeof(ILOLObject).Assembly.GetTypes();
foreach(var type in types)
{
List<string> typeProperties = type.GetProperties().Select(f => f.Name).OrderBy(f => f).ToList();
if (fieldNames.SequenceEqual(typeProperties) && typeof(ILOLObject).IsAssignableFrom(type))
{
selectedType = type;
break;
}
}
ILOLObject result = System.Activator.CreateInstance(selectedType) as ILOLObject;
foreach(var prop in result.GetType().GetProperties())
{
prop.SetValue(result, entry.First(f => f.Key == prop.Name).Value);
}
return result;
}
}
So all the objects I have have the ILOLObject implemented. I'm sure it's not working for everything, but I guess that would be a good approach?
Edit2: Just by looking at it I see I'll have a lot of work to do, but I think the idea behind it is quite clear.
I think your best bet for json "fragments" is to deserialize into a dynamic object:
dynamic stuff = JsonConvert.DeserializeObject(inputData);
Then you can deserialize parts that make sense into proper .NET objects.
SomeObject o = JsonConvert.DeserializeObject<SomeObject>(stuff["someProperty"].ToString());
If you want to ignore the root altogether (e.g. it changes its name everytime) use Json.NET to parse it into an object and ignore the topmost element. Example:
JObject obj = JObject.Parse(json);
if (obj != null)
{
var root = obj.First;
if (root != null)
{
var sumJson = root.First;
if (sumJson != null)
{
var sum = sumJson.ToObject<Sum>();
}
}
}
this is my first question in stackoverflow and I am a beginner in using reflection.
I would like to dump all values of an object instance for reference (to keep track about used values on a test). I am using Compact Framework 3.5 not the full framework. Keep that in mind for your suggestions.
Imagine following classes:
public class Camera : IDisposable
{
public Camera.FilenameProperties SnapshotFile;
public double DigitalZoomFactor { get; set; }
public bool DisplayHistogram { get; set; }
public int ImageUpdateInterval { get; set; }
public Camera.ImprintCaptionPosType ImprintCaptionPos { get; set; }
public string ImprintCaptionString { get; set; }
}
where the 'special' types are:
public class FilenameProperties
{
public string Directory { get; set; }
public string Filename { get; set; }
public Camera.FilenamePaddingType FilenamePadding { get; set; }
public Camera.ImageType ImageFormatType { get; set; }
public Camera.ImageResolutionType ImageResolution { get; set; }
public int JPGQuality { get; set; }
public void Restore();
public void Save();
public enum Fnametype
{
tSnapshot = 0,
tCircularCapture = 1,
}
}
public enum ImprintCaptionPosType
{
Disabled = 0,
LowerRight = 1,
LowerLeft = 2,
LowerCenter = 3,
UpperRight = 4,
UpperLeft = 5,
UpperCenter = 6,
Center = 7,
}
Now, I can get the 'base' names and properties and the field names of an instance of camera:
Camera cam = new Camera();
dumpProperties(cam);
...
void dumpProperties(object oClass)
{
System.Diagnostics.Debug.WriteLine(oClass.ToString());
FieldInfo[] _Info = oClass.GetType().GetFields(BindingFlags.Public | BindingFlags.Instance);
for(int i = 0; i<_Info.Length; i++)
{
System.Diagnostics.Debug.WriteLine(_Info[i].Name + ":'" + _Info[i].GetValue(oClass).ToString()+"'");
}
foreach (PropertyInfo pi in oClass.GetType().GetProperties())
{
System.Diagnostics.Debug.WriteLine(pi.Name + ":'" + pi.GetValue(oClass, null)
+ "' Type=" + pi.PropertyType.ToString());
}
}
and then get soemthing like this:
Intermec.Multimedia.Camera
SnapshotFile:'Intermec.Multimedia.Camera+FilenameProperties'
DigitalZoomFactor:'1' Type=System.Double
DisplayHistogram:'False' Type=System.Boolean
ImageUpdateInterval:'1' Type=System.Int32
ImprintCaptionPos:'Disabled' Type=Intermec.Multimedia.Camera+ImprintCaptionPosType
ImprintCaptionString:'' Type=System.String
Now, for simple properties like DigitalZoomFactor and ImageUpdateInterval I get what I need, but for the nested class (correct wording?) I only get the type as for example with SnapshotFile. For the nested enum I get the value as with 'ImprintCaptionPos'.
How can I get the values of the nested values like FilenameProperties.Filename of the SnapshotFile field/property?
If I use dumpProperties(cam.SnapshotFile), I get the output I am looking for:
Intermec.Multimedia.Camera+FilenameProperties
Directory:'\Program Files\FrmCamera' Type=System.String
Filename:'myphoto' Type=System.String
ImageFormatType:'JPG' Type=Intermec.Multimedia.Camera+ImageType
FilenamePadding:'None' Type=Intermec.Multimedia.Camera+FilenamePaddingType
ImageResolution:'Medium' Type=Intermec.Multimedia.Camera+ImageResolutionType
JPGQuality:'100' Type=System.Int32
But how can I automate that?
I did a lot of search and test coding but was unable to find a solution. The problem seems to be getting the instance of the field to be able to iterate thru it.
I do not have the source code of the Camera class, so I cannot add or remove code in there.
Can anyone help?
I need to get something like the debugger shows:
You simply need to use recursion, and loop back into the method if your property is a class. Here's an example of an XML Serialization routine we use, that effectively walks the properties of a target using reflection, and generates an XElement from it. Your logic would be somewhat different as you're not going to build up XML, but the structure of what you're going to do will be pretty similar.
public XElement Serialize(object source,
string objectName,
bool includeNonPublicProperties)
{
XElement element;
var flags = BindingFlags.Instance | BindingFlags.Public;
if(includeNonPublicProperties)
{
flags |= BindingFlags.NonPublic;
}
var props = source.GetType().GetProperties(flags);
var type = source.GetType();
string nodeName;
if(objectName == null)
{
if (type.IsGenericType)
{
nodeName = type.Name.CropAtLast('`');
}
else
{
nodeName = type.Name;
}
}
else
{
nodeName = objectName;
}
element = new XElement(nodeName);
foreach (var prop in props)
{
string name = prop.Name;
string value = null;
bool valIsElement = false;
if (!prop.CanRead) continue;
if(prop.PropertyType.IsEnum)
{
value = prop.GetValue(source, null).ToString();
}
else
{
string typeName;
if (prop.PropertyType.IsNullable())
{
typeName = prop.PropertyType.GetGenericArguments()[0].Name;
}
else
{
typeName = prop.PropertyType.Name;
}
switch (typeName)
{
case "String":
case "Boolean":
case "Byte":
case "TimeSpan":
case "Single":
case "Double":
case "Int16":
case "UInt16":
case "Int32":
case "UInt32":
case "Int64":
case "UInt64":
value = (prop.GetValue(source, null) ?? string.Empty).ToString();
break;
case "DateTime":
try
{
var tempDT = Convert.ToDateTime(prop.GetValue(source, null));
if (tempDT == DateTime.MinValue) continue;
value = tempDT.ToString("MM/dd/yyyy HH:mm:ss.fffffff");
}
catch(Exception ex)
{
continue;
}
break;
default:
var o = prop.GetValue(source, null);
XElement child;
if (o == null)
{
child = new XElement(prop.Name);
}
else
{
child = Serialize(o, prop.Name, includeNonPublicProperties);
}
element.Add(child);
valIsElement = true;
break;
}
}
if (!valIsElement)
{
element.AddAttribute(name, value);
}
}
return element;
}
OK, I find a way (a workaround) to get all properties (in an XML but who cares) using the code from here:
The output is xml like but acceptable for me. Here an excerpt:
<xml version="1.0" encoding="utf-8">
<Camera xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
...
<ImprintCaptionPos>Disabled</ImprintCaptionPos>
<SnapshotFile>
<Directory>\\Program Files\\FrmCamera</Directory>
<Filename>myphoto</Filename>
<ImageFormatType>JPG</ImageFormatType>
<FilenamePadding>None</FilenamePadding>
<ImageResolution>Medium</ImageResolution>
<JPGQuality>100</JPGQuality>
</SnapshotFile>
...
In my code I just have to call
string s = serialization.mySerialize.SerializeObject<Intermec.Multimedia.Camera>(cam);
To get a 'dump' of all current properties of the instance.
Thanks to all for your help. Possibly I was misunderstood with my question and reflection is unable to give what I want.
Thanks
Josef
You have to do the iteration to all inner object members like you did for outer class. Will be an exercise for you to implement it for complete set of .NET types. Below is the pseudo code of simple implementation
void dumpProperties(object target)
{
if (target.GetType().IsSimple() || target.GetType().IsMethodImplemented("ToString"))
System.Diagnostics.Debug.WriteLine(target.ToString());
else if (target is IEnumerable)
{
foreach (object item in (IEnumerable)target)
{
System.Diagnostics.Debug.WriteLine(dumpProperties(target));
}
}
else
{
foreach (FieldInfo fieldInfo in target.GetType().GetFields(BindingFlags.Public | BindingFlags.Instance))
{
System.Diagnostics.Debug.WriteLine(dumpProperties(fieldInfo.FieldHandle.Value));
}
foreach (PropertyInfo propertyInfo in oClass.GetType().GetProperties())
{
System.Diagnostics.Debug.WriteLine(dumpProperties(propertyInfo.GetGetMethod().MethodHandle.Value));
}
}
}
Or you can use Cinchoo framework, which has built in function to dump any object.
Console.WriteLine(ChoObject.ToString(camera));
Here is my class:
public class Command
{
[XmlArray(IsNullable = true)]
public List<Parameter> To { get; set; }
}
When I serialize an object of this class:
var s = new XmlSerializer(typeof(Command));
s.Serialize(Console.Out, new Command());
it prints as expected (xml header and default MS namespaces are omitted):
<Command><To xsi:nil="true" /></Command>
When I took this xml and tried to deserialize it I got stucked, because it always print "Not null":
var t = s.Deserialize(...);
if (t.To == null)
Console.WriteLine("Null");
else
Console.WriteLine("Not null");
How to force deserializer to make my list null, if it is null in xml?
If you use an array instead of a list it works as expected
public class Command
{
[XmlArray(IsNullable = true)]
public Parameter[] To { get; set; }
}
Ugh, annoying isn't it. You can see it being doing by running sgen.exe on your assembly with the /keep and /debug options so you can debug the deserialization code. It looks roughly like this:
global::Command o;
o = new global::Command();
if ((object)(o.#To) == null) o.#To = new global::System.Collections.Generic.List<global::Parameter>();
global::System.Collections.Generic.List<global::Parameter> a_0 = (global::System.Collections.Generic.List<global::Parameter>)o.#To;
// code elided
//...
while (Reader.NodeType != System.Xml.XmlNodeType.EndElement && Reader.NodeType != System.Xml.XmlNodeType.None) {
if (Reader.NodeType == System.Xml.XmlNodeType.Element) {
if (((object)Reader.LocalName == (object)id4_To && (object)Reader.NamespaceURI == (object)id2_Item)) {
if (!ReadNull()) {
if ((object)(o.#To) == null) o.#To = new global::System.Collections.Generic.List<global::Parameter>();
global::System.Collections.Generic.List<global::Parameter> a_0_0 = (global::System.Collections.Generic.List<global::Parameter>)o.#To;
// code elided
//...
}
else {
// Problem here:
if ((object)(o.#To) == null) o.#To = new global::System.Collections.Generic.List<global::Parameter>();
global::System.Collections.Generic.List<global::Parameter> a_0_0 = (global::System.Collections.Generic.List<global::Parameter>)o.#To;
}
}
}
Reader.MoveToContent();
CheckReaderCount(ref whileIterations1, ref readerCount1);
}
ReadEndElement();
return o;
No less than 3 places where it makes sure the #To property isn't null. The first one is somewhat defensible, hard to deserialize data when the structure doesn't exist. The second one does the null test again, that's the only real good one. The third one is the problem, ReadNull() returned true but it still creates a non-null property value.
If you want to differentiate between empty and null then you have no good solution but edit this code by hand. Do this only if you are really desperate and the class is 100% stable. Well, don't do it. João's solution is the only good one.
I agree with #Oliver's comment, but you can solve it like this if you absolutely need it to return null. Instead of using an automatic property, create your own backing field.
List<Parameter> _to;
public List<Parameter> To
{
get
{
if (_to != null && _to.Count == 0) return null;
return _to;
}
set { _to = value; }
}
If you really need that a collection is deserialized to null when no values are provided you can do it by not providing a set accessor, like this:
public class Command
{
private List<Parameter> to;
public List<Parameter> To { get { return this.to; } }
}
For those who need it you can define the type as array with original element name and then wrap it, this will get you nullable list.
[XmlArray(ElementName = nameof(Metadata), IsNullable = true)]
public string[] MetadataArray { get; set; }
[XmlIgnore]
public List<string> Metadata
{
get => this.MetadataArray?.ToList();
set => this.MetadataArray = value?.ToArray();
}