我最近在C#中创建了一个多线程服务器作为控制台应用程序。最初它运行在通过端口转发暴露于互联网的公司计算机上。但是,我相信随着客户端的增加,可能需要推出真正的服务器设置。我之前从未这样做过,所以我想知道:
如何将这样的C#控制台应用程序部署到服务器上?是否需要转换为服务?我可以获得一个VPS并运行它吗?
我非常感谢任何答案或建议,谢谢
答案 0 :(得分: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
}
}
希望我的代码有所帮助。询问您是否有任何问题
答案 1 :(得分:0)
为这种程序提供服务更好。控制台应用程序输出使用大量资源,必须手动启动。虽然可以在每台计算机上执行服务,而用户甚至无需登录。
为了部署它,最好的方法是创建一个安装过程,然后将其安装在服务器上。然后,您可以为服务器创建一个uptade流程,这样您就不需要为每次更新安装它。