Skip to content

Commit

Permalink
Add project files.
Browse files Browse the repository at this point in the history
  • Loading branch information
DavidThielen committed Oct 3, 2024
1 parent 914c3e2 commit 365cc3d
Show file tree
Hide file tree
Showing 19 changed files with 1,444 additions and 0 deletions.
32 changes: 32 additions & 0 deletions .github/workflows/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Docs for the Azure Web Apps Deploy action: https://github.com/Azure/webapps-deploy
# More GitHub Actions for Azure: https://github.com/Azure/actions

name: Build and deploy ASP.Net Core app to Azure Web App - louishowe

on:
push:
branches:
- master
- feature/*
workflow_dispatch:

jobs:
build:
runs-on: windows-latest
timeout-minutes: 30

steps:
- uses: actions/checkout@v4

- name: Set up .NET Core
uses: actions/setup-dotnet@v1
with:
dotnet-version: '8.x'
include-prerelease: true

- name: Build
run: dotnet build .\TradeWindsExtensions\TradeWindsExtensions.csproj --configuration Release

- name: Unit Tests
run: dotnet test .\UnitTests\UnitTests.csproj

21 changes: 21 additions & 0 deletions LICENSE.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2024 Trade Winds Studios (David Thielen)

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
31 changes: 31 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# TradeWindsCommon

These are some basic classes I use throughout my code, including in some of my other NuGet projects.

> This is under the MIT license. If you find this very useful I ask (not a requirement) that you consider reading my book [I DON’T KNOW WHAT I’M DOING!: How a Programmer Became a Successful Startup CEO](https://a.co/d/bEpDlJR).
>
> And if you like it, please review it on Amazon and/or GoodReads. The number of legitimate reviews helps a lot. Much appreciated.
## Extensions

These are some classes I created to extend a number of basic classes.

The StringExtensions has some pretty specific methods that we use to extract metadata from search strings. Included here because this is used by many apps for their tags, etc. It can extract [tag], {tag}, (tag), and @tag from a string. The @tag does not allow spaces (the space is the end delimiter).

## Debug

Trap() is a construct I discuss in my book No Bugs! Basically you place this when you write new code, at the entry to each function, inside every if, else, where, case, etc.

When you first run that new code it will drop you in to the debugger at each trap. Mark that Trap() to be deleted and then single step through the new code. 90% of the time the code is fine. 10% of the time the code will do something unexpected and you can then fix the issue.

The way I mark the traps I hit is to put a * at the beginning of that line
```csharp
* Trap();
```
That way the line numbers don't change so the debugger is in sync with the source code. But when your debug session is complete, a compile will fail until you remove those traps you've now walked through.

## Unit Tests

Not all of these have unit tests. But all have been tested thoroughly in use in our applications.

And some, like DoubleFinish and ConfigurationUtils can only be well tested in use in a Blazor application.
31 changes: 31 additions & 0 deletions TradeWindsCommon.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.12.35209.166
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TradeWindsCommon", "TradeWindsCommon\TradeWindsCommon.csproj", "{619B9837-7A01-4CF8-A162-C66DB90C1EEA}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTests", "UnitTests\UnitTests.csproj", "{B1441523-4479-4B7E-8A31-C659C9F821FC}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{619B9837-7A01-4CF8-A162-C66DB90C1EEA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{619B9837-7A01-4CF8-A162-C66DB90C1EEA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{619B9837-7A01-4CF8-A162-C66DB90C1EEA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{619B9837-7A01-4CF8-A162-C66DB90C1EEA}.Release|Any CPU.Build.0 = Release|Any CPU
{B1441523-4479-4B7E-8A31-C659C9F821FC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B1441523-4479-4B7E-8A31-C659C9F821FC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B1441523-4479-4B7E-8A31-C659C9F821FC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B1441523-4479-4B7E-8A31-C659C9F821FC}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {D5BCF809-6426-4076-B3AC-B63DD645C5FF}
EndGlobalSection
EndGlobal
2 changes: 2 additions & 0 deletions TradeWindsCommon.sln.DotSettings
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/UserDictionary/Words/=Thielen/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
166 changes: 166 additions & 0 deletions TradeWindsCommon/Extensions/AccessPrivateMembers.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@

// Copyright (c) 2024 Trade Winds Studios (David Thielen)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

using System.ComponentModel;
using System.Reflection;

namespace TradeWindsCommon.Extensions
{
/// <summary>
/// Extensions to access private class members.
/// </summary>
public static class AccessPrivateMembers
{
/// <summary>
/// Returns a _private_ Property Value from a given Object. Uses Reflection.
/// Throws a ArgumentOutOfRangeException if the Property is not found.
/// </summary>
/// <typeparam name="T">Type of the Property</typeparam>
/// <param name="obj">Object from where the Property Value is returned</param>
/// <param name="propName">Property name as string.</param>
/// <returns>PropertyValue</returns>
public static T? GetPrivatePropertyValue<T>(this object obj, string propName)
{
if (obj == null)
throw new ArgumentNullException("obj");
PropertyInfo? pi = obj.GetType().GetProperty(propName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
if (pi == null)
throw new ArgumentOutOfRangeException(propName,
$"Property {propName} was not found in Type {obj.GetType().FullName}");
return (T?)pi.GetValue(obj, null);
}

/// <summary>
/// Returns a private Property Value from a given Object. Uses Reflection.
/// Throws a ArgumentOutOfRangeException if the Property is not found.
/// </summary>
/// <typeparam name="T">Type of the Property</typeparam>
/// <param name="obj">Object from where the Property Value is returned</param>
/// <param name="propName">Property name as string.</param>
/// <returns>PropertyValue</returns>
public static T? GetPrivateFieldValue<T>(this object obj, string propName)
{
if (obj == null)
throw new ArgumentNullException("obj");
Type? t = obj.GetType();
FieldInfo? fi = null;
while (fi == null && t != null)
{
fi = t.GetField(propName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
t = t.BaseType;
}
if (fi == null)
throw new ArgumentOutOfRangeException(propName,
$"Field {propName} was not found in Type {obj.GetType().FullName}");
return (T?)fi.GetValue(obj);
}

/// <summary>
/// Returns a field value from a given Object. Uses Reflection. Returns null if not found.
/// </summary>
/// <typeparam name="T">Type of the Property</typeparam>
/// <param name="obj">Object from where the Property Value is returned</param>
/// <param name="propName">Property name as string.</param>
/// <returns>PropertyValue or null</returns>
public static T? GetFieldValueOrDefault<T>(this object obj, string propName) where T: class
{
if (obj == null)
throw new ArgumentNullException("obj");
Type? t = obj.GetType();
FieldInfo? fi = null;
while (fi == null && t != null)
{
fi = t.GetField(propName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
t = t.BaseType;
}

if (fi == null)
return null;
return (T?)fi.GetValue(obj);
}

/// <summary>
/// Sets a _private_ Property Value from a given Object. Uses Reflection.
/// Throws a ArgumentOutOfRangeException if the Property is not found.
/// </summary>
/// <typeparam name="T">Type of the Property</typeparam>
/// <param name="obj">Object from where the Property Value is set</param>
/// <param name="propName">Property name as string.</param>
/// <param name="val">Value to set. null is a valid value.</param>
/// <returns>PropertyValue</returns>
public static void SetPrivatePropertyValue<T>(this object obj, string propName, T? val)
{
Type? t = obj.GetType();
PropertyInfo? propertyInfo = null;

while (propertyInfo == null && t != null)
{
propertyInfo = t.GetProperty(propName, BindingFlags.Public | BindingFlags.NonPublic
| BindingFlags.Instance | BindingFlags.SetProperty);
t = t.BaseType;
}

if (propertyInfo == null)
throw new ArgumentOutOfRangeException(propName,
$"Property {propName} was not found in Type {obj.GetType().FullName} or its ancestor types.");

propertyInfo.SetValue(obj, val);
}

/// <summary>
/// Set a private Property Value on a given Object. Uses Reflection.
/// </summary>
/// <typeparam name="T">Type of the Property</typeparam>
/// <param name="obj">Object from where the Property Value is returned</param>
/// <param name="propName">Property name as string.</param>
/// <param name="val">the value to set</param>
/// <exception cref="ArgumentOutOfRangeException">if the Property is not found</exception>
public static void SetPrivateFieldValue<T>(this object obj, string propName, T val)
{
if (obj == null)
throw new ArgumentNullException("obj");
Type? t = obj.GetType();
FieldInfo? fi = null;
while (fi == null && t != null)
{
fi = t.GetField(propName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
t = t.BaseType;
}
if (fi == null)
throw new ArgumentOutOfRangeException(propName,
$"Field {propName} was not found in Type {obj.GetType().FullName}");
fi.SetValue(obj, val);
}

public static string GetDescription(this Enum genericEnum)
{
Type genericEnumType = genericEnum.GetType();
MemberInfo[] memberInfo = genericEnumType.GetMember(genericEnum.ToString());
if ((memberInfo.Length > 0))
{
var attributes = memberInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);
if (attributes.Any())
return ((DescriptionAttribute)attributes.ElementAt(0)).Description;
}
return genericEnum.ToString();
}
}
}
40 changes: 40 additions & 0 deletions TradeWindsCommon/Extensions/AssemblyExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@

// Copyright (c) 2024 Trade Winds Studios (David Thielen)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

using System.Reflection;

namespace TradeWindsCommon.Extensions
{
/// <summary>
/// Extensions to the Assembly class.
/// </summary>
public static class AssemblyExtensions
{
/// <summary>
/// Return the file version for the assembly.
/// </summary>
public static string GetAssemblyFileVersion(this Assembly assembly)
{
var attr = assembly.GetCustomAttribute<AssemblyFileVersionAttribute>();
return attr == null ? "" : attr.Version;
}
}
}
49 changes: 49 additions & 0 deletions TradeWindsCommon/Extensions/BitmapExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@

// Copyright (c) 2024 Trade Winds Studios (David Thielen)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

namespace TradeWindsCommon.Extensions
{
/// <summary>
/// Utilities for Bitmaps.
/// </summary>
public static class BitmapExtensions
{
/// <summary>
/// For the passed in file contents, return the inline html bitmap contents.
/// </summary>
/// <param name="bytes">The file image.</param>
/// <returns>The src= value.</returns>
public static string GetImgData(byte[] bytes)
{
var type = bytes[0] switch
{
0x89 => "image/png",
0xFF => "image/jpeg",
0x47 => "image/gif",
0x49 => "image/tiff",
0x4D => "image/tiff",
_ => "image/svg+xml"
};

return $"data:{type};base64,{Convert.ToBase64String(bytes)}";
}
}
}
Loading

0 comments on commit 365cc3d

Please sign in to comment.