如何使用“本地服务”而不是“本地系统”?

5
我使用ServiceProcessInstaller安装我的C#服务(目前在Windows 7上;我已经了解到它只存在于XP和2003,但这应该是我处理所需的全部)。我的服务可以在“本地系统”下运行,但不能在“本地服务”或“网络服务”下运行。即使我的服务基本上是空的(请参见下面的代码),我仍然会收到以下错误消息:
“Windows无法在本地计算机上启动[服务名称]服务。错误5:拒绝访问。”
以下是我的主要为空的服务: 编辑:我更新了代码,以便为“本地服务”提供必要的访问权限。
// Needs System.Configuration.Install.dll and System.ServiceProcess.dll
using System;
using System.Collections;
using System.ComponentModel;
using System.Configuration.Install;
using System.Linq;
using System.Reflection;
using System.ServiceProcess;

namespace ServiceTest
{
    static class Constants
    {
    public const string LocalServiceAcctName = @"NT AUTHORITY\LOCAL SERVICE";
        public const string ServiceName = "MySvc";
    }

    class Program
    {
        /// <summary>
        /// Main entry point.
        /// </summary>
        /// <param name="args">
        ///     If the 1st argument is "i", it will simply install the service.
        ///     If it's something else, it will run as a Console application.
        ///     If it's empty, it will run as a service.
        /// </param>
        static void Main(string[] args)
        {
            if (args != null && args.Length != 0 && args[0] == "i")
            {
                bool result = InstallService(Assembly.GetExecutingAssembly().Location, Constants.ServiceName);
                Console.WriteLine(result ? "INSTALLED" : "ERROR INSTALLING");
                Console.ReadLine();
            }
            else
            {
                var host = new Host();
                bool runAsSvc = args == null || args.Length == 0;
                host.Launch(runAsSvc);
            }
        }

        static bool InstallService(string exeFullPath, string serviceName)
        {
            AssemblyInstaller installer = new AssemblyInstaller(exeFullPath, null);

            if (ServiceController.GetServices().Any(svcCtlr => svcCtlr.ServiceName == serviceName))
                installer.Uninstall(null);

            Hashtable dico = new Hashtable();
            installer.Install(dico);
            installer.Commit(dico);

        // Gives "Local Service" the necessary rights on the folder and subfolders and files.
        DirectoryInfo dirInfo = new DirectoryInfo(Path.GetDirectoryName(exeFullPath));
        DirectorySecurity dirSec = dirInfo.GetAccessControl(AccessControlSections.Access);

        FileSystemRights rights = FileSystemRights.Modify;
        AccessControlType accessType = AccessControlType.Allow;
        dirSec.AddAccessRule(new FileSystemAccessRule(Constants.LocalServiceAcctName, rights, InheritanceFlags.ObjectInherit, PropagationFlags.InheritOnly, accessType));
        dirSec.AddAccessRule(new FileSystemAccessRule(Constants.LocalServiceAcctName, rights, InheritanceFlags.ContainerInherit, PropagationFlags.InheritOnly, accessType));
        dirSec.AddAccessRule(new FileSystemAccessRule(Constants.LocalServiceAcctName, rights, accessType));
        dirInfo.SetAccessControl(dirSec);


            return true;
        }
    }

    class Host
    {
        internal void Launch(bool runAsSvc)
        {
            if (runAsSvc)
                RuntimeService.CreateAndRun(this);
            else
            {
                OnStart();
                Console.WriteLine("Component started as a Console app.");
                Console.WriteLine("We work a lot...and then we're done.");
                OnStop();

                Console.WriteLine("Press enter to stop.");
                Console.ReadLine();
            }
        }

        internal void OnStart() { Console.WriteLine("We're starting!"); }

        internal void OnStop() { Console.WriteLine("We're stopping..."); }
    }

    class RuntimeService : ServiceBase
    {
        Host _host;

        public RuntimeService(Host host) { _host = host; }

        protected override void OnStart(string[] args) { _host.OnStart(); }

        protected override void OnStop() { _host.OnStop(); }

        internal static void CreateAndRun(Host host) { ServiceBase.Run(new RuntimeService(host)); }
    }

    /// <summary>
    /// Class used to install the service.
    /// </summary>
    [RunInstaller(true)]
    public class RuntimeInstaller : Installer
    {
        public RuntimeInstaller()
        {
            var processInstaller = new ServiceProcessInstaller();
            processInstaller.Account = ServiceAccount.LocalService; // ServiceAccount.LocalSystem;

            var serviceInstaller = new ServiceInstaller();
            serviceInstaller.StartType = ServiceStartMode.Automatic;
            serviceInstaller.ServiceName = Constants.ServiceName;

            Installers.Add(serviceInstaller);
            Installers.Add(processInstaller);
        }
    }
}
2个回答

3
您安装服务的位置在哪里?错误似乎表明本地服务帐户无法访问服务位置。因此,服务管理器甚至无法加载可执行文件并使其运行,更不用说启动服务了。
我经常看到开发人员在开发/调试服务时这样做。他们将服务安装在其中一个开发文件夹中,但将其设置为在另一个帐户下运行。但默认情况下,只有用户、系统和管理员组可以访问用户的文件夹 - 因此,服务会因为访问被拒绝而失败。

你说得太对了。文件夹在我的桌面上,而“本地服务”没有任何权限。我刚刚添加了“读取和执行”、“列出文件夹内容”和“读取”权限,现在它可以正常启动了。非常感谢,我真的没有想到那个! - user276648

0
你使用的操作系统是什么?
根据Microsoft的说法:

LocalService和NetworkService这两个值仅适用于Windows XP和Windows Server 2003系列。

当我第一次阅读此处的评论时,我认为它是在这些操作系统是最新版本时编写的,并且是为了排除早期的操作系统,但是这个评论仍然存在于最新的文档中。

谢谢报价。我正在使用带有.Net 4的Win7,但仍然可以看到LocalService和NetworkService是可用的:它可以编译,并且我可以使用两者安装服务(我在services.msc中看到“登录为”设置为“本地服务”或“网络服务” - 同样还有许多使用这些帐户的Windows服务)。也许他们忘记更新文档了,因为这些帐户仅从XP和2003开始提供? - user276648
显然这取决于您的服务所需的特权。我的带有WCF的服务无法在Win 7上运行。请参考:http://msdn.microsoft.com/en-us/library/windows/desktop/ms684190%28v=vs.85%29.aspx,这证明了微软的声明是不正确的。 - 27k1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接