using System; using System.ComponentModel; using System.Configuration; namespace Hemit.OpPlan.Common.Extensions { /// <summary> /// Utility methods for ConfigurationManager. Also included methods for handling OpenExeConfiguration (running process configuration, for example in tests and installers) /// </summary> public static class ConfigurationManagerWrapper { /// <summary> /// Sets an appsetting for the exe configuration /// </summary> /// <param name="appsetting"></param> /// <param name="value"></param> public static void SetAppsettingForExecConfiguration(string appsetting, object value) { System.Configuration.Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None); config.AppSettings.Settings[appsetting].Value = Convert.ToString(value); config.Save(ConfigurationSaveMode.Modified); } /// <summary> /// Sets an appsetting for the exe configuration /// </summary> /// <param name="appsetting"></param> /// <param name="value"></param> public static string GetAppsettingExecConfiguration(string appsetting, object value) { return ConfigurationManager.AppSettings[appsetting]; } /// <summary> /// Sets an appsetting for the exe configuration /// </summary> /// <param name="appsetting"></param> /// <param name="value"></param> public static void SetAppsettingForConfiguration(string appsetting, object value) { ConfigurationManager.AppSettings[appsetting] = Convert.ToString(value); } /// <summary> /// Sets an appsetting for the exe configuration /// </summary> /// <param name="appsetting"></param> /// <param name="value"></param> public static string GetAppsettingForExecConfiguration(string appsetting, object value) { System.Configuration.Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None); return config.AppSettings.Settings[appsetting].Value; } /// <summary> /// Use this extension method to get a strongly typed app setting from the configuration file. /// Returns app setting in configuration file if key found and tries to convert the value to a specified type. In case this fails, the fallback value /// or if NOT specified - default value - of the app setting is returned /// </summary> /// <typeparam name="T"></typeparam> /// <param name="appsettingKey"></param> /// <param name="fallback"></param> /// <returns></returns> public static T GetAppsetting<T>(string appsettingKey, T fallback = default(T)) { string val = ConfigurationManager.AppSettings[appsettingKey] ?? ""; if (!string.IsNullOrEmpty(val)) { try { Type typeDefault = typeof(T); var converter = TypeDescriptor.GetConverter(typeof(T)); return converter.CanConvertFrom(typeof(string)) ? (T)converter.ConvertFrom(val) : fallback; } catch (Exception err) { Console.WriteLine(err); //Swallow exception return fallback; } } return fallback; } } }
Friday, 28 February 2020
Strongly typed ConfigurationManager in .NET Framework
Handling configuration files in .NET Framework is often tedious. You retrieve the app setting as a string and must then parse it out. Dont you wish we could have a generic method to get a strongly typed app setting instead and spare ourselves with some code ? Sure you can!
Thursday, 20 February 2020
Generic method ShouldAll for FluentAssertions
This is a simple etension method for Fluent Assertions called ShouldAll that can be run on a collection and you can pass in your predicate of your choice and see the output.
Consider this unit test:
var oneyearPeriodComparions = new [] { new ReferencePeriodComparisonResult { ReferencePeriod = reportPeriod2017 , CalculatedPeriod = calculatedReportPeriod2017.First() }, new ReferencePeriodComparisonResult { ReferencePeriod = reportPeriod2017 , CalculatedPeriod = calculatedReportPeriod2017.Last()}, new ReferencePeriodComparisonResult { ReferencePeriod = reportPeriod2018 , CalculatedPeriod = calculatedReportPeriod2018.First()}, new ReferencePeriodComparisonResult { ReferencePeriod = reportPeriod2018 , CalculatedPeriod = calculatedReportPeriod2018.Last() }, new ReferencePeriodComparisonResult { ReferencePeriod = reportPeriod2019 , CalculatedPeriod = calculatedReportPeriod2019.First() }, new ReferencePeriodComparisonResult { ReferencePeriod = reportPeriod2019 , CalculatedPeriod = calculatedReportPeriod2019.Last() } }; oneyearPeriodComparions.ShouldAll(comparison => comparison.CalculatedPeriod.ReportPeriodStartDateAndEndDateIsEqualTo(comparison.ReferencePeriod), outputPassingTests:true);This uses this extension test for Fluent Assertions:
using FluentAssertions; using System; using System.Collections.Generic; using System.Linq.Expressions; namespace SomeAcme.SomeLib { public static class FluentAssertionsExtensions { /// <summary> /// Inspects that all tests are passing for given collection and given predicate /// </summary> /// <typeparam name="T"></typeparam> /// <param name="instances"></param> /// <param name="predicate"></param> /// <param name="outputFailingTests"></param> public static void ShouldAll<T>(this IEnumerable<T> instances, Expression<Func<T, bool>> predicate, bool outputFailingTests = true, bool outputPassingTests = false) { foreach (var instance in instances) { var isTestPassing = predicate.Compile().Invoke(instance); if (!isTestPassing && outputFailingTests || outputPassingTests) Console.WriteLine($@"Test Running against object: {instance} Test Pass?:{isTestPassing}"); isTestPassing.Should().Be(true); } } } }
Etiketter:
c#,
fluentassertions,
nunit,
tdd,
test driven
Saturday, 4 January 2020
Implementing GetPropertyNames in Typescript
I am currently working on a Linq-like library for Typescript and wanted to implement something like GetProperties of C# in Typescript / Javascript. The more I work with Typescript and generics, the clearer picture I get of that you usually have to have an instantiated object with intialized properties to get any useful information out at runtime about properties of a class. But it would be nice to retrieve information anyways just from the constructor function object, or an array of objects and be flexible about this.
I was following a question thread on Stack Overflow and found a good answer that helped me out:
https://stackoverflow.com/questions/40636292/get-properties-of-a-class/59586570#59586570
Here is what I ended up with for now.
First off, I define Array prototype method ('extension method' for you C# developers).
export { } //creating a module of below code declare global { interface Array>T< { GetProperties>T<(TClass: Function, sortProps: boolean): string[]; } } The GetProperties method then looks like this, inspired by madreasons answer. if (!Array.prototype.GetProperties) { Array.prototype.GetProperties = function >T<(TClass: any = null, sortProps: boolean = false): string[] { if (TClass === null || TClass === undefined) { if (this === null || this === undefined || this.length === 0) { return []; //not possible to find out more information - return empty array } } // debugger if (TClass !== null && TClass !== undefined) { if (this !== null && this !== undefined) { if (this.length < 0) { let knownProps: string[] = Describer.describe(this[0]).Where(x =< x !== null && x !== undefined); if (sortProps && knownProps !== null && knownProps !== undefined) { knownProps = knownProps.OrderBy(p =< p); } return knownProps; } if (TClass !== null && TClass !== undefined) { let knownProps: string[] = Describer.describe(TClass).Where(x =< x !== null && x !== undefined); if (sortProps && knownProps !== null && knownProps !== undefined) { knownProps = knownProps.OrderBy(p =< p); } return knownProps; } } } return []; //give up.. } }The describer method is about the same as madreason's answer on Stack Overflow concerning this. It can handle both class Function and if you get an object instead. It will then use Object.getOwnPropertyNames if no class Function is given (i.e. the class 'type' for C# developers).
class Describer { private static FRegEx = new RegExp(/(?:this\.)(.+?(?= ))/g); static describe(val: any, parent = false): string[] { let isFunction = Object.prototype.toString.call(val) == '[object Function]'; if (isFunction) { let result = []; if (parent) { var proto = Object.getPrototypeOf(val.prototype); if (proto) { result = result.concat(this.describe(proto.constructor, parent)); } } result = result.concat(val.toString().match(this.FRegEx)); result = result.Where(r =< r !== null && r !== undefined); return result; } else { if (typeof val == "object") { let knownProps: string[] = Object.getOwnPropertyNames(val); return knownProps; } } return val !== null ? [val.tostring()] : []; } }Here you see two specs for testing this out with Jasmine.
class Hero { name: string; gender: string; age: number; constructor(name: string = "", gender: string = "", age: number = 0) { this.name = name; this.gender = gender; this.age = age; } } class HeroWithAbility extends Hero { ability: string; constructor(ability: string = "") { super(); this.ability = ability; } } describe('Array Extensions tests for TsExtensions Linq esque library', () =< { it('can retrieve props for a class items of an array', () =< { let heroes: Hero[] = [>Hero<{ name: "Han Solo", age: 44, gender: "M" }, >Hero<{ name: "Leia", age: 29, gender: "F" }, >Hero<{ name: "Luke", age: 24, gender: "M" }, >Hero<{ name: "Lando", age: 47, gender: "M" }]; let foundProps = heroes.GetProperties(Hero, false); //debugger let expectedArrayOfProps = ["name", "age", "gender"]; expect(foundProps).toEqual(expectedArrayOfProps); expect(heroes.GetProperties(Hero, true)).toEqual(["age", "gender", "name"]); }); it('can retrieve props for a class only knowing its function', () =< { let heroes: Hero[] = []; let foundProps = heroes.GetProperties(Hero, false); let expectedArrayOfProps = ["this.name", "this.gender", "this.age"]; expect(foundProps).toEqual(expectedArrayOfProps); let foundPropsThroughClassFunction = heroes.GetProperties(Hero, true); //debugger expect(foundPropsThroughClassFunction.SequenceEqual(["this.age", "this.gender", "this.name"])).toBe(true); }); ..And as madreason mentioned, you have to initialize the props to get any information out from just the class Function itself, or else it is stripped away when Typescript code is turned into Javascript code. Typescript 3.7 is very good with Generics, but coming from a C# and Reflection background, some fundamental parts of Typescript and generics still feels somewhat loose and unfinished business. Like my code here, but at least I got out the information I wanted - a list of property names for a given class or instance of objects.
Subscribe to:
Posts (Atom)