2009-07-19 12 views
61

¿Se puede usar enrutamiento ASP.Net (no MVC) para servir archivos estáticos?Uso del enrutamiento ASP.NET para servir archivos estáticos

decir que quiero ruta

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

a

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

y quiero hacerlo de forma dinámica en el sentido de que la URL reescrito se calcula sobre la marcha. No puedo configurar una ruta estática de una vez por todas.

De todos modos, puedo crear una ruta como esta:

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

En el método FileRouteHandler.ProcessRequest puedo reescribir el camino de /static/picture.jpg a /a/b/c/picture.jpg. Entonces quiero crear un controlador para archivos estáticos. ASP.NET utiliza el StaticFileHandler para este fin. Desafortunadamente, esta clase es interna. He tratado de crear el controlador usando la reflexión y que realmente funciona:

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

Pero el uso de tipos internos no parece ser la solución adecuada. Otra opción es implementar mi propio StaticFileHandler, pero hacerlo correctamente (admitir cosas HTTP como rangos y etags) no es trivial.

¿Cómo debo abordar el enrutamiento de archivos estáticos en ASP.NET?

Respuesta

37

Después de investigar este problema durante unas horas, descubrí que simplemente agregando las reglas de ignorar se obtendrán los archivos estáticos.

En RegisterRoutes (rutas RouteCollection), añadir las siguientes reglas ignorar:

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

Para mí funciona, pero no puedo analizar un archivo JS en una carpeta de visualización de un área. Para solucionarlo, uso en su lugar otra carpeta en la carpeta base del área como /Areas/MyArea/ClientScripts/foo.js – eka808

+20

De alguna manera parece que me pierdo una pieza en el rompecabezas ... ¿cómo ayuda ignorar las rutas a sus archivos estáticos con el enrutamiento de '/ static' a'/a/b/c' (que solicitó OP)? ¿Podrían por favor arrojar más luz sobre su respuesta, realmente me gustaría entender esta solución? – Oliver

+17

Acuerde con Oliver que esto NO responde al OP y no debe aceptarse como la solución. – dhochee

48

¿Por qué no utilizar IIS para hacer esto? Simplemente podría crear una regla de redireccionamiento para señalar cualquier solicitud desde la primera ruta hasta la segunda antes de que la solicitud llegue a su aplicación. Debido a esto, sería un método más rápido para redirigir las solicitudes.

Asumiendo que tienen IIS7 +, haces algo como ...

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

O, si es que no es necesario volver a dirigir, según lo sugerido por @ ni5ni6:

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

Editar 2015-06-17 para @RyanDawkins:

Y si se pregunta dónde va la regla de reescritura, aquí está un mapa de su ubicación en el archivo web.config.

<?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="https://stackoverflow.com/a/b/c/{R:1}" redirectType="Permanent" /> 
     </rule> 
     </rules> 
    </rewrite> 
    </system.webServer> 
</configuration> 
+0

yo preferiría este enfoque, también. Moverlo a la canalización y dejar que el proceso de trabajo de IIS maneje la redirección es más eficiente que los ciclos de hilado que realmente procesan la ruta a través del tiempo de ejecución, supongo. Incluso si la cantidad de abandono en el servidor es casi la misma, iría a la ruta (juego de palabras) de no usar las rutas y mantener el redireccionamiento fuera de la aplicación. –

+0

Lo que no estaba claro de mi versión inicial de la pregunta era que la URL reescrita se calcula sobre la marcha (no me preocupa el rendimiento aquí). He actualizado la pregunta para aclarar eso. De todos modos, gracias por responder. –

+0

(eliminó mi comentario anterior y lo volvió a agregar con una url no acortada). Martin, aparte de los problemas de desempeño, ¿por qué querrías manejar esta url en la aplicación, cuando fuera mejor manejarla? Supongo que podría crear una acción de controlador que maneje esto, pero aquí hay algo que puede ver: http://geekswithblogs.net/sankarsan/archive/2009/01/18/developing-custom-routehandler.aspx –

5

Se me ocurrió una alternativa al uso del StaticFileHandler interno. En el IRouteHandler llamo 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("https://stackoverflow.com/a/b/c/{0}", fileName); 
    HttpContext.Current.Server.Transfer(routedPath); 
    return null; // Never reached. 
    } 

} 

Este es un truco. Se supone que el IRouteHandler devuelve un IHttpHandler y no aborta y transfiere la solicitud actual. Sin embargo, realmente logra lo que quiero.

El uso del StaticFileHandler interno también es algo así como un truco ya que necesito reflexión para tener acceso a él, pero al menos hay algunos documentation on StaticFileHandler on MSDN por lo que es una clase un poco más "oficial". Lamentablemente, no creo que sea posible reflexionar sobre las clases internas en un entorno de confianza parcial.

Me atengo a usar StaticFileHandler ya que no creo que se elimine de ASP.NET en el futuro previsible.

9

He tenido un problema similar. Terminé usando 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("https://stackoverflow.com/a/b/c/{0}", fileName)); 
     } 
    } 
} 
+1

Muchas gracias por compartir esto. Me encontré con esto en busca de una solución para la Reescritura de URL durante el desarrollo local, y me di cuenta de que puedo hacer esto en todas partes. Lo estoy usando no para el análisis de entrada, sino para la gestión de versiones de archivos JS y CSS. –

+0

Para cualquier persona interesada, para administrar archivos de la forma 'filename.v1234.js', estoy usando' private readonly Regex regJS = new Regex ("^ (. *) ([.] V [0-9] +) ([.] (js | css)) $ ", RegexOptions.IgnoreCase);' y luego en las coincidencias que hago 'Context.RewritePath (string.Format (" {0} {1} ", matchJS.Groups [1 ] .Value, matchJS.Groups [3] .Value)); ' –

3

es necesario agregar TransferRequestHandler para el manejo de su estática files.Please ver siguiente respuesta https://stackoverflow.com/a/21724783/22858

+0

Como referencia, esto también funciona para aplicaciones que no son MVC. – Ian

Cuestiones relacionadas