February 9, 2020

Sample Regular Expression

[TestMethod]
public void ParseVideoFileForDateTime2Test()
{
    var filePath = @"D:\Temp\Nokia 6\Photos\OpenCamera\VID_20190623_085427.mp4";
    var fileNameSansExt = Path.GetFileNameWithoutExtension(filePath);
    var fi = new FileInfo(filePath);

    var dateTimeFormat = "yyyyMMdd_HHmmss";
    var result = string.Empty;
    Regex regExp = null;
    CalcRegExpForDateTimeFormat(dateTimeFormat, out regExp);
    if (regExp != null)
    {
        result = regExp.MatchFirstRegExp(fileNameSansExt);
    }
    Assert.IsNotNull(regExp);
    Assert.IsTrue(result.Length == 15);
    Assert.IsTrue(result == "20190623_085427");
}

private static bool CalcRegExpForDateTimeFormat(
    string dateTimeFormat, out Regex regExp)
{
    var res = false;
    regExp = null;
    var newRegex = new StringBuilder(dateTimeFormat.Length);
    foreach (var ch in dateTimeFormat)
    {
        if ((ch == 'y') || (ch == 'M') || (ch == 'd') ||
            (ch == 'H') || (ch == 'm') || (ch == 's'))
        {
            newRegex.Append(@"\d");
        }
        else
        {
            newRegex.Append(ch);
        }
    }
    var regexStr = newRegex.ToString();
    res = (regexStr.Length > 0);
    if (res)
    {
        regExp = new Regex(regexStr, RegexOptions.Compiled);
    }
    return res;
}

public static class RegularExpressionExtensions
{
/// <summary>
/// Match the first occurance of a regular expression in a target string.
/// </summary>
/// <param name="target">string to search</param>
/// <param name="regexp">regular expression object to use for the
/// search</param>
/// <returns>first match of the regular expression otherwise an 
/// empty string if there is no match</returns>
  public static string MatchFirstRegExp(this Regex reg, string target)
  {
    var result = "";
    MatchCollection mc = reg.Matches(target);
    if (mc.Count > 0)
    {
        result = mc[0].Value;
    }
    return result;
  }
}

November 14, 2019

Sql Server Version Finder using Value Tuples in C# Version 8

Here is an example of using the new tuples in Version 8 of the C# compiler. I've tried to use these tuples in a way which makes them as readable as possible.

public class SqlVersionFinder
{
  public (string version, string date, string copyright, string edition)
                          GetSqlVersion(string server = @".\")
  {
    // Use named arguments so that the tuple is easy to read and maintain
    var res = (version: "", date: "", copyright: "", edition: "");

    using (var connection = new SqlConnection(String.Format(
        "Server={0};Database=master;Trusted_Connection=True;",
         server)))
    {
      connection.Open();
      var sqlResult = "";

      using (var command = connection.CreateCommand())
      {
        command.CommandText = " SELECT @@VERSION";
        sqlResult = command.ExecuteScalar() as string ?? "";
      }
      if (!string.IsNullOrEmpty(sqlResult))
      {
        var versionInfo = sqlResult.Split(new[] { "\n\t" }, 
                            System.StringSplitOptions.None);
        if (versionInfo != null && versionInfo.Length >= 4)
        {
           res.version = versionInfo[0] ?? "";
           res.date = versionInfo[1] ?? "";
           res.copyright = versionInfo[2] ?? "";
           res.edition = versionInfo[3] ?? "";
        }
      }
    }
    return res;
  }
}
Here is the test code (from a Console app) that retrieves Sql Server Version information
SqlVersionFinder sqlVersionFinder = new SqlVersionFinder();
var res = sqlVersionFinder.GetSqlVersion();
Console.WriteLine("Version:   " + res.version);
Console.WriteLine("Date:      " + res.date);
Console.WriteLine("Copyright: " + res.copyright);
Console.WriteLine("Edition:   " + res.edition);
Output looks like this:

Version: Microsoft SQL Server 2016 (RTM) - 13.0.1601.5 (X64)
Date: Apr 29 2016 23:23:58
Copyright: Copyright (c) Microsoft Corporation
Edition: Standard Edition (64-bit) on Windows 10 Enterprise 6.3 (Build 17134: )


Console Application Template

Here is a simple template for console applications, including how to change the font color within the console

class Program
{
  static void Main(string[] args)
  {
    Console.WriteLine("Started SomeConsoleApplication");
    Console.WriteLine("");

    Console.ForegroundColor = ConsoleColor.Green; // Go/all is good colour
    try
    {
      // Do your console app work here
      SqlVersionFinder sqlVersionFinder = new SqlVersionFinder();
      var res = sqlVersionFinder.GetSqlVersion();
      Console.WriteLine("Version:   " + res.version);
      Console.WriteLine("Date:      " + res.date);
      Console.WriteLine("Copyright: " + res.copyright);
      Console.WriteLine("Edition:   " + res.edition);

    }
    catch (Exception ex)
    {
      Console.WriteLine("Oops, an exception occurred trying to run the application: "
                                  + ex.ToString());
      Console.ForegroundColor = ConsoleColor.Red; // Error colour
      Console.ResetColor();
    }

    Console.ResetColor();
    // This will stop the console application from finishing until a key is pressed
    // However you might not want this if the application is to be run from another
    // process or you might want to use a command line argument to enable or 
    // disable this option
    Console.WriteLine("");
    Console.WriteLine("Press any key to finish ...");
    Console.ReadKey(); 
  }
}

November 6, 2019

Getting the Current Method Name

[Test]
public void CurrentMethodNameExperiments()
{
    var method1 = MethodBase.GetCurrentMethod().DeclaringType +
                  "." + MethodBase.GetCurrentMethod().Name + "()";
    var method2 = MethodBase.GetCurrentMethod().ToString();
    var method3 = GetMethodName();
    Debug.WriteLine("Method 1: MethodBase.GetCurrentMethod().DeclaringType + " + 
        "MethodBase.GetCurrentMethod().Name");
    Debug.WriteLine("Method 2: MethodBase.GetCurrentMethod().ToString()");
    Debug.WriteLine("Method 3: Using attributes");
    Debug.WriteLine();
    Debug.WriteLine("Method 1: " + method1);
    Debug.WriteLine("Method 2: " + method2);
    Debug.WriteLine("Method 3: " + method3);
}


public string GetMethodName(
                    [CallerMemberName] string memberName = "",
                    [CallerFilePath] string sourceFilePath = "",
                    [CallerLineNumber] int sourceLineNumber = 0)
{
    string result = memberName + "() in file \"" + sourceFilePath + 
                "\" (" + sourceLineNumber + ")";
    return result;
}
Output looks like this:
Method 1: MethodBase.GetCurrentMethod().DeclaringType + MethodBase.GetCurrentMethod().Name
Method 2: MethodBase.GetCurrentMethod().ToString() 
Method 3: Using attributes
 
Method 1: ClassLibrary1.Tests.CurrentMethodNameExperiments()
Method 2: Void CurrentMethodNameExperiments()
Method 3: CurrentMethodNameExperiments() in file "...\Tests.cs" (49)

October 25, 2019

Expand Environment Variables Extension

An extension to expand environment variables within a string

namespace Common.Environment.EnvironmentVariableExtension
{
  public static class StringEnvironmentVariableExtension
  {
    public static string ExpandEnvironmentVariables(this string path)
    {
        Debug.Assert(path != null);
        string result = "";
        result = Environment.ExpandEnvironmentVariables(path);
        return result;
    }
  }
}
and usage
using Common.Environment.EnvironmentVariableExtension;

[Test]
public void ExpandEnvironmentVariablesUsage()
{
    string path = "%Temp%";
    string tempPath = path.ExpandEnvironmentVariables();
}

October 23, 2019

Using StackTrace Object to Help Debugging

This is useful when you need to ensure that an action (eg. breakpoint) occurs only when the method was invoked in the correct context. Frequently the area of interest could be invoked from several areas/contexts, the StackTrace object allows you to ensure that you are debugging the common method within the correct invokation context

StackTrace st = new StackTrace(false);
var found = st.GetFrames().Any(sf => sf.GetMethod().Name.Contains("MethodName"));

if (found) // This ensures that the action occurs in the correct context
{
 if (ix == 1) // or some other condition
 {
  Trace.WriteLine("Stack Trace of where the exception occurred: " + st.ToString());
     Debugger.Break(); // Forces a breakpoint here
  
  throw new MyException("Test exception");
 }
}

Be aware that a StackTrace object is computationally quite expensive. This technique might not work where the method being debugged is called at a high rate and which finishes processing very quickly. However, we are using it here for debugging only.


November 10, 2018

ThreadPool Extensions

A better more versatile way to do this is to use Task<> objects
public static class ThreadpoolExtensions
{
    // Execute a method/procedure on the thread pool
    // The state parameters allow you to pass parameters into the thread routine 
    public static bool ExecuteOnThreadPoolThread<T>(this Action<T> threadRoutine, T args)
    {
        return ThreadPool.QueueUserWorkItem(s => threadRoutine((T)s), args);
    }

    // Execute a method/procedure on the thread pool
    public static bool ExecuteOnThreadPoolThread(this Action threadRoutine)
    {
        return ThreadPool.QueueUserWorkItem((obj) => threadRoutine());
    }
}