Handler : comment gerer sa propre extension (tutos - asp.net)

Contenu du snippet

Cet astuce vous permettra de compter le nombre de telechargement d'un pdf, zip, etc...

Avant de me lancer dans ceci, j'ai regardé ce qu'il y avait de déjà présent sur le net, et je suis tombé sur l'excellent article de Fabrice sur asp-php.net : http://asp-php.net/tutorial/asp.net/httphandlers.php. Etant donnée qu'il fait à peu de choses près la meme chose que ce que je voulais faire, je vais juste marquer le necessaire pour comprendre comment fonctionne les handler.

Tout d'abord, ca va vous servir à quoi ? imaginons que vous voulez connaitre le nombre de personne qui telechargent un zip, pour cela il y a plusieurs solutions, soit vous faites votre propre gestionnaire de zip, dans quels cas si l'utilisateur va directement sur le zip il ne sera pas vus, soit vous mettez un handler sur les fichiers zips. A chaque fois qu'un client demandera un zip, IIS demandera a votre handler la réponse à renvoyer, c'est donc vous qui êtes chargés d'envoyer la réponse au client.

Pour cela comment faire. Tout d'abord il vous faut modifier le fichier web.config en rajoutant ces elements :
<configuration>
<system.web>
<httpHandlers>
<add verb="*" path="*.zip" type="Handler.ZipHandler, Handler"/>
</httpHandlers>
</system.web>
</configuration>

Une rapide explication la propriété verb sert à définir le type de requete : GET, POST ou HEAD (je n'ai pas encore trouvé d'infos sur la méthode HEAD !), l'attribut path définit les types de fichiers ciblés, ca peut etre *.zip pour tout les zips mais aussi path="count*.zip" pour les zips définit de maniere suivante countTest.zip, countSecondTest.zip, ... Enfin l'attribut type, contient deux paramètres séparés par une virgule, le premier paramètre est le nom de la classe du handler, et la deuxieme le nom de l'assembly.
Dans l'exemple j'ai crée un fichier .vb contenant en gros le code suivant
Namespace Handler
public class ZipHandler
' ...
Ce code je l'ai compilé dans le fichier handler.dll. Nous verrons plus en détails comment fonctionne cette classe dans la suite de l'article.

Malheureusement si l'on s'arrete ici, quand on appellera un fichier zip, le handler ne sera pas appellé. Pour cela il faut d'abord dire que les fichiers zip sont gérés par IIS. Voici la marche à suivre :
- Aller dans le gestionnaire de service IIS (demarrer executer %SystemRoot%\system32\inetsrv\iis.msc)
- Naviguer jusqu'au repertoire de l'application et aller dans ses propriétés.
- cliquer sur configuration dans l'onglet repertoire virtuelle, puis ajouter
- Dans le nom de l'executable, vous mettez : c:\windows\microsoft.net\framework\v1.1.4322\aspnet_isapi.dll (ou semblable)
- Valider et fermer

Maintenant a chaque fois qu'un utilisateur va demander un zip il passera pas IIS, le problème c'est que l'on a pas toujours accés à IIS, dans le cas d'un hebergement mutualisé par exemple. Heureusement IIS a pensé à nous, et nous a fournit une extension fourre tout : les .ashx. l'utilisation est la même que pour les autres. Ce que je vous propose c'est de faire le web.config de cette manière :
<configuration>
<system.web>
<httpHandlers>
<add verb="*" path="*.zip.ashx" type="Handler.ZipHandler, Handler"/>
</httpHandlers>
</system.web>
</configuration>

pour récuperer le nom du fichier zip, sans l'ashx, je vous propose ce bout de code suivant :
Public Class Utilities
Public Shared ReadOnly Property GetFileName(ByVal Context As System.Web.HttpContext)
Get
For Each segment As String In Context.Request.Url.Segments
If segment.ToUpper.IndexOf(".ASHX") > 0 Then
Dim rtn As String
For Each s As String In segment.Split(".")
If s.ToUpper = "ASHX" Then Return rtn.Remove(rtn.Length - 1, 1) : Exit For
rtn &= s & "."
Next
End If
Next
End Get
End Property
End Class

Maintenant examinons plus en détails notre classe ZipHandler

Pour plus de simplicité au debut de votre handler, faites les imports des classes suivantes :
Imports System.Web
Imports System.IO

Pour qu'un Handler soit valide, il faut qu'il implemente IHttpHandler, cette interface possède deux membres :
Public Class ZipHandler
Implements IHttpHandler

Public ReadOnly Property IsReusable() As Boolean Implements System.Web.IHttpHandler.IsReusable
Get

End Get
End Property

Public Sub ProcessRequest(ByVal context As System.Web.HttpContext) Implements System.Web.IHttpHandler.ProcessRequest

End Sub

End Class

Le boolean is Reusable est définit par MSDN comme ceci : "Obtient une valeur indiquant si une autre demande peut utiliser l'instance IHttpHandler." Merci Ms :p pour les quelques tests que j'ai réalisé je n'ai encore pas vu de difference si quelqu'un la connait, peut etre dans le cas de plusieurs demande du fichier.

Ensuite la méthode ProcessRequest, est la méthode qui va nous servir pour ecrire le retour, et aussi avoir des infos sur le client etc..

Source / Exemple :


Public Class Utilities
    Public Shared ReadOnly Property GetFileName(ByVal Context As System.Web.HttpContext)
        Get
            For Each segment As String In Context.Request.Url.Segments
                If segment.ToUpper.IndexOf(".ASHX") > 0 Then
                    Dim rtn As String
                    For Each s As String In segment.Split(".")
                        If s.ToUpper = "ASHX" Then Return rtn.Remove(rtn.Length - 1, 1) : Exit For
                        rtn &= s & "."
                    Next
                End If
            Next
        End Get
    End Property
End Class

Public Class ZipHandler
    Implements IHttpHandler

    Public ReadOnly Property IsReusable() As Boolean Implements System.Web.IHttpHandler.IsReusable
        Get
            Return True
        End Get
    End Property

    Public Sub ProcessRequest(ByVal context As System.Web.HttpContext) Implements System.Web.IHttpHandler.ProcessRequest

        ' Par défaut je met les fichiers telechargeable dan le repertoire Files\ dans le repertoire racine de l'application
        ' rien ne m'empeche d'avoir une URL du genre http://localhost/TestHandler/Downloads/File.zip.ashx 
        ' alors que le fichier physique se trouve http://localhost/TestHandler/Files/File.zip.ashx 
        Dim _File As String = context.Request.PhysicalApplicationPath & "Files\" & Utilities.GetFileName(context)

        ' Vérification de l'existence du fichier.
        If New FileInfo(_File).Exists = False Then
            context.Response.Write("Le fichier demandé n'existe pas")
            Return
        End If

        ' C'est ici que l'on devrait ajouter une gestion des comptes de telechargement,
        ' On pourrait aussi vérifier s'il est authorizé à recevoir le fichier via une variable session 
        ' context.Session("isAuthorized")
        ' etc...

        ' On ecrit le fichier 
        context.Response.WriteFile(_File)

    End Sub

End Class

Conclusion :


J'espere avoir été assez clair, si malgré tout ce que j'ai dit reste confus, n'hésiter par à laisser un commentaire ils sont là pour ca.

A voir également

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.