I'm trying to deploy a windows service but not quite sure how to do it right. I built it as a console app to start with, I've now turned it into a windows service project and just call my class from the OnSta开发者_如何学运维rt method in the service.
I now need to install this on a server which doesn't have Visual Studio on it, which if I've understood it correctly means I can't use the InstallUtil.exe and have to create an installer class instead. Is this correct?
I did have a look at a previous question, Install a .NET windows service without InstallUtil.exe, but I just want to make sure I've understood it correctly.
If I create the class that question's accepted answer links to, what is the next step? Upload MyService.exe and MyService.exe.config to the server, double click the exe file and Bob's my uncle?
The service will only ever be installed on one server.
I know it is a very old question, but better update it with new information.
You can install service by using sc command:
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
With SC, you can do a lot more things as well: uninstalling the old service (if you already installed it before), checking if service with same name exists... even set your service to autostart.
One of many references: creating a service with sc.exe; how to pass in context parameters
I have done by both this way & InstallUtil
. Personally I feel that using SC is cleaner and better for your health.
You can still use installutil without visual studio, it is included with the .net framework
On your server, open a command prompt as administrator then:
CD C:\Windows\Microsoft.NET\Framework\v4.0.version (insert your version)
installutil "C:\Program Files\YourWindowsService\YourWindowsService.exe" (insert your service name/location)
To uninstall:
installutil /u "C:\Program Files\YourWindowsService\YourWindowsService.exe" (insert your service name/location)
The InstallUtil.exe
tool is simply a wrapper around some reflection calls against the installer component(s) in your service. As such, it really doesn't do much but exercise the functionality these installer components provide. Marc Gravell's solution simply provides a means to do this from the command line so that you no longer have to rely on having InstallUtil.exe
on the target machine.
Here's my step-by-step that based on Marc Gravell's solution.
How to make a .NET Windows Service start right after the installation?
This is a base service class (ServiceBase subclass) that can be subclassed to build a windows service that can be easily installed from the command line, without installutil.exe. This solution is derived from How to make a .NET Windows Service start right after the installation?, adding some code to get the service Type using the calling 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;
}
}
}
}
All you have to do is to implement two public/internal methods in your real service:
new internal void InstallService()
{
base.InstallService();
}
new internal void UninstallService()
{
base.UninstallService();
}
and then call them when you want to install the service:
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);
}
}
Why not just create a setup project? It's really easy.
- Add a service installer to the service (you do it on the seemingly useless service "design" surface)
- Create a setup project and add the Service output to the setup app folder
- Most importantly add the Service project output to all the custom actions
Voila, and you're done.
See here for more: http://www.codeproject.com/KB/dotnet/simplewindowsservice.aspx
There is also a way to prompt the user for credentials (or supply your own).
Topshelf is an OSS project which was started after this question was answered and it makes Windows service much, MUCH easier.I highly recommend looking into it.
http://topshelf-project.com/
Not double click, you run it with the correct command line parameters, so type something like MyService -i
and then MyService -u
to uninstall it`.
You could otherwise use sc.exe to install and uninstall it (or copy along InstallUtil.exe).
This Problem is due to Security, Better open Developer Command prompt for VS 2012 in RUN AS ADMINISTRATOR and install your Service, it fix your problem surely.
精彩评论