첨부 실행 코드는 나눔고딕코딩 폰트를 사용합니다.

728x90
반응형
728x170

TestSolution.zip
다운로드

[TestLibrary 프로젝트]

▶ ILogHelper.cs

using System;

namespace TestLibrary
{
    /// <summary>
    /// 로그 헬퍼 인터페이스
    /// </summary>
    public interface ILogHelper
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Method

        #region 메시지 쓰기 - WriteMessage(message)

        /// <summary>
        /// 메시지 쓰기
        /// </summary>
        /// <param name="message">메시지</param>
        void WriteMessage(string message);

        #endregion
        #region 로그 쓰기 - WriteLog(format, parameterArray)

        /// <summary>
        /// 로그 쓰기
        /// </summary>
        /// <param name="format">포맷 문자열</param>
        /// <param name="parameterArray">매개 변수 배열</param>
        void WriteLog(string format, params object[] parameterArray);

        #endregion
        #region 에러 로그 쓰기 - WriteErrorLog(exception, caption)

        /// <summary>
        /// 에러 로그 쓰기
        /// </summary>
        /// <param name="exception">예외</param>
        /// <param name="caption">제목 문자열</param>
        void WriteErrorLog(Exception exception, string caption);

        #endregion
        #region 에러 로그 쓰기 - WriteErrorLog(exception, caption)

        /// <summary>
        /// 에러 로그 쓰기
        /// </summary>
        /// <param name="message">예외 메시지</param>
        /// <param name="caption">제목 문자열</param>
        void WriteErrorLog(string message, string caption);

        #endregion
        #region 덤프 로그 쓰기 - WriteDumpLog(sourceObject, caption)

        /// <summary>
        /// 덤프 로그 쓰기
        /// </summary>
        /// <param name="sourceObject">예외</param>
        /// <param name="caption">제목 문자열</param>
        void WriteDumpLog(object sourceObject, string caption);

        #endregion
    }
}

 

728x90

 

▶ FileLogHelper.cs

using System;
using System.IO;

namespace TestLibrary
{
    /// <summary>
    /// 파일 로그 헬퍼
    /// </summary>
    public class FileLogHelper : ILogHelper 
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Private

        #region Field

        /// <summary>
        /// 동기 객체
        /// </summary>
        private object syncObject;

        /// <summary>
        /// 로그 루트 디렉토리 경로
        /// </summary>
        private string logRootDirectoryPath;

        /// <summary>
        /// 파일명
        /// </summary>
        private string fileName;

        /// <summary>
        /// 파일 경로
        /// </summary>
        private string filePath;

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 생성자 - FileLogHelper(logRootDirectoryPath, fileName)

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="logRootDirectoryPath">로그 루트 디렉토리 경로</param>
        /// <param name="fileName">파일명</param>
        public FileLogHelper(string logRootDirectoryPath, string fileName)
        {
            this.syncObject = new object();

            this.logRootDirectoryPath = logRootDirectoryPath;
            this.fileName             = fileName;

            this.filePath = Path.Combine(this.logRootDirectoryPath, this.fileName);

            if(!Directory.Exists(this.logRootDirectoryPath))
            {
                Directory.CreateDirectory(this.logRootDirectoryPath);
            }
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 메시지 쓰기 - WriteMessage(message)

        /// <summary>
        /// 메시지 쓰기
        /// </summary>
        /// <param name="message">메시지</param>
        public void WriteMessage(string message)
        {
            lock(this.syncObject)
            {
                using(StreamWriter writer = File.AppendText(this.filePath))
                {
                    writer.WriteLine(message);
                }
            }
        }

        #endregion
        #region 로그 쓰기 - WriteLog(format, parameterArray)

        /// <summary>
        /// 로그 쓰기
        /// </summary>
        /// <param name="format">포맷 문자열</param>
        /// <param name="parameterArray">매개 변수 배열</param>
        public void WriteLog(string format, params object[] parameterArray)
        {
            string message;

            if(parameterArray.Length == 0)
            {
                message = format;
            }
            else
            {
                message = string.Format(format, parameterArray);
            }

            string log = string.Format("[{0}] {1}", DateTime.Now.ToString("HH:mm:ss"), message);

            WriteMessage(log);
        }

        #endregion
        #region 에러 로그 쓰기 - WriteErrorLog(exception, source)

        /// <summary>
        /// 에러 로그 쓰기
        /// </summary>
        /// <param name="exception">예외</param>
        /// <param name="source">소스 문자열</param>
        public void WriteErrorLog(Exception exception, string source)
        {
            lock(this.syncObject)
            {
                string title = string.Format("[{0}] {1}", DateTime.Now.ToString("HH:mm:ss"), source);

                using(StreamWriter writer = File.AppendText(this.filePath))
                {
                    writer.WriteLine(title);
                    writer.WriteLine("--------------------------------------------------");
                    writer.WriteLine(exception.ToString());
                    writer.WriteLine("--------------------------------------------------");
                }
            }
        }

        #endregion
        #region 에러 로그 쓰기 - WriteErrorLog(message, source)

        /// <summary>
        /// 에러 로그 쓰기
        /// </summary>
        /// <param name="message">예외 메시지</param>
        /// <param name="source">소스 문자열</param>
        public void WriteErrorLog(string message, string source)
        {
            lock (this.syncObject)
            {
                string title = string.Format("[{0}] {1}", DateTime.Now.ToString("HH:mm:ss"), source);

                using (StreamWriter writer = File.AppendText(this.filePath))
                {
                    writer.WriteLine(title);
                    writer.WriteLine("--------------------------------------------------");
                    writer.WriteLine(message);
                    writer.WriteLine("--------------------------------------------------");
                }
            }
        }

        #endregion
        #region 덤프 로그 쓰기 - WriteDumpLog(sourceObject, caption)

        /// <summary>
        /// 덤프 로그 쓰기
        /// </summary>
        /// <param name="sourceObject">예외</param>
        /// <param name="caption">제목 문자열</param>
        public void WriteDumpLog(object sourceObject, string caption)
        {
            lock(this.syncObject)
            {
                string title = string.Format("[{0}] {1}", DateTime.Now.ToString("HH:mm:ss"), caption);

                using(StreamWriter writer = File.AppendText(this.filePath))
                {
                    writer.WriteLine(title);
                    writer.WriteLine("--------------------------------------------------");
                    writer.WriteLine(sourceObject.ToString());
                    writer.WriteLine("--------------------------------------------------");
                }
            }
        }

        #endregion
    }
}

 

300x250

 

▶ RepeatWorker.cs

using System;
using System.Threading;

namespace TestLibrary
{
    /// <summary>
    /// 반복 작업자
    /// </summary>
    public class RepeatWorker : IDisposable
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Protected

        #region Field

        /// <summary>
        /// 로그 헬퍼
        /// </summary>
        protected ILogHelper logHelper = null;

        /// <summary>
        /// 스레드
        /// </summary>
        protected Thread thread = null;

        /// <summary>
        /// 루프 계속 여부
        /// </summary>
        protected bool continueLoop = true;

        /// <summary>
        /// 휴지 여부
        /// </summary>
        protected bool isSleep = false;

        /// <summary>
        /// 휴지 시간 (단위 : 밀리초)
        /// </summary>
        protected int sleepTime;

        /// <summary>
        /// 작업 액션
        /// </summary>
        protected Action<object> workAction;

        /// <summary>
        /// 작업 매개 변수
        /// </summary>
        protected object workParameter;

        /// <summary>
        /// 실행 여부
        /// </summary>
        protected bool isRunning = false;

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Property
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 로그 헬퍼 - LogHelper

        /// <summary>
        /// 로그 헬퍼
        /// </summary>
        public ILogHelper LogHelper
        {
            get
            {
                return this.logHelper;
            }
            set
            {
                this.logHelper = value;
            }
        }

        #endregion
        #region 스레드 - Thread

        /// <summary>
        /// 스레드
        /// </summary>
        public Thread Thread
        {
            get
            {
            return this.thread;
            }
        }
        
        #endregion
        #region 휴지 시간 (단위 : 밀리초) - SleepTime

        /// <summary>
        /// 휴지 시간 (단위 : 밀리초)
        /// </summary>
        public int SleepTime
        {
            get
            {
                return this.sleepTime;
            }
            set
            {
                this.sleepTime = value;
            }
        }

        #endregion
        #region 작업 액션 - WorkAction

        /// <summary>
        /// 작업 액션
        /// </summary>
        public Action<object> WorkAction
        {
            get
            {
                return this.workAction;
            }
            set
            {
                this.workAction = value;
            }
        }

        #endregion
        #region 작업 매개 변수 - WorkParameter

        /// <summary>
        /// 작업 매개 변수
        /// </summary>
        public object WorkParameter
        {
            get
            {
                return this.workParameter;
            }
            set
            {
                this.workParameter = value;
            }
        }

        #endregion
        #region 실행 여부 - IsRunning

        /// <summary>
        /// 실행 여부
        /// </summary>
        public bool IsRunning
        {
            get
            {
                return this.isRunning;
            }
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 생성자 - RepeatWorker(workAction, workParameter, sleepTime)

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="workAction">작업 액션</param>
        /// <param name="workParameter">작업 매개 변수</param>
        /// <param name="sleepTime">휴지 시간 (단위 : 밀리초(</param>
        public RepeatWorker(Action<object> workAction, object workParameter, int sleepTime = 1000)
        {
            this.workAction    = workAction;
            this.workParameter = workParameter;
            this.sleepTime     = sleepTime;
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 시작하기 - Start()

        /// <summary>
        /// 시작하기
        /// </summary>
        public void Start()
        {
            try
            {
                if(this.isRunning)
                {
                    return;
                }

                this.isRunning = true;

                #region 스레드를 설정한다.

                if(this.thread != null)
                {
                    if(this.thread.IsAlive)
                    {
                        this.thread.Abort();
                    }

                    this.thread = null;
                }

                this.thread = new Thread(new ThreadStart(ProcessThread));

                this.thread.IsBackground = true;

                #endregion

                this.thread.Start();
            }
            catch(Exception exception)
            {
                this.isRunning = false;

                this.logHelper?.WriteErrorLog(exception, "ERROR START FUNCTION");

                throw exception;
            }
        }

        #endregion
        #region 중단하기 - Stop()

        /// <summary>
        /// 중단하기
        /// </summary>
        public void Stop()
        {
            try
            {
                if(!this.isRunning)
                {
                    return;
                }

                this.isRunning = false;

                #region 스레드를 중단한다.

                this.continueLoop = false;

                Thread.Sleep(500);

                if(this.thread != null && this.thread.IsAlive)
                {
                    if(this.isSleep)
                    {
                        this.thread.Abort();
                    }
                }

                #endregion
            }
            catch(Exception exception)
            {
                this.logHelper?.WriteErrorLog(exception, "ERROR STOP FUNCTION");
            }
        }

        #endregion
        #region 리소스 해제하기 - Dispose()

        /// <summary>
        /// 리소스 해제하기
        /// </summary>
        public void Dispose()
        {
            Stop();
        }

        #endregion

        ////////////////////////////////////////////////////////////////////////////////////////// Private

        #region 스레드 처리하기 - ProcessThread()

        /// <summary>
        /// 스레드 처리하기
        /// </summary>
        private void ProcessThread()
        {
            while(this.continueLoop)
            {
                try
                {
                    this.workAction?.Invoke(this.workParameter);
                }
                catch(Exception exception)
                {
                    this.logHelper?.WriteErrorLog(exception, "ERROR WHEN PROCESS THREAD");
                }

                if(!this.continueLoop)
                {
                    break;
                }

                this.isSleep = true;

                Thread.Sleep(this.sleepTime);

                this.isSleep = false;
            }
        }

        #endregion
    }
}

 

▶ TestNode.cs

using System;

namespace TestLibrary
{
    /// <summary>
    /// 테스트 노드
    /// </summary>
    public class TestNode
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Private

        #region Field

        #region 로그

        /// <summary>
        /// 로그 헬퍼
        /// </summary>
        private ILogHelper logHelper;

        #endregion
        #region 실행 작업자

        /// <summary>
        /// 실행 작업자 주기 (단위 : 밀리초)
        /// </summary>
        private int executeWorkerInterval = 1000; // 0.1초

        /// <summary>
        /// 실행 작업자
        /// </summary>
        private RepeatWorker executeWorker = null;

        #endregion

        /// <summary>
        /// 실행 여부
        /// </summary>
        private bool isRunning = false;

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Property
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 실행 여부 - IsRunning

        /// <summary>
        /// 실행 여부
        /// </summary>
        public bool IsRunning
        {
            get
            {
                return this.isRunning;
            }
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 생성자 - TestNode()

        /// <summary>
        /// 생성자
        /// </summary>
        public TestNode()
        {
            #region 로그 헬퍼를 설정한다.

            this.logHelper = new FileLogHelper("d:\\", "TestNode.log");

            #endregion
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 시작하기 - Start()

        /// <summary>
        /// 시작하기
        /// </summary>
        public void Start()
        {
            try
            {
                this.logHelper?.WriteLog("BEGIN START FUNCTION");

                if(this.isRunning)
                {
                    this.logHelper?.WriteLog("STOP START FUNCTION : AlreadyRunning");

                    return;
                }

                this.isRunning = true;

                #region 실행 작업자를 설정한다.

                if(this.executeWorker != null)
                {
                    if(this.executeWorker.IsRunning)
                    {
                        this.executeWorker.Stop();
                    }

                    this.executeWorker = null;
                }

                this.executeWorker = new RepeatWorker(new Action<object>(ProcessExecute), null, this.executeWorkerInterval);

                #endregion

                this.executeWorker.Start();

                this.logHelper?.WriteLog("END START FUNCTION");
            }
            catch(Exception exception)
            {
                this.isRunning = false;

                this.logHelper?.WriteErrorLog(exception, "ERROR START FUNCTION");

                throw exception;
            }
        }

        #endregion
        #region 중단하기 - Stop()

        /// <summary>
        /// 중단하기
        /// </summary>
        public void Stop()
        {
            try
            {
                this.logHelper?.WriteLog("BEGIN STOP FUNCTION");

                if(!this.isRunning)
                {
                    this.logHelper?.WriteLog("STOP STOP FUNCTION : AlreadyStopped");

                    return;
                }

                this.isRunning = false;

                #region 실행 작업자를 중단한다.

                this.executeWorker.Stop();

                this.executeWorker = null;

                #endregion

                this.logHelper?.WriteLog("END STOP FUNCTION");
            }
            catch(Exception exception)
            {
                this.isRunning = false;

                this.logHelper?.WriteErrorLog(exception, "ERROR STOP FUNCTION");
            }
        }

        #endregion

        ////////////////////////////////////////////////////////////////////////////////////////// Private

        #region 실행 처리하기 - ProcessExecute(parameter)

        /// <summary>
        /// 실행 처리하기
        /// </summary>
        /// <param name="parameter">매개 변수</param>
        private void ProcessExecute(object parameter)
        {
            try
            {
                this.logHelper?.WriteLog("테스트 메시지");
            }
            catch(Exception exception)
            {
                this.logHelper?.WriteErrorLog(exception, "ERROR PROCESS EXECUTE FUNCTION");
            }
        }

        #endregion
    }
}

 

[TestService 프로젝트]

▶ ProjectInstaller.cs

using System.ComponentModel;
using System.Configuration.Install;
using System.ServiceProcess;

namespace TestService
{
    /// <summary>
    /// 프로젝트 설치자
    /// </summary>
    [RunInstaller(true)]
    public partial class ProjectInstaller : Installer
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Private

        #region Field

        /// <summary>
        /// 서비스 프로세스 설치자
        /// </summary>
        private ServiceProcessInstaller serviceProcessInstaller;

        /// <summary>
        /// 서비스 설치자
        /// </summary>
        private ServiceInstaller serviceInstaller;

        /// <summary>
        /// 서비스명
        /// </summary>
        private const string SERVICE_NAME = "TestNode";

        /// <summary>
        /// 서비스 설명
        /// </summary>
        private const string SERVICE_DESCRIPTION = "테스트 노드";

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 생성자 - ProjectInstaller()

        /// <summary>
        /// 생성자
        /// </summary>
        public ProjectInstaller()
        {
            this.serviceProcessInstaller = new ServiceProcessInstaller();

            serviceProcessInstaller.Account = ServiceAccount.LocalSystem;
            serviceProcessInstaller.Password = null;
            serviceProcessInstaller.Username = null;

            this.serviceInstaller = new ServiceInstaller();

            serviceInstaller.ServiceName = SERVICE_NAME;
            serviceInstaller.DisplayName = SERVICE_NAME;
            serviceInstaller.Description = SERVICE_DESCRIPTION;
            serviceInstaller.StartType   = ServiceStartMode.Automatic;

            Installers.AddRange(new Installer[] { this.serviceProcessInstaller, this.serviceInstaller });
        }

        #endregion
    }
}

 

▶ ProjectService.cs

using System;
using System.ServiceProcess;

using TestLibrary;

namespace TestService
{
    /// <summary>
    /// 프로젝트 서비스
    /// </summary>
    public partial class ProjectService : ServiceBase
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Private

        #region Field

        /// <summary>
        /// 에이전트 노드
        /// </summary>
        private TestNode testNode;

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 생성자 - ProjectService()

        /// <summary>
        /// 생성자
        /// </summary>
        public ProjectService()
        {
            this.testNode = new TestNode();
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 테스트 하기 - Test(argumentArray)

        /// <summary>
        /// 테스트 하기
        /// </summary>
        /// <param name="argumentArray">인자 배열</param>
        public void Test(string[] argumentArray)
        {
            OnStart(argumentArray);

            Console.ReadKey(true);

            OnStop();
        }

        #endregion

        ////////////////////////////////////////////////////////////////////////////////////////// Protected

        #region 시작시 처리하기 - OnStart(argumentArray)

        /// <summary>
        /// 시작시 처리하기
        /// </summary>
        /// <param name="argumentArray">인자 배열</param>
        protected override void OnStart(string[] argumentArray)
        {
            this.testNode.Start();
        }

        #endregion
        #region 중단시 처리하기 - OnStop()

        /// <summary>
        /// 중단시 처리하기
        /// </summary>
        protected override void OnStop()
        {
            this.testNode.Stop();
        }

        #endregion
    }
}

 

▶ Program.cs

using System;
using System.ServiceProcess;

namespace TestService
{
    /// <summary>
    /// 프로그램
    /// </summary>
    static class Program
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Static
        //////////////////////////////////////////////////////////////////////////////// Private

        #region 프로그램 시작하기 - Main(argumentArray)

        /// <summary>
        /// 프로그램 시작하기
        /// </summary>
        /// <param name="argumentArray">인자 배열</param>
        private static void Main(string[] argumentArray)
        {
            if(Environment.UserInteractive)
            {
                ProjectService service = new ProjectService();

                service.Test(argumentArray);
            }
            else
            {
                ServiceBase[] serviceBaseArray;

                serviceBaseArray = new ServiceBase[] { new ProjectService() };

                ServiceBase.Run(serviceBaseArray);
            }
        }

        #endregion
    }
}
728x90
반응형
그리드형(광고전용)
Posted by icodebroker

댓글을 달아 주세요