Force browser to use new CSS - c#

Is there a way to check if the user has a different version of the CSS cached by their browser and if so force their browser to pull the new version?

I don´t know if it is correct usage, but I think you can force a reload of the css file using a query string:
<link href="mystyle.css?SOME_UNIQUE_TEXT" type="text/css" rel="stylesheet" />
I remember I used this method years ago to force a reload of a web-cam image, but time has probably moved on...

Without using js, you can just keep the css filename in a session variable. When a request is made to the Main Page, you simply compose the css link tag with the session variable name.
Being the ccs file name different, you force the broswer to download it without needing to check what was previusly loaded in the browser.

As jeroen suggested you can have somthing like:
<link href="StyleSelector.aspx?foo=bar&baz=foz" type="text/css" rel="stylesheet" />
Then your StyleSelector.aspx file should be something like this:
<%# Page Language="cs" AutoEventWireup="false" Inherits="Demo.StyleSelector" Codebehind="StyleSelector.aspx.cs" %>
And your StyleSelector.aspx.cs like this:
using System.IO;
namespace Demo
{
public partial class StyleSelector : System.Web.UI.Page
{
public StyleSelector()
{
Me.Load += New EventHandler(doLoad);
}
protected void doLoad(object sender, System.EventArgs e)
{
// Make sure you add this line
Response.ContentType = "text/css";
string cssFileName = Request.QueryString("foo");
// I'm assuming you have your CSS in a css/ folder
Response.WriteFile("css/" + cssFileName + ".css");
}
}
}
This would send the user the contents of a CSS file (actually any file, see security note) based on query string arguments. Now the tricky part is doing the Conditional GET, which is the fancy name for checking if the user has the page in the cache or not.
First of all I highly recommend you reading HTTP Conditional GET for RSS hackers, a great article that explains the basics of HTTP Conditional GET mechanism. It is a must read, believe me.
I've posted a similar answer (but with PHP code, sorry) to the SO question can i use “http header” to check if a dynamic page has been changed. It should be easy to port the code from PHP to C# (I'll do it if later I have the time.)
Security note: it is highly insecure doing something like ("css/" + cssFileName + ".css"), as you may send a relative path string and thus you may send the user the content of a different file. You are to come up with a better way to find out what CSS file to send.
Design note: instead of an .aspx page you might want to use an IHttpModule or IHttpHandler, but this way works just fine.

Answer for question 1
You could write a Server Control inheriting from System.Web.UI.Control overriding the Render method:
public class CSSLink : System.Web.UI.Control
{
protected override void Render(System.Web.UI.HtmlTextWriter writer)
{
if ( ... querystring params == ... )
writer.WriteLine("<link href=\"/styles/css1.css\" type=\"text/css\" rel=\"stylesheet\" />")
else
writer.WriteLine("<link href=\"/styles/css2.css\" type=\"text/css\" rel=\"stylesheet\" />")
}
}
and insert an instance of this class in your MasterPage:
<%# Register TagPrefix="mycontrols" Namespace="MyNamespace" Assembly="MyAssembly" %>
...
<head runat="server">
...
<mycontrols:CSSLink id="masterCSSLink" runat="server" />
</head>
...

You should possibly just share a common ancestor class, then you can flick it with a single js command if need be.
<body class="style2">
<body class="style1">
etc.

I like jeroen's suggestion to add a querystring to the stylesheet URL. You could add the time stamp when the stylesheet file was last modified. It seems to me like a good candidate for a helper function or custom control that would generate the LINK tag for you.

I know the question was specifically about C# and I assume from that Windows Server of some flavour. Since I don't know either of those technologies well, I'll give an answer that'll work in PHP and Apache, and you may get something from it.
As suggested earlier, just set an ID or a class on the body of the page dependent on the specific query eg (in PHP)
<?php
if($_GET['admin_page']) {
$body_id = 'admin';
} else {
$body_id = 'normal';
}
?>
...
<body id="<?php echo $body_id; ?>">
...
</body>
And your CSS can target this:
body#admin h1 {
color: red;
}
body#normal h1 {
color: blue;
}
etc
As for the forcing of CSS download, you could do this in Apache with the mod_expires or mod_headers modules - for mod_headers, this in .htaccess would stop css files being cached:
<FilesMatch "\.(css)$">
Header set Cache-Control "max-age=0, private, no-store, no-cache, must-revalidate"
</FilesMatch>
But since you're probably not using apache, that won't help you much :(

Like in correct answer, i am using some similar method, but with some differences
<link href="mystyle.css?v=DIGIT" type="text/css" rel="stylesheet" />
As a DIGIT you can use a real number, set manually or automatically in your template. For example, on my projects i'm using Cache clearing modules in admin panel, and each time use this cache cleaner, it increments the DIGIT automatically.

Related

C# Variables is loading tags in .aspx

I have inserted a web.config key as below:
<add key="WebInstance" value="/testApp"/>
When I call my Site.Master
<link rel="stylesheet" href="<%= WebInstance%>/themes/bs3/css/bootstrap.min.css" />
In my Site.Master.cs
private string _webInstance = ConfigurationManager.AppSettings["WebInstance"]
public string WebInstance { get { return _webInstance ; }}
The first referencing in Site.Master works perfectly. Example:
<link rel="stylesheet" href="/testApp/themes/bs3/css/bootstrap.min.css" />
But in the other pages, it references the full tag.
For instance, when I do inspect element on the browser function, what I see on my <head></head> tags are these:
<link rel="stylesheet" href="<%= WebInstance %>/themes/bs3/css/bootstrap.min.css" />
I also had the functions of getting the key on my ascx.cs
Why is it just calling the tag instead of getting the real value?
UPDATE
SITE.MASTER and the 'other' pages are 2 different things, the WebInstance key is from the web.config file.
In Site.Master.cs I have its own function to call to the Key and also the other pages have their own respective functions to call the Key.
UPDATE AGAIN
I have found the answer to all this, I had runat="server" on my <Head></Head> tags on the other pages, removing it solved the problem. Thanks anyway ;)
Your other pages can't directly reference code-behind in their master page.
You could add the same property to your individual pages, but then you get duplication.
Although I'm not a big fan of static classes, in this case it might be good compromise:
public static class SiteSettings
{
public string WebInstance
{
get { return ConfigurationManager.AppSettings["WebInstance"];}}
}
}
Then in your .aspx, reference SiteSettings.WebInstance.
Some developers will make a base page that other pages inherit from and put common properties there. That can work but I'd use it as a last resort. Sooner or later you're going to want some behaviors of the base page but not others, or you'll have to make some broad changes to the site and it becomes a big pain.

ASP.NET C# function in HTML

I have faced a lot of issues with CSS and JS caching, so i decided to add timestamps to CSS and JS files.
so i added this param at the end of links:
?t=<%= DateTime.Now.Ticks %>
So here how it looks like:
JS:
<script type="text/javascript" src="Scripts/global_scripts.js?t=<%= DateTime.Now.Ticks %>"></script>
CSS:
<link rel="stylesheet" type="text/css" href="Styles/mysite.css?t=<%= DateTime.Now.Ticks %>" />
The JS file work fine. But for CSS files this param ?t=<%= DateTime.Now.Ticks %> gets recognized as a string. Why? I cannot find the difference
You can easily solve your problem with this simple adjustement
<link rel="stylesheet" type="text/css" href="Styles/uberhint.css?t=<%= "" +DateTime.Now.Ticks %>" />
Just add "" +.
ASP.NET is treating the link as an HtmlLink control, and rendering the contents of the href attribute as a literal. Inserting that Extra string forces ASP.NET to accept that you are trying to generate a dynamic string
While this is not an answer to your original question, I can suggest you to use a different approach altogether. Instead of adding ticks, you can use default Microsoft libraries to make bundles. When you do it that way, the engine will automatically add a string like ?v=dfsdf9fsdfasd which will be a hash of the content, so every time it changes it will be different. Then you can just cache forever the resources forever on the client.
Your approach is problematic since the browser will download js every time, this is extremely inefficient.
You can get some details on how to use bundles with minification e.g. here. Please see my answer for some details on how to make script bundles properly.
P.S. If you don't want to do bundling yourself, you can still implement the hash of the file content yourself. Another easy option is to do ?v=1, where you get the version from config, then by changing the config, you will be able to force cache update on all you clients.
With all of the approaches you should set cache for 1 year (max if I remember correctly).
If the above answers dont work, you can try to add a
<asp:placeholder runat="server" id="ph">
above script and css tag, and in the page_load you can bind placeholder.
ph.DataBind();

Change page styles Android WebView

I'm currently working on a small application that simply loads one webpage into webview and I want to be able to make this webpage look different while browsing using this application..
This page uses one .css and I want to use my own version of that .css instead of the original one or just replace part of the original with mine (by using the original and then overwriting it with my version)..
Is it possible to modify source code of the page (optionaly before it even loads) so I can change some styles to make the webpage look different?
Just to explain:
I want change
<link rel="stylesheet" type="text/css" href="original.css">
to
<link rel="stylesheet" type="text/css" href="original.css">
<link rel="stylesheet" type="text/css" href="http://www.something.com/edited.css">
I'm using Xamarin Studio, C# Android WebView project, by the way..
Also, this is very likely going to be called duplicate of this: Override web page style in Android WebView but it was never answered so it's not very helpful for me..
Have you looked at:
addJavascriptInterface (Object object, String name) of the WebView?
You could inject code to manipulate the DOM. This probably a bad idea as it is a SECURITY ISSUE in a number of ways.
Less intrusive and more secure, the WebSettings object allows you to change some presentation aspects: http://developer.android.com/reference/android/webkit/WebSettings.html
In this area another tool to explore is to create and set a WebViewClient subclass: http://developer.android.com/reference/android/webkit/WebViewClient.html
Just a few avenues to explore.
You can inject your css using Javascript. You can inject following javascript after the WebView is finished loading:
var link = document.createElement("link");
link.href = "http://example.com/mystyle.css";
link.type = "text/css";
link.rel = "stylesheet";
document.getElementsByTagName("head")[0].appendChild(link);
So your final Java code will look something like this:
String jsToInject = "var link=document.createElement('link');link.href='http://example.com/mystyle.css';link.type ='text/css'; link.rel ='stylesheet';document.getElementsByTagName('head')[0].appendChild(link);";
myWebView.loadUrl("javascript:" + jsToInject);

Adding some automatic versioning to CSS files. How come I'm not able to pull assembly info?

<link rel="stylesheet" type="text/css" href="../Content/Dashboard/CustomTooltip.css?v=<%= System.Diagnostics.FileVersionInfo.GetVersionInfo(System.Reflection.Assembly.GetExecutingAssembly().Location).FileVersion %>" />
Couple of questions:
Is this an alright way of going about this? The idea is that when our products assembly information changes, the version updates, the path to the CSS file gets modified and invalidates the cache.
If I place the C# code into a watch window I see the proper version info, but in the .aspx page it fails to load it. No error message, but it just says .css?v= with no version.
Thanks
Edit: It seems like its something to do with the reflection that's going on. If I say:
System.Reflection.Assembly.GetExecutingAssembly().GetName().Name
I see the proper name in the watch window, but when evaluated on the .aspx page it is App_Web_35 (not correct). Any idea how to fix this?
Edit2: I ended up going with a solution I'm not quite happy with, but would love to hear other inputs. I just put:
protected string GetApplicationVersion()
{
return System.Diagnostics.FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location).FileVersion;
}
on my related CS page -- and then in the code behing I called <% GetApplicationVersion() %> and now it happily returns the proper information. I wish it could be inlined, though.
A css file is static, like html. Think about create different css files and call it like this
<link rel="stylesheet" type="text/css" href="../Content/Dashboard/CustomTooltip_<%= `System.Diagnostics.FileVersionInfo.GetVersionInfo(System.Reflection.Assembly.GetExecutingAsse`m`bly().Location).FileVersion %>.css" />`
so you need a css file like this ../Content/Dashboard/CustomTooltip_1.0.css

ASP.Net - Path Problems caused by Encoded URLs

I am building a web store and I am having a bit of a problem with some of the urls.
I have a large directory of departments and categories in my database that I am using to form my main menu.
The URLs have the form Application/Store/Department/Category
(All store URLs are rewritten to store.aspx?Querystringstuff)
The problem is that some of the urls generated by my code work, but prevent the page's CSS from loading properly.
It is specifically the URLs who's source text contain slashes.
I am URL encoding the source text of course but I'm still having the problem.
My css is linked in a master page-
<link rel="stylesheet" type="text/css" href="~/CSS/Layout.css" runat="server">
Example Links that work -
Ice Machines
http://localhost:1079/ABCWeb/Store/Refrigeration+Equipment/Ice+Machines.aspx
Steam Table Pans
http://localhost:1079/ABCWeb/Store/Catering+%26+Buffet/Steam+Table+Pans.aspx
Example Links that break-
Napkin Holders/Dispensers
http://localhost:1079/ABCWeb/Store/Tabletop/Napkin+Holders%2fDispensers.aspx
Salamanders/Cheesemelters
http://localhost:1079/ABCWeb/Store/Cooking+Equipment/Salamanders%2fCheesemelters.aspx
If it matters here is my code for building URLs-
The array contains an array of items in the path
The first element is not encoded as it contains the the current store path.
private static System.Text.StringBuilder AppendAnchor(this System.Text.StringBuilder str, string[] path)
{
return str.Append("<a href='")
.Append(path.Aggregate((a, b) => a + "/" + HttpUtility.UrlEncode(b)))
.Append(".aspx'><span>")
.Append(HttpUtility.HtmlEncode(path[path.Length-1]))
.Append("</span></a>");
}
Thanks for the help!
Try including your style-sheets using a path relative to the web root. An easy way to do this in ASP .NET webforms is to use ~ on a server-side control eg.
<link rel="Stylesheet" type="text/css" href="~/Css/MyCssFile.css" runat="server" />
ASP.NET should then resolve the correct URL for you, regardless of what the URL is.
Well I looked a little further into it-- The "~" actually seems to be where the problem is occurring.
The links are working correctly but I think the server isn't parsing it correctly when it generates the relative paths...
Here is the css link from the generated code on a working link
../../CSS/Layout.css
Here is the css link on a broken page at the same depth
../../../CSS/Layout.css"
Here is a very ugly fix that works- not sure if there is a better way though
<link rel="stylesheet" type="text/css" href="<%=Request.ApplicationPath+"/Css/Layout.css" %>" />
The strange thing is that the navigation links generated from similar paths in the sitemap are working fine. Maybe it understands the full hierchy better when it is generating paths from the site-map and doesn't try to build a relative path.

Categories

Resources