darkblue

博客园 首页 新随笔 联系 订阅 管理
 

DotNet服务中集成WMI 服务提供程序

20071017

by James Moore

James展示了如何添加简单的WMI提供程序,这样我们就可以监视、修改和通过网络远程访问它。

如果你编写一个想在远程能够监视和配置的程序(例如服务),可能想让你的程序和Windows管理指令(WMI)顺利集成。WMI是一种Web Based Enterprise Management工业标准的微软实现。它允许企业用户通过多种设备访问、更改和管理信息。在微软的DotNet Framework的类库的system.management命名空间中。

在本篇文章中,我们首先编写一个通过TCPl连接访问并返回通过Telenet连接输入的任何字符的Windows 服务程序。然后,我们通过添加WMI代码让该服务能够发布i其返回的字符的数量。也就是说,我们把该服务转换为一个WMI提供者。

尽管这是一个相当简单示例,它展示了开发具有WMI功能的应用程序的关键步骤。

1、          创建和安装服务

Visual Studio中创建一个TestServiceWindows服务程序。在解决方案中打开Service1.cs文件。

添加一个类型为Thread的变量m_engineThread

Thread m_engineThread;

我们在服务启动时开始一个新的监听线程

   protectedoverridevoid OnStart(string[] args)
        {
            m_engineThread =
newThread(newThreadStart(ThreadMain));
            m_engineThread.Start();
        }

确保服务停止时,该监听线程也停止。

   protectedoverridevoid OnStop()
        {
           
try
            {
                m_engineThread.Abort();
            }
           
catch (Exception) { ;}
        }

ThreadMain代码相当简单,它只是设置一个TCPListener并接受连接。然后输出通过TCP连接输入的任何内容。在单独的一行输入”.”结束。

 publicvoid ThreadMain()
      {
         
// Setup the TCP Listener to bind to 127.0.0.1:50009
          IPAddress localAddr = IPAddress.Parse("127.0.0.1");
         
TcpListener tlistener = newTcpListener(localAddr, 50009);
         
try
          {
             
// Start listening
              tlistener.Start();
             
String data = null;
             
// Enter processing loop
              while (true)
              {
                  
// Block until we get a connection
                  TcpClient client = tlistener.AcceptTcpClient();
                  data =
null;
                 
// Get a stream object and
                  // then create a StreamReader for convience
                  NetworkStream stream = client.GetStream();
                 
StreamReader sr = newStreamReader(stream);
                 
// Read a line from the client at a time.
                  while ((data = sr.ReadLine()) != null)
                  {
                      
if (data == ".")
                      {
                         
break;
                      }
                     
byte[] msg = System.Text.Encoding.ASCII.GetBytes(data);
                      stream.Write(msg, 0, msg.Length);
                      stream.WriteByte((
byte)'"r');
                      stream.WriteByte((
byte)'"n');
                  }
                 
// Shutdown and end connection
                  client.Close();
              }
          }
         
catch (SocketException e)
          {
              ;
          }
         
finally
          {
             
// Stop listening for new clients.
              tlistener.Stop();
          }
      }

最后,我们让这个服务自动安装。要实现自动安装,在工程中添加Sytem.Configuration.Install.dll引用,并在工程中添加一个MyInstaller的类,该类从Installer中继承并标记RunInstallerAttribute属性。

 [System.ComponentModel.RunInstaller(true)]
   
publicclassMyInstaller : Installer
    {

           …..

MyInstaller构造方法中,需要添加如下代码来安装服务:

    public MyInstaller()
        {
           
ServiceProcessInstaller procInstaller = new
ServiceProcessInstaller();
           
ServiceInstaller sInstaller = newServiceInstaller();
            procInstaller.Account =
ServiceAccount.LocalSystem;
            sInstaller.StartType =
ServiceStartMode.Automatic;
            sInstaller.ServiceName =
"Simple-Talk Test Service";
            Installers.Add(sInstaller);
            Installers.Add(procInstaller);
        }

所有这些,确保服务安装正确,并出现在控制面板的服务管理中。

2、          启动和停止服务

让我们运行以下。按F6编译该程序。然后运行InstallUtil.exe来安装生成的二进制文件。如:

C:"Simple-Talk>InstallUtil.exe TestService.exe

你会看安装工具的大量的命令行安装情况提示。一旦安装完成,在开始-运行中输入services.msc运行服务管理。找到Simple-TalkTestService服务并启动它。

既然已经启动服务,在启动-运行中输入Telnet 127.0.0.1 5009,打开一个Telnet窗口,输入你想要回显得东西后按回车。

结束连接,在单独一行中输入一个”.”回车。

我们通过服务管理结束该服务。

3、添加WMI支持

现在,我们要向TestService服务添加WMI支持。作为示例,我们将自从服务启动以来,其所回显的字符总数发布出来。

要添加对WMI支持,添加对System.Management.dll引用。并在工程中添加一个EchoInfoClass类,并标记InstrumentationClass属性,并添加参数InstrumentationType.Instance. 然后,添加一个公共int 类型变量CharsEchoed

[InstrumentationClass(InstrumentationType.Instance)]
   
publicclassEchoInfoClass
    {
       
publicint CharsEchoed;
    }

InstrumentationClass属性指定该类提供WMI数据。这种WMI数据即可以是一个类的实例也可以是一个WMI事件通知使用的一个类。本例中,我们提供一个类的实例。下一步,为了能够提供WMI支持,我们需要修改之前编写的安装类,将我们的WMI对象注册到WMI类库中。

为了按钻,我们先运行InstallUtil.exe /u Testservice.exe 来卸载该服务。

现在,我们修改安装类来将WMI对象正确注册到WMI系统中。幸运的是,DotNet Framework 架构将这一切做得非常简单。在FrameWork中有一DefaultManagementProjectInstaller类为具有InstrumentationClass属性的类提供默认的安装代码. 要使用该特性,只要将MyInstaller类从DefaultManagementProjectInstaller继承,而不是从Installer.继承即可。

[System.ComponentModel.RunInstaller(true)]
   
publicclassMyInstaller :
       
DefaultManagementProjectInstaller
    {
               …

我们需要在服务启动时创建并注册这个服务实例。这样,首先定义一个服务类的变量:

EchoInfoClass m_informationClass;

然后,在OnStart代码中添加如下代码:

   protected override void OnStart(string[] args)
        {
            m_informationClass = newEchoInfoClass();
            m_informationClass.CharsEchoed = 0;
           
Instrumentation.Publish(m_informationClass);

            m_engineThread = new Thread(new ThreadStart(ThreadMain));
            m_engineThread.Start();

        }

这样,就创建了类的实例并将其注册到WMI FrameWork中并可以通过WMI进行访问了。完成后就像正常类进行访问就可以。

我们就告诉WMI FrameWork 我们自定义的类情况,并将该类的一个实例发布了出去(在OnStart方法中)。现在,我们需要更新通过WMI发布的类的信息。通过将每次回显数据给客户端时修改 m_informationClass.CharsEchoed字段来实现.ThreadMain:添加如下方法来实现:

                    while ((data = sr.ReadLine()) != null)
                    {
                        if (data == ".")
                        {
                            break;
                        }

                       byte[] msg =
                            System.Text.Encoding.ASCII.GetBytes(data);
                        stream.Write(msg, 0, msg.Length);
                        stream.WriteByte((byte)'"r');
                        stream.WriteByte((byte)'"n');

                        m_informationClass.CharsEchoed += msg.Length;
                    }

4测试WMI Provider

现在我们可以编译运行一下看看运行情况。按F6编译程序并再次运行InstallUtil

C:"Simple-Talk>InstallUtil.exe TestService.exe

然后,启动服务进行试验。

C:"Simple-Talk>net start “Simple-talk test service”
    C:"Simple-Talk>telnet 127.0.0.1 50009

Telnet 命令打开一个屏幕等待录入。录入”simple-talk”并按回车,屏幕回显”simple-talk”

所以,服务返回11个字符。我们希望WMI Provider工作正常并且记录该数据。微软提供一个wbemTest工具提供对WMI信息浏览。尽管该程序已经很老了,但是现在可以使用它来进行测试。

C:"Simple-Talk>wbemtest

单击Connect按钮,选择默认设置,然后单击OK按钮:

单击Query…按钮并输入如下信息:

WQL 返回我们请求的实例而不是行,显示给我们如下信息:

注意: WQL非常类似 SQL –事实上,它是SQL子集,让我们以非常类似与访问RDBMS的方式访问管理信息。WQL 通常返回实例而不是行。

双击类的实例:

CharsEchoed属性显示为其已经发回数为11

5、总结

WMIwindows和其他平台进行跨企业网的机器和程序管理的基础架构。尽管我们的程序相当简单。但它给你足够的信息进行编写服务或网站进行WMI集成来进行远程监视和管理。

作者简介:James Moore

posted on 2007-10-19 11:33  bluesky7305  阅读(690)  评论(0编辑  收藏  举报