在我的应用程序中,我经常需要使用相对路径。例如,当我引用JQuery时,我通常这样做:
<script type="text/javascript" src="../Scripts/jquery-1.2.6.js"></script>
既然我正在向MVC过渡,我需要考虑页面相对于root的不同路径。这当然是过去URL重写的问题,但我设法通过使用一致的路径来解决它。
我知道标准解决方案是使用绝对路径,例如:
<script type="text/javascript" src="/Scripts/jquery-1.2.6.js"></script>
但这对我来说不起作用,因为在开发周期中,我必须部署到应用程序将在虚拟目录中运行的测试机器上。根更改时,根相对路径不起作用。此外,出于维护原因,我不能简单地在部署测试期间更改所有路径 - 这本身就是一场噩梦。
那么什么是最好的解决方案?
编辑:
由于这个问题仍在接收观点和答案,我认为更新它可能是谨慎的,因为从Razor V2开始,支持根相对网址,所以你可以使用
<img src="~/Content/MyImage.jpg">
没有任何服务器端语法,并且视图引擎会自动将〜/替换为当前站点根目录。
答案 0 :(得分:92)
试试这个:
<script type="text/javascript" src="<%=Url.Content("~/Scripts/jquery-1.2.6.js")%>"></script>
或使用MvcContrib并执行此操作:
<%=Html.ScriptInclude("~/Content/Script/jquery.1.2.6.js")%>
答案 1 :(得分:51)
虽然是一篇旧帖子,但新读者应该知道Razor 2及更高版本(MVC4 +中的默认值)完全解决了这个问题。
使用Razor 1的旧MVC3:
<a href="@Url.Content("~/Home")">Application home page</a>
使用Razor 2及更高版本的新MVC4:
<a href="~/Home">Application home page</a>
没有笨拙的Razor函数式语法。 没有非标准的标记标记。
使用波形符('〜')在任何HTML属性中添加路径,通过替换正确的路径告诉Razor 2“只使其工作”。太棒了。
答案 2 :(得分:10)
注意MVC 5(来自MVC 5 release notes)
的突然变化Url Rewrite和Tilde(〜)
升级到ASP.NET Razor 3或ASP.NET MVC 5之后,代字号(〜) 如果您使用URL重写,表示法可能无法正常工作。 URL重写会影响HTML元素中的波浪号(〜)表示法,例如
<A/>
,<SCRIPT/>
,<LINK/>
,因此代字号不再映射到 根目录。例如,如果您将 asp.net/content 的请求重写为 asp.net , 中的href属性
<A href="~/content/"/>
已解决 / content / content / 而不是 / 。要禁止此更改,您可以设置 每个网页或中的 IIS_WasUrlRewritten 上下文为false Global.asax中的 Application_BeginRequest 。
他们实际上没有解释如何做,但后来我找到了this answer:
如果您在IIS 7 Integrated Pipeline模式下运行,请尝试使用 关注
Global.asax
:
protected void Application_BeginRequest(object sender, EventArgs e)
{
Request.ServerVariables.Remove("IIS_WasUrlRewritten");
}
注意:您可能需要首先检查Request.ServerVariables
实际包含IIS_WasUrlRewritten
,以确保这是您的问题所在。
PS。我以为我遇到过这样的情况,我正在将src="~/content/..."
生成的URL发送到我的HTML中 - 但事实证明,在我的代码编译时,这些内容并不令人耳目一新。编辑和重新保存布局和页面cshtml文件会以某种方式触发一些工作。
答案 3 :(得分:6)
在ASP.NET中,我通常使用<img src='<%= VirtualPathUtility.ToAbsolute("~/images/logo.gif") %>' alt="Our Company Logo"/>
。
我不明白为什么类似的解决方案不适用于ASP.NET MVC。
答案 4 :(得分:6)
<script src="<%=ResolveUrl("~/Scripts/jquery-1.2.6.min.js") %>" type="text/javascript"></script>
是我用的。更改路径以匹配您的示例。
答案 5 :(得分:5)
对于它的价值,我真的很讨厌用服务器标签乱扔我的应用只是为了解决路径,所以我做了一些研究,并选择使用我以前尝试过的东西来重写链接 - 响应过滤器。通过这种方式,我可以使用已知前缀为所有绝对路径添加前缀,并在运行时使用Response.Filter对象替换它,而不必担心不必要的服务器标记。代码发布在下面,以防它可以帮助其他任何人。
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);
}
}
}
答案 6 :(得分:4)
MVC 3的Razor视图引擎使得在运行时正确解析的虚拟根相对路径变得更加简单和清晰。只需将Url.Content()方法放入href属性值即可正确解析。
<a href="@Url.Content("~/Home")">Application home page</a>
答案 7 :(得分:1)
像Chris一样,我真的不能忍受在我干净的标记中放置膨胀的服务器端标签,纯粹是为了告诉愚蠢的东西从根向上看。这应该是一个非常简单,合理的要求。但我也讨厌不得不努力编写任何自定义C#类来做这么简单的事情,为什么我要这么做?真是浪费时间。
对我而言,我只是在“完美”上妥协,并在我的路径引用中硬编码虚拟目录的根路径名。像这样:
<script type="text/javascript" src="/MyProject/Scripts/jquery-1.2.6.js"></script>
解析URL不需要服务器端处理或C#代码,这对性能最佳,但我知道无论如何都可以忽略不计。在我干净的标记中没有臃肿丑陋的服务器端混乱。
我只需要知道这是硬编码的,并且当事物迁移到适当的域而不是http://MyDevServer/MyProject/时需要删除
干杯
答案 8 :(得分:1)
我采用了一种不同的方法,基于类似的SO帖子,但代码少得多......
http://a.shinynew.me/post/6042784654/relative-paths-in-asp-net-mvc-javascript
答案 9 :(得分:1)
游戏后期,但this post有一个处理ASP.Net路径的完整摘要。
答案 10 :(得分:1)
我使用简单的辅助方法。您可以在视图和控制器中轻松使用它。
标记:
<a href=@Helper.Root()/about">About Us</a>
帮助方法:
public static string Root()
{
if (HttpContext.Current.Request.Url.Host == "localhost")
{
return "";
}
else
{
return "/productionroot";
}
}