78 votes

Utiliser le routage ASP.NET pour servir des fichiers statiques

Le routage ASP.Net (pas MVC) peut-il être utilisé pour servir des fichiers statiques ?

Disons que je veux acheminer

http://domain.tld/static/picture.jpg

à

http://domain.tld/a/b/c/picture.jpg

et je veux le faire de manière dynamique, c'est-à-dire que l'URL réécrite est calculée à la volée. Je ne peux pas mettre en place une route statique une fois pour toutes.

Quoi qu'il en soit, je peux créer un itinéraire comme celui-ci :

routes.Add(
  "StaticRoute", new Route("static/{file}", new FileRouteHandler())
);

Dans le cadre de la FileRouteHandler.ProcessRequest je peux réécrire le chemin de /static/picture.jpg à /a/b/c/picture.jpg . Je souhaite ensuite créer un gestionnaire pour les fichiers statiques. ASP.NET utilise la fonction StaticFileHandler à cette fin. Malheureusement, cette classe est interne. J'ai essayé de créer le gestionnaire en utilisant la réflexion et cela fonctionne :

Assembly assembly = Assembly.GetAssembly(typeof(IHttpHandler));
Type staticFileHandlerType = assembly.GetType("System.Web.StaticFileHandler");
ConstructorInfo constructorInfo = staticFileHandlerType.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, Type.EmptyTypes, null);
return (IHttpHandler) constructorInfo.Invoke(null);

Mais l'utilisation de types internes ne semble pas être la bonne solution. Une autre option est d'implémenter mon propre StaticFileHandler mais le faire correctement (en prenant en charge les éléments HTTP tels que les plages et les balises) n'est pas une tâche triviale.

Comment dois-je aborder le routage des fichiers statiques en ASP.NET ?

58voto

Dan Atkinson Points 6043

Pourquoi ne pas utiliser IIS pour ce faire ? Vous pourriez créer une règle de redirection pour diriger toutes les demandes provenant de la première route vers la seconde avant même qu'elles n'atteignent votre application. Il s'agit donc d'une méthode plus rapide pour rediriger les demandes.

En supposant que vous ayez IIS7+, vous feriez quelque chose comme...

<rule name="Redirect Static Images" stopProcessing="true">
  <match url="^static/?(.*)$" />
  <action type="Redirect" url="/a/b/c/{R:1}" redirectType="Permanent" />
</rule>

Ou si vous n'avez pas besoin de rediriger, comme le suggère @ni5ni6 :

<rule name="Rewrite Static Images" stopProcessing="true">
  <match url="^static/?(.*)$" />
  <action type="Rewrite" url="/a/b/c/{R:1}" />
</rule>

Modifier 2015-06-17 pour @RyanDawkins :

Et si vous vous demandez où se trouve la règle de réécriture, voici une carte de son emplacement dans le fichier web.config fichier.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.webServer>
    <rewrite>
      <rules>
        <!-- rules go below -->
        <rule name="Redirect Static Images" stopProcessing="true">
          <match url="^static/?(.*)$" />
          <action type="Redirect" url="/a/b/c/{R:1}" redirectType="Permanent" />
        </rule>
      </rules>
    </rewrite>
  </system.webServer>
</configuration>

0 votes

Je préférerais également cette approche. La déplacer vers le pipeline et laisser le processus de travail IIS gérer la redirection est plus efficace que les cycles de rotation qui traitent réellement la route via le runtime, je suppose. Même si le nombre de changements sur le serveur est à peu près le même, je choisirais la voie (jeu de mots) de ne pas utiliser les routes et de garder la redirection en dehors de l'application elle-même.

0 votes

Ce qui n'était pas clair dans ma version initiale de la question, c'est que l'URL réécrite est calculée à la volée (je ne me préoccupe pas des performances ici). J'ai mis à jour la question pour clarifier ce point. Quoi qu'il en soit, merci de m'avoir répondu.

1 votes

(j'ai supprimé mon commentaire précédent et je l'ai réajouté avec un url non raccourci). Martin, en dehors des questions de performance, pourquoi voudriez-vous gérer cette url dans l'application, alors qu'il serait préférable de la gérer à l'extérieur ? Je suppose que vous pourriez créer une action de contrôleur qui gère cela, mais voici quelque chose que vous pourriez regarder :- geekswithblogs.net/sankarsan/archive/2009/01/18/

39voto

Robert Mao Points 892

Après avoir creusé ce problème pendant quelques heures, j'ai découvert qu'il suffisait d'ajouter des règles d'ignorance pour que vos fichiers statiques soient servis.

Dans RegisterRoutes(RouteCollection routes), ajoutez les règles d'ignorance suivantes :

routes.IgnoreRoute("{file}.js");
routes.IgnoreRoute("{file}.html");

0 votes

Pour moi, cela fonctionne, mais je ne peux pas analyser un fichier JS dans un dossier View d'une zone. Pour résoudre ce problème, j'utilise à la place un autre dossier dans le dossier de base de la zone, comme /Areas/MyArea/ClientScripts/foo.js.

29 votes

En quoi le fait d'ignorer les itinéraires vers vos fichiers statiques aide-t-il le routage à partir de l'Internet ? /static à /a/b/c (ce que demandait l'OP) ? Pourriez-vous éclaircir votre réponse, j'aimerais vraiment comprendre cette solution.

21 votes

Je suis d'accord avec Oliver pour dire que cela ne répond PAS au problème posé par le PO et ne devrait pas être accepté comme solution.

13voto

sheikhomar Points 446

J'ai eu un problème similaire. J'ai fini par utiliser HttpContext.RewritePath :

public class MyApplication : HttpApplication
{
    private readonly Regex r = new Regex("^/static/(.*)$", RegexOptions.IgnoreCase);

    public override void Init()
    {
        BeginRequest += OnBeginRequest;
    }

    protected void OnBeginRequest(object sender, EventArgs e)
    {
        var match = r.Match(Request.Url.AbsolutePath);
        if (match.Success)
        {
            var fileName = match.Groups[1].Value;
            Context.RewritePath(string.Format("/a/b/c/{0}", fileName));
        }
    }
}

1 votes

Merci beaucoup pour ce partage. Je suis tombé dessus en cherchant une solution pour l'URL Rewrite pendant le développement local, et j'ai réalisé que je pouvais le faire partout à la place. Je ne l'utilise pas pour l'analyse des entrées, mais pour la gestion des versions des fichiers JS et CSS.

0 votes

Pour les personnes intéressées, afin de gérer les fichiers de la forme filename.v1234.js J'utilise private readonly Regex regJS = new Regex("^(.*)([.]v[0-9]+)([.](js|css))$", RegexOptions.IgnoreCase); et ensuite, lors des matches, je fais Context.RewritePath(string.Format("{0}{1}", matchJS.Groups[1].Value, matchJS.Groups[3].Value));

7voto

Martin Liversage Points 43712

J'ai trouvé une alternative à l'utilisation de l'outil interne StaticFileHandler . Dans le IRouteHandler J'appelle HttpServerUtility.Transfer :

public class FileRouteHandler : IRouteHandler {

  public IHttpHandler GetHttpHandler(RequestContext requestContext) {
    String fileName = (String) requestContext.RouteData.Values["file"];
    // Contrived example of mapping.
    String routedPath = String.Format("/a/b/c/{0}", fileName);
    HttpContext.Current.Server.Transfer(routedPath);
    return null; // Never reached.
  }

}

Il s'agit d'un piratage. Les IRouteHandler est censé renvoyer un IHttpHandler et non d'abandonner et de transférer la demande en cours. Cependant, cela permet d'obtenir ce que je veux.

L'utilisation de l'interface interne StaticFileHandler est aussi un peu un hack puisque j'ai besoin d'une réflexion pour y accéder, mais au moins il y a un peu de la documentation sur StaticFileHandler sur MSDN ce qui en fait une classe un peu plus "officielle". Malheureusement, je ne pense pas qu'il soit possible de réfléchir aux classes internes dans un environnement de confiance partielle.

Je m'en tiendrai à l'utilisation de StaticFileHandler car je ne pense pas qu'il sera retiré d'ASP.NET dans un avenir proche.

4voto

Prerak K Points 1692

Vous devez ajouter un TransferRequestHandler pour gérer vos fichiers statiques, voir la réponse suivante https://stackoverflow.com/a/21724783/22858

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X