views:

146

answers:

5

By default Master pages in .NET MVC2 placed like this /folderlevel1/folderlevel2/Site.master accessed from the url domain.com/urllevel1/urllevel2/ will resolve the URL in this tag:

<link href="/Content/Site.css" rel="stylesheet" type="text/css" />

to

<link href="../../Content/Site.css" rel="stylesheet" type="text/css" />

This becomes problematic in my multi-tennant MVC app. And I want to stop this behaviour. I want the master page to leave the url alone.

A: 

oscar,

i'm sure there will be many similar answers to follow, but the standard way would be:

<link href="<%=Url.Content("~/Content/Site.css")%>" rel="stylesheet" type="text/css" />

I may have missed something subtle here of course :)

jim
Unfortunately this is sort of what MVC already does for me. I don't MVC to change the link at all, I want to to remain as /Content/Site.css if that is what it says in the master page.
Oscar Kilhed
ok oscar, i fully understand your requirement now. hmmm, maybe removing the initial / 'may' produce a different result??
jim
+5  A: 

You are probably having this issue because ASP.NET performs magic tricks when you specify the head tag as a server side control like so:

<head runat="server">

These tricks include:

  • resolving relative CSS paths
  • populating title and meta tags from your view's @Page directive

If you don't want these tricks, simply remove the runat attribute from the head tag:

<%@ Master Language="C#" Inherits="System.Web.Mvc.ViewMasterPage" %>

<!DOCTYPE html>
<html>
<head> 
    <link href="Content/Site.css" rel="stylesheet" type="text/css" />
</head>
<body>
...
</body>
</html>
sheikhomar
That has other consequences, which should be explained along with this answer.
NickLarsen
+1  A: 

you can use

<link href="<%=Url.Content("~/Content/Site.css")%>" rel="stylesheet" type="text/css" />

but that basically always translates to this:

<link href="/Content/Site.css" rel="stylesheet" type="text/css" />

so you might as well just use the latter.

Stefanvds
jim already suggested that two weeks earlier...
Guffa
A: 

I suggest using an extension method for the HtmlHelper to take care of this task for you.

using System.Web;
using System.Web.Mvc;

namespace MyApplicationNamepsace.Views
{
    public static class HtmlExtensions
    {

        public static IHtmlString RelativeCssLink(this HtmlHelper helper, string fileNameAndRelativePath)
        {
            TagBuilder builder = new TagBuilder("link");
            builder.Attributes.Add("rel", "stylesheet");
            builder.Attributes.Add("type", "text/css");
            builder.Attributes.Add("href", fileNameAndRelativePath);

            IHtmlString output = new HtmlString(builder.ToString());
            return output;
        }
    }
}

Then make sure you add the namespace to the web.config file in the views folder.

<system.web>
  <pages>
    <namespaces>
      <add namespace="MyApplicationNamespace.Views"/>
    </namespaces>
  </pages>
</system.web>

Then use it in your masterpage.

<head runat="server">
    <title><asp:ContentPlaceHolder ID="TitleContent" runat="server" /></title>
    <%: Html.RelativeCssLink("Content/Site.css") %>
</head>
NickLarsen
+1  A: 

Like mentioned on Kazi's best practices entry (http://weblogs.asp.net/rashid/archive/2009/04/03/asp-net-mvc-best-practices-part-2.aspx), ignore routing when accessing resources. To do this it's very simple and works well. Add the below to your AddRoutes function in Global.asax

_routes.IgnoreRoute("assets/{*pathInfo}");

...where "assets/" is your content folder (by default it's "Content")

Benny