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/

Ура