ASP.NET относительные пути MVC
в моих приложениях мне часто приходится использовать относительные пути. Например, когда я ссылаюсь на JQuery, я обычно делаю так:
<script type="text/javascript" src="../Scripts/jquery-1.2.6.js"></script>
Теперь, когда я делаю переход на MVC, мне нужно учитывать различные пути, которые может иметь страница, относительно корня. Конечно, это была проблема с переписыванием URL в прошлом, но мне удалось обойти ее, используя согласованные пути.
Я понимаю, что стандартным решением является использование абсолютных путей, таких as:
<script type="text/javascript" src="/Scripts/jquery-1.2.6.js"></script>
но это не будет работать для меня в течение цикла разработки, мне нужно развернуть на тестовой машине, на которой приложение будет работать в виртуальном каталоге. Корневые относительные пути не работают при изменении корневого пути. Кроме того, по причинам обслуживания я не могу просто изменить все пути на время развертывания теста - это было бы кошмаром само по себе.
Итак, какое лучшее решение?
Edit:
Так как этот вопрос все еще получая представления и ответы, я подумал, что было бы разумно обновить его, чтобы отметить, что с Razor V2 поддержка корневых относительных URL-адресов запечена, поэтому вы можете использовать
<img src="~/Content/MyImage.jpg">
без какого-либо синтаксиса на стороне сервера, и механизм просмотра автоматически заменяет ~/ на любой текущий корень сайта.
11 ответов
попробуйте это:
<script type="text/javascript" src="<%=Url.Content("~/Scripts/jquery-1.2.6.js")%>"></script>
или использовать MvcContrib и этого:
<%=Html.ScriptInclude("~/Content/Script/jquery.1.2.6.js")%>
в то время как старый пост, новые читатели должны знать, что Razor 2 и более поздние версии (по умолчанию в MVC4+) полностью решает эту проблему.
старый MVC3 с бритвой 1:
<a href="@Url.Content("~/Home")">Application home page</a>
новый MVC4 с бритвой 2 и позже:
<a href="~/Home">Application home page</a>
нет неудобного синтаксиса, подобного функции бритвы. Нет нестандартных тегов разметки.
префикс пути в любых атрибутах HTML с Тильдой ( ' ~ ' ) говорит Razor 2 "просто заставить его работать", подставляя правильный путь. Это здорово.
нарушение изменений-MVC 5
следите за изменением изменения в MVC 5 (из MVC 5 примечания к выпуску)
Url переписать и Тильда (~)
после обновления до ASP.NET бритва 3 или ASP.NET MVC 5, Тильда (~) нотация может больше не работать правильно, если вы используете перезаписи URL. Переписывание URL влияет на нотацию Тильды (~) в HTML-элементах, таких как
<A/>
,<SCRIPT/>
,<LINK/>
, и, как следствие, Тильда больше нет карт корневой каталог.например, если переписать запросы для asp.net/content до asp.net, атрибут href в
<A href="~/content/"/>
решает /содержание/содержание/ вместо /. Чтобы подавить это изменение, можно установить the IIS_WasUrlRewritten контекст для false на каждой веб-странице или в Application_BeginRequest in Глобальный.асакс.
они на самом деле не объяснить, как это сделать, но потом я нашел ответ:
если вы работаете в режиме интегрированного конвейера IIS 7, попробуйте следующие
Global.asax
:
protected void Application_BeginRequest(object sender, EventArgs e)
{
Request.ServerVariables.Remove("IIS_WasUrlRewritten");
}
Примечание: Вы можете проверить Request.ServerVariables
содержит IIS_WasUrlRewritten
во-первых, чтобы убедиться, что это то, что ваша проблема.
PS. Я думал, что у меня была ситуация, когда это происходило. ко мне и я получал src="~/content/..."
URLS, сгенерированные в моем HTML, но оказалось, что что-то просто не обновлялось, когда мой код компилировался. Редактирование и повторное сохранение макета и страниц cshtml-файлов каким-то образом вызвало что-то работать.
In ASP.NET я обычно использую <img src='<%= VirtualPathUtility.ToAbsolute("~/images/logo.gif") %>' alt="Our Company Logo"/>
.
Я не вижу, почему подобное решение не должно работать в ASP.NET MVC.
<script src="<%=ResolveUrl("~/Scripts/jquery-1.2.6.min.js") %>" type="text/javascript"></script>
то, что я использовал. Измените путь в соответствии с вашим примером.
для чего это стоит, я действительно ненавижу идею засорения моего приложения тегами сервера только для разрешения путей, поэтому я сделал немного больше исследований и решил использовать то, что я пробовал раньше для перезаписи ссылок - фильтр ответов. Таким образом, я могу префиксировать все абсолютные пути известным префиксом и заменить его во время выполнения с помощью ответа.Фильтруйте объект и не беспокойтесь о ненужных тегах сервера. Код размещен ниже, если он поможет кому-либо еще.
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);
}
}
}
механизм просмотра Razor для MVC 3 упрощает и очищает использование относительных путей виртуального корня, которые правильно разрешаются во время выполнения. Просто отбросьте Url.Метод Content () в значение атрибута href, и он будет правильно разрешен.
<a href="@Url.Content("~/Home")">Application home page</a>
опоздал на игру, но этот пост имеет очень Полное резюме обработки ASP.Net тропинки.
Я использую простой вспомогательный метод. Вы можете легко использовать его в представлениях и контроллерах.
разметка:
<a href=@Helper.Root()/about">About Us</a>
вспомогательный метод:
public static string Root()
{
if (HttpContext.Current.Request.Url.Host == "localhost")
{
return "";
}
else
{
return "/productionroot";
}
}
Я пошел с немного другим подходом, основанным на аналогичном сообщении SO, но с гораздо меньшим кодом...
http://a.shinynew.me/post/6042784654/relative-paths-in-asp-net-mvc-javascript
Как и Крис, я действительно не могу стоять, чтобы положить раздутые теги на стороне сервера в мою чистую разметку, просто чтобы сказать глупую вещь, чтобы посмотреть от корня вверх. Это должна быть очень простая, разумная просьба. Но я также ненавижу идею идти писать любые пользовательские классы C#, чтобы сделать такую простую вещь, почему я должна? Пустая трата времени.
для меня я просто скомпрометировал "совершенство" и жестко закодировал корень виртуального каталога имя пути в моем пути ссылок. Вот так:
<script type="text/javascript" src="/MyProject/Scripts/jquery-1.2.6.js"></script>
нет обработки на стороне сервера или кода C#, необходимого для разрешения URL-адреса, что лучше всего для производительности, хотя я знаю, что это будет незначительно независимо. И не раздутый уродливый сервере хаос в мой чистый разметки.
Мне просто придется жить, зная, что это жестко закодировано и должно быть удалено, когда вещь мигрирует в правильный домен вместо http://MyDevServer/MyProject/
Ура