15

I have a Master Page in the root of my project. I have Content Pages throughout my project and in subfolders referencing this Master Page. What is the correct way to reference my .CSS and .JS files if I always want them to be relative to the root?

Here is how I'm doing it now:

link href="/common/css/global.css"
script src="/common/javascript/global.js"

But that breaks the link. I tried without the leading "/" but that didn't work on my pages in the subfolders.

Matt
  • 25,467
  • 18
  • 120
  • 187
Mike Cole
  • 14,474
  • 28
  • 114
  • 194

4 Answers4

20

I would use something like

Server.ResolveClientUrl("~/common/css/global.css")

This will get a proper url for you at all times.

Example:

Per the comment this would be full usage.

<link type="text/css" rel="stylesheet" 
    href='<%= Server.ResolveClientUrl("~/common/css/global.css") %>' />

According to comments, other validated usage, no "error CS1061: 'System.Web.HttpServerUtility' does not contain a definition" error:

    <script type="text/javascript" 
src="<%= Page.ResolveUrl("~/Scripts/YourScript.js") %>" ></script>

Also is important to always put the closing tag .

daniloquio
  • 3,822
  • 2
  • 36
  • 56
Mitchel Sellers
  • 62,228
  • 14
  • 110
  • 173
  • So I would just do that in an in-line code block in my .aspx file? – Mike Cole Apr 09 '09 at 19:54
  • Mike - Updated the post with an example – Mitchel Sellers Apr 09 '09 at 20:03
  • 2
    Additionally I'd use ResolveUrl vs ResolveClientUrl, Client url will work out the path relative to where it THINKS you are right now, ie - it will use ../../ if you are above, the ResolveUrl version will always do an absolute path. This may not appear important, but there is a bug regarding *cont* – meandmycode Apr 09 '09 at 20:08
  • ..how PathInfo isn't considered to be part of the path by the IUrlResolutionService, but the client browser will not see any difference between the path and PathInfo part. – meandmycode Apr 09 '09 at 20:08
  • I changed code to: link href="<%= Server.ResolveUrl("~/common/css/global.css") %>" – Mike Cole Apr 09 '09 at 20:19
  • Am getting error: error CS1061: 'System.Web.HttpServerUtility' does not contain a definition for 'ResolveUrl' and no extension method 'ResolveUrl' accepting a first argument of type 'System.Web.HttpServerUtility' could be found (are you missing a using directive or an assembly reference?) – Mike Cole Apr 09 '09 at 20:20
  • I'm getting File Not Found now. I'm going to have to look into this more. – Mike Cole Apr 09 '09 at 20:30
  • I am unable to make this work. Every value I try for a ResolveUrl parameter yields File Not Found. – Mike Cole Apr 09 '09 at 20:35
  • Is your website in a folder? does the generated link look like: /common/css/global.css? – meandmycode Apr 09 '09 at 20:37
  • My production website lies in a virtual directory, so I configured a virtual path in Visual Studio. I can't even see the generated link because it's throwing an exception. – Mike Cole Apr 09 '09 at 20:42
  • strange, just stick with the Client one, as long as you don't make use of PathInfo you'll be fine. – meandmycode Apr 09 '09 at 20:46
  • @meandmycode: I revisited this today with a fresh mind and your solution works perfectly. Thanks a ton! – Mike Cole Apr 10 '09 at 21:30
  • When I try this in a menu user control, it spits this out verbatim in the path: '<%= Server.ResolveClientUrl("~/mypage.aspx") %>' – IrishChieftain Jun 09 '11 at 19:59
  • @meandmycode sugestion worked to me but then I started getting a "__doPostBack is not defined" error. Explicitly closing the script tag solved the problem ( instead of />) – daniloquio Feb 15 '12 at 15:49
4

You can make the <link> tag to run at server so Asp.Net will resolve the URL for you like this:

<link href="~/common/css/global.css" runat="server" />

(Notice the '~')
I don't know if it can be applied to the <script> tag though, you should try...

EDIT: I discovered recently on a project that you can (and should) use a ScriptManager to hold your scripts (you can only have 1 per page). You can put one in your MasterPage and reference all your scripts. Inside your content page, you then add a ScriptManagerProxy that will 'reference' the scripts on the master page and you can even add other scripts for that content page only.

Julien Poulin
  • 12,737
  • 10
  • 51
  • 76
2

The solutions I saw so far didn't work in my project (especially not for .css links). The issues were the following:

  • inside <link> it didn't resolve the <%=...%> expression
  • it did not find the Page.ResolveURL in all cases
  • there was some trouble with ' and " quotes if you embedd <%=...%>

So I'd like to offer this solution: In code behind (your master page's C# class), add the the following 3 methods:

public partial class SiteBasic : System.Web.UI.MasterPage
{
    public string ResolveURL(string url)
    { 
        var resolvedURL=this.Page.ResolveClientUrl(url);
        return resolvedURL;
    }

    public string cssLink(string cssURL)
    {
        return string.Format("<link href='{0}' rel='stylesheet' type='text/css'/>", 
                    ResolveURL(cssURL));
    }

    public string jsLink(string jsURL)
    {
        return string.Format("<script src='{0}' type='text/javascript'></script>", 
                    ResolveURL(jsURL));
    }
}

For stylsheet references, you can then say:

<%=cssLink("~/css/custom-theme/jquery-ui-1.8.20.custom.css")%>

For JavaScript references, it looks like so:

<%=jsLink("~/Scripts/jquery-1.7.2.js")%>

And for other references, you can use:

<a href='<%=ResolveURL("~/Default.htm")%>'>link</a>
<img title='image' src='<%=ResolveURL("~/Images/logo.png")%>'/>

Note: I found it is better to use single quotes outside and double quotes inside the href or src attribute as shown in the example above. Doing it vice versa caused trouble in some cases as I found.

This solution is simple and it worked well in my case, even if the pages referencing the master page reside in different subdirectories. What it basically does is translating the ~ path (which needs to be absolute from the root of your web site) into a relative path (using as many ../ in the path as needed) based on the page you're currently displaying.


Advanced hint:

If you're using AJAX calls to invoke web service methods, then you'll have the same issue referencing them if you have ASPX pages on different directory levels. I recommend you define something like (assuming that your web services reside in the directory ~/AJAX):

<script type="text/javascript">
    function getWebServicePath() { return '<%=ResolveURL("~/AJAX/")%>'; } 
</script>

inside the <head> ... </head> section of your master page. This will make the entry path of the web service available in your JavaScript. You can use it like

$.ajax({
    type: "POST",
    url: getWebServicePath()+"myWebService.asmx/myMethod",
    data: $.toJSON({ param: "" }),
    contentType: "application/json; charset=utf-8",
    dataType: "json",
    success: function (msg) {
            // ... code on success ...
    },
    error: function (ex) {
            // ... code on error ...
    }
});
Matt
  • 25,467
  • 18
  • 120
  • 187
  • 1
    This should be the final answer. There is plenty of useful detail here. I had struggled with these issues for a while now and, unlike the marked answer, I couldn't seem to get the references that were mentioned to work properly. This cleared it up really nice and also taught me a new and helpful skill. Thank you! – Zachary Sheppard Mar 23 '16 at 07:07
2

I do it as simple as this: link href="<%=ResolveUrl("~/common/css/global.css")%>"

animuson
  • 53,861
  • 28
  • 137
  • 147
Stefan Bergfeldt
  • 345
  • 2
  • 11