2010-09-08

Visual Studio 2010: Dropped Assembly References Workaround

After adding some references to external assemblies like to NLog or Munq I found out that on some projects Visual Studio 2010 had a tendency to drop the reference to some of these assemblies.

After the usual searching of Google and Stackoverflow I've put together a combination of different solutions that seems to solve this issue.

  • Step 1: Expand your references and bring up the properties-window. Set Specific Version to True:
  • Step 2: Right click on the project and click Untload Project:
  • Step 3: Right click again on the project and click Edit ...csproject.
  • Step 4: Add an XML-element with the name SpecificVersion with the value True beneath the reference in question:
  • Step 5: Right click on the project and click Reload Project.

This works for me so far.

2010-09-01

Conditional Scrolling Banner with YUI

I was in need of a banner that would scroll along on the page, even when the user had scrolled passed it. After Googling with Bing for any done JavaScript to achieve this, I still only found plug-ins for different PHP-based CMS:es.

After spending almost as much time searching for something already built as it would have taken to build it, I did just that, I took matters into my own hands.

In my case I solved it with Yahoo's YUI 2, but you can do it just as well in any other Javascript-library, like jQuery.

<!-- Static banners above conditional scrolling one -->
<div id="scrollBanner" class="scrollBanner">
<!-- Image and/or flash-banners -->
<img src="Banner.gif" alt="Banner" />
</div>

What we need to do is to find the element to scroll in the DOM and find it's initial Y-position. Then we add a listener to the scroll-event and just flip the CSS-class of the element, depending if we've scrolled past it or not.

var scrollBanner = document.getElementById("scrollBanner");
// Initial banner Y-position
var bannerYPos = YAHOO.util.Dom.getY(scrollBanner);

YAHOO.util.Event.addListener(window, 'scroll',
    function() {
        var isBannerAboveScrollTop = (YAHOO.util.Dom.getDocumentScrollTop() > bannerYPos);
        var oldClassName = isBannerAboveScrollTop ? "scrollBanner" : "scrollBanner_fixed";
        var newClassName = isBannerAboveScrollTop ? "scrollBanner_fixed" : "scrollBanner";
        YAHOO.util.Dom.replaceClass(scrollBanner, oldClassName, newClassName);
    }
);

Just style your scrollingBanner_fixed-class with a fixed position and the width you want it to have. Adjust the top-setting to set how high up on the screen the scrolling banner should be. You could also use padding to make the scrolling-experience more smooth.

.scrollingBanner_fixed {
    position: fixed;
    top: 0px;
    width: 100px;
}

This code could of course also be used for good, to have some kind of toolbar that would scroll along on a page.

2010-08-04

Guidelines for URI Design

Jacob Gillespie has worked on a post concerning URL Guidelines, that underwent much revision and was posted as a guest post on CSS-Tricks named Guidelines for URI Design.

Clean URIs are one component of a clean website, and it is an important one. The majority of end-user access to the Internet involves a URI, and whether or not the user actually enters the URI, they are working with one nonetheless.

Here is an outtake of the general principles of the article:

  • A URI must represent an object, uniquely and permanently - The URI must be unique so that it is a one-to-one match – one URI per one data object.
  • Be as human-friendly as possible - URIs should be designed with the end user in mind. SEO and ease of development should come second.
  • Consistency - URIs across a site must be consistent in format. Once you pick your URI structure, be consistent and follow it!
  • “Hackable” URIs - Related to consistency, URIs should be structured so that they are intelligibly “hackable” or changeable.
  • Keywords - The URI should be composed of keywords that are important to the content of the page. So, if the URI is for a blog post that has a long title, only the words important to the content of the page should be in the URI.

When it comes to technical details, here are their concerned bullet-points:

  • No WWW - The www. should be dropped from the website URI, as it is unnecessary typing and violates the rules of being as human-friendly as possible and not including unnecessary information in the URI.
  • Format - Google News has some interesting requirements for webpages that want to be listed in the Google News results – Google requires at least a 3-digit unique number.
  • All lowercase - All characters must be lowercase. Attempting to describe a URI to someone when mixed case is involved is next to impossible.
  • URI identifiers should be made URI friendly - A URI might contain the title of a post, and that title might contain characters that are not URI-friendly. That post title must therefore be made URI friendly. [...] Spaces should be replaced with hyphens.

Scott Mitchell has written an article on 4GuysFromRolla.com about Techniques for Preventing Duplicate URLs in Your Website.

A key tenet of search engine optimization is URL normalization, or URL canonicalization. URL normalization is the process of eliminating duplicate URLs in your website. This article explores four different ways to implement URL normalization in your ASP.NET website.

The important subjects of this article are the following:

  • First Things First: Deciding on a Canonical URL Format - Before we examine techniques for normalizing URLs, and certainly before such techniques can be implemented, we must first decide on a canonical URL format.
  • URL Normalization Using Permanent Redirects - [...] when a search engine spider receives a 301 status it updates its index with the new URL. Therefore, if anytime a request comes in for a non-canonical URL we immediately issue a permanent redirect to the same page but use the canonical form then a search engine spider crawling our site will only maintain the canonical form in its index.
  • Issuing Permanent Redirects From ASP.NET - Every time an incoming request is handled by the ASP.NET engine, it raises the BeginRequest event. You can execute code in response to this event by creating an HTTP Module or by creating the Application_BeginRequest event handler in Global.asax.
  • Rewriting URLs Into Canonical Form Using IIS 7's URL Rewrite Module - Shortly after releasing IIS 7, Microsoft created and released a free URL Rewrite Module. The URL Rewrite Module makes it easy to define URL rewriting rules in your Web.config file.
  • Rewriting URLs Into Canonical Form Using ISAPI_Rewrite - Microsoft's URL Rewriter Module is a great choice if you are using IIS 7, but if you are using previous version of IIS you're out of luck.
  • Telling Search Engine Spiders Your Canonical Form In Markup - Consider a URL that may include querystring parameters that don't affect the content rendered on the page or only affect non-essential parts of the page.
    In the case of YouTube, all video pages specify a <link> element like so, regardless of whether the querystring includes just the videoId or the videoId and other parameters:
    <link rel="canonical" href="/watch?v=videoId">
    

2010-03-31

ASP.NET WebForms SEO: Compressing View State

In my previous post about Moving View State to Bottom of the Form I touched on one way to do some Search Engine Optimization in ASP.NET WebForms. Another thing you can do is to compress large View States on a page.

All the code in this article should be put in a class inheriting from System.Web.UI.Page. Like a page's Code-behind file or your own PageBase-class.

First we need some common logic for both loading and saving a compressed View State, the name of the hidden field to use.

private const string ViewStateFieldName = "SEOVIEWSTATE";

We start with the loading-part, where you see the use of my implementation of the CompressionHelper-class, which simplifies compression. It also solves the issue with DeflateStream and GZipStream inflating already compressed data, which is resolved in .NET Framework 4.

protected override object LoadPageStateFromPersistenceMedium() {
    return LoadCompressedPageState();
}

private object LoadCompressedPageState() {
    string viewState = Request.Form[ViewStateFieldName];
    if(string.IsNullOrEmpty(viewState)) {
        return string.Empty;
    }

    byte[] bytes = Convert.FromBase64String(viewState.Substring(1));

    bool isCompressed = Convert.ToBoolean(Convert.ToInt32(viewState.Substring(0, 1)));
    if(isCompressed) {
        bytes = CompressionHelper.Decompress(bytes);
    }

    string decompressedBase64 = Convert.ToBase64String(bytes);

    ObjectStateFormatter formatter = new ObjectStateFormatter();
    return formatter.Deserialize(decompressedBase64);
}

We then move on to the implementation of saving the page's state.

protected override void SavePageStateToPersistenceMedium(object state) {
    SaveCompressedPageState(state);
}

private void SaveCompressedPageState(object state) {
    byte[] viewStateBytes;
    using(MemoryStream stream = new MemoryStream()) {
        ObjectStateFormatter formatter = new ObjectStateFormatter();
        formatter.Serialize(stream, state);
        viewStateBytes = stream.ToArray();
    }

    byte[] compressed;
    bool successfulCompress = CompressionHelper.TryCompress(viewStateBytes, out compressed);
    string compressedBase64 =
        Convert.ToInt32(successfulCompress) + Convert.ToBase64String(compressed);

    ClientScript.RegisterHiddenField(ViewStateFieldName, compressedBase64);
}

So the summary is that this will compress the View State of an ASP.NET WebForms page, if the View State is large enough. Otherwise it will just keep it the way it is.

2010-03-30

ASP.NET WebForms SEO: Moving View State to Bottom of the Form

As we all know, SEO is very important for almost all sites and some of us are still stuck with sites based on ASP.NET WebForm. But there are still things you can do to optimize these sites.

Since Google and other search-engines only indexes X amount of KB of a page, you don't want half of that content to be meaningless View State (which you should TRULY understand by now).

One solution is to compress the View State, but in this article I will show you how to move it to the bottom of the Form-tag. To achieve the latter, I will use a HttpModule, which will intercept all requests to files served through ASP.NET in the IIS.

First we need to hook in to the BeginRequest-event to only intercept requests to .aspx-pages.

public class ViewStateSeoHttpModule : IHttpModule {
    public void Init(HttpApplication context) {
        context.BeginRequest += new EventHandler(BeginRequest);
    }

    private void BeginRequest(object sender, EventArgs e) {
        HttpApplication application = sender as HttpApplication;

        bool isAspNetPageRequest = GetIsAspNetPageRequest(application);
        if(isAspNetPageRequest) {
            application.Context.Response.Filter =
                new ViewStateSeoFilter(application.Context.Response.Filter);
        }
    }

    private bool GetIsAspNetPageRequest(HttpApplication application) {
        string requestInfo = application.Context.Request.Url.Segments.Last();
        bool isAspNetPageRequest = requestInfo.ToLowerInvariant().Contains(".aspx");
        return isAspNetPageRequest;
    }
    // [...]

What we do here is add a Reponse Filter which moves the View State to the bottom of the Form. I made this to an internal class called ViewStateSeoFilter.

internal class ViewStateSeoFilter : Stream {
    private string _topPageHiddenFields;
    private Stream _originalFilter;

    public ViewStateSeoFilter(Stream originalFilter) {
        _originalFilter = originalFilter;
    }

    public override bool CanRead { get { return true; } }
    public override bool CanSeek { get { return true; } }
    public override bool CanWrite { get { return true; } }
    public override long Length { get { return 0; } }
    public override long Position { get; set; }

    public override void Flush() {
        _originalFilter.Flush();
    }

    public override int Read(byte[] buffer, int offset, int count) {
        return _originalFilter.Read(buffer, offset, count);
    }

    public override long Seek(long offset, SeekOrigin origin) {
        return _originalFilter.Seek(offset, origin);
    }

    public override void SetLength(long value) {
        _originalFilter.SetLength(value);
    }
    public override void Close() {
        _originalFilter.Close();
    }

    public override void Write(byte[] buffer, int offset, int count) {
        byte[] data = new byte[count];
        Buffer.BlockCopy(buffer, offset, data, 0, count);
        string html = Encoding.Default.GetString(buffer);

        html = ExtractPageTopHiddenFields(html);
        html = InsertExtractedHiddenFields(html);

        byte[] outdata = Encoding.Default.GetBytes(html);
        _originalFilter.Write(outdata, 0, outdata.GetLength(0));
    }

    private string ExtractPageTopHiddenFields(string html) {
        int formStartIndex = html.IndexOf("<form");
        if(formStartIndex < 0) {
            return html;
        }

        int divStartOpenIndex = html.IndexOf("<div", formStartIndex);
        if(divStartOpenIndex < 0) {
            return html;
        }
        int divStartCloseIndex = html.IndexOf(">", divStartOpenIndex);
        int divStartLenght = divStartCloseIndex - divStartOpenIndex;
        int divEndOpenIndex = html.IndexOf("</div", divStartOpenIndex);
        int divEndCloseIndex = html.IndexOf(">", divEndOpenIndex);

        int divContentLength = divEndOpenIndex - divStartCloseIndex - 1;

        _topPageHiddenFields = html.Substring(divStartCloseIndex + 1, divContentLength);
        html = html.Remove(divStartOpenIndex, divEndCloseIndex - divStartOpenIndex + 1);
        return html;
    }

    private string InsertExtractedHiddenFields(string html) {
        if(string.IsNullOrEmpty(_topPageHiddenFields)) {
            return html;
        }

        int insertIndex = html.IndexOf("</form>");
        if(insertIndex > 0) {
            html = html.Insert(insertIndex, _topPageHiddenFields + Environment.NewLine);
            _topPageHiddenFields = null;
        }

        return html;
    }
}

One bonus is that it moves all available Hidden Input HTML-tags controlled by ASP.NET to the bottom of the Form-tag. It seems to skip the Hidden Input that handles EventValidation, which is a good thing, because ASP.NET seems to want this tag early in the Page Life Cycle.

2010-02-16

ASP.NET Request Paths Reference

I decided to write down and document for myself the different paths provided by ASP.NET, to get a grip on the subject and a reference to turn to.

The path I will be requesting is:
http://www.myurl.com/MyApplication/MyFolder/MyPage.aspx?QueryStringKey=QueryStringValue

This will be an ASP.NET-application named MyApplication in the IIS.

Request-reference

Here is the result returned by the Request-property of the page, which is a HttpRequest.

Request.ApplicationPath:
/MyApplication - Gets the ASP.NET application's virtual application root path on the server.

Request.AppRelativeCurrentExecutionFilePath:
~/MyFolder/MyPage.aspx - Gets the virtual path of the application root and makes it relative by using the tilde (~) notation for the application root (as in "~/page.aspx").

Request.CurrentExecutionFilePath:
/MyApplication/MyFolder/MyPage.aspx - Gets the virtual path of the current request.

Request.FilePath:
/MyApplication/MyFolder/MyPage.aspx - Gets the virtual path of the current request.

Request.Path:
/MyApplication/MyFolder/MyPage.aspx - Gets the virtual path of the current request.

Request.PathInfo:
- Gets additional path information for a resource with a URL extension.

Request.PhysicalApplicationPath:
C:\Visual Studio Projects\MyApplication\ - Gets the physical file system path of the currently executing server application's root directory.

Request.PhysicalPath:
C:\Visual Studio Projects\MyApplication\MyFolder\MyPage.aspx - Gets the physical file system path corresponding to the requested URL.

Request.RawUrl:
/MyApplication/MyFolder/MyPage.aspx?QueryStringKey=QueryStringValue - Gets the ASP.NET application's virtual application root path on the server.

Request.Url-reference

Then there is the property Request.Url that returns a System.Uri , with all its properties. This is an interesting thing to explore as well.

Request.Url.AbsolutePath:
/MyApplication/MyFolder/MyPage.aspx - Gets the absolute path of the URI.

Request.Url.AbsoluteUri:
http://www.myurl.com/MyApplication/MyFolder/MyPage.aspx?QueryStringKey=QueryStringValue - Gets the absolute URI.

Request.Url.DnsSafeHost:
www.myurl.com - Gets an unescaped host name that is safe to use for DNS resolution.

Request.Url.Host:
www.myurl.com - Gets the host component of this instance.

Request.Url.LocalPath:
/MyApplication/MyFolder/MyPage.aspx - Gets a local operating-system representation of a file name.

Request.Url.OriginalString:
http://www.myurl.com:80/MyApplication/MyFolder/MyPage.aspx?QueryStringKey=QueryStringValue - Gets the original URI string that was passed to the Uri constructor.

Request.Url.PathAndQuery:
/MyApplication/MyFolder/MyPage.aspx?QueryStringKey=QueryStringValue - Gets the AbsolutePath and Query properties separated by a question mark (?).

Request.Url.Query:
?QueryStringKey=QueryStringValue - Gets any query information included in the specified URI.

Request.Url.ToString():
http://www.myurl.com/MyApplication/MyFolder/MyPage.aspx?QueryStringKey=QueryStringValue - Gets a canonical string representation for the specified Uri instance.

Request also has the property Request.UrlReferrer which is of the type System.Uri and has the same properties as Request.Url. It has the following description: Gets information about the URL of the client's previous request that linked to the current URL.

2010-02-15

C# 4: Reflected Dynamics

In Scott Hanselman's blog-entry titled Back to Basics: C# 4 method overloading and dynamic types , Scott talks about method-overloads in C# 4 and the dynamic -keyword.

class Program {
    static void f(Int32 x) { }
    static void f(dynamic x) {}
    static void f(Int32 x, dynamic y) {}
    static void f(dynamic x, Int32 y) {}
    static void f(Int32 x, dynamic y, Int32 z) {}
    static void f(dynamic x, Int32 y, dynamic z) {}
    static void Main(string[] args) {
        f(10); // Works - obvious
        f(10, 10); // Ambiguous - obvious
        f(10, 10, 10); // Ambiguous - not so obvious - since it should be possible to resolve
    }
}

...the behavior is totally by design:

  • dynamic in method signatures doesn’t come into it: it behaves like System.Object does.
  • Given that, neither of the ternary signatures is better because each fits better than the other on some arguments (Int32 fits 10 better than object does)

The key point here, in bold, because it's significant is: having the type dynamic means "use my runtime type for binding".

It all becomes very clear when Reflector is used on the code. This loosens up some thought-patterns and makes it easier to really understand the dynamic -keyword.

Another way to look at this is with Reflector. This C# code:

static void f(Int32 x, dynamic y, Int32 z) {}

is essentially this, from a method signature point of view:

static void f(int x, [Dynamic] object y, int z) {}

and if there was a method that returned dynamic, it'd look like this:

[return: Dynamic]
        private static object GetCalculator() {}
    

2010-02-12

C# Coding Style Conventions

From the book Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries (2nd Edition).

I write this blog post as reference for myself and others. It's a summarized version of the chapter named 'C# coding style conventions' in above named book.

General Style Conventions

Brace usage

DO place the opening brace at the end of the preceding statement.

DO align the closing brace with the beginning of the line containing the corresponding opening brace, unless closing a single-statement block.

DO place the closing brace at the beginning of a new line.

if(someExpression){
    DoSomething();
}

CONSIDER single statement blocks that have braces that begin and end on the same line. Property accessors often use this style.

public int Foo{
    get{ return foo; }
    set{ foo = value; }
}

CONSIDER single accessor properties having all brackets on the same line.

public int Foo{ get { return foo; } }

DO place the closing brace on its own line, unless followed by an else, else if or while statement.

if(someExpression){
    do{
        DoSomething();
    } while(someOtherCondition);
}

AVOID omitting braces, even if the language allows it.

Braces should not be considered optional. Even for single statement blocks, you should use braces. This increases code readability and maintainability.

for(int i=0; i<100; i++){ DoSomething(i); }

There are very limited cases when omitting braces might be acceptable, such as when adding a new statement after an existing single-line statement is either impossible or extremely rare. For example, it is meaningless to add a statement after a throw statement.

if(someExpression) throw new ArgumentOutOfRangeException(...);

Another exception to the rule is braces in case statements. These braces can be omitted as the case and break statements indicate the beginning and the end of the block.

case 0:
    DoSomething();
break;

Space Usage

DO use one space after the opening and before the closing of braces.

public int Foo{ get{ return foo; } }

AVOID using space before the opening braces.

Preferred:  if(someExpression){
Acceptable: if(someExpression) {

DO use a single space after a comma between parameters.

Right: public void Foo(char bar, int x, int y)
Wrong: public void Foo(char bar,int x,int y)

AVOID using space between arguments.

Preferred:  Foo(myChar,0,1)
Acceptable: Foo(myChar, 0, 1)

AVOID using spaces after the opening or before the closing parentheses.

Preferred:  Foo(myChar,0,1)
Acceptable: Foo( myChar,0,1 )

DO NOT use space between a member name and opening parenthesis.

Right: Foo()
Wrong: Foo ()

DO NOT use spaces after or before the brackets.

Right: x = dataArray[index];
Wrong: x = dataArray[ index ];

DO NOT use spaces before flow control statements.

Right: while(x==y)
Wrong: while (x==y)

AVOID using space before and after binary operators.

Preferred:  if(x==y){ ... }
Acceptable: if(x == y){ ... }

DO NOT use space before or after unary operators.

Right: if(!y){ ... }
Wrong: if(! y){ ... }

Indent Usage

DO use 4 consecutive space characters for indents.

DO NOT use the tab character for indents

DO indent contents of code blocks.

if(someExpression){
    DoSomething();
}

DO indent case blocks even if not using braces.

switch(someExpression){
    case 0:
        DoSomething();
    break;
        ...
}

Other

CONSIDER using the var keyword whenever the resulting type of the variable is obvious. Avoid using it if it decreases readability.

var names = new List<string>(); // good usage of var

string source = GetSource();
var tokens = source.Split(' '); // ok; most developers know String.Split

var id = GetId(); // probably not good; it's not clear what the type if id is

Naming Conventions

In general, we recommend following the Framework Design Guidelines for naming identifiers. However, there are some additional conventions and exceptions to using the Framework Design Guidelines for naming internal and private identifiers.

DO follow the Framework Design Guidelines for naming identifiers, except for naming private and internal fields.

DO use PascalCasing for namespace, type, and member names, except for internal and private fields.

DO use camelCasing for private and internal fields.

DO use camelCasing for local variables.

DO use camelCasing for parameters.

DO NOT use Hungarian notation (i.e., do not encode the type of a variable in its name).

AVOID prefixing local variables.

DO use C# aliases instead of Framework type names. For example, use int instead of Int32 and object instead of Object.


Comments

Comments should be used to describe the intent, algorithmic overview, and logical flow. It would be ideal, if from reading the comments alone, someone other than the author could understand the function's behavior and purpose. Although there are no minimum comment requirements and certainly some very small routines need no commenting at all, it is desirable for most routines to have comments reflecting the programmer's intent and approach.

DO NOT use comments unless they describe something not obvious to someone other than the developer who wrote the code.

AVOID multiline syntax (/* --- */) for comments. The single-line syntax (// ...) is preferred even when a comment spans multiple lines.

DO NOT place comments at the end of a line unless the comment is very short.

//Avoid
public class ArrayList {
    private int count; // -1 indicates uninitialized array
}

File Organization

DO NOT have more than one public type in a source file, unless they differ only in the number of generic parameters or one is nested in the other.
Multiple internal types is one file are allowed.

DO name the source file with the name of the public type it contains. For example, String class should be in String,cs file and List<T> class should be in List.cs file.

DO organize the directory hierarchy just like the namespace hierarchy. For example, the source file for System.Collections.Generic.List<T> should be in the System\Collections\Generic directory.

CONSIDER grouping members into the following sections in the specified order:

  • All fields
  • All constructors
  • Public and protected properties
  • Methods
  • Events
  • All explicit interface implementations
  • Internal members
  • Private members
  • All nested types

DO use #region blocks around not publicly callable and explicit interface implementation groups.

#region internal members
...
#endregion
#region private members
...
#endregion

CONSIDER organizing members of each group in alphabetical order.

CONSIDER organizing overloads from the simplest to the most complex.

DO place the using directives outside the namespace declaration

using System;

namespace System.Collections{
    ...
}

Own additions

DO place namespaces that are not included in .NET Framework on their own separate lines below the .NET Framework namespaces and all in alphabetical order.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Xml;

using MyNamespace;
using MyNamespace.SubNamespace;
...