Why does MVC automatically expand virtual URLs? - asp.net

In my Layout.cshtml file I have the following line:
<link rel="stylesheet" href="~/Content/bootstrap.css" />
My assumption was that since I did not include Url.Content() call, it would actually just render what I wrote but not expand the virtual URL automatically. This assumption is wrong - the generated HTML does include the correct path to the file, not the virtual path I entered.
If I wrap the <link> in <script>
<script type="text/html">
<link rel="stylesheet" href="~/Content/bootstrap.css" />
</script>
then the URL is not expanded.
Which part of ASP.NET MVC does this automatic parsing of HTML and is there a way to control it?

This was a new feature included in Razor2 and ASP.NET MVC 4 and was designed to make life easier by not having to use Url.Content everywhere.
http://www.davidhayden.me/blog/asp.net-mvc-4-the-new-tilde-slash-feature-in-razor-2
The feature only works inside standard HTML attributes and that's why you don't get it inside your <script> tag or anywhere else.
You could use a simple output write to work around this:
<link rel="stylesheet" href="#("~/Content/bootstrap.css")" />

Related

Asp.net link runat server w3c validator

when i run a link server side like this:
<link runat="server" id="staticCss"
href="....css?v=0" media="all" rel="stylesheet" type="text/css" />
asp.net renders it with
<link runat="server" id="staticCss"
href="....css?v=0" media="all" rel="stylesheet" type="text/css" ><link>
and this fails the w3 validation
Stray end tag link.
becasuse link tag can't end with link but must end with /
How can i avoid it?
As far as I know, it can’t be avoided. These are the alternatives that you have:
Use a static link tag without the server processing, if you can
Ignore the validation error: browsers handle this markup well and you shouldn’t have any issues on your website
Use a .net literal to spit out the markup as text: this way you are in total control of the formatting
I have been struggling with .net generated html for a long time, it can be very frustrating. If anyone knows of other ways to solve this I would be very interested to learn.

Using tilde in script tag src attribute

In my asp.net website using MasterPage and Routing I use a tilde in the href attribute of the link tag for the stylesheet in the head section of the MasterPage. Like this:
<link href="~/Styles/Main.css" rel="stylesheet" type="text/css" />
Which works like a charm. Since the website uses routing the url will contain more and more /, yet the stylesheet's href remains valid because the tilde points to the root of the web application and the styles are used.
I tried using the same technique for the src attribute of the script tags, but this doesn't seem to produce the expected result. I tried:
<script src="~/Scripts/jquery-1.8.2.min.js" type="text/javascript" ></script>
But this just outputs the tilde character to the HTML of the page instead of replacing it with the root of the web application as it does for the href attribute. My experience is that asp.net replaces tilde in href attributes but not in src attributes.
How can I make the tilde work in the src atrribute of script tags?
I'm not sure there is a way to get it to work correctly without a bit of assistance. This should work, not as nice as the link though:
<script src="<%=ResolveUrl("~/Scripts/jquery-1.8.2.min.js")%>"></script>
Unfortunately, what you want just doesn't work (although I agree it should).
If you are using a script manager, then you can do something that is reasonably close:
<asp:ScriptManager>
<Scripts>
<asp:ScriptReference Path="~/Scripts/jquery-1.8.2.min.js" />
</Scripts>
</asp:ScriptManager>

Implementing CSS as a variable in the site.master page in ASP.NET MVC3

I am implementing a web application using ASP.NET MVC3. In the application I want to add the option of switching between CSS files (for themes) based on clicking some links. I did some research and I came up with the following:
To pass data to site.master, the good solution is to create an abstract controller and inherit that into the other controllers that have site.master as their template, according to this article: Passing Data to View Master Pages
I can pass a viewbag message to the link which controls the css file URL to set the current css file to use, based on the code that I am seeing being passed to scripts at the top of the site.master page:
script src="<%: Url.Content("~/Scripts/jquery-1.5.1.min.js") %>" type="text/javascript"
So I created an abstract controller, ApplicationController, with the following method:
public ApplicationController()
{ViewBag.NewMessage = "../../Content/Site2.css";}
And in the site.master, I included this link:
<link href="<%: (string) ViewBag.NewMessage %>" rel="stylesheet" type="text/css" />
However, that doesn't seem to be working, as it is being interpreted as:
<link href="<%: (string) ViewBag.NewMessage %>" rel="stylesheet" type="text/css" />
And only when I remove the quotation marks:
<link href=<%: (string) ViewBag.NewMessage %> rel="stylesheet" type="text/css" />
is it being interpreted correctly (and the webpage gets rendered with the correct css), except that it violates html standards:
<link href=../../Content/Site2.css rel="stylesheet" type="text/css" />
Any suggestion about how to go tackling this problem or is there a more elegant solution I'm missing? I was going to proceed and implement variables in the ApplicationController that get selected based on links the user clicks at the top of the page, to switch between css styles.
Thank you!
Check to make sure your <head> tag does not have runat="server".
After making this change, be sure to check your script and css tags. This change can break the paths if you use the ~/ to ref app root. To help with this, use the Url.Content(...) helper.

Best Approach: Mutliple content place holders in MVC

I am converting an ASP.Net web forms project to MVC3. The master page contains multiple content place holders at different locations.
I replaced the first content place holder with #RenderBody() but I am confused with what to do of the second one.
One approach might be to separate views and place a #Html.RenderAction() for each content place holder method. Is there a better way to do it?
Razor has got sections understanding in place of asp.net webforms ContentPlaceHolders. Take a look at this introductionary link.
You can use sections. For example, to have a section for scripts, in the head tag of the layout.cshtml, you can specifiy
<head>
<title>#ViewBag.Title</title>
<link href="#Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" />
<script src="#Url.Content("~/Scripts/jquery-1.4.4.min.js")" type="text/javascript"></script>
#RenderSection("scripts", false);
</head>
Inside of any view, you can now add a scripts section to inject your scripts:
#section scripts{
<script src="#Url.Content("~/Scripts/myscript.js")" type="text/javascript"></script>
}
the "false" param tells MVC to render the section if exists on the child page or do nothing if no call

Strange inline code error from ASP.NET

This is a really strange one. I am trying to add a cache value to my css stylesheet references in order to invalidate the http header caching I have set. I have the following code:
<link href="/css/Continuity2/layout.css?cache=<%=Global.CACHE_KEY %>" rel="stylesheet" type="text/css" />
The above is rendered as follows and does not seem to be picking up the inline code:
<link href="/css/Continuity2/layout.css?cache=<%=Global.CACHE_KEY %>" rel="stylesheet" type="text/css" />
The even stranger thing is, I have the following code for my javascript references:
<script type="text/javascript" src="/js/ajaxhelper.js?cache=<%=Global.CACHE_KEY %>"></script>
And this references as expected:
<script type="text/javascript" src="/js/ajaxhelper.js?cache=70BE31E0-E694-45ff-A920-D6564DA2FB79"></script>
Has anyone any idea why on earth this would happen?
<link> tags inside a <head> tag are converted into HtmlLink objects.
You can resolve the issue either by setting the property value programmatically from your code behind, or by using a control adapter.
It would probably also work if you moved the tag outside of your head section, although that can have an effect on the way your page is rendered (potential flashes, etc after the CSS is loaded).
I should also add that using a query string on static files to force versioning is usually not an ideal solution, because it prevents the high performance kernel mode HTTP driver (http.sys) from caching the file.

Resources