【问题标题】:Check if a service exists on a particular machine without using exception handling在不使用异常处理的情况下检查特定机器上是否存在服务
【发布时间】:2010-10-20 18:14:32
【问题描述】:

不知道是否有更好的方法来做到这一点,所以这就是问题的原因。我可以使用以下代码检查特定机器上是否存在服务:

bool DoesServiceExist(string serviceName, string machineName)
{
    ServiceController controller = null;
    try
    {
        controller = new ServiceController(serviceName, machineName);
        controller.Status;
        return true;
    }
    catch(InvalidOperationException)
    {
        return false;
    }
    finally
    {
         if (controller != null)
         {
             controller.Dispose();
         }
    }
}

但这对我来说似乎是一个低效的解决方案(由于异常处理)。有没有更好的方法来检查服务是否存在。注意 - 我最近切换到 .Net 4.0,所以如果有人知道 4.0 中有更好的解决方案,那是可以接受的。

编辑: 这是一个示例 C# 控制台应用程序,用于测试我的示例的性能以及 GetServices 代码示例。在我的测试中,我发现在服务不存在的情况下,GetServices 的性能要好得多,但在服务存在的情况下速度会慢一倍:

    static void Main(string[] args)
    {
        string serviceName = string.Empty;
        string machineName = string.Empty;

        var sw = new Stopwatch();
        sw.Reset();
        sw.Start();
        for (int i = 0; i < 1000; i++)
        {
            ServiceExistsException(serviceName, machineName);
        }
        sw.Stop();
        Console.WriteLine("Elapsed time: " + sw.ElapsedMilliseconds.ToString());
        sw.Reset();
        sw.Start();
        for (int i = 0; i < 1000; i++)
        {
            ServiceExistsGetList(serviceName, machineName);
        }
        sw.Stop();
        Console.WriteLine("Elapsed time: " + sw.ElapsedMilliseconds.ToString());

        Console.WriteLine("Done");
        Console.ReadLine();
    }

    static bool ServiceExistsException(string serviceName, string machineName)
    {
        ServiceController controller = null;
        try
        {
            controller = new ServiceController(serviceName, machineName);
            string name = controller.DisplayName;
            return true;
        }
        catch (InvalidOperationException)
        {
            return false;
        }
        finally
        {
            if (controller != null)
            {
                controller.Dispose();
            }
        }
    }

    static bool ServiceExistsGetList(string serviceName, string machineName)
    {
        ServiceController[] services = null;
        try
        {
            services = ServiceController.GetServices(machineName);
            var service = services.FirstOrDefault(s => s.ServiceName == serviceName);
            return service != null;
        }
        finally
        {
            if (services != null)
            {
                foreach (ServiceController controller in services)
                {
                    controller.Dispose();
                }
            }
        }
    }
}

【问题讨论】:

    标签: c# windows-services


    【解决方案1】:

    您可以使用ServiceController.GetServices() 方法获取机器上的所有服务,然后查看它们是否存在名为您要查找的服务:

    bool DoesServiceExist(string serviceName, string machineName)
    {
        ServiceController[] services = ServiceController.GetServices(machineName);
        var service = services.FirstOrDefault(s => s.ServiceName == serviceName);
        return service != null;
    }
    

    FirstOrDefault() 扩展方法(来自 System.Linq)将返回具有给定名称的第一个服务,如果没有匹配项,则返回 null。


    解决您的速度问题:

    对于单个方法调用,两种方法之间的差异可以忽略不计,无论是否找到服务。仅当您调用此方法数千次时才会出现问题 — 在这种情况下,获取一次服务列表并记住它。

    【讨论】:

    • 我对您的解决方案的性能有疑问,所以我进行了测试。当服务不存在时,您的解决方案的性能要高得多(即使添加了处理服务控制器的代码)。在服务确实存在的情况下,此解决方案的速度会慢一倍。我不知道现在该怎么办。就我而言,我期望该服务通常会存在。在这种情况下,我的解决方案胜出,在更通用的情况下,您的解决方案胜出。
    • @pstrjds - 您应该查找“执行性”,这样至少您可以在适当或常规的情况下说出它。
    • @CRice - 你是对的,我以前从来没有查过这个词,我在讨论性能时听说过它,我现在才查到它,哇它是不同的意思。我当然希望这里的上下文显示了预期的内容,并且不会导致在理解我所问的问题时出现任何混淆。下次我一定会先在English StackExchange 发布我的所有问题,以确保我有正确的语法和拼写内容。
    • @kayleeFrye_onDeck 完全没有危险。它们是等价的。
    • 请注意,通过 GetServices 获取所有服务的列表需要 SC_MANAGER_* 权限,而查询特定服务则不需要。在某些环境中,您可能无权枚举服务列表。
    【解决方案2】:

    与 adrianbanks 方法相同,但代码更紧凑。 如果您使用的是 LINQ,您可以使用任何语句来返回您想要的内容。 此外,如果您在本地计算机上进行检查,则无需提供计算机名称。

    bool DoesServiceExist(string serviceName)
    {
       return ServiceController.GetServices().Any(serviceController => serviceController.ServiceName.Equals(serviceName));
    }
    

    【讨论】:

    • 你没有处理ServiceControllers,这肯定是不好的做法吗?
    • ServiceController.GetServices() 是一个静态方法,因此没有要处理的实例。引擎盖下的 Any() 调用 dispose。 stackoverflow.com/questions/31931596/…
    • @JimmyV 您的链接详细说明了迭代器的处理方式/时间,而不是其中的元素。 GetServices 返回 IDisposable 对象(ServiceController 对象)的 IEnumerable,上述代码中的任何内容都不会自动处理这些对象。
    【解决方案3】:

    建立在迈克的回答之上。与 Dictionary.TryGetValue 的概念相同。

        /// <summary>
        /// Gets a <see cref="ServiceController"/> given the specified <see cref="pServiceName"/>.
        /// </summary>
        /// <param name="pServiceName">The name of the service.</param>
        /// <param name="pService">The <see cref="ServiceController"/> associated with the name.</param>
        /// <returns>
        /// <see cref="bool.True"/> if the <see cref="ServiceController"/> exists; otherwise <see cref="bool.False"/>.
        /// </returns>
        private static bool TryGetService(string pServiceName, out ServiceController pService)
        {
            pService = ServiceController.GetServices()
                .FirstOrDefault(serviceController => serviceController.ServiceName == pServiceName);
    
            return pService != null;
        }
    

    【讨论】:

    • 不错。这是我的“单线”:private static bool TryGetService(string name, out ServiceController service) =&gt; (service = ServiceController.GetServices().FirstOrDefault(s =&gt; s.ServiceName == name)) != null;
    猜你喜欢
    • 2011-06-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-08
    • 2011-05-14
    • 2014-07-18
    • 1970-01-01
    相关资源
    最近更新 更多