Newtonsoft.Json Serializer strange behaviour with dynamic and decimals - c#

I'm trying to cast dynamic structure which contains a decimal to a concrete class. I haven't been able to find a reasonable solution to that so I'm using "hacky" way by serializing the dynamic structure to JSON and then by deserializing it back to a concrete class. My first question is - Is there a better way to do that?
Actually I've noticed something really strange for me. After doing what I just explained I was trying to get string values out of those decimal values - a.ToString(CultureInfo.InvariantCulture);
To my surprise those strings were different! One was 10 and another 10.0. Can you explain why this happens? During debugging the valus both seem to be the same...
This is my code so you can easily check this:
using System.Globalization;
using Newtonsoft.Json;
using NUnit.Framework;
namespace SimpleFx.UnitTests.UnitTest
{
public class DecimalStruct
{
public DecimalStruct(decimal a)
{
A = a;
}
public decimal A { get; set; }
}
public class DynamicDecimalTest
{
/// <summary>
/// "Hacky" way of casting dynamic object to a concrete class
/// </summary>
public static T Convert<T>(dynamic obj) where T : class
{
var serialized = JsonConvert.SerializeObject(obj);
return JsonConvert.DeserializeObject<T>(serialized);
}
[Test]
public void CastTest()
{
decimal a = 10;
dynamic s1 = new DecimalStruct(a);
var s2 = Convert<DecimalStruct>(s1);
Assert.AreEqual(a, s1.A);
Assert.AreEqual(a, s2.A);
Assert.AreEqual(a.ToString(CultureInfo.InvariantCulture), s1.A.ToString(CultureInfo.InvariantCulture));
Assert.AreEqual(a.ToString(CultureInfo.InvariantCulture), s2.A.ToString(CultureInfo.InvariantCulture)); // this fails because "10.0" is not equal "10"
}
}
}

Please consider the following example to convert dynamic to concrete
var typeName = "YourNamespace.ExampleObj";
object obj = new
{
A = 5,
B = "xx"
};
var props = TypeDescriptor.GetProperties(obj);
Type type = Type.GetType(typeName);
ExampleObj instance = (ExampleObj)Activator.CreateInstance(type);
instance.A = (int)props["A"].GetValue(obj);
instance.B = (string)props["B"].GetValue(obj);
//serialize the instance now...

Related

Json array to C# class

I’ve got a very simple scenario.
I have an api response that simply returns an array of strings.
[‘test’,’test2’,’test3’]
I need to deserialise into an object to integrate with some current code.
I’ve tried using a straight class with a single property of type List but no dice.
How to deserialise into single object?
If you are using Visual Studio, you can try to use the Paste special - Paste JSON as classes under the Edit menu. Otherwise you can use this simple tool https://json2csharp.com/.
For deserialize the json string, you can use this two extension method:
using System.Runtime.Serialization.Json;
public static T DeserializeFromJsonString<T>(this string data)
{
using (MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(data)))
return stream.DeserializeFromJsonStream<T>();
}
public static T DeserializeFromJsonStream<T>(this Stream stream)
{
T result = (T)new DataContractJsonSerializer(typeof(T)).ReadObject(stream);
return result;
}
if you need deserialise the api outPut into single object:
class _object
{
public List<string> value { get; set; }
public _object(List<string> val)=>
value = val;
}
string[] apiOutput = { "test", "test2", "test3" };
_object myobject = new _object(apiOutput.ToList());
If you want to convert the array into a list of objects:
class _object
{
public string value { get; set; }
public _object(string val)=>
value = val;
}
string[] apiOutput = {"test", "test2", "test3"};
List<_object> listObjest = apiOutput.Select(x => new _object(x)).ToList();
listObjest.ForEach(x=>Console.WriteLine(x.value));

RedisSessionStateProvider with ProtoBuf serialization causing errors

I am trying to get protobuf serialization working with the RedisSessionStateProvider. I have specified the redisSerializerType as a custom class which implements Microsoft.Web.Redis.ISerializer - here is the deserialization code:
public object Deserialize(byte[] data)
{
return DeserializeDirect(data);
}
private object DeserializeDirect(byte[] data)
{
using (var memoryStream = new MemoryStream(data))
{
return Serializer.Deserialize<object>(memoryStream);
}
return null;
}
As I need to implement Microsoft.Web.Redis.ISerializer the signature for deserialize uses a return type of object and there is no way to pass in the actual type being returned. So when DeserializeDirect tries to use the Protobuf.Serializer to deserialize it (as expected) says "Type is not expected, and no contract can be inferred: System.Object". I am using a web app with .NET framework 4.6.1 and I was hoping somebody could point out what I am doing wrong.
Thanks!
Normally, protobuf-net really wants to know the exact type. You can, however, cheat using DynamicType. This tells protobuf-net to include additional type metadata - something it doesn't usually include.
Note that this can make you code brittle - it may fail if the type changes in you code!
I will be implementing Any soon (as part of 2.3.0), which is another option here.
public static void Main()
{
// the actual object we care about
object obj = new Foo { X = 1 };
// serialize and deserialize via stub
var stub = new Stub { Data = obj };
var clone = Serializer.DeepClone(stub);
// prove it worked
Console.WriteLine(clone.Data);
// prove it is a different instance
Console.WriteLine(ReferenceEquals(obj, clone.Data));
}
[ProtoContract]
public class Foo
{
[ProtoMember(1)]
public int X { get; set; }
public override string ToString() => $"X={X}";
}
[ProtoContract]
public sealed class Stub
{
[ProtoMember(1, DynamicType = true)]
public object Data { get; set; }
}

Is there any way to create in foreach loop?

Here is my code:
var json = File.ReadAllText(#"C:\sira.json");
dynamic x = JsonConvert.DeserializeObject<dynamic>(json);
Arac.adli_tip = x.adli_tip;
Arac.aile_hukuku = x.aile_hukuku;
Arac.avrupa_birligi_hukuku = x.avrupa_birligi_hukuku;
Arac.bankacilik_hukuku = x.bankacilik_hukuku;
Arac.bilisim_hukuku = x.bilisim_hukuku;
Arac.borclar_hukuku = x.borclar_hukuku;
Arac.cevre_hukuku = x.cevre_hukuku;
Arac.deniz_ticareti_hukuku = x.deniz_ticareti_hukuku;
Arac.devletler_ozel_hukuku = x.devletler_ozel_hukuku;
Arac.esya_hukuk = x.esya_hukuk;
.
.
.
sira.json is a configuration file about my winforms app.
Here is content of sira.json file:
{
"adli_tip": 15,
"aile_hukuku": 43,
"avrupa_birligi_hukuku": 22,
"bankacilik_hukuku": 10,
.
.
.
"vergi_hukuku": 3
}
I want to get some values from file and set static variables. But these config variables nearly 60.
Is there any way to set static variables programmatically, for example with forecach or while?
EDIT: #subi_speedrunner comment and #T.J.Crowder reply, I searched about Reflection and I coded like this:
But it gives an error. I did not understand why?
Assuming Arac property names match exactly to json property names and Arac properties are public static properties, the following code will work:
using Newtonsoft.Json.Linq;
using System;
namespace ConsoleApplication1
{
public static class Arac
{
public static int adli_tip { get; set; }
public static int aile_hukuku { get; set; }
public static int avrupa_birligi_hukuku { get; set; }
public static int bankacilik_hukuku { get; set; }
public static string string_value {get; set;}
public static DateTime date_value { get; set; }
}
class Program
{
static void Main(string[] args)
{
var json = #"
{
""adli_tip"": 15,
""aile_hukuku"": 43,
""avrupa_birligi_hukuku"": 22,
""bankacilik_hukuku"": 10,
""string_value"": ""some value"",
""date_value"": ""2016-01-24 11:18:00""
}";
JObject arac = JObject.Parse(json);
foreach (var prop in typeof(Arac).GetProperties(System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public))
{
var token = arac.GetValue(prop.Name);
if (token != null)
{
object value = token.ToObject(prop.PropertyType);
prop.SetValue(null, value, null);
}
}
Console.WriteLine("adli_tip {0}", Arac.adli_tip);
Console.WriteLine("aile_hukuku {0}", Arac.aile_hukuku);
Console.WriteLine("avrupa_birligi_hukuku {0}", Arac.avrupa_birligi_hukuku);
Console.WriteLine("bankacilik_hukuku {0}", Arac.bankacilik_hukuku);
Console.WriteLine("string_value {0}", Arac.string_value);
Console.WriteLine("date_value {0}", Arac.date_value);
}
}
}
Note that I use JObject directly instead of JsonConvert.DeserializeObject, this is because JsonConvert.DeserializeObject<dynamic> actually returns a JObject, and I prefer all features of JObject than working with a generic dynamic object.
The code works with integer properties as well as other type of properties as you can see on the sample code.
The following is the relevant code:
JObject arac = JObject.Parse(json);
foreach (var prop in typeof(Arac).GetProperties(BindingFlags.Static | BindingFlags.Public))
{
var token = arac.GetValue(prop.Name);
if (token != null)
{
object value = token.ToObject(prop.PropertyType);
prop.SetValue(null, value, null);
}
}
Yes, you can use reflection, defined in the System.Reflection namespace. Rough sketch:
Get the Type objects for Arac and x
Have an array of the field names you want to process, or use Type object for Arac's GetProperties and/or GetFields methods to get an array of all of its properties/fields (you can specify various features, like whether you only want public ones, etc.)
Loop through the array or the list and for each field:
If you don't already have a FieldInfo/PropertyInfo object from Arac's Type object, use Type#GetField or Type#GetProperty (or one of their relatives) to get it
Get the FieldInfo/PropertyInfo for x's Type object for the same field/property
Use the GetValue method(s) of the FieldInfo/PropertyInfo you got from x's type object to read the value, and the SetValue method(s) of the other FieldInfo/PropertyInfo object to write the value to Arac
Not necessarily saying it's a good idea, since as soon as you put those field names into strings, you make it harder to refactor them with tools, etc., but if the question is "Can I do this?" the answer is "Yes" (and sometimes it's a reasonable choice, there are just trade-offs).

ProtoBuf DeepClone Returns Empty Object When Not Using Surrogate

I'm using protobuf-net v2 and have a class that inherits "List" that I wan't to serialize/clone.
when I'm calling "DeepClone" (or deserialize) I'm getting the cloned object empty.
I can serialize the object into file and it seems to be serialized as expected but the RuntimeTypeModel can't deserialized it back from the byte[].
the single solution I've found to overcome this issue is to use surrogate.
as said, if you're skipping the "SetSurrogate" the clone is failed.
is there any other option to solve it?
attached:
class Program
{
static void Main(string[] args)
{
RuntimeTypeModel model = RuntimeTypeModel.Create();
model[typeof(Custom<string>)].SetSurrogate(typeof(Surrogate<string>));
var original = new Custom<string> { "C#" };
var clone = (Custom<string>)model.DeepClone(original);
Debug.Assert(clone.Count == original.Count);
}
}
[ProtoContract(IgnoreListHandling = true)]
public class Custom<T> : List<T> { }
[ProtoContract]
class Surrogate<T>
{
public static implicit operator Custom<T>(Surrogate<T> surrogate)
{
Custom<T> original = new Custom<T>();
original.AddRange(surrogate.Pieces);
return original;
}
public static implicit operator Surrogate<T>(Custom<T> original)
{
return original == null ? null : new Surrogate<T> { Pieces = original };
}
[ProtoMember(1)]
internal List<T> Pieces { get; set; }
}
Another thing I've found is when you're replacing the ProtoContract attribute from the class "Custom" with "System.Serializable" attribute, it deserializing the byte[] as expected even without surrogate.
The problem here is simply the fact that you explicitly turned off the list-handling, via:
[ProtoContract(IgnoreListHandling = true)]
public class Custom<T> : List<T> { }
Which, as the name suggests and the documentation verifies:
/// <summary>
/// If specified, do NOT treat this type as a list, even if it looks like one.
/// </summary>
public bool IgnoreListHandling {...}
So: there was nothing useful left to do, as Custom<T> doesn't have any other data-members to serialize.
So: if you aren't using the surrogate, don't disable list-handling. The main purpose of this option is for edge-cases where something that is intended to be an "object" also has features that make it look temptingly like a list (all protobuf-net needs is IEnumerable[<T>] and a handy Add(T) method).
[TestFixture]
public class SO11034791
{
[Test]
public void Execute()
{
RuntimeTypeModel model = RuntimeTypeModel.Create();
var original = new Custom<string> { "C#" };
var clone = (Custom<string>)model.DeepClone(original);
Assert.AreEqual(1, clone.Count);
Assert.AreEqual("C#", clone.Single());
}
public class Custom<T> : List<T> { }
}

MOQ returning dynamic types as object issue

pologise if this questions has been asked but I couldn't find the answer anywhere.
My problem is when mocking a return method using MOQ where that method returns a dynamic type. I'm using a third part library which uses dynamic times. MOQ seems to cast the dynamic type as object.
Mock<IFacebookHelper> mockFbHelp = new Mock<IFacebookHelper>();
mockFbHelp.Setup(x => x.Get("me")).Returns(new { email = "test#test.com", id="9999" });
Method in the mocked helper.
public dynamic Get(string p)
{
var client = new FacebookClient(AccessToken);
return client.Get("me");
}
Code from controller using mocked results.
_facebookHelper.AccessToken = accessToken;
dynamic result = _facebookHelper.Get("me");
int facebookId = int.Parse(result.id); //This errors as id doesn't exist.
Basically MOQ has returned a dynamic type of object that would require casting as something.
Does anyone know how to get around this problem? I'm assuming it may be because MOQ is not coded in .NET 4 therefore does not support dynamic types?
Edit
Actually I don't think this is a MOQ issue as I created my own mock class and still had the same problem. I'm new to dynamic types though so not sure what's going on.
Edit 2 - Part answered.. Problem nothing to do with MOQ after all
Actually the problem seems to be due to the dynamic type being created in a different assembly. Although I got round my initial problem using a JObject type I still want to figure this out.
namespace MyLib.Tools
{
public interface IDynTest
{
dynamic GetData();
}
}
namespace MyLib.Tools
{
public class DynTest : Effect.Tools.IDynTest
{
public dynamic GetData() {
return new { DynamicProperty = "hello" };
}
}
}
namespace Warrior.WebUI.Infrastructure
{
public class UseDynTest
{
private readonly IDynTest dynTest;
public UseDynTest(IDynTest dynTest)
{
this.dynTest = dynTest;
}
public string RetTest()
{
return dynTest.GetData().DynamicProperty;
}
}
}
namespace Warrior.Tests
{
[TestClass]
public class TestDynTest
{
[TestMethod]
public void TestMethod1()
{
//Mock<IDynTest> mockDynTest = new Mock<IDynTest>();
//mockDynTest.Setup(x => x.GetData()).Returns(new { DynamicProperty = "From Unit Test" });
DynTestProxy dynTestProxy = new DynTestProxy();
UseDynTest useTest = new UseDynTest(dynTestProxy);
string results = useTest.RetTest();
Assert.AreEqual("From Unit Test", results);
}
}
}
namespace Warrior.Tests
{
public class DynTestProxy:IDynTest
{
public dynamic GetData()
{
return (dynamic) new { DynamicProperty = "From Unit Test" };
}
}
}
There are 3 project indicated by the Namespace MyLib, Warrior.WebUI and Warrior.Tests.
As it is the test fails with an error..
'object' does not contain a definition for 'DynamicProperty'
which occurs on RetTest()
However if I simply move the DynTestProxy class into the Warrior.WebUI project everything works fine. I'm guessing there are problems when sending dynamic types accross different assemblies or something.
I did a quick test:
namespace ConsoleApplication5
{
public interface IFacebookHelper { dynamic Get(string p); }
class Program
{
static void Main(string[] args)
{
Mock<IFacebookHelper> mockFbHelp = new Mock<IFacebookHelper>();
mockFbHelp.Setup(x => x.Get("me")).Returns(new { email = "test#test.com", id = "9999" });
dynamic result = mockFbHelp.Object.Get("me");
int facebookId = int.Parse(result.id);
string email = result.email;
}
}
}
This is working fine. I don't see a problem here.
Are you sure you didn't mix some things up?
Look at the method you posted:
public dynamic Get(string p)
{
var client = new FacebookClient(AccessToken);
return client.Get("me");
}
Maybe it should be:
...
return client.Get(p);
...
Is _facebookHelper really using the Mock object? It should be of type IFacebookHelperProxy or something like that during your test.
EDIT:
The problem is your attempt to expose an anonymous type across assembly boundaries, since you can use anonymous type only within the assembly you created them.
So instead of
public class DynTestProxy:IDynTest
{
public dynamic GetData()
{
return (dynamic) new { DynamicProperty = "From Unit Test" };
}
}
you should use an ExpandoObject:
public class DynTestProxy:IDynTest
{
public dynamic GetData()
{
dynamic r = new ExpandoObject();
r.DynamicProperty = "From Unit Test";
return r;
}
}
or use the InternalsVisibleTo attribute. See here for more information. Also this question may be interesting for you.

Categories

Resources