2009-07-19 3 views
61

Il routing ASP.Net (non MVC) può essere utilizzato per servire file statici?Utilizzo del routing ASP.NET per servire file statici

dire che voglio percorso

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

a

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

e voglio farlo in modo dinamico, nel senso che l'URL riscritto viene calcolata al volo. Non riesco a impostare una rotta statica una volta per tutte.

Comunque, posso creare un percorso come questo:

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

Nel metodo FileRouteHandler.ProcessRequest posso riscrivere il percorso da /static/picture.jpg a /a/b/c/picture.jpg. Quindi voglio creare un gestore per i file statici. ASP.NET utilizza lo StaticFileHandler per questo scopo. Sfortunatamente, questa classe è interna. Ho cercato di creare il gestore utilizzando la riflessione e funziona in realtà:

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

Ma utilizzando i tipi di interni non sembra essere la soluzione adeguata. Un'altra opzione è quella di implementare il mio StaticFileHandler, ma farlo in modo appropriato (supportando elementi HTTP come intervalli ed etags) non è banale.

Come devo affrontare l'instradamento dei file statici in ASP.NET?

risposta

37

Dopo aver analizzato questo problema per alcune ore, ho scoperto che semplicemente aggiungendo regole di ignoranza i file statici verranno serviti.

In RegisterRoutes (percorsi RouteCollection), aggiungere le seguenti ignorare le regole:

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

Per me funziona, ma non riesco ad analizzare un file JS in una cartella View di un'area, per risolvere il problema, io uso invece un'altra cartella nella cartella base dell'area come /Areas/MyArea/ClientScripts/foo.js – eka808

+20

In qualche modo mi sembra di perdere un pezzo nel puzzle ... in che modo ignorare i percorsi ai file statici aiuta con il routing da '/ static' a'/a/b/c' (richiesto dall'OP)? Potresti per favore gettare un po 'di luce sulla tua risposta, mi piacerebbe davvero capire questa soluzione. – Oliver

+17

Concordare con Oliver che questo NON risponda all'OP e non dovrebbe essere accettato come soluzione. – dhochee

48

Perché non utilizzare IIS per farlo? Potresti semplicemente creare una regola di reindirizzamento per indirizzare qualsiasi richiesta dalla prima alla seconda prima che la richiesta arrivi anche all'applicazione. Per questo motivo, sarebbe un metodo più rapido per reindirizzare le richieste.

se si dispone del IIS7 +, fai qualcosa come ...

<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, se non è necessario reindirizzare, come suggerito da @ ni5ni6:

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

Modifica 2015-06-17 per @RyanDawkins:

E se ti stai chiedendo dove va la regola di riscrittura, ecco una mappa della sua posizione nel file 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

io preferirei questo approccio, pure. Spostandolo verso la pipeline e lasciando che il processo di lavoro IIS gestisca il reindirizzamento è più efficiente dei cicli di rotazione che effettivamente elaborano il percorso tramite il runtime, direi. Anche se la quantità di churn sul server è all'incirca uguale, vorrei seguire il percorso (gioco di parole) per non utilizzare i percorsi e mantenere il reindirizzamento all'esterno dell'applicazione stessa. –

+0

Ciò che non era chiaro dalla mia versione iniziale della domanda era che l'URL riscritto è calcolato al volo (non sono preoccupato per le prestazioni qui). Ho aggiornato la domanda per chiarirlo. Comunque, grazie per aver risposto. –

+0

(ha eliminato il mio commento precedente e lo ha aggiunto nuovamente con un URL non abbreviato). Martin, a parte problemi di prestazioni, perché dovresti voler gestire questo URL nell'applicazione, quando gestirlo all'esterno sarebbe meglio? Suppongo che tu possa creare un'azione controller che gestisca questo, ma qui puoi dare un'occhiata a: - http://geekswithblogs.net/sankarsan/archive/2009/01/18/developing-custom-routehandler.aspx –

5

mi si avvicinò con un'alternativa all'utilizzo interno StaticFileHandler. Nel IRouteHandler io chiamo 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. 
    } 

} 

Si tratta di un hack. Il IRouteHandler deve restituire un IHttpHandler e non interrompere e trasferire la richiesta corrente. Tuttavia, in realtà ottiene ciò che voglio.

Utilizzando l'interno StaticFileHandler è anche un po 'un hack da quando ho bisogno di riflessione per ottenere l'accesso ad essa, ma almeno c'è qualche documentation on StaticFileHandler on MSDN che lo rende un po' più di classe "ufficiale". Sfortunatamente non penso sia possibile riflettere sulle classi interne in un ambiente di fiducia parziale.

Continuerò a utilizzare StaticFileHandler poiché non penso che verrà rimosso da ASP.NET nel prossimo futuro.

9

Ho avuto un problema simile. Ho finito per usare 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

Grazie mille per aver condiviso questo. Ho sperimentato questa soluzione alla ricerca di una soluzione per Riscrivere l'URL durante lo sviluppo locale e ho capito che posso farlo ovunque. Lo sto usando non per l'analisi di input, ma per la gestione delle versioni dei file JS e CSS. –

+0

Per chiunque sia interessato, per gestire i file del modulo 'filename.v1234.js', sto usando' private readonly Regex regJS = new Regex ("^ (. *) ([.] V [0-9] +) ([.] (js | css)) $ ", RegexOptions.IgnoreCase);' e quindi sulle corrispondenze faccio 'Context.RewritePath (string.Format (" {0} {1} ", matchJS.Groups [1 ] .Value, matchJS.Groups [3] .Value)); ' –

3

è necessario aggiungere TransferRequestHandler per gestire il vostro statico files.Please vedere seguente risposta https://stackoverflow.com/a/21724783/22858

+0

Per riferimento, questo funziona anche per le app non MVC. – Ian