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

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.

Related

How can I arrange to have my favicon cached in MVC3?

I have placed a .ico and a .png file in the folder /Content/Ico and I have the following in my _layout.cshtml
<!-- Favicon -->
<link rel="shortcut icon" type="image/x-icon" href="/Content/Ico/favicon.ico">
<link rel="icon" type="image/png" href="/Content/Ico/tick-circle.png">
a) Is there some way for me to specify how long these favicons are cached for? Should I use some kind of web.config file inside the /Content folder?
b) Some of my code uses the syntax "<link href="#Url.Content("~/Content/ ... Should I be using #Url.Content? What's the difference between using that and just specifying /Content in the href ?
a) You could serve the favicon through a server side controller action in which you specify for how long it should be cached by decorating it with the [OutputCache] attribute:
[OutputCache(Duration = 3600, Location = OutputCacheLocation.Client)]
public ActionResult Favicon()
{
var icon = Server.MapPath("~/content/ico/favicon.ico");
return File(icon, "image/x-icon");
}
and then:
<link rel="shortcut icon" type="image/x-icon" href="#Url.Action("Favicon", "SomeController")" />
b) Always use #Url.Content("~/content/...") and never /content/... to specify relative paths to static files. The reason for that is that the Url.Content helper accounts for the virtual directory name and your site will continue to work even after you deploy it in a virtual directory in IIS. If you hardcode the url like this /content/... it will work locally but once you ship in IIS it will no longer work because now the correct location is /yourappname/content/... which is what the Url.Content helper takes into account.

Why use Url.Content for referencing resources?

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")%>

How to get at Header

I'm trying to pass the header object here:
<%=FileUtil.AddStylesheetToHeader(Header, "UsedItems.css") %>
In my Master page I have a <head runat="server">. And my aspx page definitely has a reference to my MasterPageFile in the page directive at the top of my MVC based .aspx.
I also have an import statement the namespace that the FileUtil class resides in :
<%# Import Namespace="xxxx.Web.Utilities" %>
In standard ASP.NET you could reference the header with this.Header but in MVC I'm not able to do this...or I'm missing some kind of Imports or something.
for some reason though at runtime, with that call to AddStylesheetToHeader, I get the following error:
The best overloaded method match for 'System.IO.TextWriter.Write(char)' has some invalid arguments.
I'm not sure why it's looking at a .NET type as I know when I mouseover my FileUtil at compile time it's definitely referencing xxxx.Web.Utilities.FileUtil.
In that method I'm using HtmlLink styleSheet = new HtmlLink(); I may not be able to use this as it's an ASP.NET Web control? Here's that method:
public static void AddStylesheetToHeader(HtmlHead header, string cssFilename)
{
HtmlLink styleSheet = new HtmlLink();
styleSheet.Href = "content/css/" + cssFilename;
styleSheet.Attributes.Add("rel", "stylesheet");
styleSheet.Attributes.Add("type", "text/css");
header.Controls.Add(styleSheet);
}
I don't think I can use conrols that stem from System.Web.Controls since this is an ASP.NET application? If so, the how can I add a control to the header controls collection? Would I need to do this differently in MVC?
There may be a way to do it the way you're attempting, but it's more common in ASP.NET MVC to create a content placeholder in the <head> rather than accessing it programmatically. For example, your master view could look something like this:
<html>
<head>
<asp:ContentPlaceHolder ID="HeadContent" runat="server" />
</head>
</html>
And your view could look like this:
<asp:Content runat="server" ContentPlaceHolderID="HeadContent">
<link href="/content/css/UsedItems.css" rel="Stylesheet" type="text/css" />
</asp:Content>
have you tried this.Request.Header?
You can use JavaScript to dynamically add content to your HEAD section as shown in the code below:
<script language="javascript" type="text/javascript">
$(document).ready(function() {
$("head").append("<link href='Content/Site.css' rel='stylesheet' type='text/css' />");
});
</script>

Better approach for external css in ASP.NET MVC?

I have a ViewPage within which I would like to specify an external style sheet. The style sheet only applies to elements in the ViewPage. After some unsuccessful attempts I settled on using "Url.Content" as follows:
<asp:Content ID="cssLinkContent" ContentPlaceHolderID="CssLinkContent" runat="server">
<link rel="stylesheet" type="text/css" href="<%= Url.Content("~/Content/custom.css")%>" />
</asp:Content>
This works fine at run time, but the error "The class or CssClass value is not defined" is displayed by the Visual Studio editor. I presume this is because Visual Studio cannot resolve the external style sheet when I use "Url.Content".
Any thoughts on a solution that will successfully resolve the URL at runtime and make Visual Studio happy?
Thanks in advance.
I would just ignore Visual Studio. It's a great tool, but sometimes it tries to hard. Are you sure that's an error or a warning? I know it's a sucky answer, but it's what I do.
Won't it complain about styles used simply as jQuery fodder as well?
As an aside, you might want to write an Html.Stylesheet helper to encapsulate the markup and url parsing behavior, as follows:
public static string Stylesheet(this HtmlHelper Html, string url) { return Html.Stylesheet(url, null); }
public static string Stylesheet(this HtmlHelper Html, string url, string media)
{
UrlHelper Url = new UrlHelper(new RequestContext(Html.ViewContext.HttpContext, Html.ViewContext.RouteData));
string html = "<link type=\"text/css\" rel=\"stylesheet\" href=\"{0}\" {1}/>";
if (!string.IsNullOrEmpty(media))
media = "media=\"" + media + "\"";
return string.Format(html, Url.Content(url), media);
}
Resulting in this, much cleaner, markup:
<%= Html.Stylesheet("~/Content/custom.css") %>
It is a weird solution but it works:
<!-- next line only for VS -->
<% if(false) { %><script src="../../Content/custom.css" type="text/javascript"></script><% } %>
<link rel="stylesheet" type="text/css" href="<%= Url.Content("~/Content/custom.css")%>" />
You can also use something like this for jQuery intellisense in your Views:
<% if(false) { %><script src="../../static/jquery/jquery-1.3.2-vsdoc2.js" type="text/javascript"></script><% } %>
Did you try
<link rel="stylesheet" type="text/css"
href="<%= ResolveUrl("~/Content/custom.css")%>" />

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