Относительные пути ASP.NET MVC - PullRequest
97 голосов
/ 25 ноября 2008

В моих приложениях мне часто приходится использовать относительные пути. Например, когда я ссылаюсь на JQuery, я обычно делаю так:

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

Теперь, когда я делаю переход на MVC, мне нужно учесть различные пути, которые может иметь страница, относительно корня. Это, конечно, было проблемой с переписыванием URL в прошлом, но мне удалось обойти это, используя согласованные пути.

Я знаю, что стандартным решением является использование абсолютных путей, таких как:

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

но это не будет работать для меня, так как во время цикла разработки мне приходится развертывать на тестовой машине, на которой приложение будет работать в виртуальном каталоге. Относительные пути root не работают, когда изменяется root. Кроме того, по причинам обслуживания я не могу просто изменить все пути на время развертывания теста - это само по себе было бы кошмаром.

Так какое же лучшее решение?

Edit:

Так как этот вопрос все еще получает представления и ответы, я подумал, что было бы разумно обновить его, чтобы отметить, что начиная с Razor V2, поддержка корневых ссылок встроена, поэтому вы можете использовать

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

без какого-либо серверного синтаксиса, и механизм просмотра автоматически заменяет ~ / на любой текущий корень сайта.

Ответы [ 11 ]

92 голосов
/ 25 ноября 2008

Попробуйте это:

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

Или используйте MvcContrib и сделайте следующее:

<%=Html.ScriptInclude("~/Content/Script/jquery.1.2.6.js")%>
51 голосов
/ 17 сентября 2012

Хотя старый пост, новые читатели должны знать, что Razor 2 и более поздние версии (по умолчанию в MVC4 +) полностью решают эту проблему.

Старый MVC3 с бритвой 1:

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

Новый MVC4 с Razor 2 и более поздними версиями:

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

Нет неуклюжего синтаксиса, похожего на Razor. Нет нестандартных разметок.

Префикс пути к любому атрибуту HTML с тильдой ('~') говорит Razor 2 "просто заставить его работать", подставляя правильный путь. Это здорово.

10 голосов
/ 26 апреля 2014

Разрывное изменение - MVC 5

Остерегайтесь критических изменений в MVC 5 (из примечаний к выпуску MVC 5 )

URL переписать и тильда (~)

После обновления до 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 на каждой веб-странице или в Application_BeginRequest в Global.asax.

Они на самом деле не объясняют, как это сделать, но потом я нашел этот ответ :

Если вы работаете в режиме интегрированного конвейера IIS 7, попробуйте установить следующие в вашем Global.asax:

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

Примечание: вы можете сначала проверить, что Request.ServerVariables содержит IIS_WasUrlRewritten, чтобы убедиться, что это ваша проблема.


PS. Я думал, что у меня была ситуация, когда это происходило со мной, и я получал src="~/content/..." URL, сгенерированных в моем HTML - но оказалось, что что-то просто не обновлялось, когда мой код компилировался. Редактирование и сохранение файлов Layout и cshtml страницы каким-то образом приводило к срабатыванию.

6 голосов
/ 25 ноября 2008
<script src="<%=ResolveUrl("~/Scripts/jquery-1.2.6.min.js") %>" type="text/javascript"></script>

Это то, что я использовал. Измените путь в соответствии с вашим примером.

6 голосов
/ 25 ноября 2008

В ASP.NET я обычно использую <img src='<%= VirtualPathUtility.ToAbsolute("~/images/logo.gif") %>' alt="Our Company Logo"/>. Я не понимаю, почему подобное решение не должно работать в ASP.NET MVC.

5 голосов
/ 25 ноября 2008

Несмотря на это, я действительно ненавижу идею засорять свое приложение тегами сервера просто для разрешения путей, поэтому я провел немного больше исследований и решил использовать что-то, что я пробовал ранее для перезаписи ссылок - фильтр ответов. Таким образом, я могу префиксить все абсолютные пути известным префиксом и заменить его во время выполнения, используя объект 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);
        }
    }
}
4 голосов
/ 22 сентября 2011

Механизм представления Razor для MVC 3 делает еще проще и понятнее использование относительных путей виртуального корня, которые правильно разрешаются во время выполнения. Просто поместите метод Url.Content () в значение атрибута href, и он разрешится правильно.

<a href="@Url.Content("~/Home")">Application home page</a>
1 голос
/ 02 декабря 2011

Я использую простой вспомогательный метод. Вы можете легко использовать его в представлениях и контроллерах.

Markup:

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

Вспомогательный метод:

public static string Root()
{
    if (HttpContext.Current.Request.Url.Host == "localhost")
    {
        return "";
    }
    else
    {
        return "/productionroot";
    }
}
1 голос
/ 03 марта 2011

Поздно к игре, но в этом посте есть очень полное резюме обработки путей ASP.Net.

1 голос
/ 16 марта 2010

Я использовал немного другой подход, основанный на аналогичном SO сообщении, но с гораздо меньшим количеством кода ...

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...