Why use Url.Content for referencing resources? - asp.net-mvc

In almost every ASP.NET MVC example I've come across, I always see Url.Content being used to reference CSS, JavaScript, and Images. Not once has anyone explained WHY to use it.
Anyone care to explain?
What's so bad about doing:
<img src="/Content/Img/MyImage.png" alt="My Image" />
<script src="/Scripts/jquery.js" type="text/javascript"></script>
<link href="/Content/Css/Default.css" rel="stylesheet" type="text/css" media="all" />

What you have works the same as Url.Content(). Url.Content() is just like adding a ~ to be beginning of your paths:
<script src="~/Scripts/jquery.js" type="text/javascript"></script>
Just ensures the path is always correct with routing. You can also make a Html helper method to make this easier:
public static string RenderScript(this HtmlHelper htmlHelper, string file) {
var f = file.EndsWith(".js") ? file : string.Concat(file, ".js");
return string.Format("<script src=\"/public/scripts/{0}\" type=\"text/javascript\"></script>", f);
}
Then you can just put this in your masterpage:
<%=Html.RenderScript("jquery")%>

Related

Internel URL for .ear file deployment [duplicate]

To working my static file (CSS, JS) I have to write absolute path like /AppName/templates/style/main.css. Is there any solution, that I could write relative path like style/main.css?
If your actual concern is the dynamicness of the webapp context (the "AppName" part), then just retrieve it dynamically by HttpServletRequest#getContextPath().
<head>
<link rel="stylesheet" href="${pageContext.request.contextPath}/templates/style/main.css" />
<script src="${pageContext.request.contextPath}/templates/js/main.js"></script>
<script>var base = "${pageContext.request.contextPath}";</script>
</head>
<body>
link
</body>
If you want to set a base path for all relative links so that you don't need to repeat ${pageContext.request.contextPath} in every relative link, use the <base> tag. Here's an example with help of JSTL functions.
<%# taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%# taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
...
<head>
<c:set var="url">${pageContext.request.requestURL}</c:set>
<base href="${fn:substring(url, 0, fn:length(url) - fn:length(pageContext.request.requestURI))}${pageContext.request.contextPath}/" />
<link rel="stylesheet" href="templates/style/main.css" />
<script src="templates/js/main.js"></script>
<script>var base = document.getElementsByTagName("base")[0].href;</script>
</head>
<body>
link
</body>
This way every relative link (i.e. not starting with / or a scheme) will become relative to the <base>.
This is by the way not specifically related to Tomcat in any way. It's just related to HTTP/HTML basics. You would have the same problem in every other webserver.
See also:
Browser can't access/find relative resources like CSS, images and links when calling a Servlet which forwards to a JSP
Is it recommended to use the <base> html tag?
Just use <c:url>-tag with an application context relative path.
When the value parameter starts with an /, then the tag will treat it as an application relative url, and will add the application-name to the url.
Example:
jsp:
<c:url value="/templates/style/main.css" var="mainCssUrl" />`
<link rel="stylesheet" href="${mainCssUrl}" />
...
<c:url value="/home" var="homeUrl" />`
home link
will become this html, with an domain relative url:
<link rel="stylesheet" href="/AppName/templates/style/main.css" />
...
home link
You start tomcat from some directory - which is the $cwd for tomcat. You can specify any path relative to this $cwd.
suppose you have
home
- tomcat
|_bin
- cssStore
|_file.css
And suppose you start tomcat from ~/tomcat, using the command "bin/startup.sh".
~/tomcat becomes the home directory ($cwd) for tomcat
You can access "../cssStore/file.css" from class files in your servlet now
Hope that helps, - M.S.
Instead using entire link we can make as below (solution concerns jsp files)
With JSTL we can make it like:
To link resource like css, js:
<link rel="stylesheet" href="${pageContext.request.contextPath}/style/sample.css" />
<script src="${pageContext.request.contextPath}/js/sample.js"></script>
To simply make a link:
<a id=".." class=".." href="${pageContext.request.contextPath}/jsp/sample.jsp">....</a>
It's worth to get familiar with tags
<%# taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
There is also jsp method to do it like below, but better way like above:
<link rel="stylesheet" href="<%=request.getContextPath()%>/style/sample.css" />
<script type="text/javascript" src="<%=request.getContextPath()%>/js/sample.js"></script>
To simply make a link:
<a id=".." class=".." href="<%=request.getContextPath()%>/jsp/sample.jsp">....</a>
This could be done simpler:
<base href="${pageContext.request.contextPath}/"/>
All URL will be formed without unnecessary domain:port but with application context.
This is a derivative of #Ralph suggestion that I've been using. Add the c:url to the top of your JSP.
<%# taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<c:url value="/" var="root" />
Then just reference the root variable in your page:
<link rel="stylesheet" href="${root}templates/style/main.css">

How to add media type to stylesheet reference asp mvc

I'm using asp mvc, and I'm using the following code to generate the CSS html reference:
#Styles.Render("~/Content/css")
which generates the following html:
<link href="/Content/site.css" rel="stylesheet"/>
and that works fine. However, I need to add media type as an additional attribute. How can I go about using this style.render to add attributes to the generated html? Should I be thinking about making the change in the bundle config instead?
edit: I would like the end product to look like this:
<link href="/Content/site.css" rel="stylesheet" media="handheld"/>
You should be using #Styles.RenderFormat() for that:
#Styles.RenderFormat(#"<link href=""{0}""
rel=""stylesheet""
media=""handheld"" />",
"~/Content/css")
Try this
< link href="#Styles.Url("~/Content/css")" rel="stylesheet" type="text/css" media="handheld" />

Stopping MVC ViewMasterPage from resolving CSS URLs

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.
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>
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.
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")
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 :)
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>

Asp.net MVC2: CSS/Images paths on internal and local server

I have an Asp.net MVC2 web application. I built the application using VS2008 and tested on internal server, everything was perfect but when I deployed that web application on a local IIS the paths to images in web pages and in CSS file was not correct.
I need to change those paths for working with internal server and local server.
How can I overcome this problem?
Have you tried opening the CSS and Images directly (i.e. not via being called on a page)? Does that work?
How do you link to them on your internal server, if the relative paths don't equate the same, you'll have the problem you describe. An example about how you might fix this is to use Url.Content().
e.g. Instead of using:
<link rel="Stylesheet" href="/Styles/Reset.css" />
You would use:
<link rel="Stylesheet" href="<%=Url.Content("~/Styles/Reset.css")%>" />
This would work out the URL depending upon where the application lives on that box - not relative for the web root.
Edit: In case you need to do this through C# code
// This can be used to create img tag
public static string Image(this HtmlHelper helper)
{
UrlHelper urlHelper = ((Controller)helper.ViewContext.Controller).Url;
TagBuilder imgTag = new TagBuilder("img");
imgTag.MergeAttribute("src", urlHelper.Content("~/Content/images/image.gif"));
imgTag.MergeAttribute("alt", "Alt text");
return imgTag.ToString(TagRenderMode.SelfClosing);
}
To avoid this sort of problems you should always use the built-in helpers to generate URLs. For example:
<script type="text/javascript" src="<%= Url.Content("~/scripts/somescript.js") %>"></script>
and for links
<%= Html.ActionLink("Link text", "action", "controller") %>
Try something like this:
<link href="<%= Url.Content("~/Content/Site.css") %>" rel="stylesheet" type="text/css" />
The tilde ("~") represents the root and the Url.Content does the appropriate magic to get you a nice tidy reference.

Paths in master pages

I've started to work a bit with master pages for an ASP.net mvc site and I've come across a question. When I link in a stylesheet on the master page it seems to update the path to the sheet correctly. That is in the code I have
<link href="../../Content/Site.css" rel="stylesheet" type="text/css" />
but looking at the source once the page is fed to a browser I get
<link href="Content/Site.css" rel="stylesheet" type="text/css" />
which is perfect. However the same path translation doesn't seem to work for script files.
<script src="../../Content/menu.js" type="text/javascript"></script>
just comes out as the same thing. It still seems to work on a top level page but I suspect that is just the browser/web server correcting my error. Is there a way to get the src path to be globbed too?
<script src="<%= ResolveClientUrl("~/Content/menu.js") %>" type="text/javascript"></script>
Make an extension method. Here's a method:
public static string ResolveUrl(this HtmlHelper helper, string virtualUrl)
{
HttpContextBase ctx = helper.ViewContext.HttpContext;
string result = virtualUrl;
if (virtualUrl.StartsWith("~/"))
{
virtualUrl = virtualUrl.Remove(0, 2);
//get the site root
string siteRoot = ctx.Request.ApplicationPath;
if (!siteRoot.EndsWith("/"))
siteRoot += "/";
result = siteRoot + virtualUrl;
}
return result;
}
You can then write your script ref like:
<script type="text/javascript" src="<%= Html.ResolveUrl("~/Content/menu.js")%>"></script>
Use this instead:
<link href="~/Content/Site.css" rel="stylesheet" type="text/css" />
or you can use BASE tag in you HEAD section of page. All you links then are relative to location entered in "base" tag, and you don't have to use "../../" and "~" stuff. Except links in CSS files (background url,etc), where links are relative to location of css file.

Resources