65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 C# 管理 IIS

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.65/5 (14投票s)

2010年8月6日

CPOL

5分钟阅读

viewsIcon

139872

downloadIcon

5408

使用 C# 管理 IIS

Copyright

IISManager 是 luckzj 的产品。任何人都可以免费使用此产品,但不得用于商业目的。如果您在使用 IISManager 时遇到任何问题,请随时通过 luckzj12@163.com 与我联系。或访问我的网站 http://soft-bin.com

本文的原始地址是

引言

我们可以使用 Microsoft 提供的 IIS 管理工具来管理我们的 IIS 服务器。然而,有时我们需要在我们的应用程序内部操作 IIS 服务器。例如,部署我们的网站相关应用程序。我将简要介绍如何使用 C# 管理 IIS 服务器。同时,我还将提供一个名为 IISManager 的 IIS 管理 DLL 及其用 C# 语言编写的源代码。

本文讨论的目标 IIS 版本是 IIS6.0 或更高版本。Windows Xp 上的 IIS 版本是 IIS 5.1,无法满足此要求。但是,您也可以在不支持 IIS 5.1 的条件下使用 IISManager 来管理它。

目前,IISManager 只能提供网站服务器管理类。但是,我将继续致力于此,并使其成为操作 IIS 服务器的完美工具。

我将从 Active Directory Service 开始本文。

Active Directory Service

我将使用 Active Directory Service (ADS) 来操作 IIS 服务器。关于 ADS 的进一步讨论将不再进行,因为网络上已经有太多介绍。我在这里只讨论如何使用它。

要访问 Active Directory Service,我们将使用 .NET 程序集 System.DirectoryServices 中定义的命名空间 System.DirectoryServices 下的类。因此,我们需要将此程序集添加到我们的项目中。

System.DirectoryServices 中,对于 IISManager 最重要的类是 DirectoryEntry。我们可以将 DirectoryEntry 视为一个节点,其中包含一组属性、方法和子节点。我们可以使用 DirectoryEntry.Properties[key] 访问属性,并使用 DirectoryEntry.Invoke 访问节点的 [方法]。我们可以使用 DirectoryEntry.SchemaClassName 获取节点的原型名称。

DirectoryEntry 的构造函数接受一个参数,该参数代表一个 ADS 节点。我将使用一个 IIS ADS 节点来构造一个 DirectoryEntry 实例,并使用它来访问 IIS 服务器。

使用 DirectoryEntry 打开 IIS 网站

我们可以使用以下方式获取一个 DirectoryEntry 实例来访问 IIS Active DirectoryServices (ADS)

DirectoryEntry Services = new DirectoryEntry("IIS:///W3SVC");  

IIS:///W3SVC” 是 IIS ADS 的名称。

我们刚刚创建了一个 IIS ADS 服务器对象。此节点上可能有许多网站,我们必须找到我们正在寻找的网站。

private DirectroyEntry websiteEntry = null;
internal const string IIsWebServer = "IIsWebServer";
 
protected IISWebsite(DirectoryEntry Server)
{
    websiteEntry = Server;
}
 
public static IISWebsite OpenWebsite(string name)
{
    // get directory service
    DirectoryEntry Services = new DirectoryEntry("IIS:///W3SVC");
    IEnumerator ie = Services.Children.GetEnumerator();
    DirectoryEntry Server = null;
 
    // find iis website
    while (ie.MoveNext())
    {
        Server = (DirectoryEntry)ie.Current;
        if (Server.SchemaClassName == IIsWebServer)
        {
            // "ServerComment" means name
            if (Server.Properties["ServerComment"][0].ToString() == name)
            {
                return new IISWebsite(Server);
                break;
             }
        }
    }
 
    return null;
} 

我使用 IISWebsite 来表示一个 IIS 网站,并使用 static 方法 ISWebsite.OpenWebsite() 来获取此类的一个实例。

DirectoryEntry.SchemaClassName 表示节点的原型。IISWebServer 的原型名称是 IISWebServer。我们将查找具有指定名称的网站。然而,DirectoryEntry.Name 不是网站的名称,而是节点的名称。要获取网站的名称,我们应该使用 DirectoryEntry.Properties["ServerComment"]DirectoryEntry.Properties 中的每个属性都表示为一个集合,我们应该使用 foreach 来访问属性的成员。但是,我们知道一个网站必须有一个名称,所以我们使用 Server.Properties["ServerComment"][0] 来获取此网站的真实名称。

创建网站

要创建网站,我们需要在“IIS:///W3SVC”下添加一个新节点。我将列出源代码并稍后进行解释。

/// <summary>
/// create a new website
/// </summary>
/// <param name="name">website name</param>
/// <param name="port">website port</param>
/// <param name="rootPath">root path</param>
/// <returns></returns>
public static IISWebsite CreateWebsite
	(string name, int port, string rootPath, string appPool)
{
    // validate root path
    if (System.IO.Directory.Exists(rootPath) == false)
    {
        throw new DirNotFoundException(rootPath);
    }
 
    // get directory service
    DirectoryEntry Services = new DirectoryEntry("IIS:///W3SVC");
 
    // get server name (index)
    int index = 0;
    foreach (DirectoryEntry server in Services.Children)
    {
        if (server.SchemaClassName == "IIsWebServer")
        {
            if (server.Properties["ServerComment"][0].ToString() == name)
            {
                throw new Exception("website:" + name + " already exists.");
            }
 
            if (Convert.ToInt32(server.Name) > index)
            {
                index = Convert.ToInt32(server.Name);
            }
        }
    }
    index++; // new index created
 
    // create website
    DirectoryEntry Server = Services.Children.Add(index.ToString(), IIsWebServer);
    Server.Properties["ServerComment"].Clear();
    Server.Properties["ServerComment"].Add(name);
    Server.Properties["Serverbindings"].Clear();
    Server.Properties["Serverbindings"].Add(":" + port + ":");
 
    // create ROOT for website
    DirectoryEntry root = Server.Children.Add("ROOT", IISWebVirturalDir.IIsVirtualDir);
    root.Properties["path"].Clear();
    root.Properties["path"].Add(rootPath);
 
    // create application
    if (string.IsNullOrEmpty(appPool))
    {
        root.Invoke("appCreate", 0);
    }
    else
    {
        // use application pool
        root.Invoke("appCreate3", 0, appPool, true);
    }
 
    root.Properties["AppFriendlyName"].Clear();
    root.Properties["AppIsolated"].Clear();
    root.Properties["AccessFlags"].Clear();
    root.Properties["FrontPageWeb"].Clear();
    root.Properties["AppFriendlyName"].Add(root.Name);
    root.Properties["AppIsolated"].Add(2);
    root.Properties["AccessFlags"].Add(513);
    root.Properties["FrontPageWeb"].Add(1);
 
    // commit changes
    root.CommitChanges();
    Server.CommitChanges();
 
    // return the newly created website
    IISWebsite website = new IISWebsite(Server);
    return website;
} 

已经澄清过,节点的名称并不意味着网站的名称。实际上,对于网站节点,节点的名称是一个整数。所以,当我尝试创建一个新的网站节点时,我应该首先找出存在的最大整数,然后加 1,这就成了我们新网站节点的名称。

添加节点似乎很容易

DirectoryEntry Server = Services.Children.Add(index.ToString(), IIsWebServer); 

然后,我们应该设置此网站的属性,包括网站名称和端口。

网站名称

node.Properties["ServerComment"].Add(name)

服务器端口

服务器端口的属性名称是 “ServerBindings”。但是,我们应该在端口字符串的前后加上“:”。例如,“:8080:”。我不知道为什么 Microsoft 会这样做,我只是按照他们的指示去做。

到目前为止,我们创建了一个网站。但是,一个网站必须有一个根目录。

// create ROOT for website
DirectoryEntry root = Server.Children.Add("ROOT", IISWebVirturalDir.IIsVirtualDir);
root.Properties["path"].Clear();
root.Properties["path"].Add(rootPath);
 
// create application
if (string.IsNullOrEmpty(appPool))
{
    root.Invoke("appCreate", 0);
}
else
{
    // use application pool
    root.Invoke("appCreate3", 0, appPool, true);
 }
 
root.Properties["AppFriendlyName"].Clear();
root.Properties["AppIsolated"].Clear();
root.Properties["AccessFlags"].Clear();
root.Properties["FrontPageWeb"].Clear();
root.Properties["AppFriendlyName"].Add(root.Name);
root.Properties["AppIsolated"].Add(2);
root.Properties["AccessFlags"].Add(513);
root.Properties["FrontPageWeb"].Add(1); 

网站根目录是网站的一个名为“ROOT”的子节点,其 SchemaClassName IIsWebVirtualDir。我还创建了一个名为 IISWebVirtualDir 的类来操作虚拟目录。我将在稍后讨论它。我们在这里应该知道的是,我们为网站创建了一个根虚拟目录。

网站的虚拟目录

每个网站都有虚拟目录,至少有一个根虚拟目录,如上所述。其他虚拟目录应该是根虚拟目录的子节点。我创建了 IISWebVirtualDir 类来表示虚拟目录。

要访问网站的根目录,我们可以使用 IISWebsite.Root

/// <summary>
/// Root path
/// </summary>
public IISWebVirturalDir Root
{
    get
    {
        foreach (DirectoryEntry entry in websiteEntry.Children)
        {
            if (entry.SchemaClassName == IISWebVirturalDir.IIsVirtualDir)
            {
                return new IISWebVirturalDir(entry);
            }
        }
 
        throw new WebsiteWithoutRootException(this.Name);
    }
} 

有了根目录,我们就可以使用 IISWebVirtualDir.OpenSubVirtualDir 来获取子虚拟目录。

/// <summary>
/// Open a sub virtual directory
/// </summary>
/// <param name="name">Name of directory to be opened. Case insensitive.</param>
/// <returns>A IISWebVirtualDir instance if open successfully done.Otherwise null.
/// </returns>
public IISWebVirturalDir OpenSubVirtualDir(string name)
{
    DirectoryEntry entry = this.FindSubEntry(name);
 
    if (entry == null)
    {
        return null;
    }
 
    return new IISWebVirturalDir(entry);
} 

我们可以使用 IISWebVirtualDir.CreateSubVirtualDir 来创建子虚拟目录。

/// <summary>
/// Create a sub virtual directory
/// </summary>
/// <param name="name">Name of the sub virtual directory to be created.</param>
/// <param name="path">Path of the sub virtual directory.</param>
/// <param name="appPool">
/// Application pool. Application pool with this name would be created if not exist.
/// Use string.Empty or null to this parameter 
/// if you don't want to use a application pool.
/// </param>
/// <returns>A IISWebVirtualDir if created. Otherwise  null.</returns>
public IISWebVirturalDir CreateSubVirtualDir(string name, string path, string appPool)
{
    // already exist
    if (this.ExistVirtualDir(name))
    {
        throw new VirtualDirAlreadyExistException(this._entry, path);
    }
 
    // validate path
    if (System.IO.Directory.Exists(path) == false)
    {
        throw new DirNotFoundException(path);
    }
 
    DirectoryEntry entry = this._entry.Children.Add(name, IIsVirtualDir);
    entry.Properties["path"].Clear();
    entry.Properties["path"].Add(path);
 
    // create application
    if (string.IsNullOrEmpty(appPool))
    {
        entry.Invoke("appCreate", 0);
    }
    else
    {
        // use application pool
        entry.Invoke("appCreate3", 0, appPool, true);
    }
 
    entry.Properties["AppFriendlyName"].Clear();
    entry.Properties["AppIsolated"].Clear();
    entry.Properties["AccessFlags"].Clear();
    entry.Properties["FrontPageWeb"].Clear();
    entry.Properties["AppFriendlyName"].Add(this._entry.Name);
    entry.Properties["AppIsolated"].Add(2);
    entry.Properties["AccessFlags"].Add(513);
    entry.Properties["FrontPageWeb"].Add(1);
 
    entry.CommitChanges();
    return new IISWebVirturalDir(entry);
}

应用程序池

我们还使用 DirectoryEntry 来访问应用程序池。应用程序池的根节点是 “IIS:///W3SVC/AppPools/”。

我编写了一个名为 IISAppPool 的类来管理应用程序池。我们可以使用 static 方法 IISAppPool.OpenAppPool 来打开一个应用程序池,或者使用 IISAppPool.CreateAppPool 来创建一个应用程序池。

/// <summary>
/// Open a application pool and return an IISAppPool instance
/// </summary>
/// <param name="name">application pool name</param>
/// <returns>IISAppPool object</returns>
public static IISAppPool OpenAppPool(string name)
{
    string connectStr = "IIS:///W3SVC/AppPools/";
    connectStr += name;
 
    if (IISAppPool.Exsit(name) == false)
    {
        return null;
    }
 
    DirectoryEntry entry = new DirectoryEntry(connectStr);
    return new IISAppPool(entry);
}
 
/// <summary>
/// create app pool
/// </summary>
/// <param name="name">the app pool to be created</param>
/// <returns>IISAppPool created if success, else null</returns>
public static IISAppPool CreateAppPool(string name)
{
    DirectoryEntry Service = new DirectoryEntry("IIS:///W3SVC/AppPools");
    foreach (DirectoryEntry entry in Service.Children)
    {
        if (entry.Name.Trim().ToLower() == name.Trim().ToLower())
        {
            return IISAppPool.OpenAppPool(name.Trim());
        }
    }
 
    // create new app pool
    DirectoryEntry appPool = Service.Children.Add(name, "IIsApplicationPool");
    appPool.CommitChanges();
    Service.CommitChanges();
 
    return new IISAppPool(appPool);
} 

对应用程序池的操作相当简单,我们可以 Start Stop 一个应用程序池。

/// <summary>
/// Start application pool.
/// </summary>
public void Start()
{
    this._entry.Invoke("Start");
}
 
/// <summary>
/// Stop application pool.
/// </summary>
public void Stop()
{
    this._entry.Invoke("Stop");
} 

DirectoryEntry 的属性

我们可以在 microsoft.com 上找到关于每个架构类属性的参考。但是,如果我们想使用 ADS 节点来枚举属性,这里有一个解决方案。

 private void ListProperty(DirectoryEntry server)
{
     foreach (DirectoryEntry e in server.Children)
     {
         ListProperty(e);
     }
 
     StringBuilder sb = new StringBuilder();
     sb.AppendLine("Property for " + server.SchemaClassName);
     sb.AppendLine("Name = " + server.Name);
     sb.AppendLine("Path = " + server.Path);
     sb.AppendLine("UserName = " + server.Username);
     sb.AppendLine("====================================================================");
      IEnumerator ie = server.Properties.PropertyNames.GetEnumerator();
      while (ie.MoveNext())
      {
          try
          {
               string name = (string)ie.Current;
               string val = "";
                foreach (object obj in server.Properties[name])
                {
                     val += obj.ToString() + ",";
                }
 
                sb.AppendLine(name + " = " + val.ToString());
           }
           catch (Exception)
           {
           }
       }
        System.IO.StreamWriter sw = new System.IO.StreamWriter
	("PropertyList_" + server.SchemaClassName + "_" + server.Name + ".txt");
        sw.Write(sb.ToString());
        sw.Close();
     }
} 

参考

历史

  • 2010 年 8 月 6 日:首次发布
© . All rights reserved.