web-dev-qa-db-fra.com

Utilisation du routage ASP.NET pour servir des fichiers statiques

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

Dis que je veux router

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

à

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

et je veux le faire dynamiquement dans le sens où l'URL réécrite est calculée à la volée. Je ne peux pas configurer 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 FileRouteHandler.ProcessRequest méthode, je peux réécrire le chemin depuis /static/picture.jpg à /a/b/c/picture.jpg. Je veux ensuite créer un gestionnaire de fichiers statiques. ASP.NET utilise le StaticFileHandler à cet effet. Malheureusement, cette classe est interne. J'ai essayé de créer le gestionnaire en utilisant la réflexion et cela fonctionne réellement:

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 consiste à implémenter mon propre StaticFileHandler, mais le faire correctement (prendre en charge des éléments HTTP comme les plages et les étiquettes) n'est pas trivial.

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

69
Martin Liversage

Après avoir creusé ce problème pendant quelques heures, j'ai constaté que le simple ajout de règles d'ignorance servira vos fichiers statiques.

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

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

Pourquoi ne pas utiliser IIS pour ce faire? Vous pouvez simplement créer une règle de redirection pour pointer toutes les demandes de la première route vers la seconde avant même que la demande ne parvienne à votre application. Pour cette raison, il serait être une méthode plus rapide pour rediriger les demandes.

En supposant que vous avez IIS7 +, vous faites 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>

O, si vous n'avez pas besoin de rediriger, comme suggéré par @ ni5ni6:

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

Modifier le 2015-06-17 pour @RyanDawkins:

Et si vous vous demandez où va la règle de réécriture, voici une carte de son emplacement dans le 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>
52
Dan Atkinson

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));
        }
    }
}
11
sheikhomar

J'ai trouvé une alternative à l'utilisation du StaticFileHandler interne. 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.
  }

}

Ceci est un hack. Le IRouteHandler est censé retourner un IHttpHandler et non pas abandonner et transférer la requête en cours. Cependant, il atteint réellement ce que je veux.

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

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

6
Martin Liversage

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

4
Prerak K