Percorsi relativi di ASP.NET MVC

Nelle mie applicazioni, spesso devo usare percorsi relativi. Ad esempio, quando faccio riferimento a JQuery, solitamente lo faccio in questo modo:

 

Ora che sto effettuando la transizione a MVC, devo tenere conto dei diversi percorsi che una pagina potrebbe avere, relativamente alla radice. Questo era ovviamente un problema con la riscrittura degli URL in passato, ma sono riuscito a ovviare usando percorsi coerenti.

Sono consapevole che la soluzione standard consiste nell’utilizzare percorsi assoluti come:

  

ma questo non funzionerà per me come durante il ciclo di sviluppo, devo distribuire su una macchina di prova su cui l’applicazione verrà eseguita in una directory virtuale. I percorsi relativi alla radice non funzionano quando la radice cambia. Inoltre, per ragioni di manutenzione, non posso semplicemente cambiare tutti i percorsi per la durata della distribuzione del test – questo sarebbe un incubo di per sé.

Quindi qual è la soluzione migliore?

Modificare:

Poiché questa domanda continua a ricevere visualizzazioni e risposte, ho pensato che potrebbe essere prudente aggiornarla per far notare che, a partire da Razor V2, il supporto per gli URL relativi a root è criptato, quindi puoi usare

  

senza alcuna syntax sul lato server, e il motore di visualizzazione sostituisce automaticamente ~ / con qualunque sia la radice del sito corrente.

Prova questo:

  

Oppure usa MvcContrib e fai questo:

 < %=Html.ScriptInclude("~/Content/Script/jquery.1.2.6.js")%> 

Mentre un vecchio post, i nuovi lettori dovrebbero sapere che Razor 2 e successivi (predefinito in MVC4 +) risolve completamente questo problema.

Vecchia MVC3 con Razor 1:

 Application home page 

Nuova MVC4 con Razor 2 e versioni successive:

 Application home page 

Nessuna syntax simile a una funzione simile a Razor. Nessun tag di markup non standard.

Il prefisso di un percorso in qualsiasi attributo HTML con una tilde (‘~’) indica a Razor 2 di “eseguirlo semplicemente” sostituendo il percorso corretto. È ottimo.

Ultime modifiche – MVC 5

Fai attenzione alle modifiche alle modifiche apportate a MVC 5 (dalle note sulla versione di MVC 5 )

Url Rewrite e Tilde (~)

Dopo l’aggiornamento a ASP.NET Razor 3 o ASP.NET MVC 5, la notazione tilde (~) potrebbe non funzionare più correttamente se si utilizza la riscrittura degli URL. La riscrittura dell’URL influisce sulla notazione tilde (~) in elementi HTML come , , e, di conseguenza, la tilde non esegue più il mapping alla directory radice.

Ad esempio, se riscrivi le richieste per asp.net/content in asp.net , l’attributo href in risolve in / content / content / invece di / . Per sopprimere questa modifica, è ansible impostare il contesto IIS_WasUrlRewritten su false in ciascuna pagina Web o in Application_BeginRequest in Global.asax.

In realtà non spiegano come farlo, ma poi ho trovato questa risposta :

Se si utilizza la modalità Pipeline integrata di IIS 7, provare a inserire quanto segue in Global.asax :

  protected void Application_BeginRequest(object sender, EventArgs e) { Request.ServerVariables.Remove("IIS_WasUrlRewritten"); } 

Nota: è ansible verificare che Request.ServerVariables contenga effettivamente IIS_WasUrlRewritten per assicurarsi che questo sia il problema.


PS. Pensavo di avere una situazione in cui questo mi stava accadendo e stavo ricevendo src="~/content/..." URL generati nel mio HTML – ma è risultato che qualcosa non si stava rinfrescando quando il mio codice veniva compilato. La modifica e il salvataggio dei file cshtml di Layout e di pagina hanno in qualche modo triggersto qualcosa su cui lavorare.

In ASP.NET di solito utilizzo Our Company Logo . Non vedo perché una soluzione simile non dovrebbe funzionare in ASP.NET MVC.

  

È quello che ho usato Cambia percorso per abbinare il tuo esempio.

Per quello che vale, odio davvero l’idea di sporcare la mia app con i tag del server solo per risolvere i percorsi, quindi ho fatto un po ‘più di ricerca e ho optato per usare qualcosa che avevo già provato per riscrivere i link: un filtro di risposta. In questo modo, posso inserire come prefisso tutti i percorsi assoluti con un prefisso noto e sostituirlo in fase di esecuzione utilizzando l’object Response.Filter e non doversi preoccupare di tag del server non necessari. Il codice è pubblicato qui di seguito nel caso in cui aiuterà qualcun altro.

 using System; using System.IO; using System.Text; using System.Text.RegularExpressions; using System.Web; namespace Demo { public class PathRewriter : Stream { Stream filter; HttpContext context; object writeLock = new object(); StringBuilder sb = new StringBuilder(); Regex eofTag = new Regex("", RegexOptions.IgnoreCase | RegexOptions.Compiled); Regex rootTag = new Regex("/_AppRoot_", RegexOptions.IgnoreCase | RegexOptions.Compiled); public PathRewriter(Stream filter, HttpContext context) { this.filter = filter; this.context = context; } public override void Write(byte[] buffer, int offset, int count) { string temp; lock (writeLock) { temp = Encoding.UTF8.GetString(buffer, offset, count); sb.Append(temp); if (eofTag.IsMatch(temp)) RewritePaths(); } } public void RewritePaths() { byte[] buffer; string temp; string root; temp = sb.ToString(); root = context.Request.ApplicationPath; if (root == "/") root = ""; temp = rootTag.Replace(temp, root); buffer = Encoding.UTF8.GetBytes(temp); filter.Write(buffer, 0, buffer.Length); } public override bool CanRead { get { return true; } } public override bool CanSeek { get { return filter.CanSeek; } } public override bool CanWrite { get { return true; } } public override void Flush() { return; } public override long Length { get { return Encoding.UTF8.GetBytes(sb.ToString()).Length; } } public override long Position { get { return filter.Position; } set { filter.Position = value; } } public override int Read(byte[] buffer, int offset, int count) { return filter.Read(buffer, offset, count); } public override long Seek(long offset, SeekOrigin origin) { return filter.Seek(offset, origin); } public override void SetLength(long value) { throw new NotImplementedException(); } } public class PathFilterModule : IHttpModule { public void Dispose() { return; } public void Init(HttpApplication context) { context.ReleaseRequestState += new EventHandler(context_ReleaseRequestState); } void context_ReleaseRequestState(object sender, EventArgs e) { HttpApplication app = sender as HttpApplication; if (app.Response.ContentType == "text/html") app.Response.Filter = new PathRewriter(app.Response.Filter, app.Context); } } } 

Il motore di visualizzazione Razor per MVC 3 rende ancora più facile e più pulito l’uso di percorsi relativi alla root virtuale che sono correttamente risolti in fase di esecuzione. Basta trascinare il metodo Url.Content () nel valore dell’attributo href e verrà risolto correttamente.

 Application home page 

Verso la fine del gioco, ma questo post ha un riepilogo molto completo della gestione dei percorsi ASP.Net.

Io uso un semplice metodo di supporto. Puoi facilmente usarlo nelle viste e nei controller.

markup:

 About Us 

Metodo di supporto:

 public static string Root() { if (HttpContext.Current.Request.Url.Host == "localhost") { return ""; } else { return "/productionroot"; } } 

Sono andato con un approccio diverso basato su un post SO simile, ma con molto meno codice …

http://a.shinynew.me/post/6042784654/relative-paths-in-asp-net-mvc-javascript

Come Chris, non riesco davvero a sopportare di dover mettere etichette gonfiabili sul lato server all’interno del mio markup pulito solo per dire alla cosa stupida di guardare dalla radice verso l’alto. Questa dovrebbe essere una cosa molto semplice e ragionevole da chiedere. Ma odio anche l’idea di dover andare allo sforzo di scrivere qualsiasi class C # personalizzata per fare una cosa così semplice, perché dovrei? Che spreco di tempo.

Per quanto mi riguarda, ho semplicemente compromesso la “perfezione” e ho codificato il nome del percorso radice della directory virtuale all’interno dei miei riferimenti ai percorsi. Quindi in questo modo:

  

Nessun codice di elaborazione lato server o codice C necessario per risolvere l’URL, che è il migliore per le prestazioni, anche se so che sarebbe trascurabile a prescindere. E nessun brutto brutto lato server sul mio bel margine pulito.

Devo solo vivere con la consapevolezza che questo è hardcoded e sarà necessario rimuoverlo quando la cosa migra su un dominio corretto invece di http: // MyDevServer / MyProject /

Saluti