August 28, 2013

LINQPad Command-Line and Scripting

LINQPad Command-Line and Scripting
Sample usage:
CALL C:\...\LinqPad\lprun.exe "C:\...\Queries\AttachDatabases.linq" DEV
This runs the given linq query. The sample is a "C# Program" and has a "Main" method taking "string[] args" as a paremeter. In this way the "DEV" string at the end of the line is passed as a parameter to the linq program.
Here is the sample linq script:
<Query Kind="Program" />

void Main(string[] args)
{
  string attachFolder = @"C:\Databases\";
  if ((args != null) && (args.Length == 1))
  {
  attachFolder = Path.Combine(attachFolder, args[0]);
  }
  Console.WriteLine("Attaching to databases in \'" + attachFolder + "\'"); 
  Console.WriteLine("");
  var server = @".\";
  var databaseNames = new[] { "XXX", "YYY", "ZZZ", "AAA" };

    using(var connection = new SqlConnection(
   string.Format("Server={0};Database=master;Trusted_Connection=True;", server)))
    {
    connection.Open();
  
    // attach the databases
    foreach(var database in databaseNames)
    {
      var dataFile = Path.Combine(attachFolder, database + "_Data.MDF");
      if (File.Exists(dataFile))
      {
        Console.WriteLine("Attaching {0}", database);
        var attachCommand = connection.CreateCommand();
        attachCommand.CommandText = "sp_attach_db  @dbName, @dataFileName, @logFileName";
        attachCommand.Parameters.AddWithValue("dbName", database);
        attachCommand.Parameters.AddWithValue("dataFileName", dataFile);
        attachCommand.Parameters.AddWithValue("logFileName", 
            Path.Combine(attachFolder, database + "_Log.LDF"));    
        attachCommand.ExecuteNonQuery();
      }
      else
      {
        Console.WriteLine("No data file for {0}", database);
      }
    }
      }
  
    Console.WriteLine("");
    Console.WriteLine("Press any key to continue ...");
    Console.ReadKey(false);
}
If you want the script to hang around a bit so that you can read the error messages then you can add the the following lines to the end
Console.WriteLine("");
Console.WriteLine("Press any key to continue ...");
Console.ReadKey(false);
This keeps the script alive until a key is pressed.

August 16, 2013

An Animated WPF Gif

The Image control in WPF does not support animated GIF files by default. However, there is a library on codeplex, here, that can be used to do this.
Here is my usage of this library for an animated busy indicator.
In the XAML, first of all create an XML namespace for the library:
xmlns:gif="http://wpfanimatedgif.codeplex.com"
then use it with an image control:
<Image Name="imgBusy" 
       Stretch="UniformToFill" VerticalAlignment="Top" Width="20"  
    gif:ImageBehavior.AnimatedSource="/ScriptRunnerWPF;component/Resources/busyIndicator.gif" 
    gif:ImageBehavior.AutoStart="False" />
In code the animation of the GIF can be controlled:
Start the animation
   
this.imgBusy.Visibility = System.Windows.Visibility.Visible;
ImageAnimationController iac = ImageBehavior.GetAnimationController(this.imgBusy);
if (iac != null)
    iac.Play();
Resume the animation
// Resume the animation (or restart it if it was completed)
ImageAnimationController iac = ImageBehavior.GetAnimationController(this.imgBusy);
if (iac != null)
 iac.Pause();
this.imgBusy.Visibility = System.Windows.Visibility.Hidden;

Using StackTrace

Using StackTrace to show the first 3 lines of a stack trace in the debugger:
StackTrace st = new StackTrace(false);
st.Dump("UpdateScriptRunning Stack Trace", 3);
and the accompanying extension method:
public static class StackTraceExtender
{
  public static void Dump(this StackTrace st, string context, int numFrames)
  {
    Debug.WriteLine(context ?? "");
    string stk = st.ToString();
    string[] wanted = stk.Split(new string[] { "\r\n" }, 
                             StringSplitOptions.RemoveEmptyEntries);
    foreach (string line in wanted.Take(numFrames))
    {
        Debug.WriteLine(line ?? "");
    }
  }
}