6bee / aqua-core Goto Github PK
View Code? Open in Web Editor NEWTransform any object-graph into a dynamic, composed dictionaries like structure, holding serializable values and type information
License: MIT License
Transform any object-graph into a dynamic, composed dictionaries like structure, holding serializable values and type information
License: MIT License
The anonymous types are identified using the class name, which always starts with "<>Anonymous" in C#, but in VB.Net the name starts with "VB$Anonymous".
Hi,
I am currently getting "Failed to pick matching constructor for type" exception for any int property in anonymous type in the following expression: "Select(x => new { x.Id})". I am using the latest Entity Framework on server side.
It looks strange, since the following combinations work well:
Any ideas?
Thanks!
I extended When_using_dynamic_object_for_complex_object_tree
class with one more test
public class When_using_dynamic_object_for_complex_object_tree
{
// ...
public When_using_dynamic_object_for_complex_object_tree()
{
var originalObject = new DynamicObject()
{
{ "DoubleValue", DoubleValue },
{
"Reference", new DynamicObject(typeof(string))
{
{ "StringValue", StringValue },
}
},
};
serializedObject = originalObject.Serialize();
}
[Fact]
public void Clone_should_contain_type_information()
{
var nestedObject = serializedObject["Reference"] as DynamicObject;
(nestedObject.Type?.Type).ShouldBe(typeof(string));
}
// ...
}
It passes with BinaryFormatter
, DataContractSerializer
and NetDataContractSerializer
, but fails with JsonSerializer
and XmlSerializer
.
Sometimes we need to map types which implement IEnumerable
but also contain other properties. The standard example is IGrouping<TKey, TElement>
which implements IEnumerable<TElement>
but also contains the Key
property.
public interface IGrouping<out TKey, out TElement> : IEnumerable<TElement>, IEnumerable
{
TKey Key { get; }
}
Class DynamicObject
provides a virtual method MapToDynamicObjectGraph
which I think I am supposed to override, f.ex. the following way
class CustomDynamicObjectMapper : DynamicObjectMapper
{
protected override DynamicObject MapToDynamicObjectGraph(object obj, Func<Type, bool> setTypeInformation)
{
if (obj != null && obj.GetType().Implements(typeof(IGrouping<,>)))
{
object mappedGrouping = typeof(CustomDynamicObjectMapper)
.GetTypeInfo()
.GetDeclaredMethod(nameof(MapGrouping))
.MakeGenericMethod(obj.GetType().GenericTypeArguments)
.Invoke(this, new[] { obj, setTypeInformation });
return (DynamicObject)mappedGrouping;
}
return base.MapToDynamicObjectGraph(obj, setTypeInformation);
}
private DynamicObject MapGrouping<TKey, TElement>(IGrouping<TKey, TElement> grouping, Func<Type, bool> setTypeInformation)
{
var mappedGrouping = new DynamicObject(typeof(IGrouping<TKey, TElement>));
mappedGrouping.Add("Key", this.MapToDynamicObjectGraph(grouping.Key, setTypeInformation));
mappedGrouping.Add("Elements", this.MapCollection(grouping, setTypeInformation).ToList());
return mappedGrouping;
}
}
and it seems to return me exactly what I want
IGrouping<string, int> grouping = Enumerable.Range(1, 5).GroupBy(x => "Hello", x => x).Single();
DynamicObject dynamicGrouping = new CustomDynamicObjectMapper().MapObject(grouping);
Unfortunately the overridden method is NOT called when mapping an object containing an IGrouping
property, which makes me believe I chose the wrong way of custom type mapping. What could you advise instead?
My example
public class When_mapping_object_from_object_with_igrouping_members
{
class CustomClass
{
public IGrouping<string, int> Grouping { get; set; }
}
class CustomDynamicObjectMapper : DynamicObjectMapper
{
protected override DynamicObject MapToDynamicObjectGraph(object obj, Func<Type, bool> setTypeInformation)
{
if (obj != null && obj.GetType().Implements(typeof(IGrouping<,>)))
{
object mappedGrouping = typeof(CustomDynamicObjectMapper)
.GetTypeInfo()
.GetDeclaredMethod(nameof(MapGrouping))
.MakeGenericMethod(obj.GetType().GenericTypeArguments)
.Invoke(this, new[] { obj, setTypeInformation });
return (DynamicObject)mappedGrouping;
}
return base.MapToDynamicObjectGraph(obj, setTypeInformation);
}
private DynamicObject MapGrouping<TKey, TElement>(IGrouping<TKey, TElement> grouping, Func<Type, bool> setTypeInformation)
{
var mappedGrouping = new DynamicObject(typeof(IGrouping<TKey, TElement>));
mappedGrouping.Add("Key", this.MapToDynamicObjectGraph(grouping.Key, setTypeInformation));
mappedGrouping.Add("Elements", this.MapCollection(grouping, setTypeInformation).ToList());
return mappedGrouping;
}
}
DynamicObject dynamicGrouping;
DynamicObject dynamicObject;
public When_mapping_object_from_object_with_igrouping_members()
{
IGrouping<string, int> grouping = Enumerable.Range(1, 5).GroupBy(x => "Hello", x => x).Single();
var source = new CustomClass
{
Grouping = grouping
};
dynamicGrouping = new CustomDynamicObjectMapper().MapObject(grouping);
dynamicObject = new CustomDynamicObjectMapper().MapObject(source);
}
[Fact]
public void Dynamic_grouping_type_should_be_igrouping()
{
dynamicGrouping.Type.Type.Implements(typeof(IGrouping<,>)).ShouldBeTrue();
}
[Fact]
public void Dynamic_object_grouping_should_be_mapped()
{
dynamicObject["Grouping"].ShouldBeOfType<DynamicObject>();
}
[Fact]
public void Dynamic_object_grouping_type_should_be_igrouping()
{
((DynamicObject)dynamicObject["Grouping"]).Type.Type.Implements(typeof(IGrouping<,>)).ShouldBeTrue();
}
}
Both asserts on dynamicObject
fail.
Originally reported in 6bee/Remote.Linq/issues/41
Const, static, read-only, and private members should be excluded from mapping. Otherwise values may/should not be assigned back when recreating the original type.
There seems to be a question mark ?
missing after the second short
if (targetType == typeof(short) || targetType == typeof(short))
{
return short.Parse(value);
}
This causes System.NotImplementedException: string parser for type System.Nullable`1[System.Int16] is not implemented.
I have a library referencing aqua-core and targeting netstandard1.3. It contains the following line of code
... = new TypeResolver(); // resolves into new TypeResolver(null, false)
The library compiles just fine, but its consuming application (in my case netcoreapp1.0 xunit test project) seems to be pulling the netstandard1.6 version of aqua-core. It doesn't look too wrong to me and I actually don't mind if it happens, but apparently aqua-core/ns1.6 does no longer expose the 2-arg ctor of class TypeResolver
which leads to a runtime error
System.MissingMethodException : Method not found: 'Void Aqua.TypeSystem.TypeResolver..ctor(System.Func`2<Aqua.TypeSystem.TypeInfo,System.Type>, Boolean)'.
After some more reflection I tend to see here a contradiction with the general statement of Microsoft
.NET Standard versions are backward compatible. That means that netstandard1.0 libraries run on netstandard1.1 platforms and higher, and so on...
If we apply this statement not only to .NET Standard itself but also to libraries targeting netstandardX_Y then it explains my MissingMethodException
.
Can you bring the following signature to aqua-core/ns1.6 for compatibility with aqua-core/ns1.3?
public TypeResolver(Func<TypeInfo, Type> typeEmitter, bool validateIncludingPropertyInfos)
or do you have any better ideas/suggestions?
Is your feature request related to a problem? Please describe.
I want to minimise dependencies in my project by utilising framework dependencies wherever possible
Describe the solution you'd like
I want the package to not have an explicit dependency on System.Text.Json as it can be provided by the framework when targeting net 6.
Describe alternatives you've considered
Accept the additional dependency
Additional context
n/a
Hello this a nice place to keep the meta data of my projects. I used to have an excel spreadsheet with the table names & two Cols for the name and type, I would like to import that into your project - so I can generate the model objects from from here.
Excel Col - ClassName
Excel Col - AtrributeName
Excel Col - Type
How can I template this excel sheet to a simple C# POCO model class with the name and type
We observe one peculiar and fairly unstable bug in TypeResolver
for which I think I found an explanation.
Apparently under certain conditions the runtime generates anonymous types with the same name <>f__AnonymousType0´2
but different DeclaringAssembly
and different sets of properties. Exactly for such cases the TypeResolver.IsValid
method contains the intelligent distinction logic based on matching property names.
The problem occurs when the first candidate is successfully resolved and cached in TypeResolver._typeCache
. Then the second candidate is fetched from the cache bypassing the TypeResolver.IsValid
method simply because the class names are identical.
It's a bit problematic to provide simple test, but I hope my explanation is clear.
If I change the type of EnumProperty
in Aqua.Tests.Dynamic.DynamicObject.When_converting_to_object_with_enum.ClassWithEnum
to CustomEnum?
then the tests would no longer pass. There seems to be a problem with enum values stored as string
and int
.
Version 4.6.3.
The following test fails with System.Reflection.AmbiguousMatchException
[Fact]
public void ResolveMemberInfo_should_return_original_property_info()
{
var typeResolver = new TypeResolver();
System.Reflection.TypeInfo type = typeof(TypeHiding).GetTypeInfo();
System.Reflection.PropertyInfo propertyInfo = type.GetDeclaredProperty(nameof(TypeHiding.Property));
Aqua.TypeSystem.PropertyInfo mappedProperty = new Aqua.TypeSystem.PropertyInfo(propertyInfo);
System.Reflection.MemberInfo resolvedMemberInfo = mappedProperty.ResolveMemberInfo(typeResolver);
resolvedMemberInfo.ShouldBe(propertyInfo);
}
Related to
Since UWP10 support was withdrawn from netstandard1.6
we should aim to add support for UWP explicitely: target platform uap10.0
see .NET Standard Versions table
The following code results in a StackOverflowException
:
Action a = delegate { };
new DynamicObject(a);
The following tests
public class When_mapping_from_object_with_collection_member
{
class CustomClass
{
public IEnumerable<object> Items { get; set; }
}
CustomClass source;
DynamicObject dynamicObject;
public When_mapping_from_object_with_collection_member()
{
source = new CustomClass { Items = new List<object> { 1, null, "hello"} };
dynamicObject = new DynamicObjectMapper().MapObject(source);
}
[Fact]
public void Dynamic_object_items_count_should_be_three()
{
((IEnumerable<object>)dynamicObject["Items"]).Count().ShouldBe(3);
}
[Fact]
public void Object_items_count_should_be_three()
{
var obj = new DynamicObjectMapper().Map<CustomClass>(dynamicObject);
obj.Items.Count().ShouldBe(3);
}
}
are failing with
Aqua.Tests.Dynamic.DynamicObjectMapper.When_mapping_from_object_with_collection_member.Dynamic_object_items_count_should_be_three [FAIL]
Shouldly.ShouldAssertException : (IEnumerable<object>)dynamicObject["Items"]).Count(
should be
3
but was
2
Aqua.Tests.Dynamic.DynamicObjectMapper.When_mapping_from_object_with_collection_member.Object_items_count_should_be_three [FAIL]
Shouldly.ShouldAssertException : obj.Items.Count()
should be
3
but was
2
The reason is possibly attributed to the misuse of .OfType
instead of .Cast
in DynamicObjectMapper
class. Please revisit all three occurrences. I suspect that my tests only cover two of them. Thanks!
Hello @6bee ,
First of all, thank you very much for the remote.linq and aqua-core libraries. It has allowed me to apply metaprogramming techniques.
I'm currently playing around with the new AssemblyLoadContext from dotnet core 3.0, which allows me to dynamically compile ASTs and load the binary which plays quite nicely with remote.linq.
The problem I'm facing now is that whenever I want to unload the context and recompile I fail to do that due to (I presume) the type cache which prevents GC to collect the assembly.
Before I go any deeper, given that you know the inner workings of this library the best, is a complete recycle of the emitted types feasible? Or a possible workaround as a hint?
The main outcome of this would be to be able to reuse remote.linq against the newly built types.
Thanks,
Cosmin
Dependency on Newtonsoft.Json
moved from aqua-core
to package aqua-core-newtonsoft-json
as of version 4.0.0-alpha-041
.
To enable JSON serialization for aqua-core
using Newtonsoft.Json
please include aqua-core-newtonsoft-json
in your project and used the provided extension method to configure JsonSerializerSettings
:
using Newtonsoft.Json;
using Aqua;
…
JsonSerializerSettings serializerSettings = new JsonSerializerSettings().ConfigureAqua();
var mapperSettings = new DynamicObjectMapperSettings { FormatPrimitiveTypesAsString = true };
var mapper = new DynamicObjectMapper(mapperSettings);
var dt1 = new DateTime(2, 1, 2, 10, 0, 0, 300);
var dtDynamic = mapper.MapObject(dt1);
var dt2 = mapper.Map<DateTime>(dtDynamic);
dt2.ShouldBe(dt1); // [PASS]
var dto1 = new DateTimeOffset(2, 1, 2, 10, 0, 0, 300, new TimeSpan(1, 30, 0));
var dtoDynamic = mapper.MapObject(dto1);
var dto2 = mapper.Map<DateTimeOffset>(dtoDynamic);
dto2.ShouldBe(dto1); // [FAIL] "0002-01-02T10:00:00.0000000+01:30" != "0002-01-02T10:00:00.3000000+01:30"
My nuget referenced code stopped working once I upgraded my solution to NET 6. I copied the lates RemoteLinq and Aqua sources to my solution and referenced it directly. This made my error go away but a new one appeared,
Below code does not work on for example OfType method. Binding flags come back as Default, so method is not marked as static.
Adding below code after DecalringType line fixes the issue:
if(member is System.Reflection.MethodInfo method)
{
IsStatic = method.IsStatic;
return;
}
In this test: test/Aqua.Tests/Dynamic/DynamicObjectMapper/When_mapping_dynamic_object_to_type_with_different_property_types
.cs
When the system environment is set to a non-english language, the exception messages are in a foreign language.
Hi,
I faced with a serialization problem of a DynamicObject. Empty DynamicObject is incorrectly deserialized by protobuf. I get the last sources to investigate the problem.
To reproduce exception you need to open the "29_RemoteQueryable_UsingProtobufNetSerializationOverTcp" sample, and at first query change
foreach (var item in await repo.Products.ToArrayAsync().ConfigureAwait(false))
to
foreach (var item in await repo.Products.Where(x => x.Id == 0).ToArrayAsync().ConfigureAwait(false))
Filter can be anything, we need to get an empty result.
As far as I know, problem is at empty array (value of dictionary) of SurrogateDynamicObject. ProtoWriter treat field as a string and deserializer throws an exception. If add check for an empty array and set field to null, everything works, but I prefer to get an empty array as a result.
Why it happens I didn't found yet.
Exception:
System.AggregateException: One or more errors occurred. (Invalid wire-type; this usually means you have over-written a file without truncating or setting the length; see https://stackoverflow.com/q/2152978/23354)
---> ProtoBuf.ProtoException: Invalid wire-type; this usually means you have over-written a file without truncating or setting the length; see https://stackoverflow.com/q/2152978/23354
at ProtoBuf.ProtoReader.SkipField() in c:\Projects\Remote.Linq-main\protobuf\src\protobuf-net\ProtoReader.cs:line 796
at proto_2(Object , ProtoReader )
at ProtoBuf.Serializers.CompiledSerializer.ProtoBuf.Serializers.IProtoSerializer.Read(Object value, ProtoReader source)
at ProtoBuf.Meta.RuntimeTypeModel.Deserialize(Int32 key, Object value, ProtoReader source)
at ProtoBuf.ProtoReader.ReadTypedObject(Object value, Int32 key, ProtoReader reader, Type type)
at ProtoBuf.ProtoReader.ReadObject(Object value, Int32 key, ProtoReader reader)
at proto_244(Object , ProtoReader )
at ProtoBuf.Serializers.CompiledSerializer.ProtoBuf.Serializers.IProtoSerializer.Read(Object value, ProtoReader source)
at ProtoBuf.Meta.RuntimeTypeModel.Deserialize(Int32 key, Object value, ProtoReader source)
at ProtoBuf.Meta.TypeModel.DeserializeCore(ProtoReader reader, Type type, Object value, Boolean noAutoCreate)
at ProtoBuf.Meta.TypeModel.Deserialize(Stream source, Object value, Type type, SerializationContext context)
at ProtoBuf.Meta.TypeModel.Deserialize(Stream source, Object value, Type type)
at Common.ProtobufNetFormatter.ReadInternalAsync[T](Stream stream, Type type, CancellationToken cancellation)
at Common.ProtobufNetFormatter.ReadAsync[T](Stream stream, CancellationToken cancellation)
at Client.RemoteRepository.<.ctor>b__2_0(Expression expression, CancellationToken cancellation)
at Remote.Linq.DynamicQuery.AsyncRemoteQueryProvider1.ExecuteAsync[TResult](Expression expression, CancellationToken cancellation) at Remote.Linq.Async.AsyncQueryableExtensions.ExecuteAsync[TResult](IQueryable source, CancellationToken cancellation) at Remote.Linq.Async.AsyncQueryableExtensions.ToArrayAsync[TSource](IQueryable
1 source, CancellationToken cancellation)
at Client.AsyncDemo.RunAsync()
--- End of inner exception stack trace ---
at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions)
at System.Threading.Tasks.Task.Wait(Int32 millisecondsTimeout, CancellationToken cancellationToken)
at System.Threading.Tasks.Task.Wait()
at IAsyncDemoExtensions.RunAsyncDemo(IAsyncDemo demo) in c:\Projects\Remote.Linq-main\samples\SharedCode\Client.IAsyncDemo.cs:line 24
[Fact]
public void ResolveMethod_ExplicitCast_should_return_original_method_info()
{
var typeResolver = new TypeResolver();
Expression<Func<decimal?, double?>> expr = x => (double?)x;
System.Reflection.MethodInfo methodInfo = ((UnaryExpression)expr.Body).Method;
Aqua.TypeSystem.MethodInfo mappedMethod = new Aqua.TypeSystem.MethodInfo(methodInfo);
System.Reflection.MethodInfo resolvedMethod = mappedMethod.ResolveMethod(typeResolver);
resolvedMethod.ShouldBe(methodInfo);
}
Shouldly.ShouldAssertException : resolvedMethod
should be
Double op_Explicit(System.Decimal)
but was
Byte op_Explicit(System.Decimal)
Hey,
we are using Remote.Linq and Aqua.DynamicObject for a long time and really like it.
It crashes on .NET 8 with the following message:
System.NotSupportedException : The converter for derived type 'Aqua.Dynamic.DynamicObject' does not support metadata writes or reads. The unsupported member type is located on type 'System.Dynamic.IDynamicMetaObjectProvider'. Path: $.
---- System.NotSupportedException : The converter for derived type 'Aqua.Dynamic.DynamicObject' does not support metadata writes or reads.
Have these configuration flags set:
MaxDepth = int.MaxValue,
ReferenceHandler = SystemTextReferenceHandler.Preserve,
NumberHandling = SystemTextJsonNumberHandling.AllowNamedFloatingPointLiterals | SystemTextJsonNumberHandling.AllowReadingFromString,
WriteIndented = true,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault,
Can you point me into the right direction? Maybe we can fix it and contribute as PR ;-)
Best Regards,
Alex
As I was playing with EntityFrameworkCore 2.0.0-preview1-final I ran into rather severe performance issues. Some of my tests would suddenly take a few minutes and even hours to execute. A bit deeper analysis hints at their new IncludeCompiler which tends to expand included navigation properties into subsequent SelectMany
/GroupJoin
more aggressively, generating a fairly large number of nested anonymous types on the way. One could certainly find their approach questionable, but I still think there exists a performance problem in aqua-core which deserves its own attention.
Apparently TypeResolver.ResolveType
doesn't scale too well with the length of the chain of nested anonymous types. I wrote a little program which generates such types and measures the performance of TypeResolver
[Fact]
public void ResolveTypePerformanceTest()
{
TypeInfo GenerateAnonymousType<T>(uint nestingCount, T value)
{
if (nestingCount == 0)
return null;
var newValue = new { Prop = value };
return GenerateAnonymousType(nestingCount - 1, newValue) ?? new TypeInfo(newValue.GetType());
}
for (uint i = 15; i <= 30; ++i)
{
TypeInfo type = GenerateAnonymousType(i, "hello");
var typeResolver = new TypeResolver();
var watch = Stopwatch.StartNew();
typeResolver.ResolveType(type);
watch.Stop();
Debug.WriteLine($"{i} | {watch.ElapsedMilliseconds}");
}
}
As one can see the cost of resolving only one type is growing quite rapidly.
nestingCount | execution time (ms) |
---|---|
15 | 55 |
16 | 56 |
17 | 88 |
18 | 117 |
19 | 199 |
20 | 319 |
21 | 525 |
22 | 792 |
23 | 1309 |
24 | 1963 |
25 | 3109 |
26 | 4943 |
27 | 8065 |
28 | 12996 |
29 | 21031 |
30 | 33822 |
The debugger suggests that it's mainly spending time computing collection hashes for nested anonymous types (TypeResolver.EqualityComparer.GetHashCode
). In real world scenarios you usually have more than one type cached in a TypeResolver
and you resolve types hundreds of times (e.g. when visiting Remote.Linq
expression trees). Then the performance starts to suffer with much shorter chains of nested types, e.g. my EFC2 test never returned with type nesting depth being only 16.
Could you please take another look at TypeResolver.EqualityComparer
from the performance point of view?
Given the fact, BinaryFormatter
was marked as obsolete starting in .NET 5.0, support binary serialization in DynamicObject
and aqua-core
in general should be re-evaluated.
More info: https://docs.microsoft.com/en-us/dotnet/core/compatibility/syslib-warnings/syslib0011
I am trying to overcome serialization problems with DynamicObjectMapper
and NodaTime.LocalTime
. I have a simple code:
mapper = new DynamicObjectMapper();
dyO = mapper.MapObject(new C());
mapper.Map<C>(dyO);
public class C
{
public LocalDate Date { get; set; } = new LocalDate(2020, 10, 10);
}
And can't replace default DynamicObject
creation, I want to serialize LocalDate
as string
but overriding MapToDynamicObjectGraph
and IDynamicObjectFactory
do not help.
Could you please provide the correct way to LocalDate
serialization?
Serializers (system.text.json, newtonsoft, and protobuf-net) fail deserialize json for dynamic object representing empty type (i.e. type without any data members).
Aqua.Newtonsoft.Json
allows deserialization of dynamic object with empty property setAqua.Text.Json
allows deserialization of dynamic object with empty property setAqua.protobuf-net
allows deserialization of dynamic object with empty property setVersion 4.5.0.
The following test fails with System.Reflection.AmbiguousMatchException
public class When_resolving_hidden_property
{
private class TypeHidingBase
{
public string Property { get; }
}
private class TypeHiding : TypeHidingBase
{
public new int Property { get; }
}
[Fact]
public void ResolveProperty_should_return_original_property_info()
{
var typeResolver = new TypeResolver();
System.Reflection.TypeInfo type = typeof(TypeHiding).GetTypeInfo();
System.Reflection.PropertyInfo propertyInfo = type.GetDeclaredProperty(nameof(TypeHiding.Property));
Aqua.TypeSystem.PropertyInfo mappedProperty = new Aqua.TypeSystem.PropertyInfo(propertyInfo);
System.Reflection.PropertyInfo resolvedProperty = mappedProperty.ResolveProperty(typeResolver);
resolvedProperty.ShouldBe(propertyInfo);
}
}
After fca4dda FormatNativeTypeAsString uses InvariantCulture (which is good), yet the serializers still seem to be implicitly using the CurrentCulture. This causes a problem when the current culture defines a decimal separator different from the invariant one.
public abstract class When_serializing_dynamic_object
{
// ...
[Fact]
public void Float_should_serialize()
{
CultureInfo.CurrentCulture = CultureInfo.GetCultureInfo("de");
var result = Serialize<float, float>(0.1F, formatValuesAsStrings: true);
result.ShouldBe(0.1F);
}
}
Aqua.Tests.Serialization.Dynamic.DynamicObject.When_serializing_dynamic_object+JsonSerializer.Float_should_serialize [FAIL]
Shouldly.ShouldAssertException : result
should be
0,1f
but was
1E+08f
Hello,
We seem to have stuck at the problem serializing/deserializing DynamicObject's with properties of types 'double' and 'decimal' in the same object (or graph) using Json.NET serializer. The easiest way to reproduce the problem for you would be to change the datatype 'double' to 'decimal' in this field and rerun the tests.
Test Name: Aqua.Tests.Serialization.Dynamic.DynamicObject.When_using_dynamic_object_for_complex_object_tree.Clone_should_contain_simple_decimal_property
Test FullName: Aqua.Tests.Serialization.Dynamic.DynamicObject.When_using_dynamic_object_for_complex_object_tree.Clone_should_contain_simple_decimal_property
Test Source: \aqua-core\src\Aqua\Aqua.Tests\Serialization\Dynamic\DynamicObject\When_using_dynamic_object_for_complex_object_tree.cs : line 43
Test Outcome: Failed
Test Duration: 0:00:00,014
Result StackTrace: at Aqua.Tests.Serialization.Dynamic.DynamicObject.When_using_dynamic_object_for_complex_object_tree.Clone_should_contain_simple_decimal_property() in \aqua-core\src\Aqua\Aqua.Tests\Serialization\Dynamic\DynamicObject\When_using_dynamic_object_for_complex_object_tree.cs:line 44
Result Message:
Assert.Equal() Failure
Expected: 123 (System.Decimal)
Actual: 123 (System.Double)
One may configure Json.NET to parse numeric literals as either 'double' or 'decimal' using FloatParseHandling option, but there is no option to preserve the original CLR type. That means DynamicObject must somehow supply it explicitly.
How would you recommend us to proceed? Thank you in advance!
Good morning,
First off, thanks so much for creating this aqua-core package. It has enabled me to pass entire graphs of data returned by Entity Framework from a WCF Service successfully to the client!
I'm working on the part of our application that makes changes to the graph of data and returns it to the WCF Service to handle the updates. I convert the updated graph object back to DynamicObject and pass it as a parameter to my WCF Service method UpdateXYZ. The service is successfully receiving the DynamicObject as a parameter, and successfully converting it back to an object graph of my type in the first line below. However, I am receiving the error above when the second line runs to attach the entity to the service's context. It isn't the top-level MyType that it's failing on, but rather one of the nested types in the graph.
Am I going about this correctly? I don't want to have to perform a field-by-field copy of the received data onto a newly retrieved entity from my service's DbContext.
MyType app = new DynamicObjectMapper().Map(obj) as MyType;
context.MyTypeCollection.Attach(app);
context.SaveChanges();
Edit: If I originally query the data as "AsNoTracking", this Attach error on the return trip goes away, but I have to manually set the EF record state to Modified (code below) to get it to save the changes. However, without the change tracking enabled while work is being done on the client side, I'll have no idea which nested entities in the graph were added, modified, or possibly deleted, so this doesn't really fix my issue.
context.Entry(app).State = EntityState.Modified;
Thanks!
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.