views:

131

answers:

5

Currently, I have a Site.Master page for my MVC app that renders great when run directly from VS2008. It looks like this:

<%@ Master Language="C#" Inherits="System.Web.Mvc.ViewMasterPage" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"&gt;
<html xmlns="http://www.w3.org/1999/xhtml"&gt;
<head>
  <meta http-equiv="content-type" content="text/html; charset=utf-8" />
  <link rel="stylesheet" type="text/css" href="../../Content/css/layout1_setup.css" />
  <link rel="stylesheet" type="text/css" href="../../Content/css/layout1_text.css" />
  <title><asp:ContentPlaceHolder ID="TitleContent" runat="server" /></title>  
</head>

Unfortunately, when used on my IIS 6.0 server in a "Virtual Directory", the CSS reference fails to load and the page fails to render properly. (By virtual directory, I mean something like http://localhost/MyTestSite where "MyTestSite" is the Virtual Directory created in IIS Manager on the server where the MVC app is installed.)

The MVC app runs fine and the HTML produced from it loads normally, but the server seems to be unable to find the location of the CSS and related images referenced. I find this baffling since it seems to work just fine when run from VS2008.

I did find a workaround to my issue, but I'm not exactly satisfied with the results:

<link rel="stylesheet" type="text/css" href=<%= Page.ResolveUrl(@"~/Content/css/layout1_setup.css") %> />
<link rel="stylesheet" type="text/css" href=<%= Page.ResolveUrl(@"~/Content/css/layout1_text.css") %> />

Using Page.ResolveUrl() feels like a hack to me as it breaks the rendering of the Split and/or Design view of page when editing in VS2008. (And all CSS tags are underlined in green as "not existing".) That said, it renders just fine in both IIS6 and VS2008 when "running".

Is there a better way to fix this problem?

EDIT: My problem sounds like the issue described here: http://haacked.com/archive/2008/11/26/asp.net-mvc-on-iis-6-walkthrough.aspx -- But I already have the fix for the default.aspx.cs file implemented as shown below.

   public void Page_Load(object sender, System.EventArgs e)
   {
        string originalPath = Request.Path;
        HttpContext.Current.RewritePath(Request.ApplicationPath, false);
 // Setting "false" on the above line is supposed to fix my issue, but it doesn't.
        IHttpHandler httpHandler = new MvcHttpHandler();
        httpHandler.ProcessRequest(HttpContext.Current);
        HttpContext.Current.RewritePath(originalPath, false);
   }
+3  A: 
<link href="<%= Url.Content("~/Content/css/mystyle.css") %>"
        rel="stylesheet" type="text/css" />

Edited:

After giving this some thought I relized that when using the VS 2008 you are probably using debug mode when running the website under "ASP.Net Development Server" And when you deploy to IIS you have probably published the code in Release Mode.

If this is the case then you can try the following:

<% #if DEBUG %>
   <link rel="stylesheet" type="text/css" href="../../Content/css/layout1_setup.css" />
   <link rel="stylesheet" type="text/css" href="../../Content/css/layout1_text.css" />
 <% #else %>
   <link rel="stylesheet" type="text/css" href="<%= Url.Content("~/Content/css/layout1_setup.css") %>" />
   <link rel="stylesheet" type="text/css" href="<%= Url.Content("~/Content/css/layout1_text.css") %>" />
 <% #endif %>

Now with this when you run in Visual Studio 2008 your code completion tools for CSS will work as well as running your website (as a Release version) inside a virtual directory.

John Hartsock
No better or worse than my existing workaround. Looks fine in IIS6 and VS2008 when running, but when editing via Design and/or Split view, it is unable to find the CSS. Thanks for the suggestion, though.
Pretzel
@Pretzel..I came up with a solution you may like.
John Hartsock
Hmmm... This looks like the answer. Let me try it out.
Pretzel
@Pretzel. how did that work out for you?
John Hartsock
@John: Been tracking down a bug all day. Haven't had a chance to test it. I'll try it now.
Pretzel
Ok, it worked in VS editor, but not when executing...
Pretzel
Looks like Awe's solution is the one that's working for me, but I think you got him on the right track, so I voted you up one.
Pretzel
A: 

Just tested the following to make sure it would solve both your problems (enabling design view & resolve properly). Hope it works for you

<link rel="stylesheet" type="text/css" href="~/Content/css/layout1_setup.css" runat="server" />
<link rel="stylesheet" type="text/css" href="~/Content/css/layout1_text.css" runat="server" />
Chris
Just tried it in VS. Doesn't work. -- Oddly though, if I take "/Content/css/layout1_setup.css" (deleting the ~) and paste it right next to http://domain/MySite/ and hit Enter, the web browser downloads the CSS sheet. It's baffling. So the tilde (~) means start at the root. But would this mean at http://domain/ -or- would it mean http://domain/MySite/ (since this site is based off this virtual directory "MySite".)
Pretzel
Good question... It might require that your virtual directory be an "Application" for it to consider the virtual directory the root for purposes of determining the virtual path. You could try that... right click on the virtual directory in IIS and say, "Convert to application".
Chris
When you run the above code on the server... what is the html it outputs (what path)?
Chris
I'm running IIS 6.0 -- I don't see a "Convert to application" in IIS manager.
Pretzel
When I run your code, it emits the source exactly how you have it written. I tried an experiment though. I added the an -A HREF- link where I specified "~/Content/css/layout_text.css" and the mouse-over of the link revealed "http://domain/~/Content/css/layout_text.css"
Pretzel
The tilde (~) means start at the root of the application, which means `domain/MySite`. Your test with adding a `<a href>` link would not work, as this is an html tag. The `~` is only interpreted by ASP.NET tags. You could try your test using `<asp:HyperLink NavigateUrl="~/Content/css/layout_text.css">Test</asp:HyperLink>` instead.
awe
+2  A: 

John Hartsock is on to something, but the preprocessor commands he is trying to execute does not work as expected in design mode (I think it actually tries to do both). You can instead try to check against a .NET Site property that is available to test if you run in design mode or not (in release configuration, the Site property is not always populated, so you also have to check if it is not null).

Also Visual Studio design viewer does not know of domain and virtual app path, so in the designer you can use / to point to app root.

<% if (Site != null && Site.DesignMode) { %>
 <link href="/Content/css/layout1_setup.css" rel="stylesheet"/>
<% } else { %>
 <link href="<%= Url.Content("~/Content/css/layout1_setup.css") %>" rel="stylesheet"/>
<% } %>
awe
@Awe: Thanks, buddy. This is the answer that worked for me. Much appreciated. :-)
Pretzel
+1  A: 

I am afraid there's no elegant way of doing this. You could perform the following horrible hack to cheat the designer:

<% if (false) { %>
<!-- That's just to cheat the designer, it will never render at runtime -->
<link rel="stylesheet" type="text/css" href="../../Content/css/layout1_setup.css" />
<link rel="stylesheet" type="text/css" href="../../Content/css/layout1_text.css" />
<% } %>
<link rel="stylesheet" type="text/css" href="<%= Url.Content("~/Content/css/layout1_setup.css") %>" />
<link rel="stylesheet" type="text/css" href="<%= Url.Content("~/Content/css/layout1_text.css") %>" />

Personally I never use the designer and would never do something like this in my code but if you really need to have this design view then it could be a solution.

I mean you are working in an ASP.NET MVC project, you should be manipulating html, why care about the design view? Look at the price you should pay just to get the design view working, it's too expensive. It's faster to hit CTRL+F5 in your favorite browser to see the result of your efforts than switching all the time between code and design view.

Darin Dimitrov
I've been living with the view broken in Design view, but some how feel that it should work in both. Seems like a simple oversight. I upvoted you because I kind of like your hack, even if it is ugly. :-)
Pretzel
+1  A: 

Maybe this is obvious or I've missed something but this looks like a path issue. You are using relative paths (../../). I believe when you run something in Visual Studio, the application is the root path (ie. default.aspx in your project's main directory would be localhost:port/default.aspx). If a relative path in any page goes up too many directories (ie ../ too many times), it will be ignored and taken from the root of the website (in this case localhost:port/). For example, if your folder structure is like this:

  • AppRoot
    • styles (folder)
    • content (folder)
    • otherfiles (folder)
      • myfile.aspx
    • default.aspx

You can access the content folder from myfile.aspx by using ../content/ or, even though you shouldn't do this, by using ../../content/ This only works if AppRoot is the same as the domain root (ie. localhost:port/content/ and domain.com/content/ are the same folder).
However, if you put those files in another (virtual) folder on your web server (ie. domain.com/virtual == new AppRoot) now ../../content from domain.com/virtual/otherfiles/myfile.aspx will be referring to domain.com/content/, which is incorrect.

I hope this helps.

Drackir