Bienvenue à Blogs CodeS-SourceS Identification | Inscription | Aide

Atteint de JavaScriptite Aiguë [Cyril Durand]

Expert ASP.net Ajax et WCF, Cyril Durand parle dans son blog de point techniques sur ASP.net, ASP.net Ajax, JavaScript, WCF et .net en général. Cyril est également consultant indépendant, n'hésitez pas à le contacter pour de l'assistance sur vos projets

Actualités

  • Blog de Cyril DURAND, passionné de JavaScript, Ajax, ASP.net et tout ce qui touche au developpement Web Client-Side.

    N'hésitez pas à me contacter pour vos projets .net : architecture, accompagnement, formation, ...

    View Cyril Durand's profile on LinkedIn
    hit counters


    Expertise Commerce server et BizTalk

Créer son serveur ASP.net : du socket au HttpRuntime, la Page en ligne de mire

Par curiosité, j'ai eu envie d'héberger manuellement ASP.net, c’est à dire coder l’application hôte, le serveur web, l'équivalent de IIS ou cassini.

Pour faire cela nous allons utiliser la méthode ApplicationHost.CreateApplicationHost. Cette méthode permet de créer un nouvel AppDomain dans lequel s’exécutera ASP.net. 
Cela se schématise ainsi :

image

Il faut bien avoir conscience que l’appel à la méthode CreationApplicationHost va créer un nouvel AppDomain ! Cela a de nombreuses incidences. Si vous n’êtes pas familier avec les AppDomains, je vous conseille de consulter ces articles What is an application domain - an explanation for .Net beginners et What ASP.NET Programmers Should Know About Application Domains 

Cette méthode prend 3 arguments : le type de l’hôte, le répertoire virtuel et le chemin physique de l’application web.

Le type de l’hôte correspond au type de l’objet qui sera instancié dans le nouvel AppDomain, cet instance est l’objet retourné par la méthode CreateApplicationHost. Puisque ce type sera échangé entre 2 AppDomains différents, il faut que celui-ci hérite de MarshallByRefObject. C’est dans cette classe que notre application va créer une requête, par exemple en écoutant sur un socket.

Pour que le second AppDomain utilise ce type, il faut que celui-ci soit connu de l’AppDomain, c’est à dire que l’assembly contenant le type soit chargé par l’AppDomain. Contrairement à la création classique d’un AppDomain, on ne peut pas spécifier les assemblies à chargé en même temps que la création de l’AppDomain. Pour cela nous allons déposer notre assembly dans le dossier /bin de l’application que l’on veut créer.

static void Main(string[] args) { // creation du dossier de l'application web // l'application web s'executera avec le compte de l'utilisateur courant String physicalPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); String binPath = Path.Combine(physicalPath, "bin"); Directory.CreateDirectory(binPath); // copie de l'assemblie contenant le type MyHost dans le dossier /bin de l'application web Assembly myHostAssembly = typeof(MyServer).Assembly; File.Copy(myHostAssembly.Location, Path.Combine(binPath, Path.GetFileName(myHostAssembly.Location))); MyServer myServer = (MyServer)ApplicationHost.CreateApplicationHost(typeof(MyServer), "/", physicalPath); }

A partir de là, nous avons créé une application web dans un nouvel AppDomain, reste maintenant à exécuter des requêtes dans cette application ASP.net. Pour cela nous allons utiliser la méthode HttpRuntime.ProcessRequest, cette méthode prend en paramètre un objet de type HttpWorkerRequest, il s’agit d’une classe abstraite qui possède des méthodes nécessaire à ASP.net, on retrouve par exemple la méthode GetRawUrl, SendResponseFromMemory, etc … Il s’agit du premier objet que l’application hôte (IIS ou cassini) va créer lorsqu’il reçoit une requête.

Il existe une implémentation simpliste de cette classe abstraite : SimpleWorkerRequest. Nous allons l’utiliser afin de simuler une requête vers le serveur que l’on vient de créer, l’appel à la méthode HttpRuntime.ProcessRequest doit évidemment se faire dans le nouvel AppDomain, pour cela nous rajoutons une méthode Start sur l’objet instancié dans le nouvel AppDomain, il suffira ensuite d’appeler cette méthode à partir de l’AppDomain parent.

public class MyServer : MarshalByRefObject { public void Start() { SimpleWorkerRequest wr = new SimpleWorkerRequest("page.aspx", null, Console.Out); HttpRuntime.ProcessRequest(wr); } }

En exécutant ce code, nous obtenons une erreur 404, ce qui est normal puisque la page appelée n’existe pas dans le dossier temporaire. Cette erreur est donc la preuve que notre serveur ASP.net fonctionne.

Notre serveur est fonctionnel ! Reste à lui faire accepter des connexions TCP, pour cela nous allons utiliser les sockets.

public class MyServer : MarshalByRefObject { public void Start() { // IP d'ecoute IPEndPoint endpoint = new IPEndPoint(IPAddress.Any, 8080); // creation du socket d'ecoute sur le port 8080 Socket listeningSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); listeningSocket.Bind(endpoint); listeningSocket.Listen(50); // 50 = le nombre de connexion simultanne en attente while (true) { // Socket de la connexion entrante Socket newRequestSocket = listeningSocket.Accept(); // recuperation de la requete HTTP sous forme de String Byte[] requestBuffer = new Byte[1024]; newRequestSocket.Receive(requestBuffer); String request = Encoding.Default.GetString(requestBuffer, 0, requestBuffer.Length); // analyse de la requete HTTP if (!request.StartsWith("GET", StringComparison.InvariantCultureIgnoreCase)) throw new NotSupportedException("Verb not supported"); String url = request.Split(' ')[1]; if (url.IndexOf('?') > 0) throw new NotSupportedException("QueryString not supported"); // execution de la reque StringBuilder sbResponse= new StringBuilder(); using (StringWriter swResponse = new StringWriter(sbResponse)) { SimpleWorkerRequest workerRequest = new SimpleWorkerRequest(url, null, swResponse); HttpRuntime.ProcessRequest(workerRequest); } // envoie de la reponse dans le socket du client Byte[] responseBuffer = Encoding.Default.GetBytes(sbResponse.ToString()); newRequestSocket.Send(responseBuffer); // fermeture du socket newRequestSocket.Close(); } } }

Nous avons utilisé les sockets TCP, mais nous aurions aussi pu créer nos SimpleWorkerRequest à partir d’un FileSystemWatcher, ou tout autre mécanisme. ASP.net n’est en rien lié à TCP !

Nous avons vu comment concevoir un serveur web ASP.net. Bien sur, ces bouts de code ne sont pas à utiliser en production, je ne gère que les requêtes HTTP GET sans querystring, il s’agit juste d’une illustration pour bien comprendre le fonctionnement interne d’un serveur ASP.net.

A partir de là, le HttpRuntime va créer un objet de type HttpContext et jouer le classique cycle de vie d'une requête : HttpModules et HttpHandler, mais ceci est une autre histoire ...

image

Il n'y a très peu d'interet à créer son propre serveur ASP.net, en production, la meilleure solution reste IIS6 ou 7. Pour avoir des détails sur le fonctionnement de l'hôte IIS6 ou IIS7, je vous conseille ses deux articles :


Je me suis intéressé à la création d'un serveur web suite à réel besoin, une idée de ce qui me trottait dans la tête ?

Posted: samedi 24 janvier 2009 19:14 par cyril
Ce post vous a plu ? Ajoutez le dans vos favoris pour ne pas perdre de temps à le retrouver le jour où vous en aurez besoin :

Commentaires

iso8859 a dit :

Très bien l'article, un sujet que j'allais commencer à investiguer.

L'intérêt d'embarquer son propre serveur aspx est que cela fonctionne sur toutes les versions de Windows.

Après il ne faut pas chercher à l'utiliser comme IIS, c'est à dire pour faire de monté en charge. Pour faire quelques échanges HTTP c'est super.

# janvier 25, 2009 10:32

cyril a dit :

Cassini fonctionne également sur toutes les versions de windows :)

De plus, le GUI est complétement séparé de la logique, si tu veux un GUI plus joli, tu peux réutiliser l'assembly Webdev.WebHost qui contient une classe Server fonctionnelle.

# janvier 25, 2009 11:32

JeremyJeanson a dit :

Cela donne des idées, par exemple : pour faire des démonstrations rapides de maquettes asp, à partir d'une clé usb sur un poste sans iis ou visual studio... humm j'adore :)

à tester de suite

# janvier 26, 2009 08:24

Amethyste a dit :

je tente ma chance:

vous êtes en train d'écrire une appli par exemple winform, capable de créer des pages web. Par exemple un Cms

Et vous avez besoin de faire des tests facilement

# janvier 26, 2009 18:15

cyril a dit :

@JeremyJeanson : techniquement cassini peut aussi faire tourner un site à partir d'une clé USB, là ou ca coince c'est au niveau de la licence. Il existe des mini serveurs web ASP.net sur codeplex

@Amethyste : Y'a de l'idée :) Je n'écris pas de CMS, mais effectivement j'ai cherché à écrire des tests unitaire pour des bouts de code qui utilisent des variables d'application initialisé par des HttpModules custom, cela permettrait également de pouvoir tester unitairement des HttpModules & co beaucoup plus facilement qu'avec ce que propose Microsoft.

Pour l'instant je suis en train de me renseigner sur comment créer son propre hote, l'utilisation de l'attribut [HostType("ASP.net")] ne me suffit pas

# janvier 26, 2009 18:33
Les commentaires anonymes sont désactivés

Les 10 derniers blogs postés

- Office 365: Script PowerShell pour auditer l’usage des Office Groups de votre tenant par Blog Technique de Romelard Fabrice le 04-26-2019, 11:02

- Office 365: Script PowerShell pour auditer l’usage de Microsoft Teams de votre tenant par Blog Technique de Romelard Fabrice le 04-26-2019, 10:39

- Office 365: Script PowerShell pour auditer l’usage de OneDrive for Business de votre tenant par Blog Technique de Romelard Fabrice le 04-25-2019, 15:13

- Office 365: Script PowerShell pour auditer l’usage de SharePoint Online de votre tenant par Blog Technique de Romelard Fabrice le 02-27-2019, 13:39

- Office 365: Script PowerShell pour auditer l’usage d’Exchange Online de votre tenant par Blog Technique de Romelard Fabrice le 02-25-2019, 15:07

- Office 365: Script PowerShell pour auditer le contenu de son Office 365 Stream Portal par Blog Technique de Romelard Fabrice le 02-21-2019, 17:56

- Office 365: Script PowerShell pour auditer le contenu de son Office 365 Video Portal par Blog Technique de Romelard Fabrice le 02-18-2019, 18:56

- Office 365: Script PowerShell pour extraire les Audit Log basés sur des filtres fournis par Blog Technique de Romelard Fabrice le 01-28-2019, 16:13

- SharePoint Online: Script PowerShell pour désactiver l’Option IRM des sites SPO non autorisés par Blog Technique de Romelard Fabrice le 12-14-2018, 13:01

- SharePoint Online: Script PowerShell pour supprimer une colonne dans tous les sites d’une collection par Blog Technique de Romelard Fabrice le 11-27-2018, 18:01