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.