私はWindowsサービスを展開しようとしていますが、それを正しく行う方法がわかりません。最初はコンソールアプリとして構築しましたが、今ではWindowsサービスプロジェクトに変換し、サービスのOnStartメソッドからクラスを呼び出すだけです。
Visual Studioがインストールされていないサーバーにこれをインストールする必要があります。これを正しく理解していれば、InstallUtil.exeを使用できず、代わりにインストーラークラスを作成する必要があります。これは正しいです?
以前の質問 InstallUtil.exeを使用せずに.NET Windowsサービスをインストールする を見てきましたが、正しく理解したことを確認したいだけです。
質問の受け入れられた回答がリンクするクラスを作成する場合、次のステップは何ですか? MyService.exeとMyService.exe.configをサーバーにアップロードし、exeファイルをダブルクリックして、Bobが私の叔父ですか?
サービスは1つのサーバーにのみインストールされます。
InstallUtil.exe
ツールは、サービス内のインストーラーコンポーネントに対するいくつかのリフレクションコールの単なるラッパーです。そのため、実際にはあまり機能しませんが、これらのインストーラーコンポーネントが提供する機能を実行します。 Marc Gravellのソリューションは、コマンドラインからこれを行う手段を提供するだけなので、InstallUtil.exe
ターゲットマシン上。
これは、マークグラヴェルのソリューションに基づいたステップバイステップです。
これは非常に古い質問ですが、新しい情報で更新することをお勧めします。
sc コマンドを使用してサービスをインストールできます。
InstallService.bat:
@echo OFF
echo Stopping old service version...
net stop "[YOUR SERVICE NAME]"
echo Uninstalling old service version...
sc delete "[YOUR SERVICE NAME]"
echo Installing service...
rem DO NOT remove the space after "binpath="!
sc create "[YOUR SERVICE NAME]" binpath= "[PATH_TO_YOUR_SERVICE_EXE]" start= auto
echo Starting server complete
pause
SCを使用すると、さらに多くのことができます。古いサービスをアンインストールし(以前にインストールしたことがある場合)、同じ名前のサービスが存在するかどうかを確認します...サービスを自動起動に設定します。
多くのリファレンスの1つ: sc.exeを使用してサービスを作成する;コンテキストパラメータを渡す方法
私はこの方法とInstallUtil
の両方を使いました。個人的には、SCを使用する方がより健康で健康的です。
Visual Studioなしでもinstallutilを使用できます。これは.netフレームワークに含まれています
サーバーで、管理者としてコマンドプロンプトを開き、次の操作を行います。
CD C:\Windows\Microsoft.NET\Framework\v4.0.version (insert your version)
installutil "C:\Program Files\YourWindowsService\YourWindowsService.exe" (insert your service name/location)
アンインストールするには:
installutil /u "C:\Program Files\YourWindowsService\YourWindowsService.exe" (insert your service name/location)
セットアッププロジェクトを作成しないのはなぜですか?本当に簡単です。
出来上がり、これで完了です。
詳細については、こちらをご覧ください: http://www.codeproject.com/KB/dotnet/simplewindowsservice.aspx
ユーザーに資格情報を要求する(または独自の資格情報を提供する)方法もあります。
これはサブサービスクラス(ServiceBaseサブクラス)であり、サブクラス化して、installutil.exeなしでコマンドラインから簡単にインストールできるWindowsサービスを構築できます。このソリューションは、 インストール直後に.NET Windowsサービスを開始する方法 から派生し、呼び出し側のStackFrameを使用してサービスタイプを取得するためのコードを追加します。
public abstract class InstallableServiceBase:ServiceBase
{
/// <summary>
/// returns Type of the calling service (subclass of InstallableServiceBase)
/// </summary>
/// <returns></returns>
protected static Type getMyType()
{
Type t = typeof(InstallableServiceBase);
MethodBase ret = MethodBase.GetCurrentMethod();
Type retType = null;
try
{
StackFrame[] frames = new StackTrace().GetFrames();
foreach (StackFrame x in frames)
{
ret = x.GetMethod();
Type t1 = ret.DeclaringType;
if (t1 != null && !t1.Equals(t) && !t1.IsSubclassOf(t))
{
break;
}
retType = t1;
}
}
catch
{
}
return retType;
}
/// <summary>
/// returns AssemblyInstaller for the calling service (subclass of InstallableServiceBase)
/// </summary>
/// <returns></returns>
protected static AssemblyInstaller GetInstaller()
{
Type t = getMyType();
AssemblyInstaller installer = new AssemblyInstaller(
t.Assembly, null);
installer.UseNewContext = true;
return installer;
}
private bool IsInstalled()
{
using (ServiceController controller =
new ServiceController(this.ServiceName))
{
try
{
ServiceControllerStatus status = controller.Status;
}
catch
{
return false;
}
return true;
}
}
private bool IsRunning()
{
using (ServiceController controller =
new ServiceController(this.ServiceName))
{
if (!this.IsInstalled()) return false;
return (controller.Status == ServiceControllerStatus.Running);
}
}
/// <summary>
/// protected method to be called by a public method within the real service
/// ie: in the real service
/// new internal void InstallService()
/// {
/// base.InstallService();
/// }
/// </summary>
protected void InstallService()
{
if (this.IsInstalled()) return;
try
{
using (AssemblyInstaller installer = GetInstaller())
{
IDictionary state = new Hashtable();
try
{
installer.Install(state);
installer.Commit(state);
}
catch
{
try
{
installer.Rollback(state);
}
catch { }
throw;
}
}
}
catch
{
throw;
}
}
/// <summary>
/// protected method to be called by a public method within the real service
/// ie: in the real service
/// new internal void UninstallService()
/// {
/// base.UninstallService();
/// }
/// </summary>
protected void UninstallService()
{
if (!this.IsInstalled()) return;
if (this.IsRunning()) {
this.StopService();
}
try
{
using (AssemblyInstaller installer = GetInstaller())
{
IDictionary state = new Hashtable();
try
{
installer.Uninstall(state);
}
catch
{
throw;
}
}
}
catch
{
throw;
}
}
private void StartService()
{
if (!this.IsInstalled()) return;
using (ServiceController controller =
new ServiceController(this.ServiceName))
{
try
{
if (controller.Status != ServiceControllerStatus.Running)
{
controller.Start();
controller.WaitForStatus(ServiceControllerStatus.Running,
TimeSpan.FromSeconds(10));
}
}
catch
{
throw;
}
}
}
private void StopService()
{
if (!this.IsInstalled()) return;
using (ServiceController controller =
new ServiceController(this.ServiceName))
{
try
{
if (controller.Status != ServiceControllerStatus.Stopped)
{
controller.Stop();
controller.WaitForStatus(ServiceControllerStatus.Stopped,
TimeSpan.FromSeconds(10));
}
}
catch
{
throw;
}
}
}
}
しなければならないことは、実際のサービスに2つのパブリック/内部メソッドを実装することです。
new internal void InstallService()
{
base.InstallService();
}
new internal void UninstallService()
{
base.UninstallService();
}
そして、サービスをインストールするときに呼び出します:
static void Main(string[] args)
{
if (Environment.UserInteractive)
{
MyService s1 = new MyService();
if (args.Length == 1)
{
switch (args[0])
{
case "-install":
s1.InstallService();
break;
case "-uninstall":
s1.UninstallService();
break;
default:
throw new NotImplementedException();
}
}
}
else {
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new MyService()
};
ServiceBase.Run(MyService);
}
}
Topshelf は、この質問に答えた後に開始されたOSSプロジェクトであり、Windowsサービスを大幅に簡単にします。
ダブルクリックではなく、正しいコマンドラインパラメーターで実行するので、MyService -i
その後 MyService -u
をアンインストールします `。
それ以外の場合は、sc.exeを使用してインストールおよびアンインストール(またはInstallUtil.exeに沿ってコピー)できます。
この問題はセキュリティによるものであり、VS 2012の開発者コマンドプロンプトをRUN AS ADMINISTRATORで開いてサービスをインストールすると、問題が確実に修正されます。