HTTPS redirect on web server

create .htaccess file at public_html root

# WHERE domain = the domain
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{SERVER_PORT} 80
RewriteCond %{HTTP_HOST} ^(www\.)?domain\.com
RewriteRule ^(.*)$ https://www.domain.com [R,L]
RewriteBase /
</IfModule>

Prevent IIS From Sleeping

    • Open IIS Manager
    • Application Pools > Right-click the App Pool > Advanced Settings
    • Set the following values:
      • (General) Start Mode = AlwaysRunning
      • (Process Model) Idle Time-out = 0
      • (Process Model) Load User Profile = False
      • (Recycling) Regular Time Interval = 0
      • (Recycling) Specific Times – clear all values from the TimeSpan[] Array
    • Click OK

Convert a C# model into a list of SqlParameters

Assumes properties are decorated with [Column("column_name")] attributes.

public static List<SqlParameter> ToSqlParameters<T>(this T obj)
{
  var result = new List<SqlParameter>();
  var properties = obj.GetType().GetProperties();
    
  properties.ToList().ForEach(propertyInfo => 
  {
    var column = propertyInfo.GetCustomAttribute<ColumnAttribute>();
    var notMapped = propertyInfo.GetCustomAttribute<NotMappedAttribute>();

    // see previous post for this method "IsNullOrDefault"
    if (column != null && notMapped = null && !propertyInfo.IsNullOrDefault(obj)) 
    {
      var fieldValue = propertyInfo.GetValue(obj, default);
      var sqlParam = new SqlParameter($"@{column.Name}", fieldValue);

      result.Add(sqlParam);
    }
  });

  return result;
}

Convert a DataTable into a List of field/value pairs

public static List<Dictionary<string, dynamic>> ToDict(this DataTable dt) 
{
    var tableDict = new List<Dictionary<string, dynamic>>();

    foreach (DataRow row in dt.Rows)
    {
        var rowDict = new Dictionary<string, dynamic>();

        foreach (DataColumn col in dt.Columns) 
        {
            var fieldValue = row[col].Equals(DBNull.Value)
                ? null
                : row[col];

            rowDict.Add(col.ColumnName, fieldValue);
        }

        tableDict.Add(rowDict);
    }

    return tableDict;
}

Install new certificate on GoDaddy

    1. run `certbot certonly –manual
    2. ssh into GoDaddy web server
    3. cd to public_html/.well-known/acme-challenge
    4. create a file named the same as everything after the last slash in the certbot result
    5. vim into the file and paste the data certbot specifies (separated by a dot)
    6. press enter on certbot terminal
    7. login to godaddy cPanel > SSL/TLS
    8. click update certificate for the domain
    9. paste the contents of CertBot\live\website\cert.pem into the CRT field
    10. paste the contents of CertBot\live\website\privkey.pem into the Private Key field
    11. leave the Certificate Authority field empty
    12. save

Get enum definitions from C# API for Angular

    internal static class EnumExt
    {
        public static List<EnumDefinition> Define<TEnum>() where TEnum : Enum
        {
            var result = new List<EnumDefinition>();
            var keys = Enum.GetNames(typeof(TEnum));

            keys.ToList().ForEach(key =>
            {
                var desc = ((TEnum)Enum.Parse(typeof(TEnum), key))
                    .GetType()
                    .GetMember(key)
                    .FirstOrDefault()
                    ?.GetCustomAttribute<DescriptionAttribute>()
                    ?.Description;

                if (string.IsNullOrWhiteSpace(desc))
                {
                    desc = key;
                }

                var value = (int)(Enum.Parse(typeof(TEnum), key));

                var def = EnumDefinition.Create(key, value, desc);

                result.Add(def);
            });

            return result;
        }
    }
 internal class EnumDefinition
    {
        public string Key { get; private set; }
        public int Value { get; private set; }
        public string Description { get; private set; }

        public static EnumDefinition Create(
            string key, int value, string desc)
        {
            return new EnumDefinition
            {
                Key = key,
                Value = value,
                Description = desc
            };
        }
    }

Generic BLL and DAL for Reference Data with caching and backup files

BLL

internal class Blc<TEntity> : IBlc<TEntity>
{
    private readonly IDao<TEntity> _dao;
 
    public Blc(IDao<TEntity> dao)
    {
        _dao = dao;
    }
 
    /// <summary>
    /// <inheritdoc cref="IBlc{TEntity}.GetAsync()"/>
    /// </summary>
    public async Task<IEnumerable<TEntity>> GetAsync()
    {
        var cache = _dao.GetFromCache();
 
        if (cache != null && cache.Any())
        {
            return cache;
        }
 
        return await _dao.GetAsync();
    }
 
    /// <summary>
    /// <inheritdoc cref="IBlc{TEntity}.GetAsync(Expression{Func{TEntity, bool}})"/>
    /// </summary>
    public async Task<IEnumerable<TEntity>> GetAsync(Expression<Func<TEntity, bool>> expression)
    {
        var cache = _dao.GetFromCache();
 
        if (cache != null && cache.Any())
        {
            return cache.Where(expression);
        }
 
        return await _dao.GetAsync(expression);
    }
 
    /// <summary>
    /// <inheritdoc cref="IBlc{TEntity}.InitializeAsync()"/>
    /// </summary>
    public async Task InitializeAsync()
    {
        var results = await _dao.GetAsync();
 
        if (!results.Any())
        {
            var fileData = _dao.GetFromFile();
 
            if (fileData == null || !fileData.Any())
            {
                throw new KeyNotFoundException("Unable to get refdata from MongoDb nor from its backup file");
            }
 
            await _dao.InsertManyAsync(fileData);
        }
 
        _dao.InsertCache(results.ToList());
    }
}
 
public interface IBlc<TEntity>
{
    /// <summary>
    /// Gets a list of TEntity from MongoDb
    /// </summary>
    Task<IEnumerable<TEntity>> GetAsync();
 
    /// <summary>
    /// Gets a filtered list of TEntity
    /// </summary>
    /// <param name="expression">filter expression</param>
    /// <example>await _blc.GetAsync(x => x.Id == 1);</example>
    Task<IEnumerable<TEntity>> GetAsync(Expression<Func<TEntity, bool>> expression);
 
    /// <summary>
    /// Called during application StartUp.
    /// Checks if data already exists in database.
    /// If not, pulls backup data from a json file and inserts that into database,
    /// then inserts the data into the cache.
    /// </summary>
    /// <exception cref="KeyNotFoundException"></exception>
    Task InitializeAsync();
}

DAL

/// <summary>
/// Ideally, this class will not be called directly, but instead via Blc
/// </summary>
internal class Dao<TEntity> : IDao<TEntity> where TEntity : class
{
    private readonly IMemoryCache _cache;
    private readonly string _cacheKey;
    private readonly string _backupFile;
    private readonly IMongoCollection<TEntity> _mongoCollection;
    private readonly IJsonFileReader _fileReader;
 
    public Dao(
        MongoClient client,
        IOptionsMonitor<Dictionary<string, MongoCollectionConfiguration>> collectionConfigs,
        IOptionsMonitor<AppSettings> appSettings,
        IMemoryCache cache,
        IJsonFileReader fileReader)
    {
        BsonClassMap.RegisterClassMap<TEntity>(cm =>
        {
            cm.AutoMap();
            cm.SetIgnoreExtraElementsIsInherited(true);
            cm.SetIgnoreExtraElements(true);
        });
 
        var database = client.GetDatabase(appSettings.CurrentValue.DbName);
        var collectionConfig = collectionConfigs.CurrentValue.FirstOrDefault(x =>
            x.Key.ToLowerInvariant() == typeof(TEntity).Name.ToLowerInvariant()).Value;
 
        _cacheKey = collectionConfig.CacheKey;
        _backupFile = collectionConfig.BackupFileName;
        _mongoCollection = database.GetCollection<TEntity>(collectionConfig.CollectionName);
        _cache = cache;
        _fileReader = fileReader;
    }
 
    /// <summary>
    /// <inheritdoc cref="IDao{TEntity}.GetAsync()"/>
    /// </summary>
    public async Task<IEnumerable<TEntity>> GetAsync()
    {
        try
        {
            var cursorResult = await _mongoCollection.FindAsync(_ => true);
            return await cursorResult.ToListAsync();
        }
        catch (MongoException ex)
        {
            throw new DatabaseException(ex.ToString());
        }
    }
 
    /// <summary>
    /// <inheritdoc cref="IDao{TEntity}.GetAsync(Expression{Func{TEntity, bool}})"/>
    /// </summary>
    public async Task<IEnumerable<TEntity>> GetAsync(Expression<Func<TEntity, bool>> expression)
    {
        try
        {
            var filter = Builders<TEntity>.Filter.Where(expression);
            var cursorResult = await _mongoCollection.FindAsync(filter);
            return await cursorResult.ToListAsync();
        }
        catch (MongoException ex)
        {
            throw new DatabaseException(ex.ToString());
        }
    }
 
    /// <summary>
    /// <inheritdoc cref="IDao{TEntity}.InsertManyAsync(List{TEntity})"/>
    /// </summary>
    public async Task InsertManyAsync(List<TEntity> data)
    {
        try
        {
            await _mongoCollection.InsertManyAsync(data);
        }
        catch (MongoException ex)
        {
            throw new DatabaseInsertException(ex.ToString());
        }
    }
 
    /// <summary>
    /// <inheritdoc cref="IDao{TEntity}.GetFromFile"/>
    /// </summary>
    public List<TEntity> GetFromFile()
    {
        var json = _fileReader.ReadAllText(_backupFile);
        return JsonSerializer.Deserialize<List<TEntity>>(json);
    }
 
    /// <summary>
    /// <inheritdoc cref="IDao{TEntity}.GetFromCache"/>
    /// </summary>
    public IQueryable<TEntity> GetFromCache()
    {
        _cache.TryGetValue(_cacheKey, out IQueryable<TEntity> cacheResults);
        return cacheResults;
    }
 
    /// <summary>
    /// <inheritdoc cref="IDao{TEntity}.InsertCache(List{TEntity})"/>
    /// </summary>
    public void InsertCache(List<TEntity> data)
    {
        var cacheEntryOptions = new MemoryCacheEntryOptions()
            .SetSlidingExpiration(TimeSpan.FromHours(12));
 
        _cache.Set(_cacheKey, data, cacheEntryOptions);
    }
}
 
public interface IDao<TEntity>
{
    /// <summary>
    /// Pulls a list of TEntity from MongoDb.
    /// </summary>
    Task<IEnumerable<TEntity>> GetAsync();
 
    /// <summary>
    /// Pulls a filtered list of TEntity from MongoDb.
    /// Converts the given Linq expression to a Mongo filter.
    /// </summary>
    Task<IEnumerable<TEntity>> GetAsync(Expression<Func<TEntity, bool>> expression);
 
    /// <summary>
    /// Inserts many TEntity into MongoDb.
    /// </summary>
    /// <param name="data">the list to be inserted into MongoDb</param>
    Task InsertManyAsync(List<TEntity> data);
 
    /// <summary>
    /// Pulls a list of TEntity from its assigned backup json file.
    /// </summary>
    List<TEntity> GetFromFile();
 
    /// <summary>
    /// Pulls a list of TEntity from cache.
    /// </summary>
    IQueryable<TEntity> GetFromCache();
 
    /// <summary>
    /// Inserts a list of TEntity into cache
    /// </summary>
    void InsertCache(List<TEntity> data);
}

Automatically / Dynamically create Swagger documentation for all API Endpoints

            // Generate Documentation for each endpoint automatically
            var actionDescriptors = actionDescriptor.ActionDescriptors.Items.ToList();
            actionDescriptors.ForEach(x =>
            {
                IFilterMetadata noContent = new ProducesResponseTypeAttribute(204);
                x.FilterDescriptors.Add(new FilterDescriptor(noContent, 0));

                IFilterMetadata unauth = new ProducesResponseTypeAttribute(401);
                x.FilterDescriptors.Add(new FilterDescriptor(unauth, 0));

                IFilterMetadata serverError = new ProducesResponseTypeAttribute(500);
                x.FilterDescriptors.Add(new FilterDescriptor(serverError, 0));
            });

Pass and retrieve data in Mat-Dialog

// Pass data to Dialog
constructor(
    private _dialog: MatDialog
) {}

someFunction(whatever) {
    let dialogConfig = new MatDialogConfig();

    
    dialogConfig.data = {
      whatever: whatever,
    };

    this._dialog.open(
      MyDialog,
      dialogConfig
    );
}


// Retrieve within the dialog
constructor(
    @Inject(MAT_DIALOG_DATA) private _inputParams: any
) {}

ngOnInit(): void {
    this.whatever = this._inputParams.whatever;
}

Update global npm packages

// Updating all globally-installed packages
npm update -g
// or 
npm install npm@latest -g

// Determining which global packages need updating
npm outdated -g --depth=0

// Updating a single global package
npm update -g <package_name>

ref