2014-11-18 5 views
1

최근에 C#에서 콘솔 응용 프로그램으로 멀티 스레드 서버를 만들었습니다. 원래 포트 포워딩을 통해 인터넷에 노출 된 회사 컴퓨터에서 실행됩니다. 그러나 클라이언트 증가로 실제 서버 설정으로 밀어 넣어야 할 수도 있습니다. 이전에이 작업을 수행 한 적이 없었으므로 궁금 해서요 :C# 서버 응용 프로그램 배포

이렇게 C# 콘솔 응용 프로그램을 서버에 배포하려면 어떻게해야합니까? 서비스로 전환해야합니까? VPS를 받아서 실행할 수 있습니까?

정말 어떤 답변이나 제안을 감사하겠습니다은, 그것은 프로그램의 종류에 대한 서비스를 만들기 위해 더 나은 당신

답변

1

C#에서는 Windows 서비스를 작성하는 것이 매우 간단합니다. 저는 콘솔 응용 프로그램과 서비스를 결합하는 것을 좋아합니다. 왜냐하면 콘솔 응용 프로그램을 디버깅하는 것이 더 낳고 프로덕션에서는 서비스가 더 좋기 때문입니다. 서비스 기지로 난 항상 사용

Program.cs :

#define __USE_AS_CONSOLE___ 

using MyService.Service; 
using System; 
using System.Collections.Generic; 
using System.Configuration.Install; 
using System.Linq; 
using System.Reflection; 
using System.Runtime.InteropServices; 
using System.Security.Principal; 
using System.Text; 
using System.Threading.Tasks; 
using System.IO; 
using System.Diagnostics; 

namespace MyService 
{ 
    public class Program 
    { 
     #region Private Member 
     private static ASServiceBase myServiceBase; 
     private static string serviceName; 
     #endregion 

     #region Console 
     const bool ShowConsole = true; 

     [DllImport("kernel32.dll", SetLastError = true)] 
     public static extern bool AllocConsole(); 

     [DllImport("kernel32.dll", SetLastError = true)] 
     public static extern bool FreeConsole(); 

     [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
     static extern bool SetDllDirectory(string lpPathName); 

     [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
     static extern bool AddDllDirectory(string lpPathName); 
     #endregion 

     static void Main(string[] args) 
     { 
      AppDomain.CurrentDomain.AssemblyResolve += ResolveError; 

      string installCommand = ""; 
      serviceName = GetServiceName(); 

      foreach(string arg in args) 
      { 
       if (arg.ToLower().StartsWith("/install")) 
       { 
        installCommand = "/install"; 
       } 
       else if (arg.ToLower().StartsWith("/uninstall")) 
       { 
        installCommand = "/uninstall"; 
       } 
      } 

      if (System.Environment.UserInteractive) 
      { 
       string parameter = ""; 

       foreach (string arg in args) 
       { 
        parameter += arg; 

        if (!arg.EndsWith(" ")) 
        { 
         parameter += ""; 
        } 
       } 

       switch (installCommand) 
       { 
        case "/install": 
         if (!IsAdministrator()) 
         { 
          System.Console.WriteLine("Die Anwendung muss als Administrator installiert werden."); 
          System.Console.ReadLine(); 
          return; 
         } 

         ManagedInstallerClass.InstallHelper(new string[] { Assembly.GetExecutingAssembly().Location }); 
         return; 
         break; 
        case "/uninstall": 
         if (!IsAdministrator()) 
         { 
          System.Console.WriteLine("Die Anwendung muss als Administrator installiert werden."); 
          System.Console.ReadLine(); 
          return; 
         } 

         ManagedInstallerClass.InstallHelper(new string[] { "/u", Assembly.GetExecutingAssembly().Location }); 
         return; 
         break; 
       } 

       AllocConsole(); 
       myServiceBase = new ASServiceBase(); 
       myServiceBase.Start(); 
       System.Console.ReadLine(); 
      } 
      else 
      { 
       // =============================================== 
       // Start Console 
       AllocConsole(); 
       System.Console.WriteLine("Version 1.0"); 

       myServiceBase = new ASServiceBase(); 

       //Start service 
       System.ServiceProcess.ServiceBase.Run(myServiceBase); 

      } 
     } 

     public static bool IsAdministrator() 
     { 
      var identity = WindowsIdentity.GetCurrent(); 
      var principal = new WindowsPrincipal(identity); 
      return principal.IsInRole(WindowsBuiltInRole.Administrator); 
     } 

     #region [Resolve Error] 
     /// <summary> 
     /// Resolve Error 
     /// </summary> 
     /// <param name="sender"></param> 
     /// <param name="e"></param> 
     private static Assembly ResolveError(object sender, ResolveEventArgs args) 
     { 
      try 
      { 
       Assembly cMyAssembly = null; 
       string strTempAssmbPath = string.Empty; 

       Assembly objExecutingAssemblies = Assembly.GetExecutingAssembly(); 
       AssemblyName[] arrReferencedAssmbNames = objExecutingAssemblies.GetReferencedAssemblies(); 

       AssemblyName myAssemblyName = Array.Find<AssemblyName>(arrReferencedAssmbNames, a => a.Name == args.Name); 

       if (myAssemblyName != null) 
       { 
        cMyAssembly = Assembly.LoadFrom(myAssemblyName.CodeBase); 
       } 
       else 
       { 
        string rootFolder = GetAssemblyPath(args, ""); 
        if (!string.IsNullOrEmpty(rootFolder)) 
        { 
         if (File.Exists(rootFolder)) 
         { 
          // Loads the assembly from the specified path.     
          cMyAssembly = Assembly.LoadFrom(rootFolder); 
         } 
        } 

        string assemblyFolder = GetAssemblyPath(args, "Assemblies\\"); 
        if (!string.IsNullOrEmpty(assemblyFolder)) 
        { 
         if (File.Exists(assemblyFolder)) 
         { 
          // Loads the assembly from the specified path.     
          cMyAssembly = Assembly.LoadFrom(assemblyFolder); 
         } 
        } 
       } 

       // Returns the loaded assembly. 
       return cMyAssembly; 
      } 
      catch (Exception exc) 
      { 
       FileLog.WriteLog("Fehler in Init.ResolveError:\r\n" + exc.ToString()); 
       return null; 
      } 
     } 

     private static string GetAssemblyPath(ResolveEventArgs args, string AdditionalDirectory) 
     { 
      string returnValue = null; 

      string cRMSAssemblyFolder = GlobalSettings.StudioPath + "\\" + AdditionalDirectory; 

      Assembly cMyAssembly = null; 
      string strTempAssmbPath = string.Empty; 

      Assembly objExecutingAssemblies = Assembly.GetExecutingAssembly(); 
      AssemblyName[] arrReferencedAssmbNames = objExecutingAssemblies.GetReferencedAssemblies(); 

      AssemblyName myAssemblyName = Array.Find<AssemblyName>(arrReferencedAssmbNames, a => a.Name == args.Name); 

      if (myAssemblyName == null) 
      { 
       if (args.Name.Contains(",")) 
       { 
        strTempAssmbPath = Path.Combine(cRMSAssemblyFolder, args.Name.Substring(0, args.Name.IndexOf(",")) + ".dll"); 
       } 
       else 
       { 
        strTempAssmbPath = Path.Combine(cRMSAssemblyFolder, args.Name + ".dll"); 
       } 

       returnValue = strTempAssmbPath; 
      } 

      return returnValue; 
     } 
     #endregion 
    } 
} 

서비스 설치 :

using System; 
using System.Configuration.Install; 
using System.ComponentModel; 
using System.ServiceProcess; 
using System.IO; 
using System.Net.Sockets; 
using System.Net; 
using System.Threading; 
using System.Configuration; 
using System.Diagnostics; 

/// <summary> 
/// Installerklasse für den Service 
/// </summary> 
[RunInstaller(true)] 
public class QServiceInstaller : Installer 
{ 
    #region private Member 
    private ServiceInstaller myThisService; 
    private IContainer components; 
    private ServiceProcessInstaller myThisServiceProcess; 
    #endregion 

    public QServiceInstaller() 
    { 
     myThisService = new ServiceInstaller(); 
     myThisServiceProcess = new ServiceProcessInstaller(); 

     string Path = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); 

     myThisServiceProcess.Account = ServiceAccount.LocalSystem; 
     myThisService.ServiceName = "Your application name"; 
     myThisService.StartType = ServiceStartMode.Automatic; 

     Installers.Add(myThisService); 
     Installers.Add(myThisServiceProcess); 
    } 

    private void InitializeComponent() 
    { 

    } 
} 

서비스 기반 :

using System; 
using System.Collections.Generic; 
using System.Diagnostics; 
using System.Linq; 
using System.ServiceProcess; 
using System.Text; 
using System.Threading; 

namespace MyService.Service 
{ 
    public class ASServiceBase : ServiceBase 
    { 
     #region Private Member 
     private Thread myServiceThread; 
     private bool myDoStop; 
     #endregion 

     #region Constructor 
     /// <summary> 
     /// Constructor 
     /// </summary> 
     public ASServiceBase() 
     { 
      myDoStop = false; 
     } 
     #endregion 

     #region Public Methods 
     #region OnStart 
     protected override void OnStart(string[] args) 
     { 
      Start(); 
     } 

     /// <summary> 
     /// Start 
     /// </summary> 
     public void Start() 
     { 
      myServiceThread = new Thread(new ThreadStart(Do)); 
      myServiceThread.Start(); 

      MainThread = myServiceThread; 
     } 
     #endregion 

     #region Do Anything 
     /// <summary> 
     /// Execute 
     /// </summary> 
     public void Do() 
     { 
      while (!myDoStop) 
      { 
       // Do some stuff 
       Thread.Sleep(10); 
      } 

      LoggingManager.Singleton.Deactivate(); 

      // ===================================================================================== 
      // Stop anything 

      // ===================================================================================== 
     } 
     #endregion 

     #region OnStop 
     protected override void OnStop() 
     { 
      Stop(); 
     } 

     /// <summary> 
     /// Stop 
     /// </summary> 
     public void Stop() 
     { 
      myDoStop = true; 
     } 
     #endregion 

     #endregion 

     #region Private Methods 

     #endregion 

     #region Public Member 
     /// <summary> 
     /// Main Thread 
     /// </summary> 
     public static Thread MainThread 
     { 
      get; 
      set; 
     } 
     #endregion 
    } 
} 

내 코드의 도움을 희망합니다. 문의 사항이 있으시면

+0

우수합니다, 감사합니다 - 이것은 나를 분석하기위한 좋은 예입니다 –

+0

Actualy 그것은 반 패턴입니다. 설치를 위해서는 MSI를 만들어야합니다. 표준이며 모든 관리자는 해당 명령 줄 호지를 선호합니다. Wix 툴셋은 수년 동안이 표준입니다. – TomTom

+0

@TomTom 귀하의 진술을지지합니다. 그러나 저는 두 가지 방법을 모두 관리자에게 제공하는 것을 좋아합니다. WiX의 ServiceControl은 다음과 같이 훌륭합니다. http://wixtoolset.org/documentation/manual/v3/xsd/wix/servicecontrol.html – BendEg

0

감사합니다. 콘솔 응용 프로그램 출력은 많은 자원을 사용하므로 수동으로 시작해야합니다. 로그온하지 않고도 각 컴퓨터에서 서비스를 시작할 수있는 반면에.

배포하려면 설치 프로세스를 만든 다음 서버에 설치하는 것이 가장 좋습니다. 그런 다음 서버 업데이트 프로세스를 만들 수 있으므로 업데이트 할 때마다 설치할 필요가 없습니다.

+0

으로 보내 주시면 감사하겠습니다. 그것을 변환하고 설정 프로세스를 만드는 방법을 살펴 보겠습니다. –