Navigation

Tuesday, 16 August 2011

I'm speaking at SharePoint Saturday UK (SPSUK)

I am proud to announce that I have been selected as one of the speakers at the SPSUK event this year in Nottingham on 12th November. The full session list can be found on their website and includes loads of great sessions throughout the day!

My session is going to be about configuring Kerberos in a SharePoint 2010 Farm and will include a live walkthrough of setting up Kerberos from scratch for a SharePoint 2010 environment, and how to use standard "out of the box" tools to prove that it is working.

This will include Excel Services and Analysis Services, constrained delegation and configuring the Claims to Windows Token Service.

This is the first IT Pro Session (9:15am) so hope you get there early! :)

For those of you who don't know about this fantastic event it is FREE to attend and consists of a whole day of SharePoint goodness. Here is a short quote from their website:
SharePoint Saturday UK 2010 was a great success with around 200 attendees!!
Brett Lonsdale (Lightning Tools), Mark Macrae (ID Live), and Tony Pounder (ID Live) are repeating last years efforts to bring you SharePoint Saturday UK 2011.
This year the event will be held in Nottingham at the East Midlands Conference Centre. The EMCC is close to East Midlands airport, Nottingham train station, and the M1 motorway with easy links to the M6 motorway.
If SharePoint Saturday is new to you, expect a day of great international speakers including Microsoft employees, SharePoint MVPs and SharePoint community experts, great content, and of course SharePint!
Hope to see you there! If you haven't already then sign up now!

Thursday, 11 August 2011

How to enable Anonymous Access to a blog site on your Office 365 public website

This has been plaguing the forums for weeks now .. if I had a pound for everytime I've seen someone complaining about blogs on Office 365 .. I'd have .. erm .. about £15 ..

But seriously, this is something that a lot of folks have been complaining about .. but no more! :)

One thing that definately surprised me is that you can set anonymous permissions through Sandbox Solutions! This means that we can write our own custom code to enable full anonymous access for comments, categories and posts :) So I've done just that.

A link to download a Sandbox Solution can be found below. Just upload the WSP to your public website site collection, activate it, and drop the new "Hatch Solutions" web part onto the home page of your blog :)
NOTE: For those who aren't interested in how this works, and just want the web part, you can grab the WSP package here.
This installs a Web Part. Place this webpart on the home page of your Blog site, and hit the big button... it should do all of the work for you.

Important: You don't need to keep the webpart on there. Once you've checked it is working you can remove the webpart and remove the WSP from your Solution Gallery!
Regional Settings -  There have been numerous reported issues regarding regional settings (as the code looks for lists called "Posts" and "Comments"). Currently this WSP only works when your SharePoint Site regional settings are set to English.
So what are we doing?
This is really quite simple. The SharePoint API exposes the list permissions for anonymous users through an SPList property called AnonymousPermMask64. This is an enumeration of SPBasePermissions values which effectively describe what access anonymous users have.

The reason this doesn't work by default for anonymous users is because the "ViewFormPages" permissions is not included by default!

So our code is quite simple:

// get the "Comments" list
SPList list = SPContext.Current.Web.Lists["Comments"];

// check if it has unique permissions
if(!list.HasUniqueRoleAssignments)
{
 list.BreakRoleInheritance(true);
}

// make sure people can edit their own items
list.WriteSecurity = 2;

// grant permissions to anonymous users
list.AnonymousPermMask64 =
  (SPBasePermissions.Open |
   SPBasePermissions.OpenItems |
   SPBasePermissions.ViewFormPages |
   SPBasePermissions.ViewListItems |
   SPBasePermissions.AddListItems);

list.Update();


So all we are doing there is granting some additional permissions (ViewFormPages, ViewListItems and AddListItems) for anonymous users. Then we just rinse-and-repeat for Posts and Categories (but remember to remove the "AddListItems" bit!! otherwise anonymous users would be able to create new blog posts!).

That's it! I have a (short-lived) demo running on my current Office 365 site: www.hatchsolutions.co.uk/Blog/

Note - depending on how much spam and rubbish ends up on there, I will probably delete it sooner rather than later. I'll try and remember to update this post after I have.
To make this easy for you I have built a Web Part which you can download and install (link at the top of this post) which does all of the work for you.

So that is all you should need .. happy blogging folks!! (all we need now is a decent blog template with things like CAPTCHA.. )

Tuesday, 9 August 2011

How to programmatically add the Related List Webpart to a list form

This is one thing that I have used a few times through the browser and always thought it was a feature missing from WSS 3.0 / MOSS 2007. But it was only when I tried to do this (relatively simple) thing as part of a list definition that I realised how oblique it was, and how little information there seems to be explaining how to do it... This blog post will try to address some of that.



So first off .. what is a Related List Webpart? This wasn't really a surprise but if you look under the hood you will notice that when you use the "Related List" ribbon button then it actually does 2 things:
  • Adds a new List View Webpart (in this case an XsltListViewWebPart) which is bound to the related list
  • Creates a web part connection from the (already present) ListFormWebPart which provides the ID which the related list will filter on.
In order to set this up programmatically we basically have to replicate this. In my example I am running this from a Feature Receiver which will setup the web parts. I have 2 lists which I will be referring to:
  • Main List (the main list which I will be modifying)
  • Related List (a list which contains a lookup field containing values from List A)
STEP 1 - Add a new List View Web Part to the List Form

In this step we will be modifying the DISPLAY form (DispForm.aspx). This is probably the most common approach although you can follow very similar steps for the Edit Form if you so wish)

// these are the 2 lists we will work with
SPList mainList = web.Lists["Main List"];
SPList relatedList = web.Lists["Related List"];

// this is the Display Form web part page
SPFile dispForm = web.GetFile(mainList.DefaultDisplayFormUrl);

// get the web part manage which we will use to interact
SPLimitedWebPartManager wpm =
dispForm.GetLimitedWebPartManager System.Web.UI.WebControls.WebParts.PersonalizationScope.Shared);

// only execute this code if there is a single web part (the default for this list)
// we don't want to add the web parts over and over again ..
if (wpm.WebParts.Count == 1)
{
   // create our List View web part
   XsltListViewWebPart wp = new XsltListViewWebPart();

   // Hook up the list and the view
   wp.ListId = relatedList.ID;
   wp.ListName = relatedList.ID.ToString();
   wp.ViewGuid = relatedList.DefaultView.ID.ToString();
   wp.XmlDefinition = relatedList.DefaultView.GetViewXml();

   // set basic properties along with the title
   wp.AllowConnect = true;
   wp.Title = "Related items from " + relatedList.Title;
   wp.ChromeType = PartChromeType.TitleAndBorder;

   // add the web part to the Main zone in position 2
   wpm.AddWebPart(wp, "Main", 2);

   // save the page
   webPartPage.Update();
}

So you can see from the example code above we are adding a simple List View webpart for our related list items. We are binding it to the "Related List" using the ID, and also choosing the View we want to display (here we have just used the Default View for simplicity).

We need to make sure we set "AllowConnect" (as we will need to use Connections in Step 2) and also set the ChromeType to "Title and Border" (as the default for Web Parts in List Forms is "None").

Finally we add the web part and save the changes to the Web Part Page ...

now for the slightly less well documented bit ..

STEP 2  - Create Web Part Connections between ListForm and ListView webparts
In this step we are going to take the Web Part which we added in STEP 1 and use standard Web Part Connections to bind them together ... don't be scared, it isn't as hard as yoy might think :)

We are going to be doing several things here:
  1. We will get instances of both web parts which need to be connected
  2. We will create "Connection Point" objects for each web part
  3. Specify which fields we want to filter on
  4. We will create a "Transformer" object which is able to pass values between each web part
  5. We will use the Web Part Manager to create the connection, using all of that information above.
// get instances of our two web parts
System.Web.UI.WebControls.WebParts.WebPart consumer = wpm.WebParts[1];
System.Web.UI.WebControls.WebParts.
WebPart provider = wpm.WebParts[0];

// Create our two Connection Point objects
// These are specific to our two types of Web Part

ProviderConnectionPoint providerPoint = wpm.GetProviderConnectionPoints(provider)["ListFormRowProvider_WPQ_"];


ConsumerConnectionPoint consumerPoint = wpm.GetConsumerConnectionPoints(consumer)["DFWP Filter Consumer ID"];

// create our "Transformer"
// we also specify which Field names we want to "connect" together
// here I am connecting my Related List's "MyLookupField" and filtering it
// using the "ID" of my List Form's item.

SPRowToParametersTransformer optimus = new SPRowToParametersTransformer();
optimus.ProviderFieldNames = new string[] { "ID" };
optimus.ConsumerFieldNames = new string[] { "MyLookupField" };

// Connect the two web parts together, using our Connection Point objects
// along with our Transformer

wpm.SPConnectWebParts(provider, providerPoint, consumer, consumerPoint, optimus);

And that is it! You don't need to do any more "Update" or "Save" methods .. your Related List web part should now be finished :)

So just to be clear, we are using the standard SPLimitedWebPartManager object and calling the SPConnectWebParts method. The only slightly odd call is the reference to the "SPRowToParametersTransformer" which is specific to the type of Connection we are making (the List Form representing a "Row").

Where did this information come from?
This is the easy bit :) I added a Related Lists Webpart using the browser, then opened up DispForm.aspx using SharePoint Designer .. and found this: 

<WebPartPages:SPWebPartConnection ConsumerConnectionPointID="DFWP Filter Consumer ID" ConsumerID="g_dc64a1e0_c2f4_4302_86df_e4d184203bbd" ID="c225174896" ProviderConnectionPointID="ListFormRowProvider_WPQ_" ProviderID="g_ffb9e36b_bc6d_489e_b7fc_e93048c32f5c"><WebPartPages:SPRowToParametersTransformer ConsumerFieldNames="IMSDataSource" ProviderFieldNames="ID"></WebPartPages:SPRowToParametersTransformer>
I have highlighted the references to the 3 things which made all of the dots join up for me: )
so if you are ever stuck, make sure you look in SharePoint Designer for :

  • Consumer Connection Point ID ("DFWP Filter Consumer ID")
  • Provider Connection Point ID ("ListFormRowProvider_WPQ_")
  • Transformer Type (SPRowToParametersTransformer)
So thats it :) Hope this was useful, comments always welcome

Monday, 25 July 2011

How to add the "Contact Us" gadget to your Office 365 Publishing Site

This follows on from my previous post which describes how to enable the Publishing Features for your Office 365 website and resolving issues with Custom Master Pages in Office 365.

Having done that on my own site (www.hatchsolutions.co.uk) I found that one of the key "Gadgets" was missing .. the Contact Us form.

This was an immediate conundrum.. Sandbox Solutions do not allow email access so I knew I couldn't use that as an out, so I thought I would hunt down that Gadget.

STEP 1 - Add Office 365 namespaces to your Custom Master Page
This is a pre-requisite, as you will be using some of the "Office 365" web controls. I found these in the header of the "oob" root.master which you will find in the All Files section of your public website in SharePoint Designer.

Add these to the top of your Custom Master Page.

<%@ Import namespace="Microsoft.SharePoint.Spx.WebSite.Controls" %>
<%@ Import namespace="Microsoft.SharePoint.Spx.WebsiteCore" %>
<%@ Import namespace="Microsoft.SharePoint.Spx.WebsiteCore.Controls" %>


(note the special Microsoft.SharePoint.Spx namespace!)

STEP 2 - Create Custom Page Layout with Contact Us Control Embedded
This was the way I chose to do it .. you don't have to do the same (although I couldn't work out an easier way of doing this myself).

I created a new custom Page Layout (based from one of the others). I deliberately removed any references to any custom code-behind or code-blocks.

This means that I will be running OOB code, and won't be consuming any Sandbox Resource points!

Then add the following ASP.Net snippet into your page:

<iws:ContactUsControl runat="server" EmailTo="info@hatchsolutions.co.uk" CultureName="en-US" SendToBCM="on" xmlns:iws="iws" />
This is the same ASP.Net tags that get used when you drop the gadget onto your page.
You can see in my example I have added my own EmailTo and CultureName attributes .. you can set these to whatever is appropriate.

The other thing to note is that you must place this control in an EditModePanel with PageDisplayMode="Display". The Contact Us form otherwise tries to validate the page when you try and Save Changes or Publish (not good!)

And that is it .. simply save your changes, publish your page layout and create your own page! :)
I have created my own custom page layout here;
http://www.hatchsolutions.co.uk/Pages/ContactUs.aspx

Please let me know how you get on with yours!


Wednesday, 20 July 2011

Office 365: Custom Master Page - Resolving "Code blocks are not allowed in this file"

This was an annoying error for quite some time. Office 365 (SharePoint Online) gives you full control to create, deploy and select custom master pages, but if you try using them you often get the error:
Code blocks are not allowed in this file
The reason for this is because of the locked down security permissions in the Master Page Gallery. This is fair enough, just means you can't have custom code running on your Master Page (but seriously .. how often do you actually need to do that?)

So .. I created my Master Page using the awesome CodePlex Starter Master Pages. And this was fine until I deployed it (using Sandbox Solutions) to my Office 365. Bam .. error message (Code blocks are not .. blah blah).

Well .. I went through my Master Page line by line .. I couldn't actually FIND any code blocks. I could find a bunch of expressions (but these don't count!) such as
  • <%@ Import %>
  • <%@ Register %>
  • <%$Resource ..>
The Resource tags reference resource strings. This is used ALL over the OOB controls and is generally very good practice!

I finally worked out what was causing it .. the actual Master page tag itself!
   
    <%@ Master language="C#" %>

The "language" attribute was causing all of the problems! (even though we didn't have any code!)

So I removed the language attribute (leaving me with):

    <%@ Master  %>

And hurrah! I all started working. Hope this helps! Happy branding!

How to configure your Office365 public website to use the SharePoint Publishing Infrastructure

Important Update (2nd September 2011) - Microsoft have announced that this is NOT SUPPORTED. Please see the following post: Update - Publishing Features "not supported" on Office 365 Public Websites

This is something that has bugged me for a LONG time .. I cannot possibly understand why SharePoint Online (with one of the most powerful Web Content Management Systems) was so thoroughly limited by cutting back to a really basic template editor. I can only think of 2 reasons:
  1. Microsoft assumes the average user won't know how to use SharePoint, so wanted to provide a simpler user interface. This is fair enough, and if this IS the reason there should be no reason why I can't go "behind the scenes" and setup the site any way I like (at my own risk .. as it were).
  2. Microsoft is trying to protect revenue from "SharePoint 2010 Server Internet Facing Sites" licenses. These are VERY expensive and a lot of companies will happily get rid of their on-premise install to put in a £80 a year Office 365 E1 plan to host their website.
Now .. if it is case (1) then we should be good to go. If it is case (2) then they probably have terms and conditions specifically stopping someone from doing this... so first off lets get the disclaimer out of the way :)
Disclaimer Update (26th July 2011) - I have received confirmation from Microsoft via the Office 365 community site that this IS ALLOWED (http://community.office365.com/en-us/f/153/p/8015/34893.aspx#34893). Having said that if you decide to do this in your own environment then proceed at your own risk! If something goes wrong it is NOT my fault .. you have been warned!
Ok .. now that is dealt with lets get on with it!
The first thing I want to note is that this is only possible using an Enterprise Plan. If you are using the Small Business version of Office 365 (such as Plan P1) then you won't be able to do this for 2 major reasons:

1) SharePoint Designer blocks access to "All Files" so you can't make some of the changes we need to do.
2) You don't have access to Site Collection Features, so you can't activate the Publishing Infrastructure Feature!

So I setup my own trial Enterprise Plan (with a 30 day expiry .. hence why I haven't bothered posting the URL) and created the standard "Public Website" site collection... then what?

STEP 1 - SharePoint Designer - Rename the Public Website Folders
This is the first fundamental step. If you don't do this then STEP 2 will throw errors at you (because folders using "Pages" for example, already exists!).

Open your site in SharePoint Designer 2010 (free download) and click on "All Files" (should be the bottom link in the left-hand navigation panel).

This will show you the URL paths being used by each of the lists and libraries. You cannot delete these (as the delete option is prohibited) but you can rename them!
RENAME each of the following libraries (I have prefixed mine with OLD).
  • Documents
  • Images (the root folder)
  • Pages
  • SiteImages (the library)
  • TemplateGallery
None of these will be required once you have activated the publishing features.

Next, go to "Lists and Libraries" (second link from top left hand side). This will show you the NAME of the same lists and libraries.
RENAME each of the following libraries (again, I have prefixed mine with OLD).
  • Documents
  • Web Pages
  • Templates
  • Images
 Your site is now primed for the publishing features to be activated (if you navigate to your website URL now, you would be taken to the blank "default.aspx" page).

STEP 2 - Activate Publishing Features
Navigate to your website and append "/_layouts/settings.aspx" onto the end
e.g. http://martinhatch-web.sharepoint.com/_layouts/settings.aspx

You will need to activate 2 features in this order:
  1. Site Collection Features - SharePoint Server Publishing Infrastructure
  2. Site Features - SharePoint Server Publishing
So you now have "publishing" functions available!

STEP 3 - Create default Page
This is really optional, and anyone familiar with SharePoint should be happy from this point onwards.
  • New Page is now available from Site Actions. This will create a new Publishing Page
  • Using the Master Page options in Site Settings change the Site Master Page (I have used NightandDay.master in the screenshot below). You can of course create and deploy your own custom master pages using either SharePoint Designer or Sandbox Solutions.
  • Advanced Navigation options are now available from Site Settings.
  • The Pages library supports Content Approval, Publishing workflows and scheduling!
And that is it .. all done :)


STEP 4 - CLEANUP?
The only problem with this is we now have a bunch of old libraries hanging around which we can't get rid of.

I'm sure there is a neat way using a Sandbox Solution or client object model to delete those forcibly, and setup all of this, but for now I'm putting up with a bunch of old libraries prefixed with "OLD" (which don't contain anything).

The other thing in the mean time is finding out if Microsoft are actually willing to let us do this? I really hope they are .. it does expose the awesome power of SharePoint to the masses .. but will it mean they sacrifice some of the on-premise installs?? fingers and toes remain crossed.

[Update]
Note - I have started a forum thread asking this specific question. We shall see !!
http://community.office365.com/en-us/f/153/p/8015/33059.aspx#33059
[/Update]


Monday, 18 July 2011

CKS:Sandbox 1.0 is now live!

For those who haven't heard I started this project off a few weeks ago because I was frustrated with the complete and utter lack for any meaningful Sandbox Solution management in SharePoint 2010. Well, the fruits of my labours are now complete and the first major version of the CKS: Sandbox Tools Edition has now been launched!
If you want to download CKS:Sandbox, are looking for more information including install instructions, screenshots or documentation about how it works, then go visit our site: http://ckssandbox.codeplex.com/
What does CKS:Sandbox actually do?
Well, its main function is as a large library of Solution Validators. All of the source code is available (through CodePlex). The tool kit itself contains loads of goodies which are listed below:


CKS:Sandbox Version 1.0 includes the following functionality:

Validation Functionality
The highly configurable validation engine runs using SharePoint Solution Validators. This allows you to customise a set of rules that are checked each time someone tries to Activate a sandbox solution anywhere in the SharePoint Farm.
  • Fully configurable Validation Rules allowing you to check Sandbox Solution Packages for:
    • Validate specific solutions using their unique Solution ID
    • Assembly Public Key Tokens to only allow specific SNK files to be used during development
    • Assembly names using wildcard matching.
    • You can validate the Type Namespaces for each type in the assembly, using wildcard matching, such as "Microsoft.SharePoint.*"
    • You can specify Blocked File Types by file extension (such as JS or XAML)
    • You can validate the content of each file in the solution using RegEx or Wildcard matching (such as blocking <script> tags)
  • You can set the default Validation Behaviour allowing you to Allow All or Block All for the different Validation Rule types
  • You can enable / disable Enforce Validation and choose whether to block solutions when a solution fails validation
Error Mesages and Emails
  • You can enable / disable Email Notification and receive emails to a configurable email address when a solution fails validation
  • Standard "CKS" error messages and pages are provided with the tool and displayed to end users if a solution is blocked during activation
    • You can use your own custom error messages by providing a URL to your own ASPX pages
Admin Tools
  • The Manage Sandbox Solutions page allows you to view every single Sandbox Solution currently installed in your farm;
    • Grouped by Site Collection, showing the Name, URL and current Resource Point Quota
    • Provides a link to the Site Collection Solution Gallery where it is stored
    • Shows the Solution ID, Title and Description information
    • Shows the Activation status of each Solution, and how many Resource Points it has currently consumed.
Finally a quick thank you Wes Hackett, of the CKS:Dev team, for the CKS introduction!

Sunday, 17 July 2011

New look and feel for martinhatch.com

Well, its that time of year I suppose. I finally got around to giving my blog a bit of a freshen up.
It's nothing too fancy .. a simple and clean white/grey style which is hopefully a little easier on the eye than my old red one (which I suppose was really a throw-back from my days working at Content and Code .. when everything we produced was a shade of red - their corporate colours).

What  else have I changed?

The main thing is the width has been increased from the downright lousy 740px width (an old blogger.com template I originally used) and up to a much more healthy 990px (which should be suitable for pretty much all modern browsers running 1024x768 or higher).
[Edit]It was set to 1000px, but this was causing horizontal scrollbars, so I made it 10px thinner[/blog]

I've also moved some of the navigation elements around, hopefully it makes it easier for you to find things, and there is a navigation bar at the top (which currently just consists of a "Blog" and "About Me" links but it was taking up too much real-estate on the right-hand side).

I also have a brand spanking new logo header. This was a bit of a cheeky freeby from fellow tweeter Dave Coleman. His son (also on twitter as CommandoUK) is starting up as a graphics designer and was offering some free blog / website headers to get his portfolio up and running.

Well, I was interested and he knocked up the logo header you see on there today :) I like it quite a lot .. it oncorporates the main logo from my company site (http://www.hatchsolutions.co.uk/) as well as some funky colours which happen to mimic my Alienware M15X laptop colours (yeh ... I know .. it's a gimicky laptop which allows you to change the colour scheme of the keyboard and stuff ..)

Anyway, let me know if you like it (or not I suppose!). Thanks for visiting and hope you enjoy my next few posts.

Got more CKS: Sandbox stuff coming up, some Office 365 stuff and probably some SharePoint BI posts on the way too!

cheers

Martin

Friday, 1 July 2011

Introducing CKS:Sandbox Tools Edition

Well, I know I know I've "gone dark" for the past few weeks and haven't blogged for a while .. I'm about knee deep in a very interesting global BI project (which I'm sure I'll be blogging about more soon) but this post is all about CKS (the Community Kit for SharePoint) and more specifically .. CKS:Sandbox.

In a nutshell the Community Kit for SharePoint is a set of best practices, templates, Web Parts, tools, and source code that enables practically anyone to create a community website based on SharePoint technology for practically any group of people with a common interest.
http://cks.codeplex.com/

My involvement is that I am going to be building a set of administrative tools for SharePoint 2010 Farm solutions to help admins to manage Sandbox Solutions.

This initial release is hopefully going to happen in July 2011 and the feature list is as follows:
  • Blocking of WSPs based on assemblies, based on provided limitations
    • Enforced Public Key Tokens (for enforcement of specific signed assemblies, great to ONLY allow your internal development team to produce sandbox solutions)
    • Enforced namespaces
    • Enforced assembly names
  • Blocked file types list
    • JS
    • XAML
    • DLL
    • Etc ..
  • Override settings
    • “Safe Publisher” (Solution ID) .. always allow regardless of above settings
    • “Blacklist” list (Solution ID) .. always block regardless of above settings
  • Email Notification
    • Allow emails to be sent to administrators if a solution is blocked
    • Allow solutions to be deployed, but send an email instead of blocking it

  • You can find more (including release information and discussions) at our CodePlex site: http://ckssandbox.codeplex.com/

    If you have any suggestions or comments, then please pass them on, and if you would like to be involved then by all means get in touch :)

    Thursday, 7 April 2011

    Page Title element and PerformancePoint Report always being blank

    This was one I came across recently while doing some custom branding work on a SharePoint 2010 site which was using Performance Point Services, and specifically the PerformancePoint Report Web Part.

    I had a simple branded master page (which was a copy of the normal v4.master) but could not for the life of me get PerformancePoint reports to work.

    The Report Web Part was blank (with zero height) and there was a JavaScript error on the page:
    Unterminated string constant
    Code: 0
    Well .. I rolled my site back to the v4.master and it was working again. I copy-pasted the v4.master <head> contents into my custom master page and it started working again .. although when I double checked the contents they were IDENTICAL.

    So far this was very very weird .. and the actual solution is even weirder.

    It seems it was to do with my <title> element in the <head> tags being broken onto separate lines:
    BAD
    <title>
       <asp:ContentPlaceHolder id="PlaceHolderPageTitle" runat="server" />
    </title>
    GOOD
    <title><asp:ContentPlaceHolder id="PlaceHolderPageTitle" runat="server" /></title>
    Why?? I have no idea .. but making this simple change solved the problem.
    Bizarre eh?