Developpez.com

Télécharger gratuitement le magazine des développeurs, le bimestriel des développeurs avec une sélection des meilleurs tutoriels

Gestion de IIS 7 avec C#

Cet article vous présente une mise en bouche de la gestion de IIS 7 grâce à C# sous Vista et Longhorn server.

N'hésitez pas à commenter cet article ! Commentez Donner une note à l'article (5)

Article lu   fois.

L'auteur

Profil ProSite personnel

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

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
  1. nom du site : siteName de type string
  2. port du site : sitePort de type int
  3. chemin physique du site : sitePhysicalPath de type string


Nous nommerons cette fonction CreateASite, voici le code :

CreateASite
Sélectionnez

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Web.Administration;

namespace DVP.InetMgrLite
{
    public class InetMgrLite
    {
        // Pour commencer créons une référence vers ServerManager et vers Site
        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);

            // Maintenant indiquons que le site démarre automatiquement.
            _site.ServerAutoStart = true;

            // Ensuite nous validons les changements
            _srvMgr.CommitChanges();
        }
    }
}



Maintenant utilisons cette méthode depuis une application console :

Utilisation de la méthode
Sélectionnez

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é :

Image non disponible

III. Les pools d'application

Afin d'en savoir plus sur la notion de pool, plutôt que de faire un copier-coller je vous invite à lire ceci : http://www.microsoft.com/france/msdn/netframework/1X/20031028-dotnet-dick-chapitre35.mspx

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
  1. poolName le nom du pool du type String
  2. pipeLineMode le type de ManagedPipelineMode voulu du type pipelineMode



Il existe deux types de ManagedPipelineMode :

  1. "Classic" : Il permet d'indiquer que IIS 7 va utiliser aspnet_isapi.dll pour router les requêtes comme dans IIS 6
  2. "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
Sélectionnez

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é
Sélectionnez

        public void CreateNewPool(string poolName, pipelineMode pipeLineMode)
        {
            _srvMgr = new ServerManager();

            // Via la méthode Add nous ajoutons notre nouveau pool
            _srvMgr.ApplicationPools.Add(poolName);

            // Nous déclarons une nouvelle instance de ApplicationPools, 
            _appPool = _srvMgr.ApplicationPools[poolName];

            // puis grâce à un switch nous indiquons le ManagedPipelineMode voulu
            switch (pipeLineMode)
            {
                case pipelineMode.classic:
                    _appPool.ManagedPipelineMode = ManagedPipelineMode.Classic;
                    break;
                case pipelineMode.integrated:
                    _appPool.ManagedPipelineMode = ManagedPipelineMode.Integrated;
                    break;
                default:
                    break;
            }

            // Ensuite on valide les changements
            _srvMgr.CommitChanges();
        }

Maintenant nous allons utiliser cette méthode dans une application console :



Utilisation de CreateNewPool dans une application console
Sélectionnez

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 :

Image non disponible

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
Sélectionnez

        private IEnumerator GetExistingPools()
        {
            _srvMgr = new ServerManager();

            //C'est ici que la collection est créée
            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 :

 
Sélectionnez

        public List<String> ExistingPools()
        {
            IEnumerator colPools = GetExistingPools();
            List<String> lstPools = new List<string>();

            int i = 0;

            // Remplissage de la liste.
            while (colPools.MoveNext())
            { 
                // Nous remplissons la liste avec le nom (.Name) du pool.
                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
Sélectionnez

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 : ");

            //Ici on parcourt la liste et on affiche le nom du pool.
            foreach (string pool in lstPools)
            {
                Console.WriteLine("{0}", pool);
            }

            Console.ReadLine();
        }
    }
}



Le résultat est le suivant :

Image non disponible

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
Sélectionnez

        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
Sélectionnez

            List<String> lstPools = new List<string>();
            lstPools = iis.ExistingPools();

            Console.WriteLine("Liste des pools : ");

            //Ici on parcourt la liste et on affiche le nom du pool.
            foreach (string pool in lstPools)
            {
                Console.WriteLine("{0}", pool);
            }

            // Comme nous sommes en mode console il faut saisir le nom du 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.
Image non disponible

Maintenant un petit tour dans IIS, histoire de voir si le pool a bien changé :
Image non disponible

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
Sélectionnez

        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 :

 
Sélectionnez

        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 :

 
Sélectionnez

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 :

Image non disponible

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
Sélectionnez

        public void CreateWebApp(string siteName, string appPath, string physicalPath)
        {
            _srvMgr = new ServerManager();

            //Ici on ajoute notre site à la collection.
            _srvMgr.Sites[siteName].Applications.Add(appPath, physicalPath);

            //On valide les changements
            _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
Sélectionnez

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 :

Image non disponible

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
Sélectionnez

        public void CreateVirtualDir(string siteName, string appPath, string virDirPath, string virDirPhysicalPath)
        {
            _srvMgr = new ServerManager();

            //On indique l'application de départ.
            Application app = _srvMgr.Sites[siteName].Applications[appPath];

            //On ajoute le répertoire virtuel à la collection
            app.VirtualDirectories.Add(virDirPath, virDirPhysicalPath);

            //On valide les changements
            _srvMgr.CommitChanges();
        }



Nous allons créer un répertoire virtuel nommé myVirDir ayant comme chemin physique d:\dvp\virdir :

Utilisation de CreateVirtualDir
Sélectionnez

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 :

Image non disponible

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
Sélectionnez

            _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
Sélectionnez

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
Sélectionnez

        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.

 
Sélectionnez

            List<ColSites> lst = iis.ListSites();
            foreach (ColSites site in lst)
            {
                Console.WriteLine("{0} - {1}", site.SiteId, site.SiteName);
            }

Image non disponible

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 :

Image non disponible

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 :

Image non disponible

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.

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

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'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.