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 /
干杯