2

I thought I'd use the base href tag to make my relative URLs work on different installations.

In my master page, I have:

<base href="http://localhost/myproject/" />
<link rel="stylesheet" type="text/css" runat="server" href="css/main.css" />
<script type="text/javascript" src="js/jquery.min.js"></script>

That works fine when I'm on http://localhost/myproject/default.aspx, the css path resolves fine, such as: http://localhost/myproject/css/main.css

But then I have a subfolder, reports. When I navigate to http://localhost/myproject/reports/default.aspx, and view source, this is what I see:

<base href="http://localhost/myproject/" />
<link rel="stylesheet" type="text/css" href="../css/main.css" />
<script type="text/javascript" src="js/jquery.min.js"></script>

Something has injected the ../ into the href attribute of the link tag, which means it's resolving as: http://localhost/css/main.css which is not found.

This is odd, because it's working as I'd expect for the script tag; just the link tag gets this injection. I viewed source in IE & Chrome and both were the same, so I assume it's IIS/.NET that's doing it, but they shouldn't really touch the HTML because it's not runat="server". Playing with this a little, I see the link tags on the Master page are modified, but not the script tags (if they're relative URLs without the leading "/"). I assume that's because they're "src" attributes and not "href" attributes. So having / not having the base href will fix the one type but break the other.

Am I going crazy, is this a bug, or am I holding it wrong?

EDIT: I'm not actually hard-coding the href of the base tag. I'm writing out the value of a setting that is loaded to application memory from a database table. So it's actually doing: <base href="<%=Settings.Configuration.website_rooturl%>" /> where on my dev machine the value could be http://localhost/ or http://localhost/project/ and on one client site it's http://www.clientsite.com/ and another client site it's a virtual directory http://www.clientsite2.com/project/.

Sean
  • 14,359
  • 13
  • 74
  • 124

5 Answers5

2
<link href="<%= ResolveClientUrl("~/css/main.css") %>" rel="stylesheet" type="text/css" />
user2258152
  • 635
  • 5
  • 13
  • Yeah, it works, but It won't work with any control having `runat="server"` attribute. See [this question](http://stackoverflow.com/questions/2588740/resolveurl-problem-in-master-page) – sohaiby Jul 23 '15 at 08:28
1

Try using ~, as in <link rel="stylesheet" type="text/css" href="~/css/main.css" />

In ASP.NET applications, the ~ refers to the root directory of the app.

danyim
  • 1,274
  • 10
  • 27
  • I assume you mean with runat="server"? Nope, it still strips the tilfe & replaces with the "../". If I remove the base tag, then it works, but then my script tags are broken. How do you then resolve the script tags? – Sean Oct 18 '12 at 18:48
  • 1
    I would say leave out the `base` tag, as that might confuse ASP.NET. Try using the tilde on the script tag also (with `runat="server"`) – danyim Oct 18 '12 at 18:54
  • you can't use the tilde on the script tag, because then you'd have to add "runat=server", which would execute the script (javascript) on the server. – Sean Oct 18 '12 at 19:03
  • The base tag seems very useful: it defines your root in a single place. It seems a very graceful way of setting the base in a single place, for the browser (after all, the browser needs to resolve the relative URLs that it subsequently calls, so it's a browser issue, not a server issue). The problem is that head tags with runat=server interfere with the href's of link tags (when the page is generated on the server) - otherwise it would be perfect. See my workaround in my answer. Will post back if I find any issues. – Sean Oct 18 '12 at 19:05
  • You're totally misunderstanding the interpretation of URLs by IIS and the use of a virtual directory. base tag is not needed. – IrishChieftain Oct 18 '12 at 21:04
1

The issue is apparently this. Because I have a head tag with runat="server", the link stylesheet & favicon tags are being treated as HtmlLink controls, so the href attribute gets rendered differently (injected with the ../).

This seems to fix it, as the empty double quotes in the inline code forces it to be outputted as an HTML control, rather than an HtmlLink ASP.NET web control:

<base href="http://localhost/myproject/" />
<link rel="stylesheet" type="text/css" runat="server" href="<%=""%>css/main.css" />
<script type="text/javascript" src="js/jquery.min.js"></script>

Strange, but true.

Sean
  • 14,359
  • 13
  • 74
  • 124
  • The href value of base won't actually be hardcoded, it will write a value from a settings table in the database, which is loaded into memory at application start. So it will actually be: ``. I'm using the base tag as explained in the comment to your post below, to make it installable on multiple environments without needing to change anything (except the website_rooturl value in the database table). – Sean Oct 18 '12 at 19:00
0

Resolve it from the root using the '~' (tilda) operator. You also need to add the runat="Server" attribute for this to work:

<link rel="stylesheet" type="text/css" runat="server" 
    href="~/css/main.css" runat="server" />

You don't need a base tag value from a DB for your site to work on different installations. Lose it completely. You also have the ability to configure virtual directories any way you want on different servers.

IrishChieftain
  • 15,108
  • 7
  • 50
  • 91
  • nope, doesn't work. i have to remove the base tag, which I don't want to do, otherwise the script tags don't resolve. – Sean Oct 18 '12 at 18:48
  • Drag both the script and CSS files from Solution Explorer to the master page header in code view and the correct relative paths will be created for you. If this doesn't work experiment with different paths for the script paths (bug in VS). – IrishChieftain Oct 18 '12 at 18:54
  • Hi again. Thanks, but I can get this to work in my current development environment. I'm trying to make it environment independent, though. So if it's installed on the root of localhost or the root of a domain, or in a subfolder on localhost (as in the above), or a virtual directory on a domain, etc. I want one solution that works for them all. Try what I've explained yourself and you'll see the strange behaviour in action! – Sean Oct 18 '12 at 18:57
  • Either way, you don't need base and you shouldn't be hard-coding localhost into the path - this won't work seamlessly in both environments. – IrishChieftain Oct 18 '12 at 18:58
  • As explained in my other comment, it's from a database field. I want it stored in one place (in the database), and output to the "pages" in one place (the base tag on the master page). I don't want to litter every single link with that value, if I can use the base tag once. – Sean Oct 18 '12 at 19:02
  • Try the runat with the tilda for the CSS file? – IrishChieftain Oct 18 '12 at 19:06
  • runat=server with tilda in a link tag's href in the head (also with runat=server) of a master page with a base tag will not resolve correctly when in a subdirectory. there are a lot of conditions there, it's not a simple example, but if you haven't tried it, take my word for it. – Sean Oct 18 '12 at 19:08
  • You don't need a base tag value from a DB for your site to work on different installations. Lose it completely. You also have the ability to configure virtual directories any way you want on different servers. – IrishChieftain Oct 18 '12 at 19:21
  • Sure, you don't "need" anything. But with the base tag, you don't have to use a single tilda, at all. Anywhere. Not a ResolveUrl or anything similar. And configuring the virtual directories is irrelevant, actually. Have you tried the scenario I've described in my previous comment above? Were you able to see the bug? I'll gladly discuss it further in chat with you if you like. I'd like to hear how others handle it. But I can assure you, this is not fixed by "adding tilda". It's a very specific scenario. And I'm trying to fix it without dropping base, which I think I've done. You should try it. – Sean Oct 18 '12 at 19:43
  • Using the tilda is the proper way of doing this in ASP.NET. Why not use it? It basically gives you what you want. YOu don;t need to be setting anything in the database. Your site can resolve all paths no matter where it's served from using this method. Paths will be resolved correctly ON THE SERVER. – IrishChieftain Oct 18 '12 at 21:12
  • It's set in the database already for other reasons. It could be In the web.config or whatever, though. I don't want to have to add runat=server to every HTML control, and screw up the client ids. My Ajax calls in .js files can't use tildas. In your model, how do you get those relative urls to resolve, pass in the base uri to the Ajax functions? Then you'd need to store that base uri somewhere, in the database/web.config? – Sean Oct 19 '12 at 06:10
0

I realize that this is by now a very old question, but I ran into the same issue today (five years after the initial post), and I was able to solve it like this.

<%="<base href='" + Page.ResolveUrl("~/") + "'/>" %>
<!-- or however you want to get the base -->

Apparently, ASP.NET interprets the base tag when it's found in a page, and does things to other server-side tags. So, I just made it so that the engine didn't see it as a control. It's a hack, but it worked.

In addition to the OP's <link> tags, <asp:ImageButton> tags were similarly affected. This hack fixed both.

Ian McLaird
  • 5,507
  • 2
  • 22
  • 31