2011-06-14 18 views
9

Desidero essere in grado di riorganizzare la struttura del sito ASP.NET MVC in modo da corrispondere più strettamente al modo in cui Rails lo esegue (eseguiamo entrambe le guide e ASP.net nella mia azienda).Come modificare la radice di file statici ASP.NET MVC

In Rails, esiste una cartella "pubblica" che si comporta come la radice del sito. Ad esempio, potrei inserire un "test.html" e accedere al file con l'url http://domain.com/test.html che dovrebbe servire sul file html statico.

In asp.net MVC c'è una cartella "Contenuto" che voglio comportarmi come root. Quindi, invece di accedere a http://domain.com/content/myfile.html, voglio essere in grado di fare http://domain.com/myfile.html.

So che posso solo rilasciare il file nella root del progetto, ma ho bisogno di fare questo con molti file tra cui CSS, JS, HTML, immagini, ecc e voglio condividere alcuni beni standardizzati tra rotaie e aspnetmvc.

C'è un modo per farlo?

risposta

8

C'è un'altra possibile soluzione. Invece di usare il codice, puoi usare una regola di riscrittura per gestirla per te. Se si utilizza IIS 7 o versione successiva, è possibile utilizzare il modulo di riscrittura degli URL di Microsoft.

Una regola come la seguente, probabilmente lo farebbe:

<rule name="Rewrite static files to content" stopProcessing="true"> 
    <match url="^([^/]+(?:\.css|\.js))$" /> 
    <conditions> 
     <add input="{APPL_PHYSICAL_PATH}content{SCRIPT_NAME}" matchType="IsFile" /> 
    </conditions> 
    <action type="Rewrite" url="/content/{R:1}" /> 
</rule> 

I regola verifica per una richiesta a un css o js File la radice del sito. Quindi controlla se il file esiste nella cartella dei contenuti. Se esiste, la riscrittura restituirà il file nella cartella del contenuto. L'ho provato solo un po ', ma sembra funzionare. Certamente ha bisogno di più test e di un possibile raffinamento.

+0

Questa è una buona idea. Pensiero molto intelligente. – NerdFury

+0

Questo sembra essere il modo più efficiente per farlo in termini di sforzo e prestazioni. Darò una prova. Grazie! – AlbertVo

2

L'unica soluzione a cui riesco a pensare è quella di utilizzare un controller personalizzato e instradarlo per farlo. Ma non è una soluzione pulita.

Per prima cosa è necessaria una classe PublicController con un metodo di azione GetFile. Ciò presuppone che tutti i file si trovino direttamente nella cartella pubblica/di contenuto. Gestire le cartelle rende le cose più complicate.

public class PublicController : Controller 
{ 
    private IDictionary<String, String> mimeTypes = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase) 
                 {{"css", "text/css"}, {"jpg", "image/jpg"}}; 

    public ActionResult GetFile(string file) 
    { 
     var path = Path.Combine(Server.MapPath("~/Content"), file); 

     if (!System.IO.File.Exists(path)) throw new HttpException(404, "File Not Found"); 
     var extension = GetExtension(file); // psuedocode 
     var mimetype = mimeTypes.ContainsKey(extension) ? mimeTypes[extension] : "text/plain"; 
     return File(path, mimetype); 
    } 
} 

Ora, basta un percorso vicino al fondo della lista dei percorsi che assomiglia a questo:

routes.MapRoute("PublicContent", "{file}", new {controller = "Public", action = "GetFile"}); 

Il problema è, ora, quando hai appena messo in un nome di controllo come la 'casa 'invece di eseguire il default al metodo di azione Index sul HomeController, si presuppone che si desideri scaricare un file chiamato "Home" dalla directory dei contenuti. Quindi, sopra il percorso del file, è necessario aggiungere una route per ciascun controller in modo che sappia ottenere l'azione Index.

routes.MapRoute("HomeIndex", "Home", new { controller = "Home", action = "Index" }); 

Così, un modo per aggirare questo è quello di cambiare il percorso migliore per raggiungere:

routes.MapRoute("PublicContent", "{file}.{extension}", new {controller = "Public", action = "GetFile"}); 

E il metodo di azione a questo:

public ActionResult GetFile(string file, string extension) 
    { 
     var path = Path.Combine(Server.MapPath("~/Content"), file + "." + extension); 

     if (!System.IO.File.Exists(path)) throw new HttpException(404, "File Not Found"); 

     var mimetype = mimeTypes.ContainsKey(extension) ? mimeTypes[extension] : "text/plain"; 
     return File(path, mimetype); 
    } 

Come ho detto, questo presuppone che tutti i i file si trovano nella directory del contenuto e non nelle sottocartelle. Ma se si voleva fare sottocartelle come Content/css/site.css si potrebbe aggiungere i percorsi come questo:

 routes.MapRoute("PublicContent_sub", "{subfolder}/{file}.{extension}", new { controller = "Public", action = "GetFileInFolder" }); 
     routes.MapRoute("PublicContent", "{file}.{extension}", new { controller = "Public", action = "GetFile"}); 

ora il metodo di azione deve cambiare troppo.

public ActionResult GetFile(string file, string extension) 
    { 
     return GetFileInFolder("", file, extension); 
    } 

    public ActionResult GetFileInFolder(string subfolder, string file, string extension) 
    { 
     var path = Path.Combine(Server.MapPath("~/Content"), subfolder, file + "." + extension); 

     if (!System.IO.File.Exists(path)) throw new HttpException(404, "File Not Found"); 

     var mimetype = mimeTypes.ContainsKey(extension) ? mimeTypes[extension] : "text/plain"; 
     return File(path, mimetype); 
    } 

Se si avvia sempre più livelli di profondità nella struttura di cartelle, questo diventa più brutto e più brutto. Ma forse questo funzionerà per te. Sono sicuro che speravi in ​​una casella di controllo nelle proprietà del progetto, ma se ce n'è una, non ne so nulla.

+0

Grazie per aver dedicato del tempo per spiegare tutto questo. Sì, è un po 'più impegnato di quanto speravo. Speravo che ci fosse un modo per sovrascrivere il comportamento simile al modo in cui è possibile creare il proprio viewEngine per sovrascrivere ViewPathLocations. – AlbertVo

+0

@AlbertVo - Sì, niente del genere per quanto ne so. La convenzione sulla configurazione a volte significa che le cose non funzionano nel modo desiderato. Ma certamente è possibile che non conosca anche qualcosa. – NerdFury

+0

Questo funzionerà sicuramente, ma non mi piace l'idea perché obbliga ogni richiesta di file statici a passare attraverso l'intera pipeline del framework. IIS7 servirà i file statici ** molto ** più velocemente direttamente. Una regola di riscrittura degli URL dovrebbe offrire prestazioni migliori. –

Problemi correlati