ASP powered CSS file and bundling - asp.net

For a while now I have adopted the practice of writing my CSS in an .aspx page and serving that page as CSS. Primarily this is because a project I was involved on had a development 'CDN' before images were finally hosted on the actual CDN, so when it came to background images I needed a way of changing the URL through the web.config. I also get a few other perks like variables. A small sample:
#id
{
color: '<%= PrimaryColor %>';
background-image: url('<%= PrependCdnUrl("myimage.jpg") %>');
}
Since working on an MVC project I'd now like to incorporate CSS bundling into the original project (a webforms project). The problem I have, an .aspx page is not allowed to be bundled up, I get errors similar to:
(1,1): run-time error CSS1019: Unexpected token, found '<'
(1,2): run-time error CSS1019: Unexpected token, found '%'
...
Does anyone know how I could get this to work?

Short answer: It is not possible.
Long answer: It is possible through some hacks.
Actually there are 2 possibilities that pop into my mind that would accomplish this (they are not tested, not sure if they work out finally tough):
In your IIS you can define which filetype gets handled by which interpreter. You can try to define .css files to use the same interpreter as ASP.NET pages. (not sure if this works)
You can create an .aspx file instead of a .css file where you output the css code you need dynamically. Set the MIME type of the return stream from this dynamic css aspx page to the MIME type of CSS. Then reference your aspx page as css file

Related

Ruby on Rails: (Beginner) How can I make my style sheet (in public/stylesheet folder) be used by my layouts?

I'm learning Ruby on Rails (sorry for the newb question, I couldn't find an answer on stackoverflow), and I am having an issue with my app using the stylesheet that was assigned to the application.
I put a simple css style (A colored body tag) into my public/stylesheets directory called "application.css"
in my "app" I have the stylesheet called via:
"<%= stylesheet_link_tag "application" %>"
When I reload my page (which has no body css style specified in it, only pure simple html), I see no change. What am I doing wrong?
I've tried to reset the server, I've inspected the code of the rendered page and see nothing glaring... What am I missing?
The only ruby on rails warning that I get when the page opens is "Warn: could not determine content-length of the response or set Response#chunked = true", which seems to be ignorable --> What does "WARN Could not determine content-length of response body." mean and how to I get rid of it?
thanks
Put it in app/assets/stylesheets
You should really do a tutorial or two on Rails before you jump in. It is a very opinionated framework and it does a lot for you automatically. If you don't know what it's doing for you automatically and where things go, you'll encounter a ton of problems like this.
I'd highly, highly recommend Michael Hartl's free tutorial: http://ruby.railstutorial.org/ruby-on-rails-tutorial-book

.NET MVC3: Prevent 404 for missing CSS files? Or ensure files exist before writing HTML?

We have a requirement to provide skinning capabilities to an ASP.NET MVC3 app.
My approach so far has been to tackle this with a cookie and child actions for the css files:
Client links to our app using a URL like www.ourapp.com/as/www.clientapp.com/then-go-to/path/in/ourapp.
The above url is routed to an action method that writes a cookie named "skin" with value "www.clientapp.com" and then redirects to /path/in/ourapp.
Our layout (masterpage) has an #Html.Action in the <head> section where the css files are to be rendered.
The child action inspects the cookie and creates a viewmodel that will tell the partial view which <link> tags to render.
The css file structure is based on the cookie value. So our css content might look like this:
/content
/www.clientapp.com
/style1.css
/style1.css
/www.client2app.com
/style1.css
/style2.css
I am open to hearing better patterns / alternatives to the above for applying skins to the layout. However this isn't the reason for my question.
There is currently a problem with this approach when the css files are not present in the filesystem. The request causes IIS to return a 404. We override the 404 page with a custom page (not using the same layout that has the #Html.Action in the <head>). This causes IIS to do some additional processing which is not necessary (for example partials & child actions to render sign-in/sign out links, horizontal nav, etc, on the 404 page's layout).
The way I see it there are 2 ways to solve this:
In the child action that configures the css, check to make sure the files exist on disk before telling the viewmodel that they should be rendered. Pro with this approach is that it should be fairly easy. Cons are that to unit test it, would have to wrap file I/O in a service that can be injected. Also the app will be deployed to Azure. I think Azure can read the filesystem (which is what would be needed), but not write to it.
Somehow prevent a 404 from being returned for css files. To do this, would we have to implement logic in global.asax Application_Error? Or is there another way to prevent missing CSS files from triggering a 404 response?
Which approach is correct? Or is there another that I'm not considering?
Update
We ended up solving this in the custom 404 error page like so:
[ActionName("not-found")]
public virtual ActionResult NotFound()
{
// do not return 404 for missing css files
if (Request.RawUrl.EndsWith(".css", StringComparison.OrdinalIgnoreCase))
{
Response.StatusCode = 404;
return new EmptyResult();
}
return View();
}
One option would be to not override 404 errors for CSS requests.
For missing CSS files, return the 404 status, but leave the body empty. The body doesn't matter with a CSS file, since a human doesn't see it, and all the browser cares about is the status.

Returning razor-parsed Javascript as a ViewResult from a controller

I've successfully created an mvc/razor web application that returns css files that have been parsed by razor. Each time there's a background-image I have a razor snippet that writes the URL prefix to the image file name. The CSS now looks like this:
body { background-image: url(#LookupUrl.Image("background.gif")); }
Css files now work fine and I've moved onto trying to get javascript .js files to function the same way but these aren't playing ball.
The code is identical to the css code and it successfully finds the .js file, but razor seems to parse it differently. Here's an example js file:
function testFunction() { alert('test function hit!'); }
testFunction();
Razor seems to think it's code that it should compile, and gives the error:
Compiler Error Message: JS1135: Variable 'alert' has not been declared
> Source Error:
>
> Line 1: function testFunction() {
> Line 2: alert('test function
> hit!'); Line 3: } Line 4:
> testFunction();
After renaming the same file to .css it works fine.
Is there a way of getting razor to function with .js files in the same way as it does for .css?
Here's how I registered the file handlers for razor:
RazorCodeLanguage.Languages.Add("js", new CSharpRazorCodeLanguage());
RazorCodeLanguage.Languages.Add("css", new CSharpRazorCodeLanguage());
WebPageHttpHandler.RegisterExtension(".js");
WebPageHttpHandler.RegisterExtension(".css");
The build provider is registered in PreApplicationStart via the method Haacked outlines in his blog post.
Do I need to remove a handler that mvc adds for .js files?
UPDATE 2 days on
While I got working what I wanted to get working, I would not recommend this method to others. Using Razor to parse css/javascript is flawed without the use of <text><text/> - it's the simplicity of razor using the # ampersand that messes it up. Consider the CSS3 #font-face. Razor hits the # and thinks it should use it as a function. The same thing can happen with javascript, and happened with Jquery 1.5.1.
Instead, I'll probably go back to aspx webforms for dynamic css/javascript, where there's less chance of the <% %> code blocks appearing naturally.
I couldn't understand why CSS worked while JS didn't, especially after the copy+pasted JS code worked inside the CSS file.
I used the find/replace dialogue within visual studio on the System.Web.WebPages.Razor source to search for the string '.js' within the project. There was nothing helpful there so I then went to the System.Web.WebPages project. It found a match in System.Web.WebPages.Util, which is a static class with a few helper methods.
One of those methods is 'EnsureValidPageType' and within there is a try/catch block. Inside the 'catch' block is a comment:
// If the path uses an extension registered with codedom, such as Foo.js,
// then an unfriendly compilation error might get thrown by the underlying compiler.
// Check if this is the case and throw a simpler error.
It made me believe .js has got some special built-in handler with it.
I googled for a bit, couldn't find anything, then looked in the web.config that's within \Windows\Microsoft.NET\Framework64{version}\Config.
In there is a buildProvider mapping for the extension .js to
System.Web.Compilation.ForceCopyBuildProvider
After removing this buildprovider in the website's web.config, .js files get compiled and work as they should!
I'm still not too sure what the ForceCopyBuildProvider does or is for but I wonder if it's for visual studio. Various extensions have different Copy/Ignore build providers registered.
Once again apologies for answering my own question but I hope the comprehensive(waffley) answer might help others out.
You could try using the special <text> node to indicate to the Razor parser to treat the content literally:
<text>
function testFunction() { alert('test function hit!'); }
testFunction();
</text>
The default Razor parser uses the HtmlMarkupParser to handle the markup components of your template. There isn't currently any alternative parsers that support other markup languages (which you would need to treat the javascript code language as). If you did create a new markup parser, I would imagine it would be quite difficult to separate the code and markup (i.e. the C# and the Javascript).
What you could do, is use the <text></text> wrapping elements to enforce the parser switches to markup mode when that section of the template is reached, e.g.
<text>function testFunction() { alert('test function hit!'); }</text>
It's not pretty, but it should do the trick.

Multi-lingual static content in ASP.NET

Is there a simple way of making the static content of an .aspx page multi-lingual? Resource files are nice for controls but it's quite hard and annoying to write big chunks of html in them. Any easier ways?
Make properties in resources files and use them, .NET automatically finds the correct resource file, also just make sure so that the property name is same in all the resource files, so it will replace the property value in .aspx page with the value in the resource file.
Don't code html markup in resource file, have the html markup in the .aspx page itself, just get the essential values from resource files.
Just to reiterate what Mahesh said: do NOT put markup in the resource files, just put the static content into them.
If you need to serve different views based on culture, consider doing something else. For example, if you're using MVC you could write a view engine that return the correct markup for each culture.
#ciscoheat what you say is correct, LOCALIZE control is the right thing to use for big chunk of data.

Minify Html output of ASP.NET Application

What are the ways by which we can reduce the size of the HTML Response sent by an asp.net application?
I am using Controls which are not owned by me and it produces output with white spaces. I am interested in Minifying the entire HTML output of the page just like how google does (View source www.google.com) to improve the timing.
Is there any Utility classes available for ASP.NET which can do this stuff for me?
There is no need to do it at run time. Because it can be done at compile time.
Details: http://omari-o.blogspot.com/2009/09/aspnet-white-space-cleaning-with-no.html
Try HTTP module as described here: http://madskristensen.net/post/a-whitespace-removal-http-module-for-aspnet-20
For Microsoft .NET platform there is a library called the WebMarkupMin, which produces the minification of HTML code. For each ASP.NET framework has its own module:
ASP.NET Core - WebMarkupMin.Web. Implemented as an HTTP module, so it can work with any framework. Suitable for use in the ASP.NET Web Pages framework (Razor).
ASP.NET MVC - WebMarkupMin.Mvc
ASP.NET Web Forms - WebMarkupMin.WebForms
Documentation is available at - http://webmarkupmin.codeplex.com/documentation
I want to comment on Thorn's suggestion (but I'm new to stack overflow).
The linked code (omari-o.blogspot.com) doesn't support MVC4, and although the code is open source it cannot easily be upgraded because of braking changes between MVC3 and MVC4.
There might be whitespaces written to the http result at runtime, only the developer of the actual site can know that. Thus static minification of template files (aspx) is not foolproof at all. Dynamic minification, which is suggested by gius, should be used to guarantee that whitespaces are removed correctly, and unfortunately this will incur a runtime computation cost. If code dynamically writes spaces to the output, it will have to be removed dynamically.
The accepted answer does not work with MVC 4, so here is a similar lib that minifies at build-time https://github.com/jitbit/HtmlOptimizerMvc4
Just adding another option I do not see listed here, which is the one I was recommended using:
Html minifier command line tool
Usage:
here and here
There is an issue, however, with this tool: it leaves single line (//) comments, and it causes problems for Razor parsing, since a single line comment placed within a C# block like the following:
#{
...
...
// anything
...
}
will cause the minification output rest of the line, from this point on, to be ignored by the Razor parser, which will thus raise an error stating there it could not find the closing "}" for the block.
My workaround for this issue was to completely removing these comments from the output.
This way it works.
To do that, simply remove the RegexOptions.SingleLine from line 145:
htmlContents = Regex.Replace(htmlContents, #"//(.*?)\r?\n", ""/*, RegexOptions.Singleline*/);

Resources