Gestion de IIS 7 avec C#
Date de publication : 13/03/2007 , Date de mise à jour : 28/03/2007
Par
David Tavan (Accueil) (Blog)
Cet article vous présente une mise en bouche de la gestion de IIS 7 grâce à C# sous Vista et Longhorn server.
I. Introduction
II. Création d'un site
III. Les pools d'application
III-A. Création d'un nouveau pool
III-B. Lister les pools existants
III-C. Assignation d'un pool existant à un site
III-D. Assignation et création d'un pool à un site
IV. Création d'une application web
V. Création d'un répertoire virtuel
VI. Lister les sites présents dans IIS 7
VII. Conclusion
VIII. Remerciements
I. Introduction
A l'heure où j'écris ces lignes, force est de reconnaitre que les articles traitants de la gestion de IIS 7 via du code managé ne sont pas légion. (ou alors j'ai mal cherché )
-
Tout cet article est donc basé sur IIS 7 présent uniquement dans Vista et Longhorn Server, la seule documentation valable que j'ai pu trouver est ici :
http://msdn2.microsoft.com/en-us/library/microsoft.web.administration.aspx
Pourquoi cet article, la raison en est simple, l'objectif est d'automatiser les tâches, pour ce faire j'utilise, Windows Vista Intégrale RTM, Visual studio 2005 et le SDK de Windows, tout le code est écrit en C#.
Je pense que cet article est lisible par toutes personnes connaissants C#. Il n'y a à ma connaissance pas de choses vraiment compliquées.
Pour résumer, dans cette article les sujets abordés seront : la création d'un site, la création et l'assignation des pools d'applications, la création d'une application web, la création d'un répertoire virtuel et comment lister les processus en cours dans IIS 7.
Avant de commencer,
pensez à ajouter une référence à Microsoft.Web.Administration à votre projet vous le trouverez dans %WinDir%\System32\InetSrv.
Bon cette fois c'est parti
II. Création d'un site
Pour ce faire nous allons créer une instance des classes ServerManager et Site puis utiliser la méthode Add de la collection Sites
, ceci va nous permettre de créer un nouveau site sur le port choisi qui pointera vers un fichier, nous passerons ces données en paramètres.
Dans toute la suite de cet article je vais développer une classe que nous utiliserons dans une application console.
Pour en revenir à nos moutons, nous allons créer cette fonction puis dans une application console créer un site web
nommé dvp, écoutant le port 8000 et pointant sur le dossier d:\dvp.
Notre fonction aura donc comme paramètres :
Liste des paramètres
- nom du site : siteName de type string
- port du site : sitePort de type int
- chemin physique du site : sitePhysicalPath de type string
Nous nommerons cette fonction CreateASite, voici le code :
| CreateASite |
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Web.Administration;
namespace DVP.InetMgrLite
{
public class InetMgrLite
{
private ServerManager _srvMgr = null;
private Site _site = null;
public void CreateASite(string siteName, int sitePort, string sitePhysicalPath)
{
_srvMgr = new ServerManager();
_site = _srvMgr.Sites.Add(siteName, sitePhysicalPath, sitePort);
_site.ServerAutoStart = true;
_srvMgr.CommitChanges();
}
}
}
|
Maintenant utilisons cette méthode depuis une application console :
| Utilisation de la méthode |
using System;
using System.Collections.Generic;
using System.Text;
using DVP.InetMgrLite;
namespace ConsumeInetLite
{
class Program
{
static void Main(string[] args)
{
InetMgrLite iis = new InetMgrLite();
iis.CreateASite("dvp", 8000, "d:\\dvp");
}
}
}
|
Maintenant regardons dans IIS 7 si tout c'est bien passé :
III. Les pools d'application
III-A. Création d'un nouveau pool
Afin de créer un nouveau pool, nous allons créer une énumération qui nous permettra d'indiquer le ManagedPipelineMode voulu,
puis une méthode CreateNewPool qui aura deux paramètres :
Paramètres de CreateNew Pool
- poolName le nom du pool du type String
- pipeLineMode le type de ManagedPipelineMode voulu du type pipelineMode
Il existe deux types de ManagedPipelineMode :
- "Classic" : Il permet d'indiquer que IIS 7 va utiliser aspnet_isapi.dll pour router les requêtes comme dans IIS 6
- "Integrated" : Il permet d'indiquer que le serveur va utiliser le pipeline intégré à IIS 7 pour router les requêtes appelant du code managé.
La plupart des applications peuvent tourner sous IIS 7 dans un pool de type "Integrated", mais pour des raisons de compatibilité
le type "Classic" peut s'avérer salvateur.
Ceci dit, commencons par créer notre énumération pour des raisons de lisibilité, elle va se nommer pipelineMode et aura l'allure suivante :
| Enumération pipelineMode |
using System;
namespace DVP.InetMgrLite
{
public enum pipelineMode
{
classic,
integrated
}
}
|
Maintenant nous allons créer une nouvelle instance de ServerManager, puis ajouter à la collection "ApplicationPools" via la méthode "Add" notre nouveau pool :
| CreateNewPool documenté |
public void CreateNewPool(string poolName, pipelineMode pipeLineMode)
{
_srvMgr = new ServerManager();
_srvMgr.ApplicationPools.Add(poolName);
_appPool = _srvMgr.ApplicationPools[poolName];
switch (pipeLineMode)
{
case pipelineMode.classic:
_appPool.ManagedPipelineMode = ManagedPipelineMode.Classic;
break;
case pipelineMode.integrated:
_appPool.ManagedPipelineMode = ManagedPipelineMode.Integrated;
break;
default:
break;
}
_srvMgr.CommitChanges();
}
|
Maintenant nous allons utiliser cette méthode dans une application console :
| Utilisation de CreateNewPool dans une application console |
using System;
using System.Collections.Generic;
using System.Text;
using DVP.InetMgrLite;
namespace ConsumeInetLite
{
class Program
{
static void Main(string[] args)
{
InetMgrLite iis = new InetMgrLite();
iis.CreateNewPool("tes222t", pipelineMode.classic);
}
}
}
|
Regardons maintenant dans IIS :
Comme prévu notre pool est créé.
III-B. Lister les pools existants
Maintenant nous allons lister les différents pools existants dans IIS. Il y a plusieurs raisons de le faire. Par exemple si nous reprenons ce que nous avons
fait précédemment,
il est enfantin de faire "planter" le programme, il suffit de le lancer deux fois,la première fois il va créer le pool, la seconde,
il va lever une exception car il va essayer de créer un pool qui existe déjà.
Une des autres raisons de le faire sera évidente dans la section "Assignation d'un pool existant ...".
Histoire de parvenir à nos fins, nous allons créer deux méthodes, la première GetExistingPools qui nous renverra un IEnumerator, la seconde ExisitingPools, nous renverra une liste de string.
En C# 3, via LINQ, vive le ToList() ;-), mais ceci est une autre histoire.
Donc dans un premier temps créons une collection de pools, pour ce faire quelques lignes suffisent :
| GetExistingPools |
private IEnumerator GetExistingPools()
{
_srvMgr = new ServerManager();
IEnumerator enumPools = _srvMgr.ApplicationPools.GetEnumerator();
return enumPools;
}
|
Maintenant créons la seconde méthode ExistingPools, le code, me semble-t'il parle de lui même :
|
public List<String> ExistingPools()
{
IEnumerator colPools = GetExistingPools();
List<String> lstPools = new List<string>();
int i = 0;
while (colPools.MoveNext())
{
lstPools.Add(_srvMgr.ApplicationPools[i].Name);
i++;
}
return lstPools;
}
|
Voici un petit exemple en mode console toujours qui met en évidence ce que nous venons de voir, nous allons tout simplement afficher le nom des pools existants.
| Pools existants |
using System;
using System.Collections.Generic;
using System.Text;
using DVP.InetMgrLite;
namespace ConsumeInetLite
{
class Program
{
static void Main(string[] args)
{
InetMgrLite iis = new InetMgrLite();
List<String> lstPools = new List<string>();
lstPools = iis.ExistingPools();
Console.WriteLine("Liste des pools : ");
foreach (string pool in lstPools)
{
Console.WriteLine("{0}", pool);
}
Console.ReadLine();
}
}
}
|
Le résultat est le suivant :
III-C. Assignation d'un pool existant à un site
Pour assigner un pool existant à un site, il faut évidemment récupérer la liste des pools existants. Pour ce faire nous utiliserons ce que nous
avons écrit lorsque nous listions les pools en mode console.
Nous allons créer une méthode AssignExistingPool qui prendra deux paramètres de type string : le nom du site (siteName) et le nom du pool (poolName).
Cette méthode est "mécanique" ;) , pour l'utiliser on signifie à ApplicationPoolName le nom du pool souhaité, on valide les changements et on recycle le pool.
Dans un premier temps voyons le code de cette méthode :
| méthode AssignExistingPool |
public void AssignExistingPool(string siteName, string poolName)
{
_srvMgr = new ServerManager();
_srvMgr.Sites[siteName].Applications[0].ApplicationPoolName = poolName;
_appPool = _srvMgr.ApplicationPools[poolName];
_srvMgr.CommitChanges();
_appPool.Recycle();
}
|
Comme je le disais rien de bien sorcier.
Maintenant voyons comment utiliser tout ceci.
Nous allons utiliser un scénario simple en mode console :
1- nous récupèrons dans une liste de string les pools existants
2- via un Console.ReadLine() nous demandons à l'utilisateur le pool choisi
3- encore avec un ReadLine nous demandons le site qui doit changer de pool
4- on valide :)
Maintenant regardons le code suivant de ce scénario :
| Utilisation de la méthode AssignExistingPool |
List<String> lstPools = new List<string>();
lstPools = iis.ExistingPools();
Console.WriteLine("Liste des pools : ");
foreach (string pool in lstPools)
{
Console.WriteLine("{0}", pool);
}
Console.WriteLine("Veuillez choisir un pool");
string sPool=Console.ReadLine();
Console.WriteLine("Nom du site qui doit changer de pool");
string sSite = Console.ReadLine();
iis.AssignExistingPool(sSite, sPool);
|
Je vous accorde que cette méthode n'est pas vraiment "User Friendly", et oui on saisit les paramètres à la main.
Maintenant un petit tour dans IIS, histoire de voir si le pool a bien changé :

Comme prévu le pool a bien changé, heureusement ;)
III-D. Assignation et création d'un pool à un site
Avant d'assigner et de créer un pool à un site, il convient de vérifier que ce pool n'existe pas, sinon celà va lever une exception.
Pour ce faire nous allons créer une méthode TestPool qui renverra un booléen et qui prendra comme paramètre une variable poolToTest de type string.
Le fonctionnement est très simple, on récupère dans une liste de string les pools existants, on parcourt cette dernière, si le nom du pool à tester figure dans la liste on renvoie false, donc impossible de créer ce pool.
| la méthode TestPool |
public bool TestPool(string poolToTest)
{
List<string> lstPools = new List<string>();
bool result = true;
lstPools = ExistingPools();
foreach (string pool in lstPools)
{
if (poolToTest == pool)
result = false;
}
return result;
}
|
Le code de cette méthode ressemble beaucoup à ce que nous avons déjà écrit, donc le voici :
|
public bool CreateAndAssignNewPool(string siteName, string poolName, pipelineMode pipeMode)
{
bool result = TestPool(poolName);
if (result)
{
_srvMgr = new ServerManager();
_srvMgr.ApplicationPools.Add(poolName);
_srvMgr.Sites[siteName].Applications[0].ApplicationPoolName = poolName;
_appPool = _srvMgr.ApplicationPools[poolName];
switch (pipeMode)
{
case pipelineMode.classic:
_appPool.ManagedPipelineMode = ManagedPipelineMode.Classic;
break;
case pipelineMode.integrated:
_appPool.ManagedPipelineMode = ManagedPipelineMode.Integrated;
break;
default:
break;
}
_srvMgr.CommitChanges();
}
return result;
}
|
Quant à l'utilisation elle est triviale comme vous allez le voir :
|
using System;
using System.Collections.Generic;
using System.Text;
using DVP.InetMgrLite;
namespace ConsumeInetLite
{
class Program
{
static void Main(string[] args)
{
InetMgrLite iis = new InetMgrLite();
bool result = iis.CreateAndAssignNewPool("dvp", "toto", pipelineMode.integrated);
if (!result)
Console.WriteLine("Le pool existe déjà");
Console.ReadLine();
}
}
}
|
Je pense que le code parle de lui même.
Histoire de se rassurer voyons si dans IIS la modification a été prise en compte :

Comme prévu tout est ok.
IV. Création d'une application web
Passons maintenant à la création d'une application web. Je ne vous cacherai pas que c'est très simple et qu'en une ligne de code notre application est créée.
Commencons par créer une méthode CreateWebApp qui prendra comme paramètres : le nom du site (siteName de type string), le chemin de l'application (appPath de type string) et le chemin physique de cette application (physicalPath aussi de type string).
Donc pour créer une application nous allons via la méthode "Add" ajouter à la collection "Applications" notre application comme suit :
| Méthode CreateWebApp |
public void CreateWebApp(string siteName, string appPath, string physicalPath)
{
_srvMgr = new ServerManager();
_srvMgr.Sites[siteName].Applications.Add(appPath, physicalPath);
_srvMgr.CommitChanges();
}
|
L'utilisation de cette méthode est implicite, créons une application web dont le chemin est /myWebApp sur le site dvp dont le chemin physique est D:\dvp\webapp :
| utilisation de la méthode CreateWebApp |
using System;
using System.Collections.Generic;
using System.Text;
using DVP.InetMgrLite;
namespace ConsumeInetLite
{
class Program
{
static void Main(string[] args)
{
InetMgrLite iis = new InetMgrLite();
iis.CreateWebApp("dvp", "/myWebApp", @"D:\dvp\webapp");
Console.ReadLine();
}
}
}
|
Allons voir dans IIS :

Comme prévu notre application web a bien été créée.
V. Création d'un répertoire virtuel
Afin de créer un répertoire virtuel, la méthode est sensiblement la même que la précédente. Dans un premier temps nous allons créer
une instance de la classe "Application" et lui indiquer quel application nous allons utiliser comme point de départ. Ensuite toujours
avec la méthode "Add" nous allons ajouter à la collection "VirtualDirectories" notre répertoire virtuel.
Notre méthode que nous nommerons CreateVirtualDir, prendra 4 paramètres tous de type string, à savoir : le nom du site (siteName),
le chemin de l'application de départ (appPath), le chemin du répertoire virtuel (virDirPath) et le chemin physique du répertoire virtuel (virDirPhysicalPath),
la méthode aura donc cette allure :
| CreateVirtualDir |
public void CreateVirtualDir(string siteName, string appPath, string virDirPath, string virDirPhysicalPath)
{
_srvMgr = new ServerManager();
Application app = _srvMgr.Sites[siteName].Applications[appPath];
app.VirtualDirectories.Add(virDirPath, virDirPhysicalPath);
_srvMgr.CommitChanges();
}
|
Nous allons créer un répertoire virtuel nommé myVirDir ayant comme chemin physique d:\dvp\virdir :
| Utilisation de CreateVirtualDir |
using System;
using System.Collections.Generic;
using System.Text;
using DVP.InetMgrLite;
namespace ConsumeInetLite
{
class Program
{
static void Main(string[] args)
{
InetMgrLite iis = new InetMgrLite();
iis.CreateVirtualDir("dvp", "/", "/myVirDir", @"d:\dvp\virdir");
Console.WriteLine("<-- END -->");
Console.ReadLine();
}
}
}
|
Regardons maintenant dans IIS :
Voilà notre répertoire virtual a bien été créé, comme prévu.
VI. Lister les sites présents dans IIS 7
Afin de lister les sites existants dans IIS 7, il suffit de parcourir la collection "Sites" de "ServerManager" et d'afficher le résultat :
| List en mode console |
_srvMgr = new ServerManager();
foreach (Site site in _srvMgr.Sites)
{
Console.WriteLine("{0} - {1} ", site.Id.ToString(), site.Name);
}
|
Bon ce n'est pas ce que je veux, je veux créer une méthode réutilisable dans ma classe et ensuite l'utiliser dans une Winform ou Webform. Pour ce faire je vais utiliser le scénario suivant : créer une classe contenant les informations dont j'ai besoin (ColSites.cs), puis créer une méthode ListSites qui renverra une liste de "ColSites", pour remplir cette liste nous allons parcourir la collection "Sites" comme je l'ai mentionné plus haut.
Commencons par créer notre classe ColSites.cs, elle va contenir deux constructeurs et des accesseurs sur les informations que nous voulons récupérer :
| ColSites.cs |
using System;
using System.Collections.Generic;
using System.Text;
namespace DVP.InetMgrLite
{
public class ColSites
{
public ColSites()
{
}
public ColSites(string siteid, string sitename)
{
this.SiteId = siteid;
this.SiteName = sitename;
}
private string _siteID;
private string _siteName;
public string SiteId
{
get { return _siteID; }
set { _siteID = value; }
}
public string SiteName
{
get { return _siteName; }
set { _siteName = value; }
}
}
}
|
Ceci fait créons notre méthode ListSites et nous allons remplir la liste à renvoyer en parcourant la collection comme suit :
| Méthode ListSites |
public List<ColSites> ListSites()
{
_srvMgr = new ServerManager();
List<ColSites> lstSites = new List<ColSites>();
foreach (Site site in _srvMgr.Sites)
{
lstSites.Add(new ColSites(site.Id.ToString(), site.Name));
}
return lstSites;
}
|
Pour utiliser cette méthode nous créons une liste de "ColSites", nous la parcourons et affichons les résultats.
|
List<ColSites> lst = iis.ListSites();
foreach (ColSites site in lst)
{
Console.WriteLine("{0} - {1}", site.SiteId, site.SiteName);
}
|
C'est bien ce que nous voulions.
VII. Conclusion
Cet article n'a pas pour but d'être exhaustif, c'est simplement une mise en bouche, les possibilités au niveau de la sécurité etc. sont énormes et devraient faire un bon sujet pour un livre (tiens c'est pas bête ca ;-) ).
Pour bien maitriser ce domaine il suffit de connaitre un peu (ou plus) le C# et comment fonctionne IIS 7 qui est à mon sens une grande avancée dans le domaine des serveurs web.
Voici d'ailleurs une image montrant la différence entre l'architecture de IIS 6 et 7 :
Ce diagramme est issu du MSDN Mag de mars 2007.
Je vous invite d'ailleurs à lire cet article en entier :
http://msdn.microsoft.com/msdnmag/issues/07/03/iis7/default.aspx?loc=fr
Pour conclure je mets à votre disposition les sources de la classe créée ainsi que le diagramme de classe :
J'espère que cet article vous aura aidé à mieux appréhender la gestion de IIS 7 via du code managé et vous donnera envie de poursuivre.
Téléchargez les codes source de la classe
VIII. Remerciements
Je tiens à remercier
dev01,
Ditch et
khany pour la relecture tant technique qu'orthographique.
Merci à vous.


Copyright © 2007 David Tavan. Aucune reproduction, même partielle, ne peut être faite
de ce site et de l'ensemble de son contenu : textes, documents, images, etc
sans l'autorisation expresse de l'auteur.
Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 E
de dommages et intérêts.
Cette page est déposée à la
SACD.