component - Rutas relativas ASP.NET MVC
forms asp net core (11)
En mis aplicaciones, a menudo tengo que usar rutas relativas. Por ejemplo, cuando hago referencia a JQuery, generalmente lo hago así:
<script type="text/javascript" src="../Scripts/jquery-1.2.6.js"></script>
Ahora que estoy haciendo la transición a MVC, necesito dar cuenta de las diferentes rutas que puede tener una página, en relación con la raíz. Esto fue, por supuesto, un problema con la reescritura de URL en el pasado, pero me las arreglé para solucionarlo mediante el uso de rutas consistentes.
Soy consciente de que la solución estándar es usar rutas absolutas como:
<script type="text/javascript" src="/Scripts/jquery-1.2.6.js"></script>
pero esto no funcionará para mí, ya que durante el ciclo de desarrollo, tengo que implementarlo en una máquina de prueba en la que la aplicación se ejecutará en un directorio virtual. Las rutas relativas de raíz no funcionan cuando la raíz cambia. Además, por razones de mantenimiento, no puedo simplemente cambiar todas las rutas durante la implementación de la prueba, sería una pesadilla en sí misma.
Entonces, ¿cuál es la mejor solución?
Editar:
Dado que esta pregunta aún recibe vistas y respuestas, pensé que sería prudente actualizarla para observar que a partir de Razor V2, el soporte para las URL relativas a la raíz está integrado, por lo que puede usar
<img src="~/Content/MyImage.jpg">
sin ninguna sintaxis del lado del servidor, y el motor de vista reemplaza automáticamente ~ / con lo que sea la raíz del sitio actual.
Rompiendo el cambio - MVC 5
Tenga cuidado con un cambio de cambio de ruptura en MVC 5 (de las notas de la versión MVC 5 )
Url Rewrite and Tilde (~)
Después de actualizar a ASP.NET Razor 3 o ASP.NET MVC 5, la notación tilde (~) puede dejar de funcionar correctamente si está utilizando reescrituras de URL. La reescritura de URL afecta a la notación de tilde (~) en elementos HTML como
<A/>
,<SCRIPT/>
,<LINK/>
, y como resultado, la tilde ya no se correlaciona con el directorio raíz.Por ejemplo, si reescribe solicitudes para asp.net/content a asp.net , el atributo href en
<A href="~/content/"/>
resuelve en / content / content / en lugar de / . Para suprimir este cambio, puede establecer el contexto IIS_WasUrlRewritten en falso en cada página web o en Application_BeginRequest en Global.asax.
En realidad, no explican cómo hacerlo, pero luego encontré esta respuesta :
Si está ejecutando en el modo Integrated Pipeline de IIS 7 intente poner lo siguiente en su
Global.asax
:
protected void Application_BeginRequest(object sender, EventArgs e)
{
Request.ServerVariables.Remove("IIS_WasUrlRewritten");
}
Nota: Es posible que desee comprobar Request.ServerVariables
realidad contiene IIS_WasUrlRewritten
primero para asegurarse de que este es su problema.
PD. Pensé que tenía una situación en la que me estaba pasando esto y estaba obteniendo src="~/content/..."
URLS generadas en mi HTML, pero resultó que algo no era refrescante cuando mi código estaba siendo compilado. Al editar y volver a guardar los archivos Layout y page cshtml de alguna manera se activó algo.
Al igual que Chris, realmente no soporto tener que poner etiquetas hinchadas en el lado del servidor dentro de mi marcado limpio simplemente para decirle a la estúpida cosa que mire desde la raíz hacia arriba. Eso debería ser algo muy simple y razonable de pedir. Pero también odio la idea de tener que esforzarme por escribir cualquier clase personalizada de C # para hacer algo tan simple, ¿por qué debería hacerlo? Que perdida de tiempo.
Para mí, simplemente me comprometí con la "perfección" y codifiqué el nombre de la ruta raíz del directorio virtual dentro de las referencias de mi ruta. Así que así:
<script type="text/javascript" src="/MyProject/Scripts/jquery-1.2.6.js"></script>
No se requiere procesamiento en el servidor o código C # para resolver la URL, lo cual es mejor para el rendimiento, aunque sé que sería insignificante. Y no hay un caos feo e hinchado en el lado del servidor en mi buen marcado limpio.
Tendré que vivir sabiendo que esto está codificado y que será necesario eliminarlo cuando la cosa migre a un dominio adecuado en lugar de http: // MyDevServer / MyProject /
Aclamaciones
El motor Razor view para MVC 3 facilita y simplifica aún más el uso de rutas relativas de raíz virtual que se resuelven adecuadamente en tiempo de ejecución. Simplemente suelte el método Url.Content () en el valor del atributo href y se resolverá correctamente.
<a href="@Url.Content("~/Home")">Application home page</a>
En ASP.NET suelo utilizar <img src=''<%= VirtualPathUtility.ToAbsolute("~/images/logo.gif") %>'' alt="Our Company Logo"/>
. No veo por qué una solución similar no debería funcionar en ASP.NET MVC.
Fui con un enfoque diferente basado en una publicación SO similar, pero con mucho menos código ...
http://a.shinynew.me/post/6042784654/relative-paths-in-asp-net-mvc-javascript
Mientras que una publicación anterior, los lectores nuevos deben saber que Razor 2 y posterior (predeterminado en MVC4 +) resuelve completamente este problema.
Viejo MVC3 con Razor 1:
<a href="@Url.Content("~/Home")">Application home page</a>
Nuevo MVC4 con Razor 2 y posterior:
<a href="~/Home">Application home page</a>
Sin una incómoda sintaxis similar a la función Razor. No hay etiquetas de marcado no estándar.
Prefijar una ruta en cualquier atributo HTML con una tilde (''~'') le dice a Razor 2 que "simplemente lo haga funcionar" sustituyendo la ruta correcta. Es genial.
Por lo que vale, realmente odio la idea de ensuciar mi aplicación con etiquetas de servidor solo para resolver rutas, así que investigué un poco más y opté por usar algo que había intentado antes para reescribir enlaces: un filtro de respuesta. De esta manera, puedo prefijar todas las rutas absolutas con un prefijo conocido y reemplazarlo en tiempo de ejecución utilizando el objeto Response.Filter y no tener que preocuparme por las etiquetas de servidor innecesarias. El código se publica a continuación en caso de que ayude a alguien más.
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("</html>", 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);
}
}
}
Prueba esto:
<script type="text/javascript" src="<%=Url.Content("~/Scripts/jquery-1.2.6.js")%>"></script>
O use MvcContrib y haga esto:
<%=Html.ScriptInclude("~/Content/Script/jquery.1.2.6.js")%>
Tarde en el juego, pero esta publicación tiene un resumen muy completo del manejo de las rutas ASP.Net.
Yo uso un método simple de ayuda. Puede usarlo fácilmente en las Vistas y Controladores.
Margen:
<a [email protected]()/about">About Us</a>
Método de ayuda:
public static string Root()
{
if (HttpContext.Current.Request.Url.Host == "localhost")
{
return "";
}
else
{
return "/productionroot";
}
}
<script src="<%=ResolveUrl("~/Scripts/jquery-1.2.6.min.js") %>" type="text/javascript"></script>
Es lo que usé Cambie la ruta para que coincida con su ejemplo.