How to replace region with own enum in AmazonEC2Client in c#? - c#

In my aspnet core 3.1 project I am using client for aws for getting all instance list for me.
In constructor AmazonEC2Client third parameter is class which is accepting RegionEndPoint, and I would like to put enum instead of RegionEndPoint.
My method looks like:
public static async Task<List<string>> AwsList(string awsAccessKeyId, string
awsSecretAccessKey) // should AwsRegion region as 3rd paramater
{
AmazonEC2Client client = new AmazonEC2Client(awsAccessKeyId,awsSecretAccessKey,
RegionEndpoint.EUWest1); // replace RegionEndpoint.EUWest1 with enum paramater
bool done = false;
var instanceIds = new List<string>();
DescribeInstanceTypesRequest request = new DescribeInstanceTypesRequest();
while (!done)
{
DescribeInstanceTypesResponse response = await
client.DescribeInstanceTypesAsync(request);
foreach ( var instanceType in response.InstanceTypes.Where(x =>
x.MemoryInfo.SizeInMiB >= 2048 && x.VCpuInfo.DefaultVCpus >= 2))
{
instanceIds.Add(instanceType.InstanceType);
}
request.NextToken= response.NextToken;
if (response.NextToken == null)
{
done = true;
}
}
return instanceIds;
}
I would like to 3rd parameter which is enum to my method and replace Region with enum. As there is no constructor which accepting enum, how I can specify AmazonECwClient constructor and specify enum using extension methods (if possible)
My enum which I want implement and replace.
public enum AwsRegion
{
/// <summary>The US East (Virginia) endpoint.</summary>
USEast1 = 1,
/// <summary>The US East (Ohio) endpoint.</summary>
USEast2 = 2,
/// <summary>The US West (N. California) endpoint.</summary>
USWest1 = 3,
/// <summary>The US West (Oregon) endpoint.</summary>
USWest2 = 4,
/// <summary>The EU West (Ireland) endpoint.</summary>
EUWest1 = 5,
/// <summary>The EU Central (Frankfurt) endpoint.</summary>
EUCentral1 = 6,
/// <summary>The Asia Pacific (Tokyo) endpoint.</summary>
APNortheast1 = 7,
/// <summary>The Asia Pacific (Seoul) endpoint.</summary>
APNortheast2 = 8,
/// <summary>The Asia Pacific (Mumbai) endpoint.</summary>
APSouth1 = 9,
/// <summary>The Asia Pacific (Singapore) endpoint.</summary>
APSoutheast1 = 10,
/// <summary>The Asia Pacific (Sydney) endpoint.</summary>
APSoutheast2 = 11,
/// <summary>The South America (Sao Paulo) endpoint.</summary>
SAEast1 = 12,
/// <summary>The US GovCloud West (Oregon) endpoint.</summary>
USGovCloudWest1 = 13,
/// <summary>The China (Beijing) endpoint.</summary>
CNNorth1 = 14
}

I think this source code of aws-sdk-net RegionEndpoint.cs will help you deal with region mapping.
Even AWSSDK has a dictionary in order to quickly convert a region string to its static RegionEndpoint object.
private static Dictionary<string, RegionEndpoint> _hashBySystemName = new Dictionary<string, RegionEndpoint>(StringComparer.OrdinalIgnoreCase);
/// <summary>
/// Gets the region based on its system name like "us-west-1"
/// </summary>
/// <param name="systemName">The system name of the service like "us-west-1"</param>
/// <returns></returns>
public static RegionEndpoint GetBySystemName(string systemName)
{
// ...skip
if (_hashBySystemName.TryGetValue(systemName, out regionEndpoint))
return regionEndpoint;
// ...skip
}
Which means you can have your own dictionary and a converting method.
private static Dictionary<AwsRegion, RegionEndpoint> _awsRegionDict = new Dictionary<AwsRegion, RegionEndpoint>(StringComparer.OrdinalIgnoreCase);
public static RegionEndpoint ConvertByAwsRegion(AwsRegion emAwsRegion)
{
if (_awsRegionDict.TryGetValue(emAwsRegion, out regionEndpoint))
return regionEndpoint;
return RegionEndpoint.EUWest1; // your default region
}
Offering another extension method would make it easiler to use.
public static class RegionEndpointExtension
{
public RegionEndpoint ToRegionEndpoint(this AwsRegion region)
{
return AwsRegionProvider.ConvertByAwsRegion(region)
}
}
Thus, use your AwsRegion enum as 3rd argument, then calling ConvertByAwsRegion or ToRegionEndpoint converting method on demand.

Related

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

How to get the My Documents folder paths from all users of a machine

I am looking for a way to get the paths of the My Documents folders from all users (each user) of a local machine.
I found several articles, but they show how to do this for the current user.
I tested the code below, using SHGetKnownFolderPath, but it works only for the logged user. In the class ctor that receives a WindowsIdentity object, I create it with tokens of other users, but the paths returned were of the logged-in user.
Does anyone know how I could get the folders paths?
Thanks.
using Syroot.Windows.IO;
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace ConsoleApplication2
{
class Program
{
private static Dictionary<KnownFolderType, KnownFolder> _knownFolderInstances;
static void Main(string[] args)
{
KnownFolderType type = KnownFolderType.Documents;
KnownFolder knownFolder = new KnownFolder(type);
//Ctor with WindowsIdentity parameter
//public KnownFolder(KnownFolderType type, WindowsIdentity identity)
//{
// Type = type;
// Identity = identity;
//}
// Write down the current and default path.
Console.WriteLine(knownFolder.Type.ToString());
try
{
Console.Write("Current Path: ");
Console.WriteLine(knownFolder.Path);
Console.Write("Default Path: ");
Console.WriteLine(knownFolder.DefaultPath);
}
catch (ExternalException ex)
{
// While uncommon with personal folders, other KnownFolders don't exist on every system, and trying
// to query those returns an error which we catch here.
Console.WriteLine("<Exception> " + ex.ErrorCode);
}
Console.ReadLine();
}
private static KnownFolder GetInstance(KnownFolderType type)
{
// Check if the caching directory exists yet.
if (_knownFolderInstances == null)
{
_knownFolderInstances = new Dictionary<KnownFolderType, KnownFolder>();
}
// Get a KnownFolder instance out of the cache dictionary or create it when not cached yet.
KnownFolder knownFolder;
if (!_knownFolderInstances.TryGetValue(type, out knownFolder))
{
knownFolder = new KnownFolder(type);
_knownFolderInstances.Add(type, knownFolder);
}
return knownFolder;
}
/// <summary>
/// The per-user Documents folder.
/// Defaults to "%USERPROFILE%\Documents".
/// </summary>
public static KnownFolder Documents
{
get { return GetInstance(KnownFolderType.Documents); }
}
}
}
KnownFolder.cs
using System;
using System.Runtime.InteropServices;
using System.Security.Principal;
namespace Syroot.Windows.IO
{
/// <summary>
/// Represents a special Windows directory and provides methods to retrieve information about it.
/// </summary>
public sealed class KnownFolder
{
// ---- CONSTRUCTORS & DESTRUCTOR ------------------------------------------------------------------------------
/// <summary>
/// Initializes a new instance of the <see cref="KnownFolder"/> class for the folder of the given type. It
/// provides the values for the current user.
/// </summary>
/// <param name="type">The <see cref="KnownFolderType"/> of the known folder to represent.</param>
public KnownFolder(KnownFolderType type)
: this(type, WindowsIdentity.GetCurrent())
{
}
/// <summary>
/// Initializes a new instance of the <see cref="KnownFolder"/> class for the folder of the given type. It
/// provides the values for the given impersonated user.
/// </summary>
/// <param name="type">The <see cref="KnownFolderType"/> of the known folder to represent.</param>
/// <param name="identity">The <see cref="WindowsIdentity"/> of the impersonated user which values will be
/// provided.</param>
public KnownFolder(KnownFolderType type, WindowsIdentity identity)
{
Type = type;
Identity = identity;
}
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
/// <summary>
/// Gets the type of the known folder which is represented.
/// </summary>
public KnownFolderType Type
{
get;
private set;
}
/// <summary>
/// Gets the <see cref="WindowsIdentity"/> of the user whose folder values are provided.
/// </summary>
public WindowsIdentity Identity
{
get;
private set;
}
/// <summary>
/// Gets or sets the default path of the folder.
/// This does not require the folder to be existent.
/// </summary>
/// <exception cref="ExternalException">The known folder could not be retrieved.</exception>
public string DefaultPath
{
get
{
return GetPath(KnownFolderFlags.DontVerify | KnownFolderFlags.DefaultPath);
}
set
{
}
}
/// <summary>
/// Gets or sets the path as currently configured.
/// This does not require the folder to be existent.
/// </summary>
/// <exception cref="ExternalException">The known folder could not be retrieved.</exception>
public string Path
{
get
{
return GetPath(KnownFolderFlags.DontVerify);
}
set
{
SetPath(KnownFolderFlags.None, value);
}
}
/// <summary>
/// Gets or sets the path as currently configured, with all environment variables expanded.
/// This does not require the folder to be existent.
/// </summary>
/// <exception cref="ExternalException">The known folder could not be retrieved.</exception>
public string ExpandedPath
{
get
{
return GetPath(KnownFolderFlags.DontVerify | KnownFolderFlags.NoAlias);
}
set
{
SetPath(KnownFolderFlags.DontUnexpand, value);
}
}
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
/// <summary>
/// Creates the folder using its Desktop.ini settings.
/// </summary>
/// <exception cref="ExternalException">The known folder could not be retrieved.</exception>
public void Create()
{
GetPath(KnownFolderFlags.Init | KnownFolderFlags.Create);
}
// ---- METHODS (PRIVATE) --------------------------------------------------------------------------------------
private string GetPath(KnownFolderFlags flags)
{
IntPtr outPath;
int result = SHGetKnownFolderPath(Type.GetGuid(), (uint)flags, Identity.Token, out outPath);
if (result >= 0)
{
return Marshal.PtrToStringUni(outPath);
}
else
{
throw new ExternalException("Cannot get the known folder path. It may not be available on this system.",
result);
}
}
private void SetPath(KnownFolderFlags flags, string path)
{
int result = SHSetKnownFolderPath(Type.GetGuid(), (uint)flags, Identity.Token, path);
if (result < 0)
{
throw new ExternalException("Cannot set the known folder path. It may not be available on this system.",
result);
}
}
/// <summary>
/// Retrieves the full path of a known folder identified by the folder's known folder ID.
/// </summary>
/// <param name="rfid">A known folder ID that identifies the folder.</param>
/// <param name="dwFlags">Flags that specify special retrieval options. This value can be 0; otherwise, one or
/// more of the <see cref="KnownFolderFlags"/> values.</param>
/// <param name="hToken">An access token that represents a particular user. If this parameter is NULL, which is
/// the most common usage, the function requests the known folder for the current user. Assigning a value of -1
/// indicates the Default User. The default user profile is duplicated when any new user account is created.
/// Note that access to the Default User folders requires administrator privileges.</param>
/// <param name="ppszPath">When this method returns, contains the address of a string that specifies the path of
/// the known folder. The returned path does not include a trailing backslash.</param>
/// <returns>Returns S_OK if successful, or an error value otherwise.</returns>
/// <msdn-id>bb762188</msdn-id>
[DllImport("Shell32.dll")]
private static extern int SHGetKnownFolderPath([MarshalAs(UnmanagedType.LPStruct)]Guid rfid, uint dwFlags,
IntPtr hToken, out IntPtr ppszPath);
/// <summary>
/// Redirects a known folder to a new location.
/// </summary>
/// <param name="rfid">A <see cref="Guid"/> that identifies the known folder.</param>
/// <param name="dwFlags">Either 0 or <see cref="KnownFolderFlags.DontUnexpand"/>.</param>
/// <param name="hToken"></param>
/// <param name="pszPath"></param>
/// <returns></returns>
/// <msdn-id>bb762249</msdn-id>
[DllImport("Shell32.dll")]
private static extern int SHSetKnownFolderPath([MarshalAs(UnmanagedType.LPStruct)]Guid rfid, uint dwFlags,
IntPtr hToken, [MarshalAs(UnmanagedType.LPWStr)]string pszPath);
// ---- ENUMERATIONS -------------------------------------------------------------------------------------------
/// <summary>
/// Represents the retrieval options for known folders.
/// </summary>
/// <msdn-id>dd378447</msdn-id>
[Flags]
private enum KnownFolderFlags : uint
{
None = 0x00000000,
SimpleIDList = 0x00000100,
NotParentRelative = 0x00000200,
DefaultPath = 0x00000400,
Init = 0x00000800,
NoAlias = 0x00001000,
DontUnexpand = 0x00002000,
DontVerify = 0x00004000,
Create = 0x00008000,
NoAppcontainerRedirection = 0x00010000,
AliasOnly = 0x80000000
}
}
}
I figured it out.
I got all SIDs from the system and then searched the Windows registry for each SID by the "Personal" key in the following format: "HKEY_USERS" + "SID" + "\ Software \ Microsoft \ Windows \ CurrentVersion \ Explorer \ Shell Folders \ Personal ".
The "Personal" key retains the current path of each user's "My Documents" folder.
Get SIDs:
public static List<string> GetMachineSids()
{
ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT * FROM Win32_UserProfile");
var regs = searcher.Get();
string sid;
List<string> sids = new List<string>();
foreach (ManagementObject os in regs)
{
if (os["SID"] != null)
{
sid = os["SID"].ToString();
sids.Add(sid);
}
}
searcher.Dispose();
return sids.Count > 0 ? sids : null;
}
Get MyDocuments Path:
public static List<string> GetMyDocumentsPathAllUsers()
{
const string parcialSubkey = #"\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders";
string subkey = string.Empty;
const string keyName = "Personal";
//get sids
List<string> sids = GetMachineSids();
List<string> myDocumentsPaths = new List<string>();
if (sids != null)
{
foreach (var sid in sids)
{
//get paths
subkey = sid + parcialSubkey;
using (RegistryKey key = Registry.Users.OpenSubKey(subkey))
{
if (key != null)
{
Object o = key.GetValue(keyName);
if (o != null)
{
myDocumentsPaths.Add(o.ToString());
}
}
}
}
}
return myDocumentsPaths.Count > 0 ? myDocumentsPaths : null;
}

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();
}
}

XmlEnum Multiple name for a single value

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.

Linq Groupby Sum a nested observable collection

I need some help aggregating data in my collection.
The RrvResponse class
/// <summary>
/// The RRV response.
/// </summary>
public class RrvResponse
{
/// <summary>
/// Initializes a new instance of the <see cref="RrvResponse"/> class.
/// </summary>
public RrvResponse()
{
this.BoDPoints = new ObservableCollection<BidOfferPoint>();
}
/// <summary>
/// Gets or sets the id.
/// </summary>
public string Id { get; set; }
/// <summary>
/// Gets or sets the message date.
/// </summary>
public DateTime MessageDate { get; set; }
/// <summary>
/// Gets or sets the BOD points.
/// </summary>
public ObservableCollection<BidOfferPoint> BoDPoints { get; set; }
}
The implementation,
var responses = new ObservableCollection<RrvResponse>();
// ....Load responses...
// ...
// ...
The count of responses is 5, So I have 5 ObservableCollection of BoDPoints inside responses.
BOD points are,
/// <summary>
/// The bid offer point.
/// </summary>
public class BidOfferPoint
{
/// <summary>
/// Gets or sets the date.
/// </summary>
public DateTime Date { get; set; }
/// <summary>
/// Gets or sets the time.
/// </summary>
public string Time { get; set; }
/// <summary>
/// Gets or sets the volume.
/// </summary>
public decimal Volume { get; set; }
/// <summary>
/// Gets or sets the price.
/// </summary>
public decimal Price { get; set; }
}
Sample,
Observable Collection Bod - 1
2013-06-21
00:00
100
10
2013-06-21
00:15
120
15
2013-06-21
00:30
150
9
Observable Collection Bod - 2
2013-06-21
00:00
Observable Collection Bod - 1
2013-06-21
00:00
100
10
2013-06-21
00:15
120
15
2013-06-21
00:30
150
9
40
1
2013-06-21
00:15
10
0.5
2013-06-21
00:30
11
0.1
Observable Collection Bod - 3
2013-06-15
00:00
100
10
2013-06-15
00:15
120
15
2013-06-15
00:30
150
9
I would like to group by date then hours across the collection and aggregate the volumes. So in the above example all volumes for 21-06-2013 for hour 00:00 should be aggregated, all volumes for 21-06-2013 for hour 00:15 should be aggregated.
What is the best approach using Linq to do this?
You can use SelectMany to aggregate the items and group them afterwards:
var result = responses
.SelectMany(r => r.BoDPoints)
.GroupBy(p => p.Date)
.Select(byDate =>
new
{
Date = byDate.Key,
EntriesByTime = byDate
.GroupBy(p => p.Time)
.Select(byTime =>
new
{
Time = byTime.Key,
TotalVolume = byTime.Sum(p => p.Volume)
})
});
You can use the following loop (e.g. to output the total volume)
foreach (var byDate in result)
{
Console.WriteLine("Entries for date " + byDate.Date);
foreach (var byTime in byDate.EntriesByTime)
{
Console.WriteLine("Total volume for time " + byTime.Time + ": " + byTime.TotalVolume);
}
}

Categories

Resources