XmlEnum Multiple name for a single value - c#

I have this scenario, declaring a enum type. Like this:
[Serializable]
[XmlTypeAttribute(Namespace = "urn:un:unece:uncefact:codelist:specification:5639:1988")]
public enum LanguageCodeContentType {
/// <summary>
/// Afar
/// </summary>
[XmlEnum(Name = "AA")]
AA,
/// <summary>
/// Abkhazian
/// </summary>
[XmlEnum(Name = "AB")]
AB,
/// <summary>
/// Afrikaans
/// </summary>
[XmlEnum(Name = "AF")]
AF,
[...]
}
Now what I need is declaring multiple name for each value of the enum. Something like this
[Serializable]
[XmlTypeAttribute(Namespace = "urn:un:unece:uncefact:codelist:specification:5639:1988")]
public enum LanguageCodeContentType {
/// <summary>
/// Afar
/// </summary>
[XmlEnum(Name = "AA"),XmlEnum(Name = "aa")]
AA,
/// <summary>
/// Abkhazian
/// </summary>
[XmlEnum(Name = "AB", XmlEnum(Name = "bb"))]
AB,
/// <summary>
/// Afrikaans
/// </summary>
[XmlEnum(Name = "AF"), XmlEnum(Name = "af")]
AF,
[...]
}

It's been a will, but I came along to this issue today.
I solved this by introducing multiple entries in my enumeration.
public enum LanguageCodeContentType {
AA = 0,
aa = 0,
AB = 1,
ab = 1,
AF = 2,
af = 2,
[...]
}
By this ether, "aa" or "AA" could be serialized.

Related

How to pull a List of objects from FormDataCollection

I'm calling my API via a post. I am trying to get the values out from the FormDataCollection, but I cannot figure out how to get the list called ResourcesInfo?
UPDATE:
Here are the raw values:
Here is my setup:
What am I doing wrong here?
var resourceInfo2 = form.Get("ResourcesInfo");
var resourceInfo = JsonConvert.DeserializeObject<IList<SchedulerConflictResourceInfoModel>>(form.Get("ResourcesInfo"));
namespace WebPortal.MVC.Areas.Scheduler.Models
{
using System;
using System.Collections.Generic;
/// <summary>
/// Scheduler conflict param model
/// Obtain the values after the start or end date changes to check for conflicts
/// </summary>
public class SchedulerConflictParamModel
{
/// <summary>
/// Gets or sets the start date.
/// </summary>
/// <value>
/// The start date.
/// </value>
public DateTime StartDate { get; set; }
/// <summary>
/// Gets or sets the end date.
/// </summary>
/// <value>
/// The end date.
/// </value>
public DateTime EndDate { get; set; }
/// <summary>
/// Gets or sets the resources information.
/// </summary>
/// <value>
/// The resources information.
/// </value>
public IList<SchedulerConflictResourceInfoModel> ResourcesInfo { get; set; }
}
}
namespace WebPortal.MVC.Areas.Scheduler.Models
{
/// <summary>
/// Scheduler conflict resource info model
/// Holds the resource type id and resource id to check for conflicts
/// </summary>
public class SchedulerConflictResourceInfoModel
{
/// <summary>
/// Gets or sets the resource type identifier.
/// </summary>
/// <value>
/// The resource type identifier.
/// </value>
public int ResourceTypeId { get; set; }
/// <summary>
/// Gets or sets the resource identifier.
/// </summary>
/// <value>
/// The resource identifier.
/// </value>
public int ResourceId { get; set; }
}
}
function schedulerCheckForConflicts2(model) {
var deferred = $.Deferred()
let apiUrl = BuildSafeURL("api/SchedulerData/SchedulerCheckForConflicts", null)
$.post(apiUrl, {
StartDate: model.StartDate,
EndDate: model.EndDate,
ResourcesInfo: model.ResourcesInfo
})
.done(function (conflicts) {
DevExpress.ui.notify("called server... ", "warning", 1200)
deferred.resolve(conflicts)
})
.fail(function (error) {
genericErrorMessage()
console.log("error⚠️", error)
})
return deferred.promise();
}
/// <summary>
/// Gets the items scheduler file manager.
/// </summary>
/// <param name="form">The form.</param>
/// <returns>File system items</returns>
[HttpPost]
[WebAPIValidateAntiForgeryToken]
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
public async Task<HttpResponseMessage> SchedulerCheckForConflicts(FormDataCollection form)
#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously
{
var startDate = form.Get("StartDate");
var endDate = form.Get("EndDate");
var resourceInfo2 = form.Get("ResourcesInfo");
var resourceInfo = JsonConvert.DeserializeObject<IList<SchedulerConflictResourceInfoModel>>(form.Get("ResourcesInfo"));
var schedulerConflictParamModel = new SchedulerConflictParamModel();
return Request.CreateResponse(new List<int>
{
1, 2, 3
});
}

Unable to assign to Hashtable item in C# class consumed from VBA

I have written a C# class (KvpHash) for consumption in VBA which provides additional useful functionality around a Hashtable. In my VBA code I have an extensive Rubberduck test suite for the KvpHash class that shows all functions of the class work as expected except for the fact that I cannot change the value of an item.
From VBA I get the error message
424 'Object required'
In the C# class the interface code is
dynamic this[dynamic Key] { get; set; }
and the implementation is
public dynamic this[dynamic Key]
{
get
{
return MyKvpHash[Key];
}
set
{
MyKvpHash[Key] = value;
}
}
where MyKvpHash is defined as
private Hashtable MyKvpHash = new Hashtable();
If I add the mscorelib reference to VBA I can create a Hashtable directly in VBA where it is fully possible to change the value of an item in the Hash Table.
I'd appreciate pointers as to what I am doing wrong in the C# code which causes the object required error.
Edited: to add example VBA code
Using a native HashTable
Public Sub TestHashtable()
' requires reference to mscorlib.dll
Dim myHt As Hashtable
Set myHt = New Hashtable
myHt.Add 5, "Hello5"
myHt.Add 10, "Hello10"
Debug.Print myHt.Item(10)
Debug.Print myHt.Item(5)
' the next line works as expected
myHt.Item(10) = "A new world"
Debug.Print myHt.Item(10)
End Sub
Gives the output
Hello10
Hello5
A new world
Using my KvpHash class ( a wrapper for HashTable)
Public Sub TestKvpHash()
Dim myHt As VBAExtensions.KvpHash
' KvpHash is a C# wrapper for a System.Collections.HashTable
Set myHt = New KvpHash
myHt.AddByKey 5, "Hello5"
myHt.AddByKey 10, "Hello10"
Debug.Print myHt.Item(10)
Debug.Print myHt.Item(5)
' The next line produces error 424
myHt.Item(10) = "A new world"
Debug.Print myHt.Item(10)
End Sub
Gives the output
Hello10
Hello5
and then stops with the 424 error.
Edited to add the full C# code as requested.
Seems there is no file hosting and I don't have another means of providing a link so I'v inserted the relevant code below. The code was originally based on a Dictionary but I updated it to Hashtable when I first found I couldn't assign to an item. That switch didn't change the behaviour of my code. Please be aware that I'm not a professional programmer and that the supplied code is essentially my first foray into C#. Typically I write Word VBA macros for my own consumption.
// VBAExtensions
//
// C# Library module for VBA
using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Linq;
namespace VBAExtensions
{
/// <summary>
/// Enum for accessing the kvphash structure returned by Method Cohorts
/// </summary>
public enum CohortType
{
/// <summary>1 = the keys in A plus keys in B that are not shared</summary>
KeysInAAndOnlyB = 1,
/// <summary>2 = the Keys from B in A where B has a different value to A</summary>
KeysInAandBWithDifferentValues,
/// <summary>3 = the keys that are only in A and only in B</summary>
KeysNotInAandB,
/// <summary>4 = the keys that are inA and B </summary>
KeysInAandB,
/// <summary>5 = the keys in A only </summary>
KeysInAOnly,
/// <summary>6 = the keys in B only</summary>
KeysInBOnly
}
/// <summary>
/// KvpHash is a C# class for VBA which implements a Key/Value HashTable
/// The object is a morer flexible version of the Scripting.Dictionary
/// </summary>
[Guid("30F9294B-11B4-4D91-9D7C-7FF02ADB3F11")]
[ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface IKvpHash
{
/// <summary>
/// Returns/Sets the "Value" specified by "Key" (i) of a Key/Value Pair
/// </summary>
/// <param name="Key"></param>
/// <returns>Type used in Set statement (C# dynamic)</returns>
dynamic this[dynamic Key] { get; set; }
/// <summary>
/// Adds "Value" to the KvpHash using an integer (VBA Long) Key.
/// The integer key is based on the first available integer greater than or
/// equal to the Count of the KvpHash
/// </summary>
/// <param name="Value"></param>
void AddByIndex(dynamic Value);
/// <summary>
/// Populates this KvpHash using AddByIndex for each character in the string
/// </summary>
/// <param name="this_string"></param>
void AddByIndexAsChars(string this_string);
/// <summary>
/// Pupulates this KvpHash using AddByIndex for each substring in this_string delineated by this_seperator
/// </summary>
/// <param name="this_string"></param>
/// <param name="this_seperator"></param>
void AddByIndexAsSubStr(string this_string, string this_seperator = ",");
/// <summary>
/// Pupulates a KvpHash using AddByIndex for each array item
/// </summary>
/// <param name="this_array"></param>
void AddByIndexFromArray(dynamic this_array);
/// <summary>
/// Adds "Value" to the KvpHash with a key pf "Key"
/// </summary>
/// <param name="Key"></param>
/// <param name="Value"></param>
void AddByKey(dynamic Key, dynamic Value);
/// <summary>
/// Groups the keys of the two KvpHash
/// </summary>
/// <param name="ArgKvpHash"></param>
/// <returns>An array of 6 KvpHash
/// keys in a {1,2,3,4,5,6}
/// keys in b {1,2,3,6,7,8}
/// 1 = the keys in A plus keys in B that are not shared {1,2,3( from A),4,5,6,7,8}
/// 2 = the Keys from B in A where B has a different value to A {3( from B) if value is different}
/// 3 = the keys that are only in A and only in B {4,5,7,8}
/// 4 = the keys that are in A and B {1,2,3,6}
/// 5 = the keys in A only {4,5}
/// 6 = the keys in B only {7,8}
/// </returns>
KvpHash Cohorts(KvpHash ArgKvpHash);
/// <summary>
/// The number of key/vaue pairs in the KvpHash
/// </summary>
/// <returns>Long</returns>
int Count();
///// <summary>
///// Return the IEnumerator interface for KvpHash
///// </summary>
///// <returns>IEnumerator</returns>
//IEnumerator GetEnumerator();
/// <summary>
/// Gets the "Key" for the first ocurrence of "Value" in the KvpHash.
/// </summary>
/// <param name="Value"></param>
/// <returns>Key</returns>
dynamic GetKey(dynamic Value);
/// <summary>
/// Returns a variant array of the Keys of the KvpHash
/// </summary>
/// /// <returns>Variant Array</returns>
dynamic[] GetKeys();
/// <summary>
/// Returns a variant array of the values of the KvpHash
/// </summary>
/// <returns>Variant Array</returns>
dynamic[] GetValues();
/// <summary>
/// True if the "Key" exists in the keys of the KvpHash
/// </summary>
/// <param name="Key"></param>
/// <returns>Boolean</returns>
bool HoldsKey(dynamic Key);
/// <summary>
/// True if the "Value" exists in the values of the KvpHash
/// </summary>
/// <param name="Value"></param>
/// <returns>Boolean</returns>
bool HoldsValue(dynamic Value);
/// <summary>
/// True if the KvpHash holds 0 key/value pairs
/// </summary>
/// <returns>Boolean</returns>
bool IsEmpty();
/// <summary>
/// True if the KvpHash holds one or more key/value pairs
/// </summary>
/// <returns>Boolean</returns>
bool IsNotEmpty();
/// <summary>
/// True is the "Key" is not found in the keys of the KvpHash
/// </summary>
/// <param name="Key"></param>
/// <returns>Boolean</returns>
bool LacksKey(dynamic Key);
/// <summary>
/// True if the "Value" is not found in the values of the KvpHash
/// </summary>
/// <param name="Value"></param>
/// <returns>Boolean</returns>
bool LacksValue(dynamic Value);
/// <summary>
/// Reverses the Key/Value pairs in a KvpHash
/// </summary>
/// <returns>New KvpHash where:
/// KvpHash.Value(1) = KvpHash Unique values as Value/Key pairs
/// KvpHash.Value(2) = KvpHash Non unique values as Key/Value pairs</returns>
KvpHash Mirror();
/// <summary>
/// Removes the Key/Value pair spacified by "Key" from the KvpHash
/// </summary>
/// <param name="Key"></param>
void Remove(dynamic Key);
/// <summary>
/// Removes all Key/Value pairs from the KvpHash
/// </summary>
void RemoveAll();
/// <summary>
/// Returns true if the Values in KvpHash are unique.
/// </summary>
/// <returns>Boolean</returns>
bool ValuesAreUnique();
/// <summary>
/// Returns true if the Values in KvpHash are not unique.
/// </summary>
/// <returns>Boolean</returns>
bool ValuesAreNotUnique();
}
[Guid("87E5A539-FDB3-40D0-9CCD-C817F9893C08")]
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.AutoDual)]
public class KvpHash : IKvpHash, IEnumerable
{
private Hashtable MyKvpHash = new Hashtable();
public dynamic this[dynamic Key]
{
get
{
return MyKvpHash[Key];
}
set
{
MyKvpHash[Key] = value;
}
}
public void AddByIndex(dynamic Value)
{
int my_index = MyKvpHash.Count + 1;
while (MyKvpHash.ContainsKey(my_index))
{
my_index++;
}
MyKvpHash.Add(my_index, Value);
}
public void AddByIndexAsChars(string this_string)
{
int my_index = MyKvpHash.Count + 1;
while (MyKvpHash.ContainsKey(my_index))
{
my_index++;
}
char[] MyArray = this_string.ToCharArray();
MyKvpHash.Clear();
for (int i = 0; i <= MyArray.GetUpperBound(0); i++)
{
//KvpHash uses ordinal indexes
MyKvpHash.Add(i + 1, MyArray[i].ToString());
}
}
public void AddByIndexAsSubStr(string this_string, string this_seperator = ",")
{
int my_index = MyKvpHash.Count + 1;
while (MyKvpHash.ContainsKey(my_index))
{
my_index++;
}
string[] MyArray = this_string.Split(this_seperator.ToArray());
for (int i = 0; i <= MyArray.GetUpperBound(0); i++)
{
//KvpHash uses ordinal indexes
MyKvpHash.Add(i + 1, MyArray[i]);
}
}
public void AddByIndexFromArray(dynamic this_array)
{
int my_index = MyKvpHash.Count + 1;
while (MyKvpHash.ContainsKey(my_index))
{
my_index++;
}
for (int i = 0; i <= this_array.GetUpperBound(0); i++)
{
//KvpHash uses ordinal indexes
MyKvpHash.Add(i + 1, this_array[i]);
}
}
public void AddByKey(dynamic Key, dynamic Value)
{
MyKvpHash.Add(Key, Value);
}
public KvpHash Cohorts(KvpHash ArgKvpHash)
{
KvpHash ResultKvpHash = new KvpHash();
// VBA reports object not set error if the resuly KvpHash are not newed
for (int i = 1; i < 7; i++)
{
ResultKvpHash.AddByKey(i, new KvpHash());
}
foreach (DictionaryEntry MyKvpHashPair in MyKvpHash)
{
// A plus unique in B
ResultKvpHash[1].AddByKey(MyKvpHashPair.Key, MyKvpHashPair.Value);
if (ArgKvpHash.LacksKey(MyKvpHashPair.Key)) // problem is here
{
// In A only or in B only
ResultKvpHash[3].AddByKey(MyKvpHashPair.Key, MyKvpHashPair.Value);
// In A only
ResultKvpHash[5].AddByKey(MyKvpHashPair.Key, MyKvpHashPair.Value);
}
else
{
// In A and In B
ResultKvpHash[4].AddByKey(MyKvpHashPair.Key, MyKvpHashPair.Value);
}
}
foreach (dynamic MyKey in ArgKvpHash.GetKeys())
{
// B in A with different value
if (ResultKvpHash[1].LacksKey(MyKey)) // Result 0 will contain all of A
{
ResultKvpHash[1].AddByKey(MyKey, ArgKvpHash[MyKey]);
ResultKvpHash[3].AddByKey(MyKey, ArgKvpHash[MyKey]);
ResultKvpHash[6].AddByKey(MyKey, ArgKvpHash[MyKey]);
}
else
{
if (ResultKvpHash[1][MyKey] != ArgKvpHash[MyKey])
{
ResultKvpHash[2].AddByKey(MyKey, ArgKvpHash[MyKey]);
}
}
}
return ResultKvpHash;
}
public Int32 Count()
{
return MyKvpHash.Count;
}
public bool IsEmpty()
{
return MyKvpHash.Count == 0;
}
public bool IsNotEmpty()
{
return !IsEmpty();
}
public IEnumerator GetEnumerator()
{
foreach (DictionaryEntry my_pair in MyKvpHash)
{
yield return my_pair.Value;
}
}
public dynamic GetKey(dynamic Value)
{
return this.Mirror()[1][Value];
}
public dynamic[] GetKeys()
{
return (dynamic[]) MyKvpHash.Keys;
}
public dynamic[] GetValues()
{
return (dynamic[]) MyKvpHash.Values;
}
public bool HoldsKey(dynamic Key)
{
return MyKvpHash.ContainsKey(Key);
}
public bool HoldsValue(dynamic Value)
{
return MyKvpHash.ContainsValue(Value);
}
public bool LacksKey(dynamic Key)
{
return !HoldsKey(Key);
}
public bool LacksValue(dynamic Value)
{
return !HoldsValue(Value);
}
public KvpHash Mirror()
{
KvpHash MyResult = new KvpHash();
MyResult.AddByIndex(new KvpHash());
MyResult.AddByIndex(new KvpHash());
foreach (DictionaryEntry my_pair in MyKvpHash)
{
if (MyResult[1].LacksKey(my_pair.Value))
{
MyResult[1].AddByKey(my_pair.Value, my_pair.Key);
}
else
{
MyResult[2].AddByKey(my_pair.Key, my_pair.Value);
}
}
return MyResult;
}
public void Remove(dynamic Key)
{
MyKvpHash.Remove(Key);
}
public void RemoveAll()
{
MyKvpHash.Clear();
}
public bool ValuesAreUnique()
{
return MyKvpHash.Count == ((dynamic[]) MyKvpHash.Values).Distinct().Count();
}
public bool ValuesAreNotUnique()
{
return !ValuesAreUnique();
}
}
}
#Freeflow if You change in Word Module the myHt definition it will by OK and will work fine.
Public Sub TestKvpHash()
Dim myHt As Object
' KvpHash is a C# wrapper for a System.Collections.HashTable
Set myHt = New VBAExtensions.KvpHash
' Rest of code

How to generate descriptions on enums from XML documentation for Swashbuckle?

I have a model with the following enum in my .NET Core web api project:
public enum Industries
{
Undefined = 0,
/// <summary>
/// Agriculture, Forestry, Fishing and Hunting
/// </summary>
AgricultureForestryFishingAndHunting = 1,
Mining = 2,
Utilities = 3,
Construction = 4,
/// <summary>
/// Computer and Electronics Manufacturing
/// </summary>
ComputerAndElectronicsManufacturing = 5,
/// <summary>
/// Other Manufacturing
/// </summary>
OtherManufacturing = 6,
Wholesale = 7,
Retail = 8,
/// <summary>
/// Transportation and Warehousing
/// </summary>
TransportationAndWarehousing = 9,
Publishing = 10,
Software = 11,
Telecommunications = 12,
Broadcasting = 13,
/// <summary>
/// Information Services and Data Processing
/// </summary>
InformationServicesAndDataProcessing = 14,
/// <summary>
/// Other Information Industry
/// </summary>
OtherInformationIndustry = 15,
/// <summary>
/// Finance and Insurance
/// </summary>
FinanceAndInsurance = 16,
/// <summary>
/// Real Estate, Rental and Leasing
/// </summary>
RealEstateRentalAndLeasing = 17,
/// <summary>
/// College, University, and Adult Education
/// </summary>
CollegeUniversityAndAdultEducation = 18,
/// <summary>
/// Primary/Secondary (K-12) Education
/// </summary>
PrimarySecondaryK12Education = 19,
/// <summary>
/// Other Education Industry
/// </summary>
OtherEducationIndustry = 20,
/// <summary>
/// Health Care and Social Assistance
/// </summary>
HealthCareAndSocialAssistance = 21,
/// <summary>
/// Arts, Entertainment, and Recreation
/// </summary>
ArtsEntertainmentAndRecreation = 22,
/// <summary>
/// Hotel and Food Services
/// </summary>
HotelAndFoodServices = 23,
/// <summary>
/// Government and Public Administration
/// </summary>
GovernmentAndPublicAdministration = 24,
/// <summary>
/// Legal Services
/// </summary>
LegalServices = 25,
/// <summary>
/// Scientific or Technical Services
/// </summary>
ScientificorTechnicalServices = 26,
Homemaker = 27,
Military = 28,
Religious = 29,
/// <summary>
/// Other Industry
/// </summary>
OtherIndustry = 30
}
I then wire up swashbuckle to include the XML documentation file:
services.AddSwaggerGen(c =>
{
c.IncludeXmlComments(Path.Combine(AppDomain.CurrentDomain.BaseDirectory,
"MySolution.xml"), true);
c.IncludeXmlComments(Path.Combine(AppDomain.CurrentDomain.BaseDirectory,
"MySolution.Client.xml"), true);
c.IncludeXmlComments(Path.Combine(AppDomain.CurrentDomain.BaseDirectory,
"MySolution.Common.xml"), true);
c.DescribeAllEnumsAsStrings();
c.SwaggerDoc("v1",
new Info {Title = "My Solution", Version = "v1"});
c.DescribeAllParametersInCamelCase();
c.DescribeStringEnumsInCamelCase();
c.IgnoreObsoleteProperties();
c.UseReferencedDefinitionsForEnums();
c.CustomSchemaIds(x => x.FullName);
});
When running this and viewing the swagger.json document, I don't see my XML comments for the enum values at all, just the values:
"definitions": {
...
"MySolution.Common.Models.Industries": {
"enum": [
"undefined",
"agricultureForestryFishingAndHunting",
"mining",
"utilities",
"construction",
"computerAndElectronicsManufacturing",
"otherManufacturing",
"wholesale",
"retail",
"transportationAndWarehousing",
"publishing",
"software",
"telecommunications",
"broadcasting",
"informationServicesAndDataProcessing",
"otherInformationIndustry",
"financeAndInsurance",
"realEstateRentalAndLeasing",
"collegeUniversityAndAdultEducation",
"primarySecondaryK12Education",
"otherEducationIndustry",
"healthCareAndSocialAssistance",
"artsEntertainmentAndRecreation",
"hotelAndFoodServices",
"governmentAndPublicAdministration",
"legalServices",
"scientificorTechnicalServices",
"homemaker",
"military",
"religious",
"otherIndustry"],
"type": "string"
}
}
What am I missing to make this work? I'm using v 2.5.0 of Swashbuckle, which looks like the latest and greatest.
Comments for the enum values are not supported by the OAS (OpenAPI-Specification) :
5.5.1.1. Valid values
The value of this keyword MUST be an array. This array MUST have at
least one element. Elements in the array MUST be unique.
Elements in the array MAY be of any type, including null.
https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#items-object
https://datatracker.ietf.org/doc/html/draft-fge-json-schema-validation-00#section-5.5.1

Understanding Serialization

Context
I'm trying to understand how to use Serialization, never used it previously.
Right now I have a populate method in my singleton object (Main class) that basically adds a few member objects to a list of members using my addMember methods
I want to serialize this Members List Once I can serialize and deserialize the list I can delete my populate method.
Questions
HOW do I serialize this list so that the members list is deserialized upon startup?
WHERE do I serialize specifically? Do I serialize when I'm creating a new member, or do I just serialize the list at shutdown and deserialize at startup.
Since member information can be edited, how do I serialize the updates and overwrite the previously held data?
Code Listings
I'm kinda new to Serialization, but here's my code, I'm using a method for this because I I think it's cleaner this way, using ISerializable in my main class. Here's a few snippets from my main class, keep in mind I have tons of comments in my code, that's kinda why I didn't post this previously:
namespace HillRacingGraded
{
[Serializable]
public class HillRacing : ISerializable
{
/// <summary>
/// Singleton object hillracing
/// </summary>
private static HillRacing hillracing;
GUIUtility gui = new GUIUtility();
/// <summary>
/// Instance property returns the singleton instance
/// </summary>
public static HillRacing Instance
{
get
{
if (hillracing == null)
hillracing = new HillRacing();
return hillracing;
}
}
/// <summary>
/// public Property that returns races list, can be accessed by other classes.
/// </summary>
public List<BaseRace> Races
{
get
{
return races;
}
set
{
races = value;
}
}
/// <summary>
/// public Property that returns members list, can be accessed by other classes.
/// </summary>
public List<BaseMember> Members
{
get
{
return members;
}
set
{
members = value;
}
}
/// <summary>
/// instantiate the list of members
/// </summary>
private List<BaseMember> members; //I WANT TO SERIALIZE THIS
/// <summary>
/// instantiate the list of races
/// </summary>
private List<BaseRace> races; //I WANT TO SERIALIZE THIS
/// <summary>
/// Default constructor for hillracing.
/// </summary>
public HillRacing()
{
//members is a new list of the BaseMember objects.
//races is a new list of the BaseRace objects.
members = new List<BaseMember>();
races = new List<BaseRace>();
//call the populate method on launch, mostly for testing purposes.
Populate();
}
/// <summary>
/// Hillracing constructor for serialization
/// </summary>
/// <param name="info"></param>
/// <param name="ctxt"></param>
public HillRacing(SerializationInfo info, StreamingContext ctxt)
{
this.members = (List<BaseMember>)info.GetValue("Members", typeof(List<BaseMember>));
this.races = (List<BaseRace>)info.GetValue("Races", typeof(List<BaseRace>));
}
/// <summary>
/// get object data
/// </summary>
/// <param name="info"></param>
/// <param name="ctxt"></param>
public void GetObjectData(SerializationInfo info, StreamingContext ctxt)
{
info.AddValue("Members", this.members);
}
/// <summary>
/// Adds a new junior member to the list of all members.
/// </summary>
/// <param name="stringfirstname">first name of the member</param>
/// <param name="stringlastname">last name of the member</param>
/// <param name="stringmiddlename">middle name of the member</param>
/// <param name="stringtitle">title of the member</param>
/// <param name="strst">street of the member</param>
/// <param name="strtwn">Town of the member</param>
/// <param name="strpc">Postcode of the member</param>
/// <param name="strEmail">email of the member</param>
/// <param name="intMobile">Mobile of the member</param>
/// <param name="intHome">Home phone of the member</param>
/// <param name="shrnumber">ID number of the member</param>
/// <param name="memtype">Type of the member</param>
/// <param name="username">username of the member</param>
/// <param name="noracesrun">number of races that the member has run</param>
/// <param name="perraceswon">percentage of races that the member has won</param>
/// <param name="mempic">image of the member</param>
/// <param name="memclub">the club the member is part of</param>
/// <param name="gender">the gender of the member</param>
/// <param name="memexp">the experience level the member has</param>
/// <param name="yearofbirth">the year of birth the member was born in</param>
/// <param name="monthofbirth">the month of birth the member was born in</param>
/// <param name="dayofbirth">the day of birth the member was born on</param>
public void addJunior(string stringfirstname, string stringlastname, string stringmiddlename, string stringtitle, string strst, string strtwn, string strpc, string strEmail, int intMobile, int intHome,
string shrnumber, string memtype, string username, string password, int noracesrun, float perraceswon, string mempic, string memclub, string gender, int memexp, int yearofbirth, int monthofbirth, int dayofbirth, string nextofkin, string docName, string docTel, string healthIssues, string parentalConsent)
{
// create a new member with the entered parameters to add to the list.
JuniorMember newMember = new JuniorMember(stringfirstname, stringlastname, stringmiddlename, stringtitle, strst, strtwn, strpc, strEmail, intMobile, intHome, shrnumber, memtype, username, password, noracesrun, perraceswon, mempic, memclub, gender, memexp, yearofbirth, monthofbirth, dayofbirth,nextofkin,docName,docTel,healthIssues,parentalConsent);
//use add functionality of list to add to the list.
members.Add(newMember);
}
/// <summary>
///
/// </summary>
/// <param name="stringfirstname">first name of the member</param>
/// <param name="stringlastname">last name of the member</param>
/// <param name="stringmiddlename">middle name of the member</param>
/// <param name="stringtitle">title of the member</param>
/// <param name="strst">street of the member</param>
/// <param name="strtwn">Town of the member</param>
/// <param name="strpc">Postcode of the member</param>
/// <param name="strEmail">email of the member</param>
/// <param name="intMobile">Mobile of the member</param>
/// <param name="intHome">Home phone of the member</param>
/// <param name="shrnumber">ID number of the member</param>
/// <param name="memtype">Type of the member</param>
/// <param name="username">username of the member</param>
/// <param name="noracesrun">number of races that the member has run</param>
/// <param name="perraceswon">percentage of races that the member has won</param>
/// <param name="mempic">image of the member</param>
/// <param name="memclub">the club the member is part of</param>
/// <param name="gender">the gender of the member</param>
/// <param name="memexp">the experience level the member has</param>
/// <param name="yearofbirth">the year of birth the member was born in</param>
/// <param name="monthofbirth">the month of birth the member was born in</param>
/// <param name="dayofbirth">the day of birth the member was born on</param>
/// <param name="nextofkin">The next family member contact</param>
/// <param name="docName">The name of the members doctor</param>
/// <param name="docTel">A telephone number for the doctor</param>
/// <param name="healthIssues">the health issues this member has.</param>
public void addSenior(string stringfirstname, string stringlastname, string stringmiddlename, string stringtitle, string strst, string strtwn, string strpc, string strEmail, int intMobile, int intHome,
string shrnumber, string memtype, string username, string password, int noracesrun, float perraceswon, string mempic, string memclub, string gender, int memexp, int yearofbirth, int monthofbirth, int dayofbirth, string nextofkin, string docName, string docTel, string healthIssues)
{
//create a new member with the entered parameters to add to the list.
SeniorMember newMember = new SeniorMember(stringfirstname, stringlastname, stringmiddlename, stringtitle, strst, strtwn, strpc, strEmail, intMobile, intHome, shrnumber, memtype, username, password, noracesrun, perraceswon, mempic, memclub, gender, memexp, yearofbirth, monthofbirth, dayofbirth,docName,docTel,healthIssues);
//use standard list functionality of list to add this new member to the list.
members.Add(newMember);
}
Here is my Serialization method in the Serializer class:
public void SerializeObject(string filename, object objectToSerialize)
{
Stream stream = File.Open(filename + ".bin", FileMode.Create);
BinaryFormatter bFormatter = new BinaryFormatter();
bFormatter.Serialize(stream, objectToSerialize);
stream.Close();
}
Problem is, I don't know how to actually use this.
Also have a deserializer:
public HillRacing DeSerializeObject(string filename)
{
HillRacing hillracing;
Stream stream = File.Open(filename + ".bin", FileMode.Open);
BinaryFormatter bFormatter = new BinaryFormatter();
hillracing = (HillRacing)bFormatter.Deserialize(stream);
stream.Close();
return hillracing;
}
Although you have done most of the part i suggest a little generics make it multiuse as
public static class StreamUtilities
{
public static T GetObject<T>(Byte[] rawimage) where T : class
{
try
{
MemoryStream memStream = new MemoryStream();
BinaryFormatter binForm = new BinaryFormatter();
memStream.Write(rawimage, 0, rawimage.Length);
memStream.Seek(0, SeekOrigin.Begin);
return binForm.Deserialize(memStream) as T;
}
catch (Exception ex)
{
return null;
}
}
public static Byte[] Serialize<T>(this T obj) where T:class
{
if (obj == null)
return null;
BinaryFormatter bf = new BinaryFormatter();
MemoryStream ms = new MemoryStream();
bf.Serialize(ms, obj);
return ms.ToArray();
}
}
then in your main class or whereever you want it to use include to namespace where the above extention method is then use
Object1 a=new Object1();// any serializable object
serializedbytes=a.Serialize<Object1>();
//deserialize
Object b=StreamUtilities.GetObject<Object1>(serializedbytes);
The above extention method will allow to seriailize/Deserialize any serializable Object.

How to convert hierarchical key value pairs from a string into json with c#?

I have the following http post body sent to a asp.net web api via a web hook from chargify.
id=38347752&event=customer_update&payload[customer][address]=qreweqwrerwq&payload[customer][address_2]=qwerewrqew&payload[customer][city]=ererwqqerw&payload[customer][country]=GB&payload[customer][created_at]=2015-05-14%2004%3A46%3A48%20-0400&payload[customer][email]=a%40test.com&payload[customer][first_name]=Al&payload[customer][id]=8619620&payload[customer][last_name]=Test&payload[customer][organization]=&payload[customer][phone]=01&payload[customer][portal_customer_created_at]=2015-05-14%2004%3A46%3A49%20-0400&payload[customer][portal_invite_last_accepted_at]=&payload[customer][portal_invite_last_sent_at]=2015-05-14%2004%3A46%3A49%20-0400&payload[customer][reference]=&payload[customer][state]=&payload[customer][updated_at]=2015-05-14%2011%3A25%3A19%20-0400&payload[customer][verified]=false&payload[customer][zip]=&payload[site][id]=26911&payload[site][subdomain]=testsubdomain
How do i convert this payload[customer][address]=value etc. to a json string using c#?
You current problem
How to convert chargify webhooks to json with c#?
can be generalized to
How to extract key value pairs from a string, convert them into the corresponding hierarchy and return them in JSON?
To answer your question:
string rawData = "id=38347752&event=customer_update&payload[customer][address]=qreweqwrerwq&payload[customer][address_2]=qwerewrqew&payload[customer][city]=ererwqqerw&payload[customer][country]=GB&payload[customer][created_at]=2015-05-14%2004%3A46%3A48%20-0400&payload[customer][email]=a%40test.com&payload[customer][first_name]=Al&payload[customer][id]=8619620&payload[customer][last_name]=Test&payload[customer][organization]=&payload[customer][phone]=01&payload[customer][portal_customer_created_at]=2015-05-14%2004%3A46%3A49%20-0400&payload[customer][portal_invite_last_accepted_at]=&payload[customer][portal_invite_last_sent_at]=2015-05-14%2004%3A46%3A49%20-0400&payload[customer][reference]=&payload[customer][state]=&payload[customer][updated_at]=2015-05-14%2011%3A25%3A19%20-0400&payload[customer][verified]=false&payload[customer][zip]=&payload[site][id]=26911&payload[site][subdomain]=testsubdomain";
ChargifyWebHook webHook = new ChargifyWebHook(rawData);
JSONNode node = new JSONNode("RootOrWhatEver");
foreach (KeyValuePair<string, string> keyValuePair in webHook.KeyValuePairs)
{
node.InsertInHierarchy(ChargifyWebHook.ExtractHierarchyFromKey(keyValuePair.Key), keyValuePair.Value);
}
string result = node.ToJSONObject();
With your specified input the result looks like this (without line breaks):
{
"id": "38347752",
"event": "customer_update",
"payload": {
"customer": {
"address": "qreweqwrerwq",
"address_2": "qwerewrqew",
"city": "ererwqqerw",
"country": "GB",
"created_at": "2015-05-14 04:46:48 -0400",
"email": "a#test.com",
"first_name": "Al",
"id": "8619620",
"last_name": "Test",
"organization": "",
"phone": "01",
"portal_customer_created_at": "2015-05-14 04:46:49 -0400",
"portal_invite_last_accepted_at": "",
"portal_invite_last_sent_at": "2015-05-14 04:46:49 -0400",
"reference": "",
"state": "",
"updated_at": "2015-05-14 11:25:19 -0400",
"verified": "false",
"zip": ""
},
"site": {
"id": "26911",
"subdomain": "testsubdomain"
}
}
}
As your problem is not limited to 1, 2 or 3 levels you clearly need a recursive solution. Therefore I created a JSONNode class which is able to insert children by specifying the hierarchy as a List<string>.
If you take A.B.C as an example, at the beginning the method InsertIntoHierarchy checks whether more levels are needed or not (depending on the length of the entries specified, in our case we would get a list containing A, B and C), if so it inserts a child (used as container) with the specified name of the level and passes the problem on to this child. Of course the name of the current recursion level is removed during that step so according to our example the container with the name A would have been added and the list containing B and C would have been passed on to this container. If the last level of recursion is reached, a node containing the name and the value will be inserted.
To get the solution working you will need the following 2 classes:
ChargifyWebHook
/// <summary>
/// Represents the chargify web hook class.
/// </summary>
public class ChargifyWebHook
{
/// <summary>
/// Indicates whether the raw data has already been parsed or not.
/// </summary>
private bool initialized;
/// <summary>
/// Contains the key value pairs extracted from the raw data.
/// </summary>
private Dictionary<string, string> keyValuePairs;
/// <summary>
/// Initializes a new instance of the <see cref="ChargifyWebHook"/> class.
/// </summary>
/// <param name="data">The raw data of the web hook.</param>
/// <exception cref="System.ArgumentException">Is thrown if the sepcified raw data is null or empty.</exception>
public ChargifyWebHook(string data)
{
if (String.IsNullOrEmpty(data))
{
throw new ArgumentException("The specified value must neither be null nor empty", data);
}
this.initialized = false;
this.keyValuePairs = new Dictionary<string, string>();
this.RawData = data;
}
/// <summary>
/// Gets the raw data of the web hook.
/// </summary>
public string RawData
{
get;
private set;
}
/// <summary>
/// Gets the key value pairs contained in the raw data.
/// </summary>
public Dictionary<string, string> KeyValuePairs
{
get
{
if (!initialized)
{
this.keyValuePairs = ExtractKeyValuesFromRawData(this.RawData);
initialized = true;
}
return this.keyValuePairs;
}
}
/// <summary>
/// Extracts the key value pairs from the specified raw data.
/// </summary>
/// <param name="rawData">The data which contains the key value pairs.</param>
/// <param name="keyValuePairSeperator">The pair seperator, default is '&'.</param>
/// <param name="keyValueSeperator">The key value seperator, default is '='.</param>
/// <returns>The extracted key value pairs.</returns>
/// <exception cref="System.FormatException">Is thrown if an key value seperator is missing.</exception>
public static Dictionary<string, string> ExtractKeyValuesFromRawData(string rawData, char keyValuePairSeperator = '&', char keyValueSeperator = '=')
{
Dictionary<string, string> keyValuePairs = new Dictionary<string, string>();
string[] rawDataParts = rawData.Split(new char[] { keyValuePairSeperator });
foreach (string rawDataPart in rawDataParts)
{
string[] keyAndValue = rawDataPart.Split(new char[] { keyValueSeperator });
if (keyAndValue.Length != 2)
{
throw new FormatException("The format of the specified raw data is incorrect. Key value pairs in the following format expected: key=value or key1=value1&key2=value2...");
}
keyValuePairs.Add(Uri.UnescapeDataString(keyAndValue[0]), Uri.UnescapeDataString(keyAndValue[1]));
}
return keyValuePairs;
}
/// <summary>
/// Extracts the hierarchy from the key, e.g. A[B][C] will result in A, B and C.
/// </summary>
/// <param name="key">The key who's hierarchy shall be extracted.</param>
/// <param name="hierarchyOpenSequence">Specifies the open sequence for the hierarchy speration.</param>
/// <param name="hierarchyCloseSequence">Specifies the close sequence for the hierarchy speration.</param>
/// <returns>A list of entries for the hierarchy names.</returns>
public static List<string> ExtractHierarchyFromKey(string key, string hierarchyOpenSequence = "[", string hierarchyCloseSequence = "]")
{
if (key.Contains(hierarchyOpenSequence) && key.Contains(hierarchyCloseSequence))
{
return key.Replace(hierarchyCloseSequence, string.Empty).Split(new string[] { hierarchyOpenSequence }, StringSplitOptions.None).ToList();
}
if (key.Contains(hierarchyOpenSequence) && !key.Contains(hierarchyCloseSequence))
{
return key.Split(new string[] { hierarchyOpenSequence }, StringSplitOptions.None).ToList();
}
if (!key.Contains(hierarchyOpenSequence) && key.Contains(hierarchyCloseSequence))
{
return key.Split(new string[] { hierarchyCloseSequence }, StringSplitOptions.None).ToList();
}
return new List<string>() { key };
}
}
JSONNode
/// <summary>
/// Represents the JSONNode class.
/// </summary>
public class JSONNode
{
/// <summary>
/// Initializes a new instance of the <see cref="JSONNode"/> class.
/// </summary>
/// <param name="name">The name of the node.</param>
/// <param name="value">The value of the node.</param>
public JSONNode(string name, string value)
{
this.Name = name;
this.Value = value;
this.Children = new Dictionary<string, JSONNode>();
}
/// <summary>
/// Initializes a new instance of the <see cref="JSONNode"/> class.
/// </summary>
/// <param name="name">The name of the node.</param>
public JSONNode(string name)
: this(name, string.Empty)
{
}
/// <summary>
/// Gets the name of the node.
/// </summary>
public string Name
{
get;
private set;
}
/// <summary>
/// Gets the children of the node.
/// </summary>
public Dictionary<string, JSONNode> Children
{
get;
private set;
}
/// <summary>
/// Gets the value of the node.
/// </summary>
public string Value
{
get;
private set;
}
/// <summary>
/// Inserts a new node in the corresponding hierarchy.
/// </summary>
/// <param name="keyHierarchy">A list with entries who specify the hierarchy.</param>
/// <param name="value">The value of the node.</param>
/// <exception cref="System.ArgumentNullException">Is thrown if the keyHierarchy is null.</exception>
/// <exception cref="System.ArgumentException">Is thrown if the keyHierarchy is empty.</exception>
public void InsertInHierarchy(List<string> keyHierarchy, string value)
{
if (keyHierarchy == null)
{
throw new ArgumentNullException("keyHierarchy");
}
if (keyHierarchy.Count == 0)
{
throw new ArgumentException("The specified hierarchy list is empty", "keyHierarchy");
}
// If we are not in the correct hierarchy (at the last level), pass the problem
// to the child.
if (keyHierarchy.Count > 1)
{
// Extract the current hierarchy level as key
string key = keyHierarchy[0];
// If the key does not already exists - add it as a child.
if (!this.Children.ContainsKey(key))
{
this.Children.Add(key, new JSONNode(key));
}
// Remove the current hierarchy from the list and ...
keyHierarchy.RemoveAt(0);
// ... pass it on to the just inserted child.
this.Children[key].InsertInHierarchy(keyHierarchy, value);
return;
}
// If we are on the last level, just insert the node with it's value.
this.Children.Add(keyHierarchy[0], new JSONNode(keyHierarchy[0], value));
}
/// <summary>
/// Gets the textual representation of this node as JSON entry.
/// </summary>
/// <returns>A textual representaiton of this node as JSON entry.</returns>
public string ToJSONEntry()
{
// If there is no child, return the name and the value in JSON format.
if (this.Children.Count == 0)
{
return string.Format("\"{0}\":\"{1}\"", this.Name, this.Value);
}
// Otherwise there are childs so return all of them formatted as object.
StringBuilder builder = new StringBuilder();
builder.AppendFormat("\"{0}\":", this.Name);
builder.Append(this.ToJSONObject());
return builder.ToString();
}
/// <summary>
/// Gets the textual representation of this node as JSON object.
/// </summary>
/// <returns>A textual representaiton of this node as JSON object.</returns>
public string ToJSONObject()
{
StringBuilder builder = new StringBuilder();
builder.Append("{");
foreach (JSONNode value in this.Children.Values)
{
builder.Append(value.ToJSONEntry());
builder.Append(",");
}
builder.Remove(builder.Length - 1, 1);
builder.Append("}");
return builder.ToString();
}
}

Categories

Resources