ASP.NET MVC相对path

在我的应用程序中,我经常需要使用相对path。 例如,当我引用JQuery时,我通常这样做:

<script type="text/javascript" src="../Scripts/jquery-1.2.6.js"></script> 

现在我正在向MVC过渡,我需要考虑页面可能具有的相对于根的不同path。 这当然是过去的URL重写问题,但我设法通过使用一致的path来解决它。

我知道标准的解决scheme是使用绝对path,如:

 <script type="text/javascript" src="/Scripts/jquery-1.2.6.js"></script> 

但是在开发周期中,这对我不起作用,我不得不部署到应用程序将运行在虚拟目录中的testing机器上。 当根改变时,根相对path不起作用。 另外,出于维护的原因,我不能简单地在部署testing期间更换所有path – 这本身就是一个噩梦。

那么最好的解决scheme是什么?

编辑:

由于这个问题仍然在收到意见和答案,我认为更新它可能是谨慎的,注意到,从Razor V2开始,支持根目录相关的url被烧入,所以你可以使用

 <img src="~/Content/MyImage.jpg"> 

没有任何服务器端的语法,并且视图引擎自动replace〜/不pipe当前网站的根目录是什么。

尝试这个:

 <script type="text/javascript" src="<%=Url.Content("~/Scripts/jquery-1.2.6.js")%>"></script> 

或使用MvcContrib并执行此操作:

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

而旧的post,新的读者应该知道,剃刀2及以后(默认在MVC4 +)完全解决了这个问题。

旧的MVC3与剃刀1:

 <a href="@Url.Content("~/Home")">Application home page</a> 

带有Razor 2和更高版本的新MVC4:

 <a href="~/Home">Application home page</a> 

没有尴尬的Razor函数式的语法。 没有非标准的标记标记。

用代字号('〜')在任何HTML属性中加上一个path,通过代替正确的path告诉Razor 2“只要使它工作”。 这很棒。

打破变化 – MVC 5

注意MVC 5中的改变(从MVC 5发行说明中 )

Url Rewrite and Tilde(〜)

升级到ASP.NET Razor 3或ASP.NET MVC 5之后,如果使用URL重写,波形符号(〜)表示法可能不再正常工作。 URL重写会影响HTML元素(如<A/><SCRIPT/><LINK/> )中的代<A/> (〜)符号,结果代字号不再映射到根目录。

例如,如果您将asp.net/content的请求重写为asp.net ,则<A href="~/content/"/>的href属性将parsing为/ content / content /而不是/ 。 要抑制此更改,可以在每个Web页面或Global.asax中的Application_BeginRequest中将IIS_WasUrlRewritten上下文设置为false。

他们实际上并没有解释如何去做,但是我发现了这个答案 :

如果您在IIS 7集成pipe道模式下运行,请尝试在Global.asax以下内容:

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

注意:您可能需要检查Request.ServerVariables实际上是否包含IIS_WasUrlRewritten ,以确保这是您的问题所在。


PS。 我以为我遇到了这种情况,我得到了src="~/content/..." URL生成到我的HTML – 但事实certificate,当我的代码正在编译时,不刷新。 编辑和重新保存布局和页面cshtml文件不知何故触发了一些工作。

在ASP.NET中我通常使用<img src='<%= VirtualPathUtility.ToAbsolute("~http://img.dovov.comlogo.gif") %>' alt="Our Company Logo"/> 。 我不明白为什么类似的解决scheme不应该在ASP.NET MVC中工作。

 <script src="<%=ResolveUrl("~/Scripts/jquery-1.2.6.min.js") %>" type="text/javascript"></script> 

是我用过的 更改path以匹配您的示例。

对于什么是值得的,我真的很讨厌乱抛垃圾我的应用程序与服务器标签只是为了解决path,所以我做了更多的研究,并select使用我以前尝试重写链接 – 响应filter。 这样,我可以用已知的前缀为所有绝对path加前缀,并在运行时使用Response.Filter对象replace它,而不必担心不必要的服务器标签。 该代码张贴在下面的情况下,将帮助其他人。

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

MVC 3的Razor视图引擎使得使用在运行时正确parsing的虚拟根相对path变得更加简单和清晰。 只要将Url.Content()方法拖放到href属性值中,就可以正确parsing。

 <a href="@Url.Content("~/Home")">Application home page</a> 

迟到了,但是这个post有一个非常完整的处理ASP.Netpath的总结。

我使用一个简单的辅助方法。 您可以在视图和控制器中轻松使用它。

标记:

 <a href=@Helper.Root()/about">About Us</a> 

帮手法:

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

我采取了一些基于SO类似的不同方法,但代码less得多…

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

和克里斯一样,我真的不能忍受在我干净的标记中放置臃肿的服务器端标记,只是纯粹地告诉愚蠢的东西从根部向上看。 这应该是一个非常简单,合理的要求。 但是我也讨厌不得不去努力编写任何自定义的C#类来做这样一个简单的事情,我为什么要这样做呢? 多浪费时间。

对我来说,我只是妥协了“完美”,并在我的path引用内硬编码虚拟目录的根path名称。 所以像这样:

 <script type="text/javascript" src="/MyProject/Scripts/jquery-1.2.6.js"></script> 

没有服务器端处理或C#代码需要parsing的URL,这是最好的性能,尽pipe我知道这将是微不足道的无论。 而且我的漂亮的清理标记中没有臃肿丑陋的服务器端混乱。

我只需要知道,这是硬编码,将需要删除时,东西迁移到一个适当的域而不是http:// MyDevServer / MyProject /

干杯