Monday, December 18, 2006

PhotoSynth Technology Preview

Personally i love seeing technology be presented to the public prior to it being finished, no matter if it works or not. This TP however works quite well and i think it's -really- cool. Check out PhotoSynth at P.

Friday, December 15, 2006

Visual Studio 2005 SP1

Also, on the topic of releases today, Service Pack 1 for Visual Studio 2005 is here. I was going to install it right away (i'm a sucker for installing new stuff as fast as possible), but then Alex's post made me think of a better reason, and that's to install it from home. 'cause, if it's going to be like Alex's installation, that way i can have a valid reason for playing gears of war while the installation runs, and that's always a good thing ;) Download links & further info: Take care, P.

ASP.NET 2.0 AJAX Extensions RC1

Yep, RC1 is now available. Grab it at: P.

another year passed

so, this post is really about 2 weeks old, but i thought i'd write it anyway.

I found myself thinking about the last couple of years that passed by, and it struck me like a blow to the head: this year has been fantastic!

The last year included:
  • working for metamatrix // interfolio
  • working with sitecore cms (which you all by now know i love)
  • went to tech ed in barcelona
  • living in stockholm
  • drinking beer
  • playing music
  • stopped smoking
  • started going to the gym (if you knew me a year ago you'd be laughing right about now)
  • bought an apartment
  • bought a car
  • started this blog
  • found what i was hoping i'd find in a company that develop top-of-the-line solutions

Now, for those of you that don't know me personally, let's just compare this year to some previous:

1 year ago i was..

  • living in stockholm
  • working for morningstar
  • drinking beer
  • smoking cigarettes
  • playing music

2 years ago i was..

  • living in london
  • working for morningstar
  • drinking beer
  • smoking cigarettes
  • playing music

3 years ago i was..

  • living in london
  • working for morningstar
  • drinking beer
  • smoking cigarettes
  • playing music

4 years ago i was..

  • living in stockholm
  • working for morningstar
  • drinking beer
  • smoking cigarettes
  • playing music

see a repetative pattern evolving here? well, for the first time that pattern is gone, completely (ok, so not -really- completely, i still like my beers, stockholm and my music).

morningstar was great working for, don't get me wrong, and london was a fantastic city to live in. the friends i have there i'll keep for life, without doubt. the thing that separates those years from today is that today i'm loving it. 100% loving it.

and yeah, it's true: i'm going to the gym these days and yeah, it's true: i've stopped smoking (so far anyway)

time sure flies..

i'm -so- looking forward to another great year!


Extending the RSS Module

the RSS module i really like. it's a good example of a great module that does what it's supposed to be doing. Alexey Rusakov is a wizard, can't put it any other way. his last posts about deletion workflow are really interesting and if you've ever thought about custom workflows i encourage you to read (apart from all the stuff at SDN5) Alexey's Deletion Workflow Part 1 & 2, and also Alex Shyba's Workflow with unpublishing article. now, with that said, i just thought i'd share a little example of how you can easily make your pages 'advertise' that there's feed content available on the page. modern browsers 'light up' to indicate a feed is present, and it's really, really, really simple - it's just a link in the header to the atual rss istelf. you don't need to have the RSS module, you can of course create your own, but i strongly recommend that you use the module. so, assuming you have the module installed & running you'd have a node somewhere that stores your feeds, here's what you do: 1) add a new Tree list field (i -so- love this field, i use it all the time) called "RSS_Feeds" to your content templates (even better if you got a sitewide template your content templates inherit from) and set the source of that field to your Feeds node (like '/sitecore/content/global/rss feeds' or something). 2) create a new class called RssAlternativeRenderer - this class will output the alternative links to the header of your page 3) add the following code to your new class
public static void GetRssUrls() { Item root = Sitecore.Context.Item; System.Text.StringBuilder sb = new System.Text.StringBuilder(); if (root != null) { if (root.Fields["Rss_Feeds"]!=null) { Sitecore.Data.Fields.MultilistField mf = root.Fields["Rss_Feeds"]; if (mf != null) { if (mf.Count > 0) { foreach (Item itm in mf.GetItems()) { sb.AppendLine("<link rel=\"alternate\" type=\"application/rss+xml\" title=\"" + itm.Fields["Title"].Value.ToString() + "\" href=\"" + itm.Paths.GetFriendlyUrl() + "\" />"); } } } Sitecore.Context.Page.Page.Header.Controls.Add(new LiteralControl(sb.ToString())); } } }
4) add the following code to your Page_Load event

protected void Page_Load(object sender, EventArgs e) { RssAlternativeRenderer.GetRssUrls(); }

that's it. now compatible browsers will 'light up' all shiny and stuff when you select a feed that will be available on a page - ain't that great for christmas? finally, wrapping up, Alex de Groot just posted his 1-year-blogging-anniversary post. Congratulations! today is friday - today is afterwork - today is gonna be one more day that i forget to go buy gifts.. but hey, at least it's friday.. take care, P.

Wednesday, December 13, 2006

10 steps to adding search providers to a sitecore website using OpenSearch specifications

yep, 10 steps to adding search providers to a sitecore website using OpenSearch specifications. ok, so there's a lot of sub-steps and some code, but at least the highlighted parts are only 10 :) here we go!

1) create a new layout called OpenSearch

2) create a new template called OpenSearchSource     2.1) add the following fields to this template         2.1.1) OpenSearchDescription : text         2.1.2) ShortName : text         2.1.3) LongName : text         2.1.4) Description : text         2.1.5) Tags : text         2.1.6) Contact : text         2.1.7) URL_RSS : text         2.1.8) URL_Atom : text         2.1.9) URL_HTTP : text         2.1.10) Attribution : text         2.1.11) Language: text         2.1.12) AdultContent : checkbox         2.1.13) inputEncoding : text         2.1.14) outputEncoding : text         2.1.15) count : text         2.1.16) Icon_Large : text         2.1.17) Icon_Small : text     2.2) set the standard values of the fields accordingly (without the qoutes):         2.2.1) OpenSearchDescription : ""         2.2.2) ShortName : "MyExample" (set your site name or something)         2.2.3) LongName : "Search using MyExample Search" (just a more detailed name)         2.2.4) Description : "Use our own search engine to search our site"         2.2.5) Tags : "example web"         2.2.6) Contact : "" (your email would be better)         2.2.7) URL_RSS : "{searchTerms}&view=rss" (set this to the result querystring of your rss search page (if any) and add the {searchTerms} to the query param, or leave empty)         2.2.8) URL_Atom : "{searchTerms}&view=atom" (set this to the result querystring of your atom search page (if any) and add the {searchTerms} to the query param, or leave empty)         2.2.9) URL_HTTP : "{searchTerms"} (set this to the result querystring of your search page and add the {searchTerms} to the query param)         2.2.10) Attribution : "Copyright 2006, Peter Johansson, All Rights Reserved."         2.2.11) Language: "*" (can be set to a desired language, like sv-SE)         2.2.12) AdultContent : unchecked :)         2.2.13) inputEncoding : "UTF-8"         2.2.14) outputEncoding : "UTF-8"         2.2.15) count : 10         2.2.16) Icon_Large : "" (or leave blank to show no icon)         2.2.17) Icon_Small : "" (or leave blank to show no icon)     2.3) create a master for the newly created template

3) add a folder where you'll store your OpenSearch specification items (perhaps /sitecore/content/global/OpenSearch)     3.1) assing the master created in 2.4 to the newly created folder     3.2) assing the layout we created at step 1 to the standard values of our OpenSearchSource template

4) add a dummy specification item that we can change later, i'm naming mine OpenSearchExample, but you can name it what you want.

5) here you can approach it from many angles, but since this is my tutorial we're gonna look at it my way :),     5.1) create a template that your site-specific templates will inherit from (make sure it inherits Standard template), maybe even name it SitewideSettings like i'm doing.     5.2) add a Tree list field to that template, name it OpenSearch_Sources and specify it's source to be your newly created folder at step 3, and finally check the shared checkbox.     5.3) make your site-specific templates inherit from the SitewideSettings template created at step 4.1.

6) edit an item (or create a new one) and select the dummy item we created at step 4 in the OpenSearch_Sources tree list

7) commit a full publish

That's it for sitecore desktop stuff.. for now.. next up, let's change the OpenSearch layout file.

8) Create a new class called OpenSearchPage     8.1) Set the Inherits attribute of the layout to the newly created class, like Inherits="OpenSearch.OpenSearchPage"     8.2) make the new class inherit from the standard Page class     8.3) override the OnLoad event     8.4) create code to output our OpenSearch specification. Instead of doing this the really fancy way i'll just show a really simple way to output it. What should really be done is to make use of an xmltextwriter and an actual xml document to make sure the output is nice all follows standards, but to save time i've simply sent the format straight to the page and made sure the ContentType is text/xml. to make this better, go ahead and change all this, it should be made better so if you use any of this think about that :) anyway, here's really all of the code needed for (the not-so-correct-way-of) returning the output:

public class OpenSearchPage : Page { protected override void OnLoad(EventArgs e) { base.OnLoad(e); if (Sitecore.Context.Item != null) { this.Context.Response.Clear(); this.Context.Response.ContentType = "text/xml"; System.Text.StringBuilder sb = new System.Text.StringBuilder(); sb.AppendLine("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); sb.AppendLine("<OpenSearchDescription xmlns=\"" + Sitecore.StringUtil.GetString(Sitecore.Context.Item.Fields["OpenSearchDescription"].Value, "") + "\">"); sb.AppendLine("<ShortName>" + Sitecore.StringUtil.GetString(Sitecore.Context.Item.Fields["Shortname"].Value, "") + "</ShortName>"); sb.AppendLine("<Description>" + Sitecore.StringUtil.GetString(Sitecore.Context.Item.Fields["Description"].Value, "") + "</Description>"); sb.AppendLine("<Tags>" + Sitecore.StringUtil.GetString(Sitecore.Context.Item.Fields["Tags"].Value, "") + "</Tags>"); sb.AppendLine("<Contact>" + Sitecore.StringUtil.GetString(Sitecore.Context.Item.Fields["Contact"].Value, "") + "</Contact>"); if (Sitecore.StringUtil.GetString(Sitecore.Context.Item.Fields["URL_RSS"].Value, "") != "") sb.AppendLine("<Url type=\"application/rss+xml\" template=\"" + Server.HtmlEncode(Sitecore.StringUtil.GetString(Sitecore.Context.Item.Fields["URL_RSS"].Value)) + "\"/>"); if (Sitecore.StringUtil.GetString(Sitecore.Context.Item.Fields["URL_Atom"].Value, "") != "") sb.AppendLine("<Url type=\"application/atom+xml\" template=\"" + Server.HtmlEncode(Sitecore.StringUtil.GetString(Sitecore.Context.Item.Fields["URL_Atom"].Value)) + "\"/>"); if (Sitecore.StringUtil.GetString(Sitecore.Context.Item.Fields["URL_HTTP"].Value, "") != "") sb.AppendLine("<Url type=\"text/html\" method=\"get\" template=\"" + Server.HtmlEncode(Sitecore.StringUtil.GetString(Sitecore.Context.Item.Fields["URL_HTTP"].Value)) + "\"/>"); if (Sitecore.StringUtil.GetString(Sitecore.Context.Item.Fields["LongName"].Value, "") != "") sb.AppendLine("<LongName>" + Sitecore.StringUtil.GetString(Sitecore.Context.Item.Fields["LongName"].Value) + "</LongName>"); if (Sitecore.StringUtil.GetString(Sitecore.Context.Item.Fields["Icon_Large"].Value, "") != "") sb.AppendLine("<Image height=\"64\" width=\"64\" type=\"image/png\">" + Sitecore.StringUtil.GetString(Sitecore.Context.Item.Fields["Icon_Large"].Value) + "</Image>"); if (Sitecore.StringUtil.GetString(Sitecore.Context.Item.Fields["Icon_Small"].Value, "") != "") sb.AppendLine("<Image height=\"16\" width=\"16\" type=\"image/png\">" + Sitecore.StringUtil.GetString(Sitecore.Context.Item.Fields["Icon_Small"].Value) + "</Image>"); sb.AppendLine("<Attribution>"); sb.AppendLine(Sitecore.StringUtil.GetString(Sitecore.Context.Item.Fields["Attribution"].Value, "Copyright, All rights reserved.")); sb.AppendLine("</Attribution>"); sb.AppendLine("<AdultContent>" + Sitecore.StringUtil.GetString(Sitecore.Context.Item.Fields["AdultContent"].Value, "false") + "</AdultContent>"); sb.AppendLine("<Language>" + Server.HtmlEncode(Sitecore.StringUtil.GetString(Sitecore.Context.Item.Fields["language"].Value, "*")) + "</Language>"); sb.AppendLine("<OutputEncoding>" + Sitecore.StringUtil.GetString(Sitecore.Context.Item.Fields["outputEncoding"].Value, "UTF-8") + "</OutputEncoding>"); sb.AppendLine("<InputEncoding>" + Sitecore.StringUtil.GetString(Sitecore.Context.Item.Fields["inputEncoding"].Value, "UTF-8") + "</InputEncoding>"); sb.AppendLine("</OpenSearchDescription>"); this.Context.Response.Write(sb.ToString()); this.Context.Response.End(); } } }

9) add functionality to add content to the header. all we really need now is a way to tell the browser that there's a search provider available on the site, and here's a little code snippet for that as well

public class OpenSearchRenderer { public static void GetOpenSearchUrls() { Item root = Sitecore.Context.Item; System.Text.StringBuilder sb = new System.Text.StringBuilder(); if (root != null) { if (root.Fields["OpenSearch_Sources"] != null) { Sitecore.Data.Fields.MultilistField mf = root.Fields["OpenSearch_Sources"]; if (mf != null) { if (mf.Count > 0) { foreach (Item itm in mf.GetItems()) { sb.AppendLine("<link title=\"" + itm.Fields["ShortName"].Value.ToString() + "\" rel=\"search\" type=\"application/opensearchdescription+xml\" href=\"http://localhost" + itm.Paths.GetFriendlyUrl() + "\">"); } } } Sitecore.Context.Page.Page.Header.Controls.Add(new LiteralControl(sb.ToString())); } } } }

10) output the header information. to finalize the entire thing and actually get the output to the page, all you have to do is add a call to the GetOpenSearchUrls method on the pages, so for example just add a call to it in the Page_Load event;

protected void Page_Load(object sender, EventArgs e) { OpenSearch.OpenSearchRenderer.GetOpenSearchUrls(); }

now, to wrap it all up you should have a working example of how to add OpenSearch information that will enable your site to 'tell' the browser there's one or more search providers available on your site, it should light up the down arrow to the right of the magnifying glass in the top-right search area part of your IE7 toolbar and if you expand it it should show your newly added search provider. you could also extend the definition of the xml output to include mozilla specific resources (like xmlns:moz="") and even further extend the functionality in a lot of customized ways since OpenSearch has many ways to extend the specifications and results.

further reading: OpenSearch: OpenSearch Specifications 1.1: Search Provider Extensibility in Internet Explorer 7: Adding Search providers to IE 7 using OpenSearch 1.1:

well, i guess that's that. Sorry for the bad formatting, one of these days i'll actually change the design, but right now this will have to do. take care, P.

Tuesday, December 12, 2006

December 2006 Sandcastle CTP

What actually should (and probably will) be another post from Alex is this: The December 2006 CTP version for Sandcastle is now available for download. After reading his article about it, i had to check it out.. and, i really like it. So, if you're interested you can read more about the December CTP at, and make sure to read Alex's article too. P.

Wednesday, December 06, 2006

XNA Game Studio Express Launch

Microsoft has announced that Monday the 11th of December signals the launch of XNA Game Studio Express. Some of you might think that posting about XNA is not really for this blog, but hey, i'm a die-hard xbox360 fan, so this is fantastic news if you ask me. I've tried the beta of XNA Game Studio Express, and it really is great fun creating your own games, take my word for it. Further reading & details on the event: P.

Tuesday, December 05, 2006

ASP.NET 2.0 CSS Friendly Control Adapters 1.0

Well, it's not a brand-new release (1.0 was released 20th of November), but i still felt like writing a little about it. ASP.NET 2.0 CSS Friendly Control Adapters 1.0 is a great add-on to visual studio for those of you out there that develop websites and keep to css styled sites. Basically, what it does is that it hooks on to existing controls as a control adapter and instead of generating annoying table/tr/td etc tags it transforms the output into css friendly elements. Really good addition to your visual studio installation. More info & download: P.


Seems Microsoft just announced the first CTP of "WPF/E" (codename), their new cross-platform/xaml/wpf combo.. thingy.. something.. If you find it interesting (like i do), you'll find it at P.

Monday, December 04, 2006

The Panel

I like microsoft's "The Panel" initiative, it's quite cool to see different XAML applications and also to get your hands on the sourcecode to see how it's implemented. Gathered that some require massive CPU & RAM it's still awesome and enjoyable to test it, if your computer is XAML capable that is. Right now i'm trying the UniveRSS application, and yep, it's cool alright. The Panel: