Tuesday, 27 December 2011

Git .gitignore entries on a Mac

Note to self. Don't forget to add .DS_Store to the Git ignore file when creating a new repository!

Tuesday, 6 December 2011

Throttle network speed on a Mac

I've often needed to throttle my bandwidth to replicate a slow connection. This is often useful when building mobile sites or when using ajax and you want to see how your loader message is behaving. On my PC I use Netlimiter which is very intuitive and configurable. You can specify precise speeds for different bandwidth consumers on your machine, and you can also specify different upload and download speeds.

You can't get Netlimiter for Mac, but there is a simple way of throttling your bandwidth. Simply type this into your terminal to limit your bandwidth to 20 kilobytes per second:
sudo ipfw pipe 1 config bw 20KByte/s
sudo ipfw add 100 pipe 1 src-port 80
When you're done, be sure to delete the rule:
sudo ipfw delete 100
sudo ipfw flush
which will delete all custom rules.

Monday, 28 November 2011

Putting SEO advice into context

I've been building websites since 1996, which is almost as long as is possible. I've seen the advent of modern-day SEO and witnessed it mature into a serious and valuable discipline in its own right.

SEO is a good thing. Get it right (SEO services Bristol) and it can reap rewards. Ignore it and you'll be throwing money down the drain on your new site.

I've been at the sharp end of several debates between technicians and SEOs adjudicated by account managers doing the best they can to do the best thing for their client. They often pan out like this:
  • SEO: I think we should be doing XYZ to this site because it will improve ranking
  • Tech: OK, cool, we've looked into it and it could take up to 2 days to implement
  • AM: Oh that's a bit expensive
  • Tech: Where did you learn about XYZ? Can we quantify for the client how much benefit this will have?
  • SEO: I read it on seo-speculation.com. Apparently it's really important for the Google algorithm.
  • Tech & AM: How important?
  • SEO: Very
  • Tech & AM: Really?
  • SEO: Yes
And so AM and Tech are left with a 'demand' from SEO for which they (SEO, through no fault of their own) have found impossible to quantify the benefits. Nobody's arguing that there won't be any benefit, but nobody can say how much. The deciding factor always seems to be the threat that the client might have their site prodded and poked by other agencies or specifically SEO consultants who could highlight the lack of XYZ as evidence of ineptitude. In all of this to-ing and fro-ing, the client may not have been consulted.

Many blogs about SEO by SEOs are full of what seem like theories and speculation about the search engine algorithms, that appear to lack quantification or qualification. Evidence is often scant and anecdotal. I'm not saying SEOs should do their job differently - they can't, they're operating in a speculative, theoretical, anecdotal, iterative, experimental world as long as search engines keep their algorithm under wraps, which of course will be forever.

We should instead put SEO advice into context. We should be open with clients about the fast-moving world of SEO so that when new techniques arise we discuss with them the costs and speculate with them about the benefits. Make it the client's decision, and if they say 'no' we remember this. And when a few months down the line they call up and say that an independent SEO expert has spotted failings their site we remind them that they chose not to get their cheque book out.

Monday, 21 November 2011

Sharepoint site running under multiple URLs

I needed to make our dev site run under a further URL today, and it really wasn't obvious how this is done. I got it working in the end, here's the screen snaps:

And, don't forget to add it as a host header in IIS too...yes you have to do this manually!

Friday, 18 November 2011

System.Configuration configurationmanager reference

Note to self. Today I tried to use System.Configuration to access configurationmanager. I had 'using System.Configuration' at the top of my class and Visual Studio seemed happy with this.....until compilation time.

It turned out that I needed to add System.Configuration as a project reference too.

Tuesday, 18 October 2011

SPMetal and workflows - excluding columns and content types

<web xmlns="http://schemas.microsoft.com/SharePoint/2009/spmetal"> 
<list name="My List Name">
 <contenttype name="My Content Type Name">
      <excludecolumn name="ColumnName">

Friday, 16 September 2011

British pound Sterling sign (£) in xml causes error

British pound Sterling sign (£) in xml causing an error? Try this:

<?xml version="1.0" encoding="ISO-8859-1"?>

Thursday, 15 September 2011

Using a custom task list template for a Workflow task list

In Visual Studio I created a custom content type, a custom task list template and a custom list instance using the template, but couldn't get this list to appear in the task list when trying to add a new Workflow in the SharePoint UI.

The problem turned out to be my use of the wrong value for the 'Type' attribute of the <ListTemplate> element in my list definition. When creating a workflow you are only able to select task lists with Type="107". The Elements.xml file should look some like this:

        DisplayName="Custom Tasks"
        Description="Custom Tasks"

Monday, 12 September 2011

SharePoint base content type ID list

Workflow History0x0109
East Asia Contact0x0116

Wednesday, 7 September 2011

Specifying a namespace in SPMetal generated entities files

Today I generated two entities.cs files using SPMetal without specifying namespaces, and was met with a whole host of ambiguity errors, such as
Ambiguity between 'Item._entityState' and 'Item._entityState'
Deleting my files and re-running SPMetal, this time specifying different namespaces for each file, resolved the problem:
SPMetal /web:http://mysite/myweb /code:C:\Projects\MyProject\MyEntities.cs /namespace:MyExampleNamespace

Thursday, 14 July 2011

How to determine if your 'Assigned To' field contains user(s) or group(s)

public override void ItemAdded(SPItemEventProperties properties)
 // Check that the item has been assigned to someone and that the ListItem isn't an empty one.
 if (properties.AfterProperties["AssignedTo"] != null && properties.ListItem.Name != null)
  this.EventFiringEnabled = false;

  SPFieldUserValue field = new SPFieldUserValue(properties.Web, properties.AfterProperties["AssignedTo"].ToString());

  // Test for a user or group value (null indicates a group)
  if (field.User != null)
  this.EventFiringEnabled = true;

Friday, 1 July 2011

A deployment or retraction is already under way for the solution

Find job like this:
C:\Program Files\Common Files\Microsoft Shared\web server extensions\14\BIN>stsadm.exe -o enumdeployments
Cancel it like this:
C:\Program Files\Common Files\Microsoft Shared\web server extensions\14\BIN>stsadm.exe -o canceldeployment -id "jobId"

Wednesday, 22 June 2011

Using comma-delimited lists in SQL searches

Today I wanted to run a search against a comma-delimited list of values, a little like this:
Select name from People Where category IN ('N,S,L,C')
I wanted the comma-delimited list to be set as a parameter value in a stored procedure. However, the IN operator cannot accept a comma-delimited string. It only accepts comma-delimited constants or the results of a SQL query.

Eventually I found this excellent solution on the 4 Guys site. It shows you how to build a UDF (user-defined function) that will split a comma-delimted string into a recordset representation, and then how to make use of it. It's a neat and effective solution.

Wednesday, 8 June 2011

Language code

The following table lists all the possible language codes used to specify various system settings.

afAfrikaans sqAlbanian
ar-saArabic (Saudi Arabia) ar-iqArabic (Iraq)
ar-egArabic (Egypt) ar-lyArabic (Libya)
ar-dzArabic (Algeria) ar-maArabic (Morocco)
ar-tnArabic (Tunisia) ar-omArabic (Oman)
ar-yeArabic (Yemen) ar-syArabic (Syria)
ar-joArabic (Jordan) ar-lbArabic (Lebanon)
ar-kwArabic (Kuwait) ar-aeArabic (U.A.E.)
ar-bhArabic (Bahrain) ar-qaArabic (Qatar)
euBasque bgBulgarian
beBelarusian caCatalan
zh-twChinese (Taiwan) zh-cnChinese (PRC)
zh-hkChinese (Hong Kong SAR) zh-sgChinese (Singapore)
hrCroatian csCzech
daDanish nlDutch (Standard)
nl-beDutch (Belgium) enEnglish
en-usEnglish (United States) en-gbEnglish (United Kingdom)
en-auEnglish (Australia) en-caEnglish (Canada)
en-nzEnglish (New Zealand) en-ieEnglish (Ireland)
en-zaEnglish (South Africa) en-jmEnglish (Jamaica)
enEnglish (Caribbean) en-bzEnglish (Belize)
en-ttEnglish (Trinidad) etEstonian
foFaeroese faFarsi
fiFinnish frFrench (Standard)
fr-beFrench (Belgium) fr-caFrench (Canada)
fr-chFrench (Switzerland) fr-luFrench (Luxembourg)
gdGaelic (Scotland) gaIrish
deGerman (Standard) de-chGerman (Switzerland)
de-atGerman (Austria) de-luGerman (Luxembourg)
de-liGerman (Liechtenstein) elGreek
heHebrew hiHindi
huHungarian isIcelandic
idIndonesian itItalian (Standard)
it-chItalian (Switzerland) jaJapanese
koKorean koKorean (Johab)
lvLatvian ltLithuanian
mkMacedonian (FYROM)msMalaysian
mtMaltese noNorwegian (Bokmal)
noNorwegian (Nynorsk) plPolish
pt-brPortuguese (Brazil) ptPortuguese (Portugal)
rmRhaeto-Romanic roRomanian
ro-moRomanian (Republic of Moldova) ruRussian
ru-moRussian (Republic of Moldova) szSami (Lappish)
srSerbian (Cyrillic) srSerbian (Latin)
skSlovak slSlovenian
sbSorbian esSpanish (Spain)
es-mxSpanish (Mexico) es-gtSpanish (Guatemala)
es-crSpanish (Costa Rica) es-paSpanish (Panama)
es-doSpanish (Dominican Republic) es-veSpanish (Venezuela)
es-coSpanish (Colombia) es-peSpanish (Peru)
es-arSpanish (Argentina) es-ecSpanish (Ecuador)
es-clSpanish (Chile) es-uySpanish (Uruguay)
es-pySpanish (Paraguay) es-boSpanish (Bolivia)
es-svSpanish (El Salvador) es-hnSpanish (Honduras)
es-niSpanish (Nicaragua) es-prSpanish (Puerto Rico)
sxSutu svSwedish
sv-fiSwedish (Finland) thThai
tsTsonga tnTswana
trTurkish ukUkrainian
urUrdu veVenda
viVietnamese xhXhosa
jiYiddish zuZulu

Sunday, 29 May 2011

Rubymine Ruby on Rails IDE makes me feel more at home

Working without an IDE makes me shudder at the memory of my days coding PHP in BBEdit, and then classic ASP using some other win-based text editor whose name escapes me. Since moving into C#.NET I've led a privileged life of code completion, syntax checking, snippets, and a multitude of other killer-functionality that makes me highly productive and feel warm and fuzzy inside.

So it's of some surprise to me that a good proportion of the Ruby on Rails community appear to favour text editors (such as TextMate) and command-line activity to an IDE. It may be due to old-skool stubbornness, like one of my colleagues whose core job is javascript development, yet he uses a simple text editor without even any syntax colouring...yikes. It could be lack of choice, but when I recently installed Rubymine I breathed a deep sigh of relief, and could see that me and RoR could get on well together.

On first appearances, and having read reviews, it seems to do everything I'd want of an IDE and the productivity gains it will provide are well worth the small license fee. I have little doubt I'll be buying it after my 30 day trial.

Wednesday, 18 May 2011

Iterate through a SharePoint list (SPList)

SPList list = web.Lists["TestTasks"];
SPListItemCollection listItems = list.Items;

foreach (SPListItem item in listItems)
//do stuff

Determine if your SPFieldUserValue is a user or group

SPFieldUserValue field = new SPFieldUserValue(web, item["AssignedTo"].ToString());

 // Test for a user or group value (null indicates a group)
      if (field.User != null)

Thursday, 12 May 2011

IIS .NET globalization settings affecting date displays

I had a strange problem today - a site I recently deployed to live from my local dev environment was displaying dates in American formay (mm/dd/yyyy), yet when running locally it was fine (dd/mm/yyyy). At first I thought I must have had the wrong default language for the db user, but everything was as it should be.

Later I discovered that the live website in IIS had a culture setting of "Invariant Language (Invariant Country)". Changing this to "English (United Kingdom) (en-GB)" resolved the problem. It adds an entry to the system.web entry your web.config like so:

globalization culture="en-GB"

I don't recall ever having to do this before, and this entry isn't present in my local webconf, but it's one I'll look out for in the future.

Tuesday, 10 May 2011

Community Kit for SharePoint

"The Community Kit for SharePoint: Development Tools Edition extends the Visual Studio 2010 SharePoint project system with advanced templates and tools. Using these extensions you will be able to find relevant information from your SharePoint environments without leaving Visual Studio. You will have greater productivity while developing SharePoint components and you will have greater deployment capabilities on your local SharePoint installation."


Thursday, 5 May 2011

Setting up SharePoint - note to self

Setting up a new SharePoint installation today on a virtual machine, and I came across a couple of problems that will probably repeat themselves next time.

First off, I never set up a password for my Win Server 2008 account. This was later to cause problems with the subsequent SharePoint installation. In the end I uninstalled SharePoint, setup a password for the user, then started again.

Secondly, Network Discovery and File and Printer in Win Server 2008 sharing was off by default, meaning I couldn't browse to my SharePoint sites across the network. Switching these on resolved the issue.

Tuesday, 22 March 2011

Profiling, measuring and analysing your Entity Framework code

I love the Entity Framework. Most recently I've been using the model-first approach which allows me to not think too much about databases at all. And despite a few problems with the Migration SQL produced (or rather sometimes not produced) by the Database Generation Power Pack, and some sceptical colleagues, I'm firmly pro-EF.

I'll happily admit that I've yet to use it for a high-demand or high-traffic application, meaning I haven't had to spend too much time considering performance, but running the Entity Framework Profiler from Hibernating Rhinos has proved to be enlightening, revealing some non-optimal queries in my recent projects and gently advising how I might make them better!

It's a doddle to install and use and I have little doubt that it'll come in very handy for some of my imminent projects; I'll be encouraging the people I work with to invest in a license when my trial has ended.

Thursday, 10 March 2011

Unable to evaluate expression because the code is optimized or a native frame is on top of the call stack

I got this error when using Response.Redirect in a Try-Catch. I'd never seen it before, but it is resolved by specifying 'false' after the URL like below. This tells the execution of the current page not to terminate:


Wednesday, 9 March 2011

Redirect users on login according to membership roles

If you wish to send membership users to different locations according to their role, then intervene at the LoggedIn event on your login page like so:

protected void Login1_LoggedIn(object sender, EventArgs e)
if (string.IsNullOrEmpty(Request.QueryString["ReturnUrl"]))
  // User.IsInRole won't work here here
  if (Roles.IsUserInRole(LoginUser.UserName, "SysAdmin"))
  else if (Roles.IsUserInRole(LoginUser.UserName, "Owner"))

Output XML from aspx page

Response.ContentType = "text/xml; charset=utf-8";

string myXML="" +
   "<book id=\"book1\">"+
      "<author>Pitt, Ed</author>"+
      "<title>Another Programming Book</title>"+


Monday, 7 March 2011

IE8 bug - image max-width and table cells

In a very recent post I described a way to limit image sizes using max-width and max-height. Unfortunately a problem developed with this in IE8 when the images were being displayed in a table. The images would resize correctly, but the table cell wouldn't.

A work-around for the bug was quickly found...
img.myImage { max-width: 100px; max-height: 100px; }
div.imageWrapper { width: 110px;  }
<div class="imageWrapper">
     <img src="images/blah.jpg" class="myImage" />

...thanks to my esteemed front-end colleagues and this post from Jon Jungman.

Microsoft encouraging IE6 demise

Microsoft have launched a website ie6countdown.com to encourage and map the shift away from IE6, the bane of web developers around the world. "We know that web developers are spending too much time supporting Internet Explorer 6. We understand, and we're here to help. Join us in moving Internet Explorer 6 users to a modern browser", they say.

This is great news and not a moment too soon. Having the endorsement of Microsoft behind you when you explain to clients that really nobody should be using IE6 carries great weight.

I hope this campaign is a success, and I expect to be seeing (errr, if I was using IE6) this banner on many big-brand sites very soon:

Thursday, 3 March 2011

Setting a maximum image height or width using max-wdth and max-height

I've been building a simple image library for a content management system and part of it requires the listing of images with thumbnails displayed. The image dimensions are highly variable, and so I needed to some way to display the image at its natural size and aspect ratio, but to limit both dimensions so large images couldn't upset the way the list appears.

I used this style setting at the top of my page, imposing the limits on all <img> elements. Naturally this could be made more specific, but this suited me fine.

img {
max-width: 100px;
max-height: 100px;
/* Resize the image for IE6 */
width: expression(this.width > 100 ? 100: true);
height: expression(this.height > 100 ? 100: true);

Tuesday, 15 February 2011

jQuery Colorbox - resizing iframe to match content

The designers and HTMLers I work with are a pernickety bunch, and rightfully so. Quite often they want a lightbox-type overlay for a form that can vary in size depending on what selections the user makes in the form, and when the form is submitted a small thank you message is displayed. They want the overlay to resize itself when the content changes.

Until recently we were using colorbox with divs, not iframes, as there was seemingly no way of resizing the iframe to match content. The knock-on effect of this was a whole heap of trouble trying to avoid postbacks of the overlay content as the parent page would postback too.

Using an iframe would make things so much easier technically as we could postback all we wanted in our overlay, opening up the opportunity for server-validation, pagination, file uploading etc, without posting back the parent page. And so it was that I looked into iframe resizing.

I achieved this using colorbox v1.3.9, and assume it works on later versions. Working code is available on my github here. In summary, drop this code into your jquery.colorbox.js file just before the publicMethod.resize function:
publicMethod.myResize = function (iW, iH) { 
 if (!open) { return; }
 if (settings.scrolling) { return; }
 var speed = settings.transition === "none" ? 0 : settings.speed;
 $window.unbind('resize.' + prefix);
 settings.w = iW;
 settings.h = iH;
 $loaded.css({ width: settings.w, height: settings.h });

And then in your iframe content page use the following:

jQuery(document).ready(function (){
 jQuery(window).bind("load", function () {
 var frameWidth = jQuery(document).width();
 var frameHeight = jQuery(document).height() + 20;
 parent.$.fn.colorbox.myResize(frameWidth, frameHeight);
This solution was adapted from a post found on the Google colorbox group.

Friday, 11 February 2011

Escaping a curly bracket in string.format

This doesn't work because the curly brackets (or braces) aren't escaped:
newStr = string.Format("{Hello {0}, in curly braces}", yourName);
Do we need to escape the brackets with a backslash like this? No, it doesn't work:
newStr = string.Format("\{Hello {0}, in curly braces\}", yourName);
Seems strange, but you need to escape your curly brackets with another one like, this:
newStr = string.Format("{{Hello {0}, in curly braces}}", yourName);

Monday, 31 January 2011

Once-per-session javascript

Want to run some javascript only once per session? Here's some code, not written by me, that does the trick:

// ++++++++++++++++++++++++++++++++++++++++++ 
// Run Once Per Session 
// Replace the alerts by functions that need to 
// be run once per session. 
// Written by: Michael Regan 
// Website   : www.owt4nowt.ca 
// Released under the GPL. 
// ++++++++++++++++++++++++++++++++++++++++++ 
var key_value = "myTestCookie=true"; 
var foundCookie = 0; 

// Get all the cookies from this site and store in an array 
var cookieArray = document.cookie.split(';'); 

    // Walk through the array 
    for(var i=0;i < cookieArray.length;i++) 
               var checkCookie = cookieArray[i]; 
        // Remove any leading spaces 
               while (checkCookie.charAt(0)==' ') 
                 checkCookie = checkCookie.substring(1,checkCookie.length); 
        // Look for cookie set by key_value 
                if (checkCookie.indexOf(key_value) == 0) 
                  alert("Found Cookie "); 
            // The cookie was found so set the variable 
                   foundCookie = 1; 
    // Check if a cookie has been found 
    if ( foundCookie == 0) 
        // The key_value cookie was not found so set it now 
        document.cookie = key_value; 
        alert("Setting Cookie"); 

Wednesday, 26 January 2011

Adding a 3rd party cookie using an image as Response.ContentType

I've been working on a bit of tracking code that can be dropped onto websites so that we can record and analyze visitor data and resolve issues regarding conversion origins, particularly regarding PPC vs affiliate traffic. There are a few techniques, but this one in particular uses .net code to perform some logic (database calls etc) prior to placing a cookie and then responding to the browser as though it is an image:
//prepare the cookie
HttpCookie trackingCookie = new HttpCookie(cookie_name, cookie_value);
 trackingCookie.Expires = DateTime.Now.AddMonths(1);

//this line is a 'compact privacy policy' for IE
HttpContext.Current.Response.AddHeader("p3p", "CP=\"IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT\"");   

//drop tracking cookie
//Write image
string loc = Server.MapPath("/img/track.gif");
Response.ContentType = "image/gif";

The js code to initiate it, placed in the host website:


where the javascript value trackingData is populated by clientside code included (before the above code) like so:

This is some simple javascript that grabs the utm_source, utm_campaign (etc..) values from the URL and puts them into the value of trackingData.

Using this technique we can use specific cookie names and values to provide persistence between visitor sessions and to record and analyze their origins.

Tuesday, 25 January 2011

IE8 Developer Tools - Could not get cookie information

Has your developer tools suddenly stopped showing you cookie information with the following error:
Could not get cookie information.
You can fix it by doing the following:
Tools > InternetOptions > General > BrowsingHistory > Delete > Cookies and Temporary Files

Thursday, 20 January 2011

Trouble with Darren Johnstone asp.net file upload module

I'd used Darren Johnstone's brilliant file upload module before now, but I thought I'd take a look at SWFUpload just to see what it was like. I found SWFUpload a little too unintuitive to implement, so given my shortage of time I resorted back to the old faithful aforementiond DJFileUpload.

But this time round I just couldn't get it to work. I downloaded the sample C# project and that worked. I drafted all the relevant code into my own project but it still wouldn't work. I spent a long time trying to work out what was different between my project and the sample that worked. Was it because I was using VS2010 with .Net 4.0? What about some kind of permissions problem on my project?

Eventually I found the problem. While trying out SWFUpload I'd added the following code to my Global.asax file. This same code makes Darren Johnstone's file uploader no longer work! Remove it, and hey presto:

void Application_BeginRequest(object sender, EventArgs e)
            /* Fix for the Flash Player Cookie bug in Non-IE browsers.
             * Since Flash Player always sends the IE cookies even in FireFox
             * we have to bypass the cookies by sending the values as part of the POST or GET
             * and overwrite the cookies with the passed in values.
             * The theory is that at this point (BeginRequest) the cookies have not been read by
             * the Session and Authentication logic and if we update the cookies here we'll get our
             * Session and Authentication restored correctly

                string session_param_name = "ASPSESSID";
                string session_cookie_name = "ASP.NET_SESSIONID";

                if (HttpContext.Current.Request.Form[session_param_name] != null)
                    UpdateCookie(session_cookie_name, HttpContext.Current.Request.Form[session_param_name]);
                else if (HttpContext.Current.Request.QueryString[session_param_name] != null)
                    UpdateCookie(session_cookie_name, HttpContext.Current.Request.QueryString[session_param_name]);
            catch (Exception)
                Response.StatusCode = 500;
                Response.Write("Error Initializing Session");

                string auth_param_name = "AUTHID";
                string auth_cookie_name = FormsAuthentication.FormsCookieName;

                if (HttpContext.Current.Request.Form[auth_param_name] != null)
                    UpdateCookie(auth_cookie_name, HttpContext.Current.Request.Form[auth_param_name]);
                else if (HttpContext.Current.Request.QueryString[auth_param_name] != null)
                    UpdateCookie(auth_cookie_name, HttpContext.Current.Request.QueryString[auth_param_name]);

            catch (Exception)
                Response.StatusCode = 500;
                Response.Write("Error Initializing Forms Authentication");

Friday, 14 January 2011

Configuring SMTP on new Win 2008 server

I just spent far too long trying to get this to work, so this is a note-to-self so I don't re-invent the wheel next time.

Open Server Manager and add the feature 'SMTP'. Go with all the defaults. This will include the required IIS6.

Go to IIS6 and then setup the SMTP server thus:

In IIS7 configure the SMTP E-mail of the website thus:

Friday, 7 January 2011

Create a new Guid

Here's how you create a new globally unique identifier in C#:


Thursday, 6 January 2011

Page Load event firing multiple times - why?

Today I had a weird problem - my Page Load event was firing twice for every visit, whether postback or not. I eventually found the problem:

It looks like an empty src attribute in an HTML img element is interpreted as a relative URL to the current page, thereby calling the page.