可以从WCF与Windows服务进行通信

时间:2013-07-01 04:11:04

标签: wcf windows-services

我对windows services有点新鲜。我在一台机器(机器1)上运行WCF service,在另一台机器(机器2)上运行Windows服务。

我需要使用WCF服务在机器2上运行powershell脚本。我不知道从哪里开始以及如何实现这一目标。我还需要将消息从WCF Web服务传递到Windows服务

请建议我或提供一些好的示例或教程。

修改
我想在机器2上运行一个powershell脚本。这个powershell脚本只能通过WCF服务知道 简单地想要做的就是将powershell传递给机器2.如何做到?

1 个答案:

答案 0 :(得分:3)

首先,我假设您正在接管一个现有项目,因为您的问题有点矛盾:您不熟悉Windows服务,但您声明您的系统中有一个。我还要考虑您必须维护现有的软件模型,同时还要控制两台机器。所以:

  • 计算机1 上的WCF服务提供PS脚本
  • 计算机2 上的Windows服务应在可用时立即执行这些脚本并由计算机1 上的WCF服务传递

为了解决这个问题,您可以考虑在计算机2上托管另一个WCF服务 How to: Host a WCF Service in a Managed Windows Service

这将如何运作?每次有新的PS脚本可用时,您都可以通过 machine 1 上的WCF服务在 machine 2 上调用第二个WCF服务。随后, machine 2 上的WCF服务可以将脚本保存到某个存储库(文件,数据库,内存中)并调用Windows服务上的ServiceController.ExecuteCommand Method。此时,Windows服务将从其保存的位置获取脚本并执行它。虽然我觉得这是一个不必要的过于复杂的软件项目,但这是一个针对您的情况的实现,只是回答您的问题,是的,可能

计算机2 上,安装包含WCF服务的Windows服务:

using System;
using System.Linq;
using System.ComponentModel;
using System.ServiceModel;
using System.ServiceProcess;
using System.Configuration.Install;
using System.IO;
using System.Management.Automation;
using System.Management.Automation.Runspaces;

namespace Sample.Services
{
    [ServiceContract(Namespace = "http://Sample.Services")]
    public interface IScriptExecutor
    {
        [OperationContract]
        void ExecuteScript(string script);
    }

    /// <summary>
    /// The WCF service class which will pass the script to the Windows
    /// service
    /// </summary>
    public class ScriptExecutorService : IScriptExecutor
    {
        const string PATH = @"C:\test\queue.txt";
        public void ExecuteScript(string script)
        {
            File.WriteAllText(PATH, script);
            ServiceController myService = 
                new ServiceController("WCFScriptWindowsService");
            myService.ExecuteCommand((int)MyCustomCommands.ExecuteScript);

        }
    }

    public class ScriptWindowsService : ServiceBase
    {
        const string PATH = @"C:\test\queue.txt";
        const string PATH_OUT = @"C:\test\out.txt";

        public ServiceHost serviceHost = null;
        public ScriptWindowsService()
        {
            ServiceName = "WCFScriptWindowsService";
        }

        protected override void OnCustomCommand(int command)
        {
            switch (command)
            {
                case (int)MyCustomCommands.ExecuteScript:
                    // Execute the PS script
                    var ps = PowerShell.Create();
                    var runspace = RunspaceFactory.CreateRunspace();
                    ps.Runspace = runspace;
                    // read the command from a repository, 
                    // could also be a database
                    ps.AddCommand(File.ReadAllText(PATH));
                    runspace.Open();
                    var results = ps.Invoke().ToList();
                    runspace.Close();
                    foreach (var result in results)
                    {
                        // writing the results to a file
                        File.AppendAllText(PATH_OUT, 
                            String.Format("{0}\r\n", 
                                result.BaseObject.GetType()));
                    }
                    break;
                default:
                    break;
            }
        }

        public static void Main()
        {
            ServiceBase.Run(new ScriptWindowsService());
        }

        protected override void OnStart(string[] args)
        {
            if (serviceHost != null)
            {
                serviceHost.Close();
            }
            serviceHost = 
                new ServiceHost(typeof(ScriptExecutorService));
            serviceHost.Open();
        }

        protected override void OnStop()
        {
            if (serviceHost != null)
            {
                serviceHost.Close();
                serviceHost = null;
            }
        }
    }

    // Provide the ProjectInstaller class which allows 
    // the service to be installed by the Installutil.exe tool
    [RunInstaller(true)]
    public class ProjectInstaller : Installer
    {
        private ServiceProcessInstaller process;
        private ServiceInstaller service;

        public ProjectInstaller()
        {
            process = new ServiceProcessInstaller();
            process.Account = ServiceAccount.LocalSystem;
            service = new ServiceInstaller();
            service.ServiceName = "WCFScriptWindowsService";
            Installers.Add(process);
            Installers.Add(service);
        }
    }

    /// <summary>
    /// Holds the custom commands (only one, in our case)
    /// </summary>
    public enum MyCustomCommands { ExecuteScript = 128 };
}

计算机1 上,修改WCF服务,使其在计算机2 上调用WCF服务:

using System.ServiceModel;

namespace Sample.Services
{
    [ServiceContract(Namespace = "http://Sample.Services")]
    public interface IScriptProvider
    {
        [OperationContract]
        string GetScript();
    }
    public class ScriptProviderService : IScriptProvider
    {
        public string GetScript()
        {
            // do some processing ...
            // let's say we end up with the "Get-Service" script
            var script = "Get-Service";
            // make sure you add a reference to the ExecutorServiceReference
            // WCF service on machine 2
            var client = new WcfService1.ExecutorServiceReference
                .ScriptExecutorClient();
            client.ExecuteScript(script);
            return script;
        }
    }
}

我会再次强调:您不必从Windows服务本身执行PS脚本。通过在Windows服务中托管新的WCF服务,您可以轻松调用它的方法并将逻辑从OnCustomCommand方法的覆盖移动到ScriptExecutorService的{​​{1}}方法。

如果我的模型假设错误,我会更新我的答案。