extendedxmlserializer / home Goto Github PK
View Code? Open in Web Editor NEWA configurable and eXtensible Xml serializer for .NET.
Home Page: https://extendedxmlserializer.github.io/
License: MIT License
A configurable and eXtensible Xml serializer for .NET.
Home Page: https://extendedxmlserializer.github.io/
License: MIT License
via #35, we should implement a way to enable the user to flush out cached values stored in memory if they make use of cfg.EnableValueOptimizations(bool)
. Something to the effect of:
var aware = serializer as IValueOptimizationAware;
aware?.ClearAll();
The new v2 infrastructure is in place but it is nearly twice as slow as v1. The goal/expectation/requirement is to preserve the magic speed that made v1 so cool. Should be around the same or maybe 10us differential.
ExtendedXmlSerializer should have a configuration API that allows users to setup the configuration of the serializer and then instantiate it accordingly. From #20 (comment):
//Without configuratino
var serializer = new ExtendedXmlSerializer();
// with configuration
var serializer = new ExtendedXmlSerializer(config);
// or from configuration
var serializer= config.CreateSerializer();
In configuration you will be able to configure all settings:
for example:
ExtendedXmlSerializer.Initialize(cfg =>{
cfg.ConfigType<OtherClass>()
.Property(p=>p.Id).ObjectReference().AsAttribute()
.Property(p=>p.Password).Encrypt()
.Property(p=>p.UserName).ChangeName("User").Order(1)
.AddExtension(AttachedPropertyToOtherClass);
cfg.UseAutoProperties();
cfg.UseNamespaces();
cfg.AddExtension(AttachedPropertyToAllTypeExtension);
});
Part of our deployment readiness should be to ensure code adheres to a basic set of code analysis rules. I have a good set that I have landed on with my framework if that is a good starting point:
https://github.com/DragonSpark/Framework/blob/master/DragonSpark.ruleset
BTW, I broke up the remaining tasks into milestones and got rid of the v2 label. It's pretty cool. You can view and add issues directly to the milestone here:
https://github.com/wojtpl2/ExtendedXmlSerializer/milestone/1
Right now if I get an error it could take me hours to figure out its cause.
E.g. messages like "{"Value cannot be null.\r\nParameter name: method"}" or just a plain "System.NullReferenceException" are not very helpfull.
I hate to suggest this, but it's worth exploring. The XML emitted by EXS is quite pretty. Although, it does suffer from what I feel/believe is non-compliant XML, or rather XML that does not conform to a valid schema.
In particular, all of the properties that it emits are done in the default namespace, which does conflict with the content it is trying to serialize. It works for EXS, but another serializer would break reading it (I think).
It would be nice/ideal to introduce an exs
(or xxs
? or xs
?) namespace that these attributes use.
So for example this:
<TestClassWithReadOnlyCollectionProperty
type="ExtendedXmlSerialization.Test.TestObject.TestClassWithReadOnlyCollectionProperty" />
... would become this:
<TestClassWithReadOnlyCollectionProperty
xmlns:exs="https://github.com/wojtpl2/ExtendedXmlSerializer"
exs:type="ExtendedXmlSerialization.Test.TestObject.TestClassWithReadOnlyCollectionProperty" />
By default XmlSerializer outputs indented XML, but ExtendedXmlSerializer does not.
Can you either provide a way to configure the output or match the default output of XmlSerializer?
Or both...
OK we've come this far. Can't turn back now. ๐
The idea is to provide an extension that will allow documents to format and serialize as a JSON document. I am not sure how involved this will be, but I am giving myself a week. I don't want/expect it to be 100% fidelity with the likes of JSON.NET, but more like a proof-of-concept to show off the power/flexibility of the extension model.
As per #24, we want to make it so that we can describe a core set of namespaces/assemblies that are searched for type resolution. This should decrease emitted XML considerably, but also can lead to problems if there is more than one type with the same name in an assembly. This will be a very simple implementation with a "use at your own risk" expectation.
Using version 1.5.0 nuget package ExtendedXmlSerializer on .NET framework 4.6.1
When serializing a class that has properties that have either not been set or have a value set to null, the property does not appear in the serialized XML.
For simple values such as string, date time I would expect an empty node to be included in the serialized data.
I'm trying to Deserialize the following XML which was produced by ExtendedXmlSerializer:
<?xml version="1.0" encoding="utf-8"?>
<ArrayOfIPreflightCheck>
<DiskSpace type="ImageMenu.PreflightChecks.DiskSpace">
<MinimumMb>20480</MinimumMb>
<RecommendedMb>40960</RecommendedMb>
<DiskNumber>0</DiskNumber>
<Name>Disk 0 Size Check</Name>
</DiskSpace>
</ArrayOfIPreflightCheck>
Yet I immediately get a NullReferenceException.
Here's my code:
public class DiskSpace : IPreflightCheck
{
public uint MinimumMb { get; set; }
public uint RecommendedMb { get; set; }
public ushort DiskNumber { get; set; }
public DiskSpace(ushort diskNumber, uint minimumMb, uint recommendedMb)
{
DiskNumber = diskNumber;
MinimumMb = minimumMb;
RecommendedMb = recommendedMb;
Name = $"Disk {DiskNumber} Size Check";
}
public string Name { get; set; }
[XmlIgnore]
public PreflightCheckStatus Status { get; private set; }
[XmlIgnore]
public string Message { get; private set; } = "";
public PreflightCheckStatus Validate()
{
...
}
}
public interface IPreflightCheck
{
string Name { get; }
PreflightCheckStatus Status { get; }
string Message { get; }
PreflightCheckStatus Validate();
}
var diskSpace = new DiskSpace(0, 20 * 1024, 40 * 1024);
var t = new ExtendedXmlSerializer();
var xml = t.Serialize(diskSpace);
var co = t.Deserialize<DiskSpace>(xml);
Any ideas what the problem might be? I'm using version 1.5
Well, double whammy. While implementing the feature for #56, I found out two issues.
Method | Mean | StdDev |
---------------------------------- |----------- |---------- |
SerializationClassWithPrimitive | 34.9980 us | 0.0149 us |
DeserializationClassWithPrimitive | 44.8417 us | 0.0299 us |
And here it is currently:
Method | Mean | StdDev |
---------------------------------- |----------- |---------- |
SerializationClassWithPrimitive | 37.0960 us | 0.0456 us |
DeserializationClassWithPrimitive | 48.5083 us | 0.0949 us |
I took some time to see where it could be taking place, but could not see anything obvious. I did find one area that I fixed, but it is still too slow. To be honest, I am a little burnt out on fixing the performance, so I am definitely open to any assistance here. It has easily consumed 40% of my time on this project, if not more.
XmlSerializer
was not accurate. I have updated the tests so that they are doing the same thing as how we are testing v2 (using XmlWriter/Reader directly), and here are the new results: Method | Mean | StdDev |
---------------------------------- |----------- |---------- |
SerializationClassWithPrimitive | 40.8919 us | 0.2061 us |
DeserializationClassWithPrimitive | 57.7255 us | 0.0529 us |
This is from ~62/60 on my machine. So, a considerable jump.
Just so you know, I start a new work project on April 3rd, so I will not be able to help out here much after that. I hope to have all the outstanding issues complete by then. Although I am not so sure about this one. If you want to help out and look at this issue, please feel free to do so.
Move from #20
It is great page https://www.staticgen.com/. On this page you can see comparison of static web generators. I think that http://gohugo.io/ or http://jekyllrb.com could be useful for us.
Then we can host this page as github pages.
I've checked hugo. It is very simple. I am able to create web for API like this: http://themes.gohugo.io/hugo-theme-learn. I think it is enough for us.
We can also create home page like this: http://themes.gohugo.io/theme/hugo-universal-theme/.
Jekyll is harder to configure than Hugo. I don't have enough time to learn it now.
We have to think about address of web page. If we use default address for this repository it will be look like: https://wojtpl2.github.io/ExtendedXmlSerializer/. I've configured it.
If we want address
extendedxmlserializer.github.io
we must create new account on github, named ExtendedXmlSerializer and move this repository there.
We can also buy custom address and set it without moving repository.
ExtendedXmlSerializer.com would be great.
But we don't have any budget ๐
Result Message:
Test method XXX.Tests.Config.ConfigTests.TestSolutionSerialization threw exception:
System.IO.FileLoadException: Could not load file or assembly 'ExtendedXmlSerializer, Version=1.2.0.0, > Culture=neutral, PublicKeyToken=null' or one of its dependencies. A strongly-named assembly is required. (Exception from HRESULT: 0x80131044)
In looking at some serialized examples, I see that the type
attribute is emitted along with the ref
attribute:
<ObjectA type="ExtendedXmlSerialization.Test.TestObject.TestClassReference" ref="1" />
Is this required? I am thinking it should be:
<ObjectA ref="1" />
... as once an object is in memory, the object type (or any data for that matter) is not necessary. I can look at a PR to fix this if needed.
These are personal preferences (and open to discussion, of course):
var
instead of typereadonly int a
vs. private readonly int
)this.
Basically the less code the better. :)
We have to add xml comment to public API.
For all classes, functions and properites.
After that we will generate api doc. This comments are shown in intellisense in VisualStudio.
If I have a property like this: public virtual IEnumerable<CswTestData> TestData => Monotonic.Concat(new CswTestData[] {Sweep}).Where(td => td != null);
it causes the Serialize method to fail, like this:
System.ArgumentNullException: Value cannot be null.
Parameter name: method
at System.Linq.Expressions.Expression.Call(Expression instance, MethodInfo method, IEnumerable`1 arguments)
at ExtendedXmlSerialization.Cache.ObjectAccessors.CreateMethodAddCollection(Type type, Type elementType)
at ExtendedXmlSerialization.Cache.TypeDefinition..ctor(Type type)
at ExtendedXmlSerialization.Cache.TypeDefinitionCache.<>c.<GetDefinition>b__3_0(Type t)
at System.Runtime.CompilerServices.ConditionalWeakTable`2.GetValue(TKey key, CreateValueCallback createValueCallback)
at ExtendedXmlSerialization.Cache.TypeDefinitionCache.GetDefinition(Type type)
at ExtendedXmlSerialization.Cache.PropertieDefinition..ctor(Type type, PropertyInfo propertyInfo, String name)
at ExtendedXmlSerialization.Cache.TypeDefinition.GetPropertieToSerialze()
at System.Lazy`1.CreateValue()
at System.Lazy`1.LazyInitValue()
at System.Lazy`1.get_Value()
at ExtendedXmlSerialization.ExtendedXmlSerializer.WriteXml(XmlWriter writer, Object o, TypeDefinition type, String name, Boolean writeReservedObject, Boolean forceSaveType)
at ExtendedXmlSerialization.ExtendedXmlSerializer.WriteXmlArray(Object o, XmlWriter writer, TypeDefinition def, String name, Boolean forceSaveType)
at ExtendedXmlSerialization.ExtendedXmlSerializer.WriteXml(XmlWriter writer, Object o, TypeDefinition type, String name, Boolean writeReservedObject, Boolean forceSaveType)
at ExtendedXmlSerialization.ExtendedXmlSerializer.WriteXml(XmlWriter writer, Object o, TypeDefinition type, String name, Boolean writeReservedObject, Boolean forceSaveType)
at ExtendedXmlSerialization.ExtendedXmlSerializer.Serialize(Object o)
This happens because IEnumerable<T>
is assumed to be a collection type, and thus it tries to find an Add method, which naturally returns null. This case isn't checked, which causes this error.
Two ways to fix this:
ICollection
rather than IEnumerable
as a collection base type. That way you know there must be an Add method - it's defined in the interface.There appears to be some unsafe code lurking about. I have run tests and they will pass sometimes, but not others (usually just one). Running the failed test again passes successfully, so this is sign of a (unsafe) threading issue.
I'm trying to deserialize the class with private constructor and receiving NullReferenceException somewhere in ReadXML method. With changing access modifier to public the issue has gone.
So I am looking at the Configuration API now. I think you mentioned you did this, but the Legacy
configuration was moved from legacy into v2 root.
The point of Legacy
was to have it there in case people wanted to migrate their XML from v1 to v2.
But now I am thinking, maybe we should have an ExtendedXmlSerializer.Legacy
nuget for this.
So we can take the Legacy
out, and put it in this new package, along with tests. It would help make it less confusing? What do you think?
I have been mentioning this, but I wanted to ping and get this on the radar. How difficult would it be with the current setup to deploy a prerelease version of v2? I have been planning on looking into this when I get the chance, but the thought strikes me that if it is an easy thing to do based on current setup and configuration, why not do that instead? :)
Add support for XmlAttribute
Another issue to be aware of that should be resolved for v2:
Currently default values for enumerations (the first value) are emitted.
So in the example of TestClassPrimitiveTypes
, it currently expects this in the results:
<PropEnum>EnumValue1</PropEnum>
When in fact that should not be emitted at all.
Hey Wojtpl2,
your Project is really nice and useful, but what I need to do is to define the order of the Attributes in the XML. You wrote that the ExtendedXmlSerializer 1.4.0 support "XmlElement", so I try [XmlElement(Order = 1)], but it doesn't work for me.
Is there any other way to define the order of the Attributes?
Now the order of the Attributes is the order how the Properties are defined in the C# class.
Examples:
how it works now:
C# class
class Test{
string B {get; set;}
string A {get; set;}
}
XML Output:
What I would like to do:
C# class
class Test{
[XmlElement(Order = 2)]
string B {get; set;}
[XmlElement(Order = 1)]
string A {get; set;}
}
XML Output:
Thank you in advance for your answer!
Topics to version 2.0:
While adding Sprache, we encountered a problem with signed assemblies, captured in sprache/Sprache#87. The thinking is that libraries by default should not be signed, but should instead also deploy a signed version using the convention .Signed
. So in the case of EXS, this would be ExtendedXmlSerializer.Signed
The hits continue along here. On the heels of markup extension support, I am going to attempt to add attached properties support, but make them a bit more powerful/flexible than System.Xaml and Xamarin.Forms xaml reader and make it so that it works on POCOs. System.Xaml and Xamarin.Forms have their own "bindable objects" that are coupled to this feature. The idea here is that you should be able to attach a property to any POCO and have it serialize/deserialize.
This is my weekend project. Let's see how I do. :)
Looks like types are being emitted for read-only properties. This is not needed since the property is assigned internally to the object (in theory).
Another consideration is perhaps move to read-only properties for properties, and move initialization to constructors. For instance with SimpleSerializationToolsFactory
making it look like this:
public class SimpleSerializationToolsFactory : ISerializationToolsFactory
{
public SimpleSerializationToolsFactory(IEnumerable<IExtendedXmlSerializerConfig> configurations, IPropertyEncryption encryption)
{
Configurations = new List<IExtendedXmlSerializerConfig>(configurations);
EncryptionAlgorithm = encryption;
}
public IList<IExtendedXmlSerializerConfig> Configurations { get; }
public IPropertyEncryption EncryptionAlgorithm { get; }
public IExtendedXmlSerializerConfig GetConfiguration(Type type)
{
foreach (var migrationMap in Configurations)
{
if (migrationMap.IsSatisfiedBy(type))
{
return migrationMap;
}
}
return null;
}
}
What this moves towards is immutability, which is automatically a thread-safe(r) design. Also note the use of IList
rather than List
, which will allow consumers to use any object that implements IList
rather than being forced to use a specific implementation.
These of course would be breaking changes to the current code. You would have to Obsolete
them and move users to the new classes.
Hello again!
In the last few days I worked very intensive with XML serializing. For my Tests I used the default XmlSerializer and the ExtendedXmlSerialize to be able to compare the advantages and disadvantages of both. By my Tests I noticed two issues of the ExtendedXmlSerializer, which I want to tell you.
Example class:
public class ListOfTest : List
{
public string name { get; set; }
}
The default XmlSerializer can do this, but there are also some Problems with it:
-) List only works when T is not an Interface
-) only the List get serialized and deserialized, all other Properties don't. (from example the property "name" would not get serialized)
Example:
public class Test
{
public object testProperty { get; set; }
}
TestData:
Test t = new Test() { testProperty = 1234; }
Test t2 = new Test() { testProperty = "name"; }
Xml-Output would look like this:
<?xml version="1.0" encoding="utf-8"?>
<Test>
<testProperty>
1234
</testProperty>
</Test>
<Test>
<testProperty>
name
</testProperty>
</Test>
TestData after deserialize:
t.testProperty == "System.Object";
t2.testProperty == "System.Object";
I hope this information will help you by bugfixing and by upgrading the ExtendedXmlSerializer.
As per #69, ensure that only ConfigurationAPI and its products/dependencies are public, and everything else is internal for v2.
Hi,
I want to deserialize a xml file into a class (Scene.cs) containing this variable:
public List<GameObject> SceneGraph { get; set; }
This is the GameObject class: I'm trying to serialize this class:
https://github.com/michidk/BrokenEngine/blob/master/BrokenEngine/GameObject.cs
My xml file currently looks like this:
<?xml version="1.0"?>
<Scene xmlns="BrokenEngine.Scene">
<SceneGraph>
<GameObject type="BrokenEngine.GameObject">
<Name>Super Cool GameObject</Name>
<Position type="OpenTK.Vector3">
<X>1</X>
<Y>1</Y>
<Z>1</Z>
</Position>
</GameObject>
</SceneGraph>
</Scene>
I've already added a public, parameterless constructor.
I get the following error: {"Value cannot be null.\r\nParameter name: method"}
What do I do wrong?
So, this is a personal pet peeve, and I would totally understand not doing this, but I hate the word Config
and like seeing it typed out as Configuration
(like App
instead of Application
seems lazy).
I understand ExtendedXmlSerializerConfiguration
seems a little lengthy though... so maybe ExtendedXmlConfiguration
?
No worries if you don't like it, but thought I would ask!
Would it be possible to have methods that accept a path to a file in order to serialize/deserialize to/from the file directly, or alternatively passing a Stream as a parameter...
It seems natural to me to have this on something that does serialization :)
Hey Wojtpl2,
very nice Feature!!!! Thx, but how can i manipulate the generated XML-Tags and XML-Attribute?
Example:
<?xml version="1.0" encoding="utf-8"?>
<Definitions type="BPMN2.Definitions">
<id>text</id>
<Exports>text</Exports>
</Definitions>
i want to generate this
<?xml version="1.0" encoding="utf-8"?>
<Definitions id="text">
<Exports>text</Exports>
</Definitions>
with e.g. [XmlElement("Exports")] or [XmlAttribute("id")]
Can u help me? THX!
Hey,
I get a NullReferenceException with this code:
var xml = ResourceManager.GetString($"Scenes/{ name }.xml");
var serializer = new ExtendedXmlSerializer(); // also tried with new SimpleSerializationToolsFactory() as parameter
var scene = serializer.Deserialize<Scene>(xml);
This is the exception:
System.NullReferenceException was unhandled
HResult=-2147467261
Message=Object reference not set to an instance of an object.
Source=ExtendedXmlSerializer
StackTrace:
at ExtendedXmlSerialization.ExtendedXmlSerializer.ReadXml(XElement currentNode, TypeDefinition type, Object instance)
...
This is my xml file:
<?xml version="1.0"?>
<Scene xmlns="BrokenEngine.Scene">
<MetaData>
<Name>Test</Name>
<Author>me</Author>
<Description>A simple test scene just to test stuff...</Description>
</MetaData>
<Materials>
<Material>
<Name>My First Material</Name>
<Shader>phong.glsl</Shader>
<Properties type="BrokenEngine.Materials.BlinnPhongMaterial">
<Blinn>True</Blinn>
</Properties>
</Material>
</Materials>
</Scene>
var xml is just the string read directly from the .xml file using File.ReadAllText. It's not null.
What's wrong with my code? I'm using the newest version from NuGet.
Edit:
I noticed that it does work if I removed the this part:
<Properties type="BrokenEngine.Materials.BlinnPhongMaterial">
<Blinn>True</Blinn>
</Properties>
But it seems like it can find the type, because if I remove the namespace it tells me that it can't find the type.
Oh man, I've been trying to work on references but got caught up in another blasted performance rabbit hole. The news is good, however. I found the problem and it is actually faster than before (~33us serialization and ~44us deserialization on my machine).
Well, almost. Please read this issue. There is a better solution to this, but it requires .NET 4.6. Do you see any problem in upgrading to this?
I have been thinking lately that I would be remiss to spend so much time and energy on this project and not enable markup extensions, my favorite feature from Xaml. This would in effect make EXS as a Xaml parser in addition to being a XML POCO parser.
This should be an extension, obviously. FWIW while I am not the happiest with the ConfigurationAPI (I'd rate it like 6/10), I am very happy with the ExtensionModelAPI (an 8 or 9 out of 10). Lots of cool stuff there and I think it's a great new way to look at serialization. ๐
As per #69 (comment), we should get our dependencies into submodules, and reduce the amount of generated assemblies for EXS.
NewConfiguration
-> Configuration
This should be the very very very last thing that we do.
Have you installed VS2017 yet? I have not, and I have not seen very many positive things said about it. Since its launch it has increased by 2,000 problems:
https://developercommunity.visualstudio.com/spaces/8/index.html
:/
I know that ReSharper 2017.1 is due to release next week or the week after. They are already working on a VS2017 Update. Ideally we could upgrade when both of those are released.
FWIW, I am thinking "v2.0" milestone as "feature complete" and then "v2.1" will be all the fixings like documentation and website. I will update them accordingly.
As mentioned in #7 (comment), it would be ideal to support read-only collection properties. I will be taking a look at this and submitting a PR if successful.
In V2 list with reference object works differently.
You can see ExtendedXmlSerializer.Tests.Legacy.SerializationReferenceTest.SerializationListWithReference.
It is list with elements what have reference to other elements. Eg. First element has reference to other element in list.
@Mike-EEE Do you know Fluent Assertions? http://www.fluentassertions.com/
I think that it is good framework. What do you think about it?
As discussed in #54 (comment)
Protobuf has some cool functionality around this. I have been thinking a little about how we could do it here for EXS, and it might be challenging, but it still might be worth checking out.
I should have asked this a long time ago. :P
I have encountered a lot of friction in the v2 design with having to account for v1/legacy functionality. In fact a lot of my time has been spent having to account for both it and v2 vision. This has proved quite challenging and time-intensive.
So the thought occurs to me... how open would you be to simply moving all current components to a Legacy
folder (much like what I did in the performance testing project) and deprecate the public components? Some thoughts around this:
ISerializationToolsFactory
at all. They will have to update their references from ExtendedXmlSerialization.ExtendedXmlSerializer
to ExtendedXmlSerialization.Legacy.ExtendedXmlSerializer
(or ``ExtendedXmlSerialization.Legacy.LegacyExtendedXmlSerializer` if we wish).The last point is why I haven't brought it up until now. As a general, wise rule, breaking changes should be avoided if at all possible, but I am thinking since this project only has 18 stars at the moment, maybe it's something to do before it gets 18,000? :)
Definitely open to thoughts on this!
I use my xml file as configuration file for the end user.
It would be great if I could specify aliases for types.
So that the user could do sth like
<AlbedoColor type="Color">
<R>156</R>
<G>208</G>
<B>84</B>
<A>255</A>
</AlbedoColor>
Instead of
<AlbedoColor type="OpenTK.Graphics.Color4">
<R>156</R>
<G>208</G>
<B>84</B>
<A>255</A>
</AlbedoColor>
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.