After looking at google analytics (ga) graphs all these months, I've come to the conclusion that if my site's ga graph were that of a stock/eft/etc I'd be a RICH dude. I'm guessing you'd be too since it's not a terribly new phenomenon; traffic or sales dropping off on the weekend. Akin to the turmoil on wall street, investors are often afraid to hold securities over the weekend. I don't blame them.
But really what do people do on the weekends? Beats me. I guess they don't read my blog! Granted it is somewhat technical-related. I don't read anyone's on the w/e either so whatev.
Ok, so here is the ga graph... (this is a snapshot from a month ago... by week)

I can assure you, this continues on for months...and months.... and months.
"So what does this all mean?" you ask. Well, in the next highly technically list, I will tell you the secret to becoming rich in this psuedo website exchange.
1. Know the future (which I clearly know regarding this site's traffic)
2. Buy / Cover low.
3. Sell / Short high.

Here I've clearly laid out the points for which actions should be taken! Depending on your strategy, buying, shorting or both (just not at the same time :)) you too can be richy!
happy trading.
If you're like me, and make all of your data-related html bits yourself because you want full control of its output or you enjoy micro optimization... read on.
You're doing your loop thing with your StringBuilder thing because your specs say all the data needs to be on the same page (no paging, more-data-as-you-scroll (or other ajax) [bad specs, eh? Or you're just doing it wrong].
You finally got your page finished, loaded and hot DAMN it's 950kb. That's CRAZY! You gotta do something about that! You'll definitely want to optimize the html that is created during the looping operation. You know, it looks something like this...
StringBuilder sb = new StringBuilder(); sb.Append("<table>"); for(int i=0; i<aZillion; i++) { sb.Append(@"<tr class=""oddTableDataRow""><td align=""center"" valign=""middle"">blah</td> <td class=""bottomBorderDarkest""><strong>zonk</strong></td></tr>"); } sb.Append("</table>");
Ok, so that was very simple. Obviously most cases are much more complicated, but still, it can be optimized. Some of these are general, others are very specific... some might not even be 100% html standards compliant. But hey, no one likes a slow loading page?
here we go:
· Make sure all css classes are actually used, and necessary.
· NO, I repeat, NO inline styles or style-like attributes. Everything should be done in your style sheet(s).
sb.Append(@"<tr><td width=""500"" align=""left"" valign=""top"">...);
· Use the smallest possible names for css classes, css ids, and javascript function names
Instead of id="header" use id=hdr
Instead of class="topBorderNew" use class=tbn
Instead of SomeJsFunctionThatIsPairedWithEachRow(); use s();
· If you have to make words 'stand out,' use <b> instead of <strong>, it's shorter
<b>a</b> = 8 characters.
<strong>a</strong> = 18 characters.
We're on an html diet, so sorry semantics!
· use <i> instead of <em>
(same logic as above)
· Use the innerHTML of a dropdown (<select>, rather than its value) (unless innerHTML and value are wildly different). <select> boxes are notorious for using up lots of Kbs.
· don't use double quotes (or any quotes for that matter).
<img src=image.jpg /> rather than <img src="image.jpg" />
<td class=blah> instead of <td class="blah">
· if you have lots of line breaks, use <br> instead of <br />
google does it all the time.
· limit the use of <span> tags
Use a parent container/selector to modify a would-be span-wrapped item.
· Don't use an 'odd' and an 'even' class for row highlighting.
Use one of them. You pick. (You could argue that this can easily be done client-side, but with large datasets you will notice the striping applied after the page is loaded.)
With some of these strategies, I turned a 950kb dynamically-generated page into 603kb page. That's a 36% savings! You could argue that, it's still pretty hefty, or most of this now can be done client-side, or hey "use a templating language" dumbo... but it isn't always an option.
$$cha-ching!$$

If you tried any of these and they worked for you, let me know how many kbs you saved! Or please give any of your own.
Is it me... or did today, about perhaps 2-3pm EST, google made all their fonts a tad bit smaller?
UPDATE: I'm a dumbsky :)
Really? Yeah you bet!
I usually just toss that junk snailmail from the cable/phone company, but this time, they made me a special deal with part of my name in the url! We'll call this company pomcast (no disrespect to the real pomcast.com). I couldn't resist.
Something like http://www.mypomcastsavings.com/MYNAMEHERE0321... (like that sort of dynamic url has never been done before. dumbskys).
So in my clicking around the site specifically made for me and all my bundled needs, i noticed a nifty little savings calculator!
Since I don't have cable (minus the ~8 channels that comes with my internet), I entered $59.00 for internet and $0.00 for telephone (mobile phone is all I need)...

And look at my savings...

that's right, $-7.00. I would have the amazing privilege of paying them more per month for a service completely useless to me! HOT.
Not a terribly great marketing tactic.
You have a data-driven site and you like to keep the number of .aspx files to a minimum, so you opt for UserControls. Ok cool!
Something you can do to be more dynamic-y is to name a UserControl the same as the requesting url, then check its existence on PageLoad. If it exists, load it into an asp:PlaceHolder control (or some other control). This can help keep your site more modular, and perhaps increase the chances that you'll reuse a UserControl in another project...or not.
Here the UserControls are stored in the /UserControls/dynamic folder on my site.
In your aspx page, we make an asp:PlaceHolder...
<asp:PlaceHolder ID="PHUserControls" runat="server"></asp:PlaceHolder>
And in code behind, on PageLoad... we make the path of the UserControl and see if it exists. If it does, we add it to the placeholder.
string path = AppDomain.CurrentDomain.BaseDirectory + "UserControls\\dynamic\\" + PageUrl + ".ascx"; if (File.Exists(path)) { Control c = LoadControl("~/UserControls/dynamic/" + PageUrl + ".ascx"); PHUserControls.Controls.Add(c); }
Extension methods have been around since C# 3.0 came out, which I guess was some time ago. I really like using them. The syntax is short and neat. Notice how the example below lives in a static class. Nutty eh!?
This example is for all you foos out there that might not be checking input before it's passed down into the database. It checks the input string for null/empty and if there's something, it will replace a single quote with two single quotes (since the single quote is arguably the most devastating character in user inputs / SQL inserts)
public static class StringUtils { public static string ToSafeSql(this string s) { return (s == null || s.Trim().Length == 0) ? "" : s.Replace("'", "''"); } }
So, I totally dig pre-processor directives. Use them all the time. Do you? I hope so! It can make a Debug build ready for a Release build with the change of a dropdown in Visual Studio.
Here's an example to change the logPath string if you're building in Debug mode (or anything else). This could be very handy with programmatically creating a log4net config.
string logPath; #if DEBUG logPath = @"C:\csharptocsharp.com\log.txt"; #else logPath = @"Q:\sites\csharptocsharp.com\logs\log.txt"; #endif
Anyway, if you're not using preprocessor directives in your code, then what are you waiting for?
Other References:
MSDN Preprocessor directives
So in my first Log4Net Config post a weee time back, I talked about a hot way to configure your log4net settings using a composite, rolling logging model.
Here, I have that same log4net config, but done in code! It doesn't have the same flexibility of the web.config or an xml file if you're frequently changing values--since you'd have to push code for any changes--but it does make any logic easier.
It begs the usage of preprocessor directives for setting File [location], PatternLayout, or Threshold.
log4net.Appender.RollingFileAppender a = new log4net.Appender.RollingFileAppender(); a.Name = "RollingFileAppender"; a.File = @"c:\blah.com\log.txt"; a.AppendToFile = true; a.RollingStyle = log4net.Appender.RollingFileAppender.RollingMode.Composite; a.MaxSizeRollBackups = 14; a.CountDirection = 1; a.MaximumFileSize = "15000KB"; a.StaticLogFileName = true; a.Layout = new log4net.Layout.PatternLayout(@"{%level}%date{MM/dd HH:mm:ss} - %message%newline"); a.ActivateOptions(); a.Threshold = log4net.Core.Level.Debug; log4net.Config.BasicConfigurator.Configure(a);
(Thanks to my buddy J.A. for showing me this).
One of the things I learned at DevConnections 08 is the magic behind ASP.NET MVC, and how it actually works. Beside the UrlRouting (which you can do with HttpModule stuff), it's pretty easy and relies a lot on Activator.CreateInstance(). As seen in my post about creating a csv from list, you can read about it here.
The magic is...shhh...
|
![]() |
Yeah, no-DUH you say. Well it took MS this long to come up with it for public consumption when MVC has been around for decades. Anyhooo.
NOTE: I'm more of an MVP guy, so this is geared toward using the MVP's Presenter rather than the MVC's Controller. They're similar patterns, 'cept MVP is a bit more decoupled (and deprecated...), so in my example below, you can replace 'Presenter' with 'Controller' if it makes you fuzzy, because really, that's where all the work gets done.
Here we go.
A request comes in for blah.com/hotguitars.aspx. Your UrlRouting can match the url up with the correct view [handler] and rewrite its path to that page handler. In this case, I'd most likely use the DefaultView since the page lives off of the root (/).
On PageLoad the presenter factory is going to take the url and try to figure out which class to instantiate [return] to make the contents for the view. Each of the classes returned implement Presenter, which implements IPresenter... so I can code to the interface, which is nicer. (Notice the interfaces. I'm an interface kinda dude, because they're hot when it comes to testing).
Ok, so here's the little POC for you.
// Presenter class implements this because all *Presenter // classes need to have a DoIt() method public interface IPresenter { void DoIt(); } public class Presenter : IPresenter { public Presenter() { } public virtual void DoIt() { } } public class PresenterFactory { //return the url minus hyphens private static string GetPresenterName(Regex re, string url) { return re.Match(url).Groups[1].Value.Replace("-",""); } //get the url private static Regex rePage = new Regex(@"/(.+?)\.aspx", RegexOptions.IgnoreCase);
This is the sexiness....
public static Presenter GetPresenter(Page page) { // this is blah.com/hotguitars.aspx string rewrittenUrl = page.Request.RawUrl; string presenterName = GetPresenterName(rePage, rewrittenUrl); //here is where you make sure you have a HotGuitarsPresenter string className = "BunchaJunk.Presenters." + presenterName + "Presenter"; // get the type, throw error, and ignore case Type type = Type.GetType(className, true, true); // create an instance of the correct Presenter/Controller and return it return (Presenter)Activator.CreateInstance(type, new object[] { page }); } } public interface IBasicPage { string HtmlTitle { get; set; } string HtmlMetaKeywords { get; set; } string HtmlMetaDescription { get; set; } string MainContent { get; set; } } public class HotGuitarsPresenter : Presenter { private IBasicPage ibp; public HotGuitarsPresenter(IBasicPage ibp) { this.ibp = ibp; } public override void DoIt() { ibp.HtmlMetaDescription = "Hot stuff!"; ibp.HtmlMetaKeywords = "jackson, paul reed smith"; ibp.HtmlTitle = "Here are the hottest guitars at csharptocsharp!"; ibp.MainContent = "paul reed smith, jackson, gibson"; } }
Here is how it is called from aspx code behind
public partial class _Default : Page, IBasicPage { protected void Page_Load(object sender, EventArgs e) { //coding to the interface is the cat's meoooooooooooow IPresenter p = PresenterFactory.GetPresenter(this); p.DoIt(); } public string HtmlTitle { get; set; } public string HtmlMetaKeywords{get;set;} public string HtmlMetaDescription { get; set; } public string MainContent{get;set;} }
Here is how it's used in the aspx
<title><%=HtmlTitle%></title>
Since I'm a .NET dude, you might find this post a wee bit odd, because, I should worship MS, right?... well I don't :), so in any case...

Hokay. So...
I recently made the jump to be *that* much closer to an all-unix setup [at home]. I've had my macbook now for about a year, and it's totally dope, I love it. In fact, I just got 4 gigs of ram for $35 beans from newegg.com.
The reason why I got that hot upgrade was because of the VMWare Fusion trial I had just decided to checkout.
Now, I'm very familiar with VMWare and its hotness. I used VMWare server on Ubuntu for some years as a way to tinker with a bunch of Unix and Linux OSes.
After DLing and messing around with it out for some time, (I used it at DevConnections Vegas 08) I knew that hog had to be mine! After turning my boot camped-Vista-partition into a virtual machine I soon realized that it was worth every penny. Twas always such a pain to have to reboot just to tinker with some idea in Visual Studio for five minutes. Just need to find a replacement for Texter (Spotlight is a great replacement for Launchy).
On that note.... a couple weeks ago I setup my older ASUS Pundit-R barebones machine to run the latest version of Ubuntu (8.10 as of today)... and it flies. With a P4 chip, 1 gig of ram, and some low-end NVidia card, it's totally acceptable for doing most webby stuff. I haven't rally monkeyed with Ubuntu since Dapper/Edgy, but I can say it has come a long way since I started w/Hoary.

















