Category Archives: C#

NUnit Test Cases picking up cached version of an assembly

We all know that Test Driven Development makes development so much quicker and safer. However, I’ve had a problem for a while whereby my NUnit test cases which reference libraries built for BizTalk projects don’t update when I make a change to the code and re-run the test case. The only way around it was to restart Visual Studio – a major pain.

Today I did a bit more digging and found out what was wrong. BizTalk needs signed assemblies deployed to the GAC to be picked up at runtime so I’ve always automatically done this and also added a post build event to add my assemblies to the GAC on a successful build. It was this that was causing my NUnit test case to pick up the signed version instead.

The solution is to untick the “sign the assembly” box in the properties of the library and also REM the post build events whilst you are in the unit testing phase. This will mean the NUnit library will pick up the version of the .dll within your Visual Studio environment.

Running Command Line Process from c# code is Hanging / Locking and never Finishing

I created a WCF Service to allow remote machines to run command line scripts (in this case batch files) and then return the error and standard output as a string to the caller. The batch files worked fine when you ran them directly but whenever I ran them via the WCF service they kept hanging / locking and never completing. Mysterious.

I have since found out that this is because you have to redirect either or both of the standard out or error out to read in an asynchronous thread otherwise you get a deadlock when the buffer on one becomes full. Here is my code which does this and there is now no locking.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
using System.Diagnostics;
using System.Security;
using System.Security.Principal;
using System.Security.Permissions;
using System.IO;

namespace MyCompany.BatchScriptsService
{
    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "Service1" in code, svc and config file together.
    /// <summary>
    ///
    /// </summary>
    [ServiceBehavior(Namespace = "http://MyCompany.LaunchBatchScript")]
    public class LaunchBatchScriptService : ILaunchBatchScriptService
    {

        private StringBuilder allStandardOutput;

        public StringBuilder AllStandardOutput
        {
            get { return allStandardOutput; }
            set { allStandardOutput = value; }
        }

        private static readonly log4net.ILog log = log4net.LogManager.GetLogger
    (System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

        /// <summary>
        /// Launches the batch script.
        /// </summary>
        /// <param name="batchScriptFilename">The batch script filename.</param>
        /// <param name="runAsUsername">The run as username.</param>
        /// <param name="runAsPassword">The run as password.</param>
        /// <param name="arguments">The arguments.</param>
        /// <returns></returns>
        public string LaunchBatchScript(LaunchBatchScriptDataContract inputVariables)
        {

            try
            {
                // Initiate the logging
                log4net.Config.XmlConfigurator.Configure();
                log.Info(String.Format("Start LaunchBatchScriptService call"));

                // Create a new process object
                Process p = new Process();

                // Redirect the output stream of the child process.
                p.StartInfo.UseShellExecute = false;

                p.StartInfo.RedirectStandardOutput = true;
                p.StartInfo.RedirectStandardError = true;
                p.StartInfo.RedirectStandardInput = true;
                p.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Normal;

                if (inputVariables.BatchScriptFilename.Contains(" ") && !inputVariables.BatchScriptFilename.StartsWith("\""))
                {
                    // Ecapsulate in double quotes
                    inputVariables.BatchScriptFilename = String.Format("\"{0}\"", inputVariables.BatchScriptFilename);
                }

                p.StartInfo.FileName = inputVariables.BatchScriptFilename;
                log.Info(String.Format("Running script {0}", inputVariables.BatchScriptFilename));

                if (!String.IsNullOrEmpty(inputVariables.Arguments))
                {
                    p.StartInfo.Arguments = inputVariables.Arguments;
                }

                // This is where the output is redirected
                p.ErrorDataReceived += build_ErrorDataReceived;
                p.OutputDataReceived += build_ErrorDataReceived;

                // Initialise the StringBuilder Object
                AllStandardOutput = new StringBuilder();

                // Kick off the command
                bool isProcessStarted = p.Start();

                string output = "Process not started";

                if (isProcessStarted)
                {

                    log.Info(String.Format("Process Started Successfully"));
                    p.BeginOutputReadLine();
                    p.BeginErrorReadLine();

                    p.WaitForExit(); // wait for both threads to finish

                    output = AllStandardOutput.ToString();

                }

                log.Info(String.Format("Returning {0}", output));

                log.Info(String.Format("End LaunchBatchScriptService call"));
                return output;

            }
            catch (Exception ex)
            {
                log.Error(String.Format("There was a problem running the script: {0}",ex.Message));
                throw new FaultException(System.String.Format("There was a problem executing the script {0}: {1}", inputVariables.BatchScriptFilename, ex.Message));
            }
        }

        /// <summary>
        /// Handles the ErrorDataReceived event of the build control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Diagnostics.DataReceivedEventArgs"/> instance containing the event data.</param>
        public void build_ErrorDataReceived(object sender, DataReceivedEventArgs e)
        {
            string strMessage = e.Data;

            AllStandardOutput.Append(strMessage);
            AllStandardOutput.Append(System.Environment.NewLine);
        }
    }
}