.NET XML serialization - c#

I would like to serialize and deserialize mixed data into XML. After some searches I found out that there were two ways of doing it: System.Runtime.Serialization.Formatters.Soap.SoapFormatter and System.Xml.Serialization.XmlSerializer. However, neither turned out to match my requirements, since:
SoapFormatter doesn't support serialization of generic types
XmlSerializer refuses to serialize types that implement IDictionary, not to mention that it's far less easy-to-use than "normal" serialization (e.g. see this SO question)
I'm wondering if there exists an implementation that doesn't have these limitations? I have found attempts (for example CustomXmlSerializer and YAXLib as suggested in a related SO question), but they don't seem to work either.
I was thinking about writing such serializer myself (though it certainly doesn't seem to be a very easy task), but then I find myself limited by the CLR, as I cannot create object instances of types that won't have a paramaterless constructor, even if I'm using reflection. I recall having read somewhere that implementations in System.Runtime.Serialization somehow bypass the normal object creation mechanism when deserializing objects, though I'm not sure. Any hints of how could this be done?
(See edit #3)
Could somebody please point me to the right direction with this?
Edit: I'm using .NET 3.5 SP1.
Edit #2: Just to be clear, I'd like a solution that is as much like using BinaryFormatter as possible, meaning that it should require the least possible extra code and annotations.
Edit #3: with some extra Googling, I found a .NET class called System.Runtime.Serialization.FormatterServices.GetUninitializedObject that actually can return "zeroed" objects of a specified type, which is great help in deserialization (if I get to implement it myself). I'd still like to find an existing solution though.

Ive had great success using the datacontractserializer class.here
Here's a pretty good article comparing serializers link

Depending on your .NET version and the complexity of your data, you may have luck using LINQ to XML to serialize:
internal class Inner
{
public int Number { get; set; }
public string NotNumber { get; set; }
}
internal class Outer
{
public int ID { get; set; }
public Dictionary<string, Inner> Dict { get; set; }
}
internal class Program
{
private static void Main()
{
var data = new Outer
{
ID = 1,
Dict =
new Dictionary<string, Inner>
{
{
"ABC",
new Inner
{
Number = 1,
NotNumber = "ABC1"
}
},
{
"DEF",
new Inner
{
Number = 2,
NotNumber = "DEF2"
}
}
}
};
var serialized =
new XDocument(new XElement("Outer",
new XAttribute("id", data.ID),
new XElement("Dict",
from i in data.Dict
select
new XElement(
"Entry",
new XAttribute(
"key", i.Key),
new XAttribute(
"number",
i.Value.Number),
new XAttribute(
"notNumber",
i.Value.
NotNumber)))));
Console.WriteLine(serialized);
Console.Write("ENTER to finish: ");
Console.ReadLine();
}
}
Result:
<Outer id="1">
<Dict>
<Entry key="ABC" number="1" notNumber="ABC1" />
<Entry key="DEF" number="2" notNumber="DEF2" />
</Dict>
</Outer>
Deserializing:
private static Outer Deserialize(XDocument serialized)
{
if (serialized.Root == null)
{
return null;
}
var outerElement = serialized.Root.Element("Outer");
if (outerElement == null)
{
return null;
}
return new Outer
{
ID =
int.Parse(
outerElement.Attribute("id").Value),
Dict =
outerElement.Element("Dict").
Elements("Entry").ToDictionary(
k => k.Attribute("key").Value,
v => new Inner
{
Number = Convert.ToInt32(v.Attribute("number").Value),
NotNumber = v.Attribute("notNumber").Value
})
};
}

Which version of the .NET Framework do you use? If you are on .NET 3.0 or higher, you may have luck with the DataContractSerializer or the NetDataContractSerializer. Both of those do serialize to XML but work quite different than the XmlSerializer.

Implementing custom XML serialization is not too bad. You could implement IXmlSerializable in the class that the normal XmlSerializer cannot support by default.
This CodeProject article has a good explanation of IXmlSerializable, and this blog post provides another look at more or less the same thing.

I suggest DataContractJsonSerializer, which gives shorter output and handles dictionaries better.

Related

.NET Core 6, Options Pattern, how to get array of json objects from appsettings

This particular set up continues to elude me. I'm on .NET Core 6, so all of the set up stuff is gone. I'm left with the code below (I think). I have a json array of objects. I've seen where people say that this is a dictionary, so I've tried this, but the values within the array don't populate.
I'm able to get simpler objects to populate their values. I've also tried this pattern according to other SO posts, but no dice.
I keep getting close, but no cigar - What am I doing wrong?
Appsettings.json:
"TimeSlotMenuIds": [
{
"FounderWallEvening": 900000000001136943
},
{
"BravoClubEvening": 900000000001136975
}
]
My mapping class:
public class TimeSlotMenuIds
{
public Dictionary<string, long> TimeSlotMenuId { get; set; }
}
The thing that doesn't populate the values from my json file:
var test = _configuration.GetSection("TimeSlotMenuIds").Get<TimeSlotMenuIds[]>();
var t2 = _configuration.GetSection("TimeSlotMenuIds").GetChildren();
Your JSON structure doesn't really lend itself to being deserialised as a Dictionary directly, instead it would work as an array of dictionaries e.g. Dictionary<string, long>[]. I'm sure you don't want this, so an option would be to manually process the configuration:
var test = Configuration.GetSection("TimeSlotMenuIds")
.GetChildren()
.ToDictionary(
x => x.GetChildren().First().Key,
x => long.Parse(x.GetChildren().First().Value));
Though I would suggest this is a nasty hack. Instead, you should fix the JSON to something like this:
"TimeSlotMenuIds": {
"FounderWallEvening": 900000000001136943,
"BravoClubEvening": 900000000001136975
}
Which would then allow you to do this:
var test = Configuration.GetSection("TimeSlotMenuIds").Get<Dictionary<string, long>>();

How to deserialize an object in ASP.NET?

I am trying to deserialize an object that an API sends me, but when doing so I cannot extract the values.
My object as JSON looks like this:
{
"Obj":
{
"id":19,
"name":"test",
"email":"test#mail.com",
"password":"0439434dae91c10c3bc073af1e76addf8f57a30ce0a7de0438b3aaad34b85200d41d01078f2ee786b3130b4ed4e39e3e26090da5d9f87420454dfdd182761cce",
"city":"Texas",
"age":37,
"date":"2022-05-09T00:00:00",
"mp":0,
"du":0,
"active":false,
"userid":0,
"user":""
},
"message":null,
"error":false,
"information":
{
"menssages":"Ok, Results",
"error":false,
"success":true,
"userId":0,
"user":"",
"register":0,
"pages":0
}
}
My code:
result = GetWebRequest("api/ClientId/" + id);
object rest = new JavaScriptSerializer().DeserializeObject(result.ToString());
Dictionary<string, object> keys = (Dictionary<string, object>)((object)rest);
I'd suggest using JSON.Net for both performance as well as features.
var account = JsonConvert.DeserializeObject<Account>(jsonString);
If you're using ASP.NET Core (not quite clear from your question/tags), you can also use the built-in System.Text.Json:
var weatherForecast = JsonSerializer.Deserialize<WeatherForecast>(jsonString);
Both approaches are much cleaner as you're working with classes instead of a Dictionary. Not that a Dictionary is wrong in any sense, this is just not an optimal use case for it, in particular because you're dealing with nested instances. Though in general, typed access to the properties of your data is almost always a preferred solution.

Can roslyn generate enums?

So, I feel like it's possible, but i don't have the chops to put it together. I have lookup tables (with ID and Name fields). I have enums that I keep in sync with the lookups. What I'd like is to make a list of SQL tables, and have roslyn create the enums during/before compile. this way I know my enums are always in sync, and it's one more thing off my plate.
Could someone out there show me the way, or tell me why it would be a bad idea? I feel like the solution isn't really a lot of code...
Thanks!
This is how you create enums with roslyn;
class Program
{
static void Main(string[] args)
{
var member1 = Syntax.EnumMemberDeclaration(
identifier: Syntax.Identifier("Member1")
);
var declaration = Syntax.EnumDeclaration(
identifier: Syntax.Identifier("MyEnum"),
modifiers: Syntax.TokenList(Syntax.Token(SyntaxKind.PublicKeyword)),
members: Syntax.SeparatedList(member1)
);
Console.WriteLine(declaration.Format());
Console.ReadLine();
}
}
this returns:
public enum MyEnum
{
Member1
}
Now to your question, I don't know if this is what you really need.
First I think there is not yet any built in functionality to do this at precompile, so you'd need to create a console exe and call it in your prebuild events.
So at this point probably it is a better idea to do this manually via code generation and not on every build, unless these tables are changing very frequently.
An in this case you don't really need roslyn to do it for you, you can just spit it out with any code generation software, or roll your own...
Here is some code updated for the current version of Roslyn and also shows adding attributes and values to the enum items.
public EnumDeclarationSyntax GenerateEnum()
{
var loanPurpose = new[]
{
"Business Launching",
"HomePurchase",
"HomeImprovement"
};
var enumDescriptions = new[]
{
"Launch a new business",
"Buy a home",
"Make home improvements"
};
var i = 0;
var members = new List<EnumMemberDeclarationSyntax>();
foreach (var item in loanPurpose)
{
var attribute = SyntaxFactory.Attribute(
SyntaxFactory.IdentifierName("Description"));
var attributeArgument = SyntaxFactory.AttributeArgument(
SyntaxFactory.LiteralExpression(
SyntaxKind.StringLiteralExpression,
SyntaxFactory.Literal(enumDescriptions[i ])));
attribute = attribute.WithArgumentList(
SyntaxFactory.AttributeArgumentList(
SyntaxFactory.SingletonSeparatedList(attributeArgument)));
var attributes = SyntaxFactory.SingletonList(
SyntaxFactory.AttributeList(SyntaxFactory
.SingletonSeparatedList(attribute)));
var objectCreationExpression = SyntaxFactory.EqualsValueClause(
SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression,
SyntaxFactory.Literal(i)));
var member = SyntaxFactory.EnumMemberDeclaration(attributes,
SyntaxFactory.Identifier(item),
objectCreationExpression);
members.Add(member);
i++;
}
var declaration = SyntaxFactory.EnumDeclaration
(new SyntaxList<AttributeListSyntax>(),
baseList: null,
identifier: SyntaxFactory.Identifier("LoanPurpose"),
modifiers: SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.PublicKeyword)),
members: SyntaxFactory.SeparatedList(members)
);
return declaration;
}
The syntax for adding the attributes gets a little awkward but I find that I often need some attributes added. You probably already have the data for the attributes and values in the lookup tables driving the code generation.
The Answer provided by Sebastian 6 years ago likely used to work but no longer does.
New set of sample code to accomplish the same thing as of 18/12/2017
EnumMemberDeclarationSyntax member1 = EnumMemberDeclaration(identifier: Identifier("Member1"));
var members =new SyntaxNodeOrToken[]{member1};
var declaration = EnumDeclaration(
identifier: Identifier("MyEnum")).WithMembers(
members: SeparatedList< EnumMemberDeclarationSyntax>(members));

XML serialization and LINQ

I've currently got an XML element in my database that maps to an object (Long story short the XML is complicated and dynamic enough to defy a conventional relational data structure without massive performance hits).
Around it I've wrapped a series of C# objects that encapsulate the structure of the XML. They work off a base class and there's multiple different possible classes it'll deserialize to with different data structures and different implemented methods. I'm currently wrapping the functionality to serialize/deserialize these into a partial class of the LINQ-generated database objects.
My current approach to this is:
public Options GetOptions()
{
if (XmlOptions == null) return null;
XmlSerializer xs = new XmlSerializer(typeof(Options));
return (Options)xs.Deserialize(XmlOptions.CreateReader());
}
public void SetOptions(Options options)
{
if (XmlOptions == null) Options = null;
else
{
XmlSerializer xs = new XmlSerializer(typeof(Options));
using (MemoryStream ms = new MemoryStream())
{
xs.Serialize(ms, options);
XmlOptions = System.Xml.Linq.XElement.Parse(System.Text.UTF8Encoding.UTF8.GetString(ms.ToArray()));
}
}
}
(To help with reading given the changed names aren't too clear, XmlOptions is the XElement element from LINQ and Options is my class it deserializes into)
Now, it works. But that's not really enough to call it "finished" to me :P It just seems incredibly inefficient to serialize XML to a memory stream, convert it to a string, then re-parse it as XML. My question is - Is this the cleanest way to do this? Is there a more efficient/tidy mechanism for doing the serialization? Is there a better approach that'll give me the same benefits (I've only got test data in the system so far, so I can change the XML structure if required)?
PS: I've renamed the fields to be more generic - so don't really need comments about naming conventions ;)
XmlSerializer.Serialize has an overload that takes an XmlWriter.
You can create an XmlWriter that writes to an existing XElement by calling the CreateWriter method.
You can therefore write the following:
static readonly XmlSerializer xs = new XmlSerializer(typeof(Options));
...
var temp = new XElement("Parent");
using (var writer = temp.CreateWriter())
xs.Serialize(writer, options);
XmlOptions = Temp.FirstNode;

c# looping object creation

I'm very new with c#, and was previously attempting to ignore classes and build my small program structurally more similar to PHP. After reaching a road block, I'm trying to start over and approach the problem properly OO. I'm taking a long file, and in a loop, every time certain conditions are met, I want to make a new object. How can I have it create a new object, without having to specify a unique name?
Referral ObjectName = new Referral(string, string, int);
Secondly, once this is done, and the strings & int set their appropriate object properties, how can i unique-ify the class by one property, and then sort the class by another?
I'm sorry if these are basic questions, I have spent a large, large amount of time first trying to figure it out on my own with google, and a textbook. If only C# would allow multi-dimensional arrays with different types!
Thank you so much!
PS. I do mean to extract a list of unique objects.
All these answers, while helpful, seem to involve creating a shadow set of IEnumerables. Is there no way to do this with the class itself?
Trying the first solution, provided by Earwicker, adding each object to a List from within the loop, when I try to Write a property of the element to the console, i get the ClassName+Referral. What could I be doing wrong?--solved. still needed .property
still working. . .
C# does allow untyped arrays. All objects are derived ultimately from object, so you use an array or container of objects. But it's rarely necessary. How many types of object do you have?
Within the loop block, you can create an object exactly as you do in that line of code (except with the syntax fixed), and it will be a new object each time around the loop. To keep all the objects available outside the loop, you would add it to a container:
List<Referral> referrals = new List<Referral>();
// in the loop:
Referral r = new Referral(str1, str2, num1);
referrals.Add(r);
Suppose Referral has a numeric property called Cost.
referrals.Sort((l, r) => l.Cost - r.Cost);
That sorts by the cost.
For ensuring uniqueness by some key, you may find it easier to pick a more suitable container.
Dictionary<string, Referral> referrals = new List<Referral>();
// in the loop:
Referral r = new Referral(str1, str2, num1);
referrals[str1] = r;
This stores the referral in a "slot" named after the value of str1. Duplicates will overwrite each other silently.
First, you're going to need to spend some time familiarizing yourself with the basics of the language to be productive. I recommend you take a little time to read up on C# before getting in too deep - otherwise you'll spend a lot of your time spinning your wheels - or reinventing them :)
But here's some info to get you started.
Typically, in C# you create classes to represent elements of your program - including those that are used to represent information (data) that your program intends to manipulate. You should really consider using one, as it will make data manipulation clearer and more manageable. I would advise avoiding untyped, multi-dimensions array structures as some may suggest, as these rapidly become very difficult to work with.
You can easily create a Referall class in C# using automatic properties and a simple constructor:
public class Referall
{
// these should be named in line with what they represent...
public string FirstString { get; set; }
public string AnotherString { get; set; }
public int SomeValue { get; set; }
public Referall( string first, string another, int value )
{
FirstString = first;
AnotherString = another;
SomeValue = value;
}
}
You can add these to a dictionary as you create them - the dictionary can be keyed by which ever property is unique. Dictionaries allow you to store objects based on a unique key:
Dictionary<string,Referall> dict = new Dictionary<string,Referall>();
As you process items, you can add them to the dictionary:
Referall ref = new Referall( v1, v2, v3 );
// add to the dictionary, keying on FirstString...
dict.Add( ref.FirstString, ref );
If you need to sort items in the dictionary when you're done, you can use LINQ in C# 3.0:
IEnumerable<Referall> sortedResults =
dict.Values.OrderBy( x => x.AnotherString );
You can sort by multiple dimension using ThenBy() as well:
IEnumerable<Referall> sortedResults =
dict.Values.OrderBy( x => x.AnotherString )
.ThenBy( x => x.SomeValue );
List<Referral> referrals = new List<Referral>();
for (...)
{
referrals.Add(new Referral(string1, string2, number1));
}
Then, if you're using Linq (which I highly suggest), you can do this:
IEnumerable<Referral> sorted = referrals.OrderBy(x => x.string1).ThenBy(x => x.string2);
Otherwise, you can use the Sort() method on List<Referral>.
You can create an object without a reference, but you won't have any access to it later:
new Referral(string, string, int);
If you wish to put them in an array/list, these different types need to have a common base class. This is called polimorfism, which is a very important concept in OO programming.
You cannot ignore classes while using c#. Don't resist the change!
Do you really not need to create a class here? Do you really not need to give it a name? C# does allow loose typing, but type safety is a good thing.
I don't fully understand what you're trying to do. But maybe LINQ is what you're looking for. There's tons of documentation around, but as a quick 'teaser' have a look at the 101 Linq samples on MSDN
C# includes a wonderful feature called "iterator blocks". What you want to do is use the yield keyword to create an Enumerable of your Referal object, something like this (not that I'm making the file format and property names up, because you didn't share that):
public class Referral
{
public Guid id { get; private set; } // "uniquify"
public int ReferringId { get; set; }
public string ReferrerText { get; set; }
public string ReferrerDescription { get; set; }
private Referral()
{
id = new Guid();
}
private Referral(string Text, string Description, int ReferringId) : this()
{
this.ReferrerText = Text;
this.ReferrerDescription = Description;
this.ReferringId = ReferringId;
}
public static IEnumerable<Referral> GetReferrals(string fileName)
{
using (var rdr = new StreamReader(fileName))
{
var next = new Referrer();
int state = 0;
string line;
while ( (line = rdr.ReadLine() ) != null)
{
switch (state)
{
case 0:
next.ReferrerText = line;
state = 1;
break;
case 1:
next.ReferrerDescription = line;
state = 2;
break;
case 2:
next.ReferringId = int.Parse(line);
yield return next;
next = new Referral();
state = 0;
break;
}
}
}
}
}
Now you want to sort the referrals and presumable enumerate over them for some purpose. You can do that easily like this:
foreach (var referral in Referral.GetReferrals(#"C:\referralfile.txt").OrderBy( r => r.Text ) )
{
OutputReferral(referral);
}

Categories