profile for TheDaveJay at Stack Overflow, Q&A for professional and enthusiast programmers

Wednesday 19 December 2012

No Pain - No Gain


No Pain - No Gain (or so they say)

I am recently learning that the saying “No Pain – No Gain” really depends on the software you are developing and the culture of the company you may have recently joined. I believe this phrase can be broken into 3 rather more accurate sayings which also depict a journey that a 10 years old start-up company could expect (base on my experience so far) when trying to move to a well-established company that can stand with its head high and proud.

Step 1 in the journey : Pain – No Gain

For the past 6 months, I have witnessed really painful development practises, long winded and very complex deployments, framework architecture which is so swollen with already existing FREE off the shelf software, and to end it off, a bastardised agile methodology.  “Pain – No Gain” sums up the company’s future.
If we have to leave the companies software and culture in its current state, it will collapse on itself.  It’s becoming more and more difficult to meet the customers’ requirements because the underlying framework is over engineered, and was designed by junior developers, and self-acclaimed architects at the time, and was never intended to cope with the modern requirements of today.
This part of the journey lasts the longest. It usually requires people of strong will and determination to break out of this phase. Skilled developers and architects that join are usually gone within 2 weeks because it takes too long to get over the “change inertia”. This is also years of turning a blind eye to the issues thinking they will go away.

Step 2 in the journey : Pain –  Gain (Feel the burn!)



Once we managed to get the right resources in place to start the change, things become more painful. One of the first things we tried to correct, which is critical to the business process is implementing SCRUM into the development team.

As most people who have implemented Agile methodologies in their work environment would know,  is that Agile has this amazing ability to show the true issues happening in a company - and this was no different for us. This is not a bad thing, and should not be feared. The more we know about what’s going wrong, they more we are able to fix it – evolving “Pain – No Gain” to “Pain – Gain”.

This is where Pain starts turning into Gain. The gain we are achieving may not affect the customers yet, but it’s definitely going to help with the future. This step can last a year or 2 due to the following factors:

<!--[if !supportLists]-->·         Spreading the cost of redevelopment and migration in a low risk fashion
<!--[if !supportLists]-->·         <!--[endif]-->Changing a company’s culture is hard work – there is some Stockholm syndrome involved for certain individuals. This may sound weird, but the guys who worked with the original framework have come to love it  - even though its killing them
<!--[if !supportLists]-->·         <!--[endif]-->Implementing Agile methodologies take time, and usually only start coming right after having at least 6 sprints. Unconscious habits only happen after doing it for long periods of time



Step 3: No Pain –  Gain (Now what?)

This is the final step that all companies should strive for in the journey. This is the part where all the right practises are being followed; the software is amazing to work with for the developers. The long winded deployments are done at the click of a button and the users get an amazing user experience.
Unfortunately this step is hard to come by in the real world – but it is achievable. Sometimes it happens unnoticed because we are always busy. When you get to the “..now what” point, let me know. I would be interested to see if you end up back at “Pain - No Gain”.





Thursday 12 April 2012

Custom logging handler for NLOG

Just a quick one - below is a custom Nlog helper which offers a centralized location for logging in a windows service. Its compatible to use with elmahs add proc. It allows you to easily log to multiple NLog settings using a flagged enum.

Class code (Must add the nlog dll as a reference)


 using System;
    using System.Collections.Generic;
    using System.Configuration;
    using System.Linq;
    using System.Security.Principal;
    using System.Text;
    using NLog;
    using PixelTrackingQueueService.Exceptions;
  
    public class LogHelper
    {
        public static LogHelper CurrentHelper = new LogHelper();

        [Flags]
        public enum LogType
        {
            Error = 0x01,
            CriticalError = 0x02,
            Warning = 0x04,
            Info = 0x08,
            Debug = 0x10,
            Trace = 0x20
        }

      
        public void Log(string message, LogType logType, Exception ex = null, Type currentType = null)
        {
            Logger logger = (currentType == null)
                                ? LogManager.GetCurrentClassLogger()
                                : LogManager.GetLogger(currentType.FullName);

            Action<string> log = null;
            Action<string, Exception> exLog = null;

            foreach (LogType flag in Enum.GetValues(typeof(LogType)))
            {

                LogType logLevel = (flag & logType);
                LogLevel level = LogLevel.Off;
                switch (logLevel)
                {
                    case LogType.Warning:
                        level = LogLevel.Warn;
                        break;
                    case LogType.CriticalError:
                        level = LogLevel.Fatal;
                        break;
                    case LogType.Error:
                        level = LogLevel.Error;
                        break;
                    case LogType.Info:
                        level = LogLevel.Info;
                        break;
                    case LogType.Trace:
                        level = LogLevel.Trace;
                        break;
                    case LogType.Debug:
                        level = LogLevel.Debug;
                        break;
                    default:
                        continue;
                }

                DoLog(logger, message, level, ex, currentType);
            }
        }


        private static void DoLog(Logger logger, string message, LogLevel level, Exception ex = null, Type type = null)
        {
            LogEventInfo info = new LogEventInfo(level,
                                                ((type == null) ? typeof(LogManager).FullName : type.FullName),
                                                null,
                                                message,null, ex);

            info.Properties["ApplicationName"] = ConfigurationManager.AppSettings["ApplicationName"];
            info.Properties["Host"] = System.Environment.MachineName;
            info.Properties["Type"] = (ex == null) ? level.ToString() : ex.GetType().FullName;
            info.Properties["CurrentUser"] = WindowsIdentity.GetCurrent().Name;
            info.Properties["Source"] = ex == null ? level.ToString() : ex.Source;

            string error = ex == null ? message : ex.ToString();
            string stackTrace = ex == null ? level.ToString() : ex.StackTrace;

            info.Properties["Error"] =
                string.Format(
                    @"<error host=""{0}"" type=""{1}"" message=""{2}"" source=""{3}"" detail=""{4}"" ><serverVariables>
                        <item name=""SERVICE_NAME""><value string=""{5}""/></item>              
                        <item name=""LOGON_USER""><value string=""{6}""/></item>
                        </serverVariables></error>",
                    System.Environment.MachineName,
                    info.Properties["Type"],
                    System.Security.SecurityElement.Escape(message),
                     info.Properties["Source"],
                    System.Security.SecurityElement.Escape(error),
                    "ServiceName",
                    info.Properties["CurrentUser"]);

            

            logger.Log(info);

        }
   
        private Logger GetLoggerFromType(Type currentType)
        {
             return  (currentType == null)
                                ? LogManager.GetCurrentClassLogger()
                                : LogManager.GetLogger(currentType.FullName);
        }
      
    }

 Nlog Config (with elmah proc) 

Add this file to your solution, calling it Nlog.config. This is the file Nlog will look for:

<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" >

  <!--
  See http://nlog-project.org/wiki/Configuration_file
  for information on customizing logging rules and outputs.
   -->
  <targets>
    <!-- add your targets here -->
   
    <!--
    <target xsi:type="File" name="f" fileName="${basedir}/logs/${shortdate}.log"
            layout="${longdate} ${uppercase:${level}} ${message}" />
    -->
    <target name="elmah" xsi:type="Database" keepConnection="true" useTransactions="true"
        dbProvider="sqlserver" connectionString="Data Source=im-dev01\;Initial Catalog=Elmah;Integrated Security=False;User ID=Elmah;Password=1234;">
      <commandText>
        DECLARE @ID UNIQUEIDENTIFIER = NEWID(), @time DATETIME = GETUTCDATE()
        SELECT @time
        EXEC ELMAH_LogError @ID ,'${event-context:item=ApplicationName}', '${event-context:item=Host}',
        '${event-context:item=Type}', '${event-context:item=Source}', '${message}','${event-context:item=CurrentUser}','${event-context:Error}', 1, @time
      </commandText>     
    </target>
    <target xsi:type="Mail" name="mailman" smtpServer="Mail.MailService.local" from="serviceerror@somewhere.com"
            html="true" to="someone@somewhere.com"
            subject="Service Error"
            cc="someoneelse@somewhere.com"
            body="&lt;h1&gt;Date and Time&lt;/h1&gt;${longdate}    &lt;h1&gt;Message&lt;/h1&gt;${message} &lt;h1&gt;Exception Details&lt;/h1&gt;
                  &lt;h2&gt;Error Details&lt;/h2&gt; ${exception:format=ToString} &lt;h2&gt;Stack Trace Details&lt;/h2&gt; ${exception:format=StackTrace}" />
    <target name="TraceLog" xsi:type="File" fileName="Logs/Traces.log" createDirs="true"/>
    <target name="ErrorLog" xsi:type="File" fileName="Logs/Errors.log" createDirs="true" layout="${message}\r\n${exception:format=ToString}"/>
    <target name="WarningLog" xsi:type="File" fileName="Logs/Warnings.log" createDirs="true"/>
    <target name="InfoLog" xsi:type="File" fileName="Logs/Info.log" createDirs="true"/>
  </targets>

  <rules>
    <logger name="*" level="Fatal" writeTo="mailman" />   
    <logger name="*" level="Error" writeTo="elmah" />
    <logger name="*" level="Info" writeTo="elmah" />
    <logger name="*" level="Trace" writeTo="elmah" />
    <logger name="*" level="Warn" writeTo="elmah" />
    <logger name="*" level="Debug" writeTo="elmah" />
  </rules> 
</nlog>


Example on using the code:

LogHelper.CurrentHelper.Log("Error has occured", LogHelper.LogType.Debug | LogHelper.LogType.CriticalError, exceptionObject, this.GetType());       

will log to both elmah and send a mail at the same time.

Network tracing for an app without code!

There have been times when I needed to dump the incoming and outgoing packets at a network level.

The simplest way and, which is quite efficient was to add System.Diagnostics to you .config file of the application.

Below is an example:

<system.diagnostics>
    <sources>
      <source name="System.Net" tracemode="includehex" maxdatasize="1024">
        <listeners>
          <add name="System.Net"/>
        </listeners>
      </source>
      <source name="System.Net.Sockets">
        <listeners>
          <add name="System.Net"/>
        </listeners>
      </source>
      <source name="System.Net.Cache">
        <listeners>
          <add name="System.Net"/>
        </listeners>
      </source>
      <source name="System.Net.HttpListener">
        <listeners>
          <add name="System.Net"/>
        </listeners>
      </source>
    </sources>
    <switches>
      <add name="System.Net" value="Verbose"/>
      <add name="System.Net.Sockets" value="Verbose"/>
      <add name="System.Net.Cache" value="Verbose"/>
      <add name="System.Net.HttpListener" value="Verbose"/>
    </switches>
    <sharedListeners>
      <add name="System.Net"
        type="System.Diagnostics.TextWriterTraceListener"
        initializeData="network.log"
      />
    </sharedListeners>
    <trace autoflush="true"/>
  </system.diagnostics>

Below gives a brief description on what the different sources will trace for:

System.Net.Sockets:

Some public methods of the Socket, TcpListener, TcpClient, and Dns classes

System.Net:

Some public methods of the HttpWebRequest, HttpWebResponse, FtpWebRequest, and FtpWebResponse classes, and SSL debug information (invalid certificates, missing issuers list, and client certificate errors.)

System.Net.HttpListener

Some public methods of the HttpListener, HttpListenerRequest, and HttpListenerResponse classes.

System.Net.Cache

Some private and internal methods in System.Net.Cache.

Self installing c# windows service - the safe and easy way.

Introduction

This post is on how to create a windows service that is self installing using c# and the managed installation features that comes with .net.

The source code for this example can be found here: GitHub

Step1 - Creating the new project

First of all, we need to create a new project called SelfInstallingService. I am using visual studio 2010 (.net 4) for this project. This will be a standard console app.  There are many tutorials on how to create a console app, so if you are unsure, I suggest you google it :)

Step2 - Adding the references to the project.

 You will need to add the following references to your project:

- System.ServiceProcess
- System.Configuration.Install

Step3 - Creating the service


  1. Open the Program class and extend the class by inheriting from the ServiceBase class.
  2. Add a public static string to hold the current service name
  3. Create a new constructor in the Program class, and put the code you want to run there i.e. code that      normally would go into the main method

You code will look as follows:

 


     4. Add the following methods to the class and resolve the namespaces for the new classes being used:


        protected override void OnStart(string[] args)
        {
            //start any threads or http listeners etc
        }

        protected override void OnStop()
        {
           //stop any threads here and wait for them to be stopped.
        }

        protected override void Dispose(bool disposing)
        {
            //clean your resources if you have to
            base.Dispose(disposing);
        }

        private static bool IsServiceInstalled()
        {
            return ServiceController.GetServices().Any(s => s.ServiceName == InstallServiceName);
        }

        private static void InstallService()
        {
            if ( IsServiceInstalled())
            {
                UninstallService();
            }
           
            ManagedInstallerClass.InstallHelper(new string[] { Assembly.GetExecutingAssembly().Location });
        }

        private static void UninstallService()
        {           
            ManagedInstallerClass.InstallHelper(new string[] { "/u", Assembly.GetExecutingAssembly().Location });
        }

5) Update the main method in the class to have the following code:

static void Main(string[] args)
        {
            bool debugMode = false;
            if (args.Length > 0)
            {
                for (int ii = 0; ii < args.Length; ii++)
                {
                    switch (args[ii].ToUpper())
                    {
                        case "/NAME":
                            if (args.Length > ii + 1)
                            {
                                InstallServiceName = args[++ii];
                            }
                            break;
                        case "/I":
                            InstallService();
                            return;
                        case "/U":
                            UninstallService();
                            return;
                        case "/D":
                            debugMode = true;
                            break;
                        default:
                            break;
                    }
                }
            }

            if (debugMode)
            {
                Program service = new Program();
                service.OnStart(null);
                Console.WriteLine("Service Started...");
                Console.WriteLine("<press any key to exit...>");
                Console.Read();
            }
            else
            {
                System.ServiceProcess.ServiceBase.Run(new Program());
            }
        }

You can see that the following command line arguments can be input:
- /NAME - sets the name of the service
- /I - Installs the service
-/U - Uninstalls the service
-/D - Runs the service in debug mode i.e. a Console Application

Step4 - Creating the installed

1) Add a new class called CustomServiceInstaller and inherit from the Installer.
2) Add a class attribute "RunInstaller" which takes a boolean value. Set this to value to True.
3) Resolve any namespace issues in the class.

You code will look as follows:

[RunInstaller(true)]
    public class CustomServiceInstaller : Installer
    {
    }

4) In the same class, create a constructor that creates the new process info and service:

        private ServiceProcessInstaller process;
        private ServiceInstaller service;

        public CustomServiceInstaller()
        {
            process = new ServiceProcessInstaller();
           
            process.Account = ServiceAccount.LocalSystem;

            service = new ServiceInstaller();
            service.ServiceName = Program.InstallServiceName;

            Installers.Add(process);
            Installers.Add(service);
        }

 

Step5 - Your done!

Your service is now complete. To run your program as debug, you can add the /D to your debug commands in the project settings, or you can set "debugMode" to true.

Below is an example of the command lines you can use to install and uninstall the service:

Install a service with the default name:

SelfInstallingService.exe /I

Uninstall service with the default name:

SelfInstallingService.exe /U

Install a service with custom service name:

SelfInstallingService.exe /NAME SelfIntallingServiceCustom /I

Uninstall service with custom name:


SelfInstallingService.exe /NAME SelfIntallingServiceCustom /U

Run the service as a console app

SelfInstallingService.exe /D