More servicesWindows Live
HomeHotmailSpacesOneCare
 
MSN
Sign in
 
 
Spaces home  PottytrainingProfileFriendsBlog Tools Explore the Spaces community

Pottytraining

Learning on the toilet...
April 11

Using the Gaia ajax framework in EPiServer

If you're working with Gaia Ajax Widgets in your EPiServer project, you need to read this blog post. In short, it fixes a problem where the Gaia callbacks are done in the context of your start page instead of the currently loaded page.

The funny thing is that Gaia works with EPiServer out of the box, and this problem only manifests itself if you are trying to work with the page data (via the CurrentPage property on your template for an example). The default behaviour in EPiServer is to populate CurrentPage with the start page if no page id can be found when a web form (your template) is loaded. If you use Gaia to show other types of data, this will not be a problem for you.

It is not a bug in Gaia, nor in EPiServer, but the combination of these two and the Friendly Url rewrite module in CMS 5 led to some confusion. When Gaia makes callbacks, it uses the url of the currently loaded web form (just as most ajax frameworks for ASP.NET). I would guess that the url is retrieved from the Request.Url property, perfectly normal. In CMS 5, this will be the "real" url of the request (like /templates/page.aspx?id=123), not the friendly one, and for some reason, if you try to use this url in your request (or callback) the Friendly Url module will choke (and remove the id part).

Don't really know why, as this is how the server would actually like to see it, but I guess this could mix up things on a different level. When Friendly Urls are enabled, you're not really supposed to send the id=123 in as a querystring, someone could use this to trick EPiServer into loading another page than the one mapped to the friendly url for an example.

I downloaded Gaia to try to reproduce this, and see if I could make a workaround. I have to say - from previous experiences with ajax frameworks, I was expecting some work in order to get things up and running (with EPiServer.) Ajax frameworks are usually quite advanced in how they interact with the request framework in ASP.NET, and the same can be said about EPiServer, and the combination can be lethal.

Not so with Gaia. It just worked. I installed it (see this if you have problems with the Visual Studio integration) added a few Gaia controls to my masterpage (a label and a button), added a button click event and wrote a timestamp to the label.

<%@ Register Assembly="Gaia.WebWidgets" 
             Namespace="Gaia.WebWidgets" 
             TagPrefix="gaia" %>
<gaia:Panel ID="Panel1" runat="server" DefaultButton="Button1">
    Page Retrieved: <%= DateTime.Now.ToString("hh:mm:ss fff") %>
    <br />
    <gaia:Label ID="lblGaiaLabel" 
            runat="server">Gaia Label</gaia:Label>
    <br />
    <gaia:Button ID="Button1" 
                 runat="server" 
                 OnClick="Button1_Click" 
                 Text="CallBack" />
</gaia:Panel>

Server side:

protected Gaia.WebWidgets.Label lblGaiaLabel;

protected void Button1_Click(object sender, EventArgs e)
{
    lblGaiaLabel.Text = 
        "CurrentPage Name: " + 
        ((PageBase)this.Page).CurrentPage.PageName + 
        " - Called: " + 
        DateTime.Now.ToString("hh:mm:ss fff");
}

When I dragged the controls to my masterpage, it registered a reference to the Gaia.WebWidgets assembly automatically. I just copied the license file from the C:\Program Files\Gaia Ajax Widgets 2008 Q2 Glory BETA1 Developer\Licenses folder to the root of my site, compiled, and it worked. Well, except for the fact that it always gave me the name of the start page, regardless of the page I was actually looking at.

Read the Gaia blog for the fix.

I love EPiServer because it does not get in the way, the architecture follows the general ASP.NET architecture and flow, and if something does not work the way I'd like or expect, I can work around it - on many different levels. My first impression of Gaia is the same, if your architecture is good, it should be simple, and it should just work. It does. If you're thinking about ajax, have a look at Gaia.

February 28

Taking Control of Property Rendering

I answered a question in the developer forum today, about the span tags that the EPiServer:Property control renders when you pass it the name of a PropertyString property. The thing is; the Property control itself supports setting a CSS class, colors, borders and all the other things supported by the WebControl class in ASP.NET. So it needs to render a stylable container, hence the <span> tag.

So your:

<EPiServer:Property CssClass="MyClass" 
                    PropertyName="PageName" 
                    runat="server" />

will render:

<span class="MyClass">My Page Name</span>

If you remove the CssClass like this:

<EPiServer:Property PropertyName="PageName" 
                    runat="server" />

it will render:

<span>My Page Name</span>

but you really want it to render:

My Page Name

and nothing more. The experienced EPiServer developer will tell you that:

<%= CurrentPage["PageName"] %>
will do exactly that. Yes - true, but what if you've got lots of these Property controls? Or they are inside repeaters or page lists, and you don't want to forget to databind anything. And - you don't want to lose the On Page Editing possibility.

There has to be a smart way to do this! And of course there is - duh - I'm blogging about it.

The new property architecture in CMS 5 is really powerful, and I'll show you how you can override the default rendering for any property type in the system.

In EPiServer 4, a property ultimately inherited from the PropertyData class, and could provide its own rendering by overriding the CreateChildControls method (you kind of had to - in order to do anything useful.)

In EPiServer CMS 5, the property data has been split from the rendering. You now have your PropertyData class, holding the data, and another class doing the rendering, which inherits from EPiServer.Web.PropertyControls.PropertyDataControl or any of the more specialized classes in the same namespace.

A PropertyData object can override the CreatePropertyControl() method, and return a PropertyDataControl that knows how to render the PropertyData in the correct way. It will default to the PropertyStringControl class, which will render a span tag in view mode, and a simple textbox in edit mode.

The Property web control uses a different approach. It uses the EPiServer.Core.PropertyControlClassFactory class to retrieve the PropertyDataControl class. It has a table of mapped PropertyData to PropertyDataControl types, which gives us the possibility to change the control class on the fly. (If there is no mapping, it will call the PropertyData.CreatePropertyControl() method.)

So - lets make a better PropertyStringControl class. Add the following code to your project:

/// <summary>
/// A no nonsense renderer for PropertyString values. Will
/// not render a span tag around the content (as the default)
/// implementation will if not needed by attributes set on
/// the Property control.
/// </summary>
/// <remarks>
/// The control supports On Page Editing (which will
/// render a span tag as long as you do the editing, and
/// after the submit postback).
/// Note! If you set any style attributes or the CSS class
/// on the Property control in the markup it will render
/// the text enclosed in a span tag.
/// </remarks>
public class PropertyStringExControl : PropertyStringControl
{
    public override void CreateDefaultControls()
    {
        bool needContainer = false;
        if (AttributeSourceControl.ControlStyle.IsEmpty == false)
            needContainer = true;

        ITextControl target;
        if (needContainer == true)
        {
            // Default is a Label control, which will
            // render a span tag around the content.
            target = new Label();
            target.Text = this.ToWebString();
            // The label should get the styles, the
            // Literal will not.
            this.CopyWebAttributes((WebControl)target);
        }
        else
        {
            // The Literal will only render the text
            target = new Literal();
            target.Text = this.ToWebString();
        }

        this.Controls.Add((Control)target);
    }
}

We inherit from the PropertyStringControl, and the only method we need to change is the CreateDefaultControls. This shows how powerful the new property architecture is.

The code above checks to see if you have put any CssClass or style attributes on the Property control in your markup. In that case, you will get a span tag. If not, we will only render the text itself, without the enclosing span tag.

When entering On Page Editing mode, the CreateOnPageEditControls method will be called instead of our CreateDefaultControls. And the default behaviour fits us just fine (because it works.) As a side note, if you'd like to change the edit mode behaviour, override the CreateEditControls method.

The hard work is done, all we need to do now is tell EPiServer about it. Open global.asax.cs, and make sure your Application_Start looks something like this:

protected void Application_Start(Object sender, EventArgs e)
{
    PropertyControlClassFactory.Instance.RegisterClass(
        typeof(PropertyString), typeof(PropertyStringExControl));
}

This will register the PropertyStringExControl as the default render control for all PropertyString properties you've got.

So, there you go. You can now control how any property type will render when using the Property web control.

January 30

Opening a new EPiServer CMS 5 SP1 project in VS 2008

When you install a new EPiServer CMS 5 project using the EPiServer CMS Manager, the .csproj file shipped is for Visual Studio 2005 SP1. Opening the project in Visual Studio 2008 will start the project upgrade wizard, which will fail if you have installed the new site as a root site in IIS.

Open the .csproj file in your favorite editor. In the bottom of the file, it should look something like this:

<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  ...
  <ProjectExtensions>
    <VisualStudio>
      <FlavorProperties GUID="{349c5851-65df-11da-9384-00065b846f21}">
        <WebProjectProperties>
          <AutoAssignPort>False</AutoAssignPort>
          <DevelopmentServerPort>6666</DevelopmentServerPort>
          <DevelopmentServerVPath>/</DevelopmentServerVPath>
          <NTLMAuthentication>False</NTLMAuthentication>
          <UseIIS>True</UseIIS>
          <IISUrl>http://localhost/publictemplates</IISUrl>
        </WebProjectProperties>
      </FlavorProperties>
    </VisualStudio>
  </ProjectExtensions>
</Project>

The line you need to change is

<IISUrl>http://localhost/publictemplates</IISUrl>

to:

<IISUrl>http://localhost</IISUrl>

You can then open the project in Visual Studio 2008, run the upgrade wizard and you're good to go.

January 22

EPiServer CMS 5 SP1 has shipped

You can grab it on the Knowledge Center. Make sure you use the new EPiServer CMS Manager.

One of the new things in the SP1 release is the Content Channel Service, which can be used to feed and synchronize your EPiServer content from external systems. This feature is used by the Sharepoint Connector, but is a general implementation, and can be used by other services too. Read more in the tech note.

If you have written your own role or membership providers, be sure to read the release notes, as the ProviderCapabilities class has changed.

The way the profile provider in ASP.NET 2.0 is used by EPiServer has also changed. This is a breaking change if you have code that relies on the HttpContext.Current.Profile being an EPiServerProfile class. From SP1, it is not. Instead, all the profile properties that EPiServer uses has been added to the profile configuration, but the profile provider does not have to inherit from EPiServerProfile. This give you added flexibility, and the profile can now be stored anywhere.

Also, the Event Management System has been changed (and simplified). If you want to configure cache invalidation, or use the event system to communicate your own data between sites, have a look at the new tech note. The event system uses Windows Communication Foundation, and there is a diagnostics tool available if you need to troubleshoot this (see the tech note).

January 14

Compare and keep language files in sync

In my opinion, one of the coolest features of EPiServer is the way language resources are handled. The ease of use and flexibility of xml files in the /lang directory is very powerful.

At startup, your EPiServer site will load all the .xml files in the ~/lang directory, alphabetically. A DOM of all language resources will be built in memory, adding all elements from each .xml file, and then cached for the rest of the application life-time (if you change one of the files, it will automatically trigger a reload.)

If you have defined the same element twice, the last definition will be used, and as the files are read alphabetically, you can use this to overwrite "system" language resources, instead of changing the files shipped with EPiServer. This is a best practice, as you do not have to worry about your changes being overwritten during an upgrade. In most of my projects I define a "z_overrides.xml" file, where I put all elements that override values defined in the shipped xml files.

Unfortunately, there is no tool for working with these files. You basically have to use your favorite xml editor, notepad or Visual Studio. Another pain in larger projects is that these files can get out of sync, if people are sloppy when adding new language resources. Usually, when a site has more than one language, and I cannot translate to that language, I just copy the English (or Norwegian) text to the other language files, and someone will have to translate the files later.

At some time, the files will probably get out of sync, and you will have entries for one language that do not exist in another. The result is the well known - and dreaded - "[Missing text /pagetypes/common/ohno for en]" labels on your site.

It is time to open the toolbox, and fix this. For a long time, I've been using Beyond Compare for all my diff needs (I have even replaced the TortoiseSVN diff tool with Beyond Compare). It is not free, but almost (only $30) and is worth every penny! One of the (many) features of Beyond Compare is that you can write your own "File Comparison Rules", to compare files exactly the way you want to. I've made an "Xml - no values" rule, to compare xml files, ignoring values, and concentrating on elements and attributes. This is perfect for EPiServer xml language files, as the elements and attributes should be the same regardless of language, but the values will of course be different.

This is how it looks (click image for full-size version):

Comparing two language files in Beyond Compare. Click for full size image.

In the picture above, you can see that the English lang_EN.xml file is missing two language elements that are defined in the Swedish one (lang_SE.xml), "privacy" & "send". For this comparison to work, each language must be in a separate file (which I think is a good idea anyway.)

In Beyond Compare I can just right click the lines with red background, and select "Copy to Other Side" (and even change the text directly if I know how to translate it).

The magic is in the rule. If you've got Beyond Compare installed, compare two language files, go to the Tools menu, select "Pick Rules" submenu and click "New Rules". Name it "Xml - no values", and change the values on the "Importance" tab to this:

episerver-compare-languagefiles-beyond-compare-settings

When you compare xml language files, you can just select this new rule on the Tools menu, and it will show you the mismatches. With Beyond Compare, keeping your language files in sync is a breeze.

(Also see Fail Safe EPiServer Translation, Do not change the name of default properties in EPiServer)

January 11

Multiplexing Provider and Security

The Multiplexing providers in EPiServer CMS 5 allows several role and membership providers to be chained together, thus attempting to authenticate and authorize users against different providers. This is very powerful, allowing users from different sources to log in. The typical example is to enable the SqlServer and Windows membership and role providers, allowing both Windows users and users stored in a SqlServer database to log in to the site. By default, only the Windows role and membership providers are enabled, allowing local Administrator users to log in after the installation.

However - there is a catch. If you have the same name for roles (groups) in two different role providers, you might open a security hole. If you assign access to a page for a group in Role Provider A, and then someone creates the same group in Role Provider B, any users that are member of the group in Role Provider B will get access to this page. This might not be what you want.

You have to be particularly careful if you create your own providers, authenticating against other systems (other sites, back-end systems, etc.) You do not want to have two role providers with an Administrators role (unless you plan for it)!

January 10

Installing EPiServer CMS 5 on Windows Vista

Personally I haven't installed Vista - yet. Don't know when, but I don't really see the point right now, I've got the tools I need, and developing on Windows XP with VS 2005 or 2008 is slow enough as it is. I bet the Vista eye candy does not exactly improve performance :-) Anyway, I'm digressing.

If you have taken the plunge, you probably want to read the fantastic walk through by Ruwen Jin over at EPiServer Labs. Way to go Ruwen!

December 18

Just the thing you don't want to see...

... after waiting for hours and hours to get that 3.4GB download of Visual Studio 2008 Pro downloaded, it laughs in your face:

vs-ohno1

vs-ohno2

Don't think I dare to even try the installation, counting in previous experiences with Visual Studio installations. Better safe than sorry, doing it by the book.

On my second download attempt now, 38%, crossing my fingers!

October 29

You're missing out

Today we solved a problem on the #EPiCode IRC channel.

Could not load file or assembly 'blah' or one of its dependencies. The system cannot find the file specified.

Adding a dynamic property crashed the site. But we found the cause, and we fixed it. Nice! And you missed it. Too bad.

Sadly - I haven't had too much time to hang out on the EPiCode channel lately. A busy project schedule, and network administrators with paranoia has made things a little bit difficult, but I'm there as often as I can (and when I remember!) Send me an email if you miss me there ;-)

Disclaimer! The #EPiCode channel on IRC is not a support channel. We discuss things related to the EPiCode modules and EPiServer in general. Occasionally we solve some problems too.

October 28

My Sony Ericsson K800i died. This is how I fixed it!

Earlier this week, the "internal" speaker died on my trusty K800i. Only way I could hear the person in the other end was turning on the loud speaker, or attaching a hands free set. Turned it off and on a couple of times, which did not seem to have any effect. Then suddenly, a day later, everything worked.

But - yesterday I had the SIM card out (I needed to test an older phone I was selling), and after that, the K800i did not want to start again. When pressing the power button, I could see the IR diode blink (6 times I think), but that was it. Nothing else. Black screen. Nothing. Nada. Nothing but despair!

Googling the subject gave me lots and lots of hits - I'm obviously not the only one with this problem.

One pointed at the Wotan Client (WotanClient) from WotanServer. But - you need the USB drivers in order for Wotan to see the phone. I tried installing Sony Ericsson PC Suite 2.10.46, and the Update Service Setup (2.7.9.14). The install went fine - but I could not open the Update Service due to some stupid dependency to a specific version of Flash (I presume). Someone ought to get fired at SE for this!

The forum postings I came by told me to hold the keys 2 and 5 on the phone, then attach the USB cable to it. Windows (XP in my case) then saw the new "USB Flash Device", and asked me for the drivers. I pointed it at the "\Program Files\Sony Ericsson\Mobile2\Drivers\Signed" directory. No luck.

Uninstalled PC Suite and Update Service (lots of reboots), and installed PC Suite v2.10.34 instead (Update Service 2.7.6.8). Still no luck.

Googled some more, found some "K800 USB Signed Drivers" download somewhere for K800, did not help. More searching - found "sony-ericsson-k-series-drivers.zip" somewhere else. Did not work. (Thats why I'm not linking.)

Getting anxious - very anxious!

Then I did some searching inside the Update Service folders (this is version 2.7.6.8). Seems that under "\Program Files\Sony Ericsson\Update Service\setup\drivers" you will find a file called USBFlashDriver.zip. Unzip this, hold 2&5 on your phone (I kept holding them all the time during the installation - probably not neccessary - but better safe than sorry at this point), connect the USB cable to the phone. Windows asks for drivers, point it to the folder where you unzipped the USBFlashDriver.zip file. It should install just fine.

Disconnect the phone from the USB cable. Remove SIM and memory card (if you haven't done so already.)

Now - open the Wotan Client (I downloaded 1.0.2.0). It will download some stuff for you. Clear the Server settings fields in the lower right corner, and click the Start button. It will wait for you to connect the phone. Hold 2&5, connect USB cable, and Wotan will do its magic. Close Wotan, disconnect phone, remove battery. Wait (10sec), insert SIM and battery, close back panel and turn phone on.

It worked for me!

This will probably work with the latest Update Service too.

The Wotan Client (from WotanServer) is a tool for debranding Sony Ericsson phones and for upgrading them too. You usually buy the updates from them (using "credits") to unlock your phone (I assume). But for this case, it seems like the software kind of kickstarts the phone or something, because I have not bought any upgrades from Wotan. It did work though, and I think I'll actually buy the credits to unlock my phone just to support them. Thanks guys!

August 23

Of all the stupidest things...

... have someone moan your IP!

http://www.moanmyip.com/

Still - just thinking of doing something like this, impresses me.

August 14

Summer summer summer...

The summer in Norway (well - at least where I've been) has not been much to brag about. Raining, cloudy, rain, more rain, and - well - actually, there has been a couple of days where I have seen the sun (typically after I started working again.)

I'm not complaining, I have had a great summer, and cloudy weather is not bad at all for shooting photos.

 

And I have not had all of my vacation yet :-) I will get to see the sun! Oh yeah! Tickets are booked.

June 11

Omega Geek

Tony just sent me this hilarious link: The OmegaGeek Manifesto 
 
Count me in!
 
Oh yeah - caught this nugget before it escaped:
 - can't wait to push that link!
May 08

New Features on CodeResort

My good colleague Odd Simon Simonsen - the mastermind behind our CodeResort site - stayed up late yesterday and deployed a new version, including something we call "User Projects". The idea is that you, as a registered user on CodeResort, now have your own "project space", almost like a real project, with a few limitations.

The user project has two main goals:

  1. A place to store your private notes, probably regarding the projects you're involved with on CodeResort, but it could be anything.
  2. Give you as a user a "home" on CodeResort where we'll provide consolidated information across projects

Registering Your User Project

You need to register some information in order to create the project, like the your name and the company you work for. This is a way for us to know who you are (by using the PublicInformationPage wiki page you're exposing things to the public, which could be anything, also illegal things we'd rather not have on CodeResort. By requiring some personal details we make these things less likely to occur.)

Log in to CodeResort as usual. The link in middle in the top navigation will say "My CodeResort (create profile)". Click it and register your username today before anyone else takes it. 

 
(click image for full size).

Wiki Pages

The user project has the same wiki module as the real projects, which means you can create as many wiki pages as you'd like. If you create one called PublicInformationPage it will be exposed to visitors that navigate to your user project (like www.coderesort.com/u/stevec).

Here is my private index page and my public information page:

 
(Click image for full size)

I've chosen to create list of the projects I use most often on the start page of my user project. I've even set my user project as the start page in Firefox which will log me in and show the list of often used projects without having to click anything. Nice!


(Click image for full size)

My public page is not that interesting. It links to EPiCode and my blog. Using every opportunity to advertise :-)

My Tickets

The coolest feature so far is the list of tickets from all the projects you're involved in. Especially for me, as I'm involved in quite a few projects. With this I get a view of what I've got to do, and what tickets I'm involved in. The list was quite long, way to long actually. Another good reason to get those tickets closed.


(Click image for full size)
In this screenshot I've limited the list to only show EPiCode (Open Source EPiServer modules) tickets (can't show you all of my bad conscience you know :-)

We're planning on adding more features to the user project later on. I'll keep you posted.

The API project

As you might now, CodeResort is based on Trac, which has an XMLRPC module for communicating with the site from code. We've created an API project which you'll have access to if you have a CodeResort login. You can find example code on how to retrieve information from a CodeResort project from both Python and C# code (It could be any language that have an XMLRPC library.) Take a look and see if you can think of something smart to build. Use the forum if you have questions, or the ticket system for any bug-reports or feature requests.

Read more about it on https://www.coderesort.com/p/api/help/common/News#a2007-05-07:::CodeResortAPIavailable.

Other things

The urls on CodeResort has been "shortened". For an example www.coderesort.com/projects/epicode is now www.coderesort.com/p/epicode (the old one still works of course). Less to read, less to write and fewer line breaks on urls in textmode emails. Less is truly more.

May 04

EPiServer CMS RC 1 is out

Download it from episerver.com today (requires log in). The presentations from our last tech forum (about EPiServer CMS) is also available online (the page is in Norwegian, but the presentations are in English.)

At first, the new version of EPiServer did not look that "new" to me. Ok - maybe a few features here and there, but nothing major. I've had the time to look under the covers for some time now, and I have been seriously proven wrong. There are lots and lots of new stuff, mostly for developers like you and me, which - in my book - makes this a great release :-)

If you develop sites using EPiServer, chances are that this is what occupies most of your work day. Because we ship lots of web controls, a really nice configurable authentication chain, configuration wrappers and lots of other features that help you develop sites, chances are you have not had the chance or time to look at all the new features that shipped in ASP.NET 2.0. The thing is - lots of the features shipped in ASP.NET 2.0 - were already present in EPiServer. The time has come to stop developing, extending and fixing bugs in code that Microsoft has a good alternative to.

As a developer you can start preparing today by reading and learning about some of the things that you'll have to master the day you'll start your first EPiServer CMS project. The nice thing by aligning our feature set with standard features in ASP.NET 2.0 (and .NET 3.0) is all the information that has already been published, by both Microsoft and others.

Here are some links to get you started: 

Membership, Roles and Personalization

Data source controls

Themes and Skins

Control Adapters

Configuration API

Master Pages

 Do you have other links to good resources, please comment.

EPiCode now on IRC

We're trying something old (!) - we've created an #epicode IRC channel on irc.freenode.net. I'll try to remember to log in there in the morning, and keep the chat client open most of the day. There might be others there too, helping out with questions and taking part in discussions.

If you don't have an IRC client installed you might want to try the XChat client.

So, if you're a member of EPiCode, or just curious about it, drop by and chat with us. See you there?

UPDATE: I've trashed the XChat client, and moved to http://www.hydrairc.com/ instead.

March 28

EPiServer TechNews for March is out

See http://www.episerver.com/en/Start_page/NewsEvents/EPiServer-TechNews/EPiServer_TechNews/EPiServer-TechNews-March-2007/

If you're not receiving it already, you should subscribe now. Make sure you add the sender email address (news from episerver.com) to your "white list" to prevent it from ending in your junk mail folder.

This time you can read about the next version of EPiServer - officially named EPiServer CMS. Look ma' - no version number. Wonder what we'll call the version after that? EPiServer CMS+1? :-) Jokes aside, the name of the product is EPiServer CMS, the version will be 5.something, but we're moving away from the strong version focus in EPiServer 4 in our marketing material. For us tech'ies, knowing the version will be equally important as before, but for other reasons.

I've been "playing" with EPiServer CMS for some time now, and for you developers out there, this is a major update. I'll blog more about EPiServer CMS in the weeks to come. Stay tuned!

March 22

OK, I'll do it!

This morning I finally took the leap. I'm doing it, I  HAVE SET FIREFOX AS MY DEFAULT BROWSER.

I'm sick and tired of having Internet Explorer 7 crash and die violently when I open new browser windows. Taking my two hours of wiki text work with it.

I do not care if you blame it on a plug-in - I've tried to disable all of them. I just want things to work! Btw, I've got more - and better - plug-ins installed for Firefox. It has not crashed for me yet.

As a software developer I can live with a certain amount of bugs, crashes and strange things in general. It is not a perfect world, and software development is hard. But this is beyond ridiculous. Good thing there is an alternative.

March 13

Failed to load some types from...

I've been working on some of the modules in the EPiCode project on www.coderesort.com, and was getting this really annoying error:

Failed to load some types from "BVNetwork.EPiPageTypeUtil": Could not load file or assembly 'EPiServer, Version=4.60.0.165, Culture=neutral, PublicKeyToken=8fe83dea738b45b7' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)

The site I'm running is version 4.61 of EPiServer, but the assembly redirect in web.config should ensure that the module loads the correct version from web.config never the less:

<dependentAssembly>
  <assemblyIdentity name="EPiServer" publicKeyToken="8fe83dea738b45b7" culture="neutral" />
  <bindingRedirect oldVersion="4.0.0.0-4.65535.65535.65535" newVersion="4.61.0.83" />
</dependentAssembly>

But it does not.

I do not want to upgrade the reference in the EPiCode module, because it does not really need that version of EPiServer to run, and people might want to use it on older versions of EPiServer. I tried the Assembly Binding Log Viewer (Fuslogvw.exe) to see if that would give me more useful information, but that too was a dead end (to be fair, I did not spend too much time inspecting the logs.)

The stack trace looks like this:

[PlugInException: Failed to load some types from "BVNetwork.EPiPageTypeUtil": Could not load file or assembly 'EPiServer, Version=4.60.0.165, Culture=neutral, PublicKeyToken=8fe83dea738b45b7' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040) ]
EPiServer.PlugIn.AssemblyTypeInfo.?() +258
EPiServer.PlugIn.AssemblyTypeInfo.?() +147
EPiServer.PlugIn.PlugInLocator.get_Assemblies() +375
EPiServer.PlugIn.PlugInLocator.FindPlugInAttributes() +61
?.?() +8
EPiServer.Global..ctor() +429
EPiServerSample.Global..ctor() in C:\OWGeekCruise\trunk\web\Global.asax.cs:24
ASP.global_asax..ctor() in c:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files\root\f18ec31b\ca9f6b79\App_global.asax.mrrtlali.0.cs:0

[TargetInvocationException: Exception has been thrown by the target of an invocation.]
System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandle& ctor, Boolean& bNeedSecurityCheck) +0
System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean fillCache) +103
System.RuntimeType.CreateInstanceImpl(Boolean publicOnly, Boolean skipVisibilityChecks, Boolean fillCache) +261
System.Activator.CreateInstance(Type type, Boolean nonPublic) +66
System.RuntimeType.CreateInstanceImpl(BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes) +1036
System.Activator.CreateInstance(Type type, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes) +114
System.Web.HttpApplicationFactory.GetSpecialApplicationInstance() +175
System.Web.HttpApplicationFactory.FireApplicationOnStart(HttpContext context) +3412998
System.Web.HttpApplicationFactory.EnsureAppStartCalled(HttpContext context) +125
System.Web.HttpApplicationFactory.GetApplicationInstance(HttpContext context) +91
System.Web.HttpRuntime.ProcessRequestInternal(HttpWorkerRequest wr) +317

When EPiServer starts, it will try to locate all plug-ins by inspecting the assemblies in the bin directory looking for the different plug-in attributes (see the EPiServer.PlugIn namespace). This is short what the call stack above tells us. For some reason, when EPiServer triggers the load of these assemblies, including my offending one, ASP.NET does not obey the assembly redirect settings in web.config.

I did some searching, and came by the <startup> element that you can use to specify which .NET runtime you want. Wondering what other attributes the startup element supported, I opened the web.config file in VS 2005, and expected IntelliSense to tell me. It did not. Ah - that darn v2.0 xml namespace they introduced in 2.0 messes up IntelliSense for web.config:

<configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0">

should be:

<configuration>

Now, IntelliSense works, and you what? The error is gone! By pure luck I managed to find the reason to the problem. Weeeeell, maybe not the real real reason, but I know what I need to do to make it go away. Go figure.

I'm not 100% sure, but it seems like Assembly.Load(...) fails to recognize the assembly binding redirect instructions in web.config if the xmlns attribute is present.

February 16

EPiTrace is now available for free

The founder of EPiServer - Mikael Runhem - announced on the EPiServer Day 2007 that EPiTrace, the real-time über-cool statistics module will be a free download for all customers and partners.

Screenshot of EPiTrace

This module is a flash application that talks to your site in real-time, and shows how many visitors you've got, and where they are on the site. Now there is no excuse to not buy that 42" flat-screen for your office or reception!

As this is now part of the research projects on the Research site, it means that support is limited, but you'll get the source too, so you can fix it yourself.

Head over to http://r.ep.se/projects/EPiTrace/ to download it.

November 01

Understanding caching

Caching (especially in EPiServer) is a favourite of mine. Output caching, custom caching, caching dependencies and the like. However, just understanding how caching works in ASP.NET and EPiServer is not enough. You also need to know what happens to your data when it leave your server, and how proxy servers, gateways and clients might cache the data.

Mark Nottingham writes about this in his Caching Tutorial for Web Authors and Webmasters. Read it on http://www.mnot.net/cache_docs/.

October 24

Do not change the name of default properties in EPiServer

When developing EPiServer solutions, do not change the name of the default properties, like MainIntro and MainBody, especially if you're still going to use them for the same purpose.

The office integration uses these properties, so does a lot of 3rd party components and add-ins. Most of these can be reconfigured to use your new property names, but you'll save yourself some time down the line if you just stick with the default names.

If you don't need a property, you should delete it. If you rename it for the sake of editors, you're on the wrong track, you should use the language xml files for this.

To override the English label and tooltip for a property (in this case, the WriterName), create a file called z_overrides.xml in the /lang directory of the site, and add this xml:

<?xml version="1.0" encoding="utf-8" ?>
<languages>
  <language name="English" id="EN">
    <pagetypes>
      <common>
        <property name="WriterName">
          <caption>Content Owner</caption>
          <help>Name of the person who is responsible for the content</help>
        </property>
      </common>
    </pagetypes>
  </language>
</languages>

This works for all page types, but you can also specify property labels and tooltips for specific page types.

All language xml files are read alphabetically, so the name is important. This xml will override the property element found in the templateLanguageEN.xml file. By doing this, you don't have to change any of the existing xml files, which is a good thing if you plan on upgrading the site later.

October 22

Oh my! More Crazy Frog

But this one is just hilarious: http://www.giagia.co.uk/?p=104

Ding ding!

September 12

Fail Safe EPiServer Translation

I rather like the xml based text translation feature in EPiServer. The "best practice" method would be to store these in a resource file, but I feel the EPiServer solution is more flexible, and more maintainable for sure.

I'm not going to cover how the translation features work, if you're reading my blog, you probably know this already.

Sometimes, when rendering texts directly from code (behind), we need to make sure the text we output is useful, even if someone has removed the language file, or forgot to deploy it. Error messages is one example.

The global language manager (EPiServer.Global.EPLang) has a method TranslateFallback which allow you to write something like this:

string verb = EPiServer.Global.EPLang.TranslateFallback("/episerver.webparts/delete", "Delete");

If the key is not found, "Delete" will be returned instead.

August 24

Beware when comparing page references

Consider the following code:

// pageRef is a parameter to the function, and it is
// the page link of the currently loaded page
while (pageRef != PageReference.EmptyReference &&
       pageRef != EPiServer.Global.EPConfig.StartPage)
{
    PageData pd = GetPage(pageRef.ParentPageLink);
    pageRef = pd.PageLink;
}

It does one small thing, it walks the three towards the root, and stops on the start page.

There is a subtle issue with this code, one that I haven't stumbled over in all the years I've been doing EPiServer development. If you're viewing a given version of the start page (and you often do in Edit Mode), the PageReference will have a work id. Comparing a specific version of the start page and the Global.EPConfig.StartPage will return false. The two PageReferences are not equal. Gotcha!

If this code was part of something bigger, where you'd expect it to return a page below the start page OR the start page itself, and you gave the function the versioned start page as input, you would get an exception, or an EmptyReference.

The solution is of course to do a version independent comparison:

while (pageRef != PageReference.EmptyReference && 
       pageRef.CompareToIgnoreWorkID(EPiServer.Global.EPConfig.StartPage) == false)

The devil is in the details.