tirsdag, november 14, 2006

Visual Studio 2005 Build Performance

I had some performance issues with my Visual Studio 2005, where one of my C# ASP.NET web sites simply took forever to build and compile. I knew that there was an issue in VS 2005 with large Visual Basic projects due to a compiler error in the Visual Basic compiler(http://blogs.msdn.com/webdevtools/archive/2006/07/24/677180.aspx) but I am not using VB!

Then it hit me, ASP.NET web sites can run with both C# and VB code mixed so the Visual Basic compiler must run each time you build your website. To test this, I simply removed Visual Basic from my installation (seldom use it anyway) and bang ! – My website builds lightning fast again.

The lesson learned is this:
- Performance problems with compiling your website?
- Remove Visual Basic from your Visual Studio installation! (or apply the MS hotfix)

Resume of a lecture

I attended Anders Hejlsberg’s guest lecture at ITU Copenhagen last Friday and want to share with all of you the information he revealed.

First of all – it was a great lecture. He showed how all the language features of C# 3.0 together made LINQ possible and explained how they implemented LINQ using every one of these new language features. I must say that C# 3.0 is innovation on a high level, surely a something I will be waiting for with anticipation.

Besides from a great lecture, Anders revealed some information I want to share with you. (I hope MS don’t mind)

Concurrent Programming
The next step, after the release of C# 3.0 and LINQ – the language team will probably focus on concurrent programming. Anders believes that the available constructs for concurrent programming simply are to complex for the average programmer (Threads and so fourth) Therefore they will look at how they can improve the runtime and/or the language to better support concurrent programming, making it easier for developers to take advantage of multiple CPU’s that are getting more and more common in standard PC.

Release of C# 3.0 and LINQ
Anders revealed that the language team currently is improving some details of the compiler for C# 3.0 and we (the general public) will have a beta version of the next Visual Studio codename “Orcas” in about six months. He also ensured that there will be no more CTP – only Betas from now on.

UPDATE 2007-03-09
-----
Seams that Anders Hejlsberg was wrong :-)Last week a new CTP (March CTP) was released after all. I wonder if the Beta still will be available six months after the lecture ?
------------

Last note
There will finally be a Set collection implementation available in Orcas. Jubii.

tirsdag, oktober 31, 2006

Anders Hejlsberg in Copenhagen (IT University)

I just learned from my former professor (Peter Sestoft) that Anders Hejlsberg will host a guest lecture at ITU, Copenhagen on November 10th at 14:00 hours.

As you probably already know, Anders is the man behind C# and this lecture will contain a walkthrough of the new language features of C# 3.0 as well as his reasons for including these language features in this future release of C#.

C# 3.0 will include really cool features like:
- Implicitly typed local variable declaration: (for example var i = 42)
- Extension methods (the possibility to extend existing types with additional methods)
- Lambda expressions (cool SML like syntax for methods: x=> x + 42 )
- Greater type inference
- Object and collection initializers ( shorter syntax for creating instances)
- Anonymous types (like: new{Name = “Runi”, Language=”C sharp”})
- Implicity types arrays
- And the LINQ (declarative type safe access to query relational and hieratical data)

To register for this FREE event, register here:
http://www.microsoft.dk/MSDN/Hejlsberg@ITU

I will surely be there - see you all.

/Runi

fredag, oktober 27, 2006

Sitecore Instructur at last

I have yesterday reached the level of higher existence (or competence) - Sitecore V5 Certified Instructor, Level 2.

I just completed my first instruction in the Sitecore API course. It was actually quite giving and interesting to teach Sitecore on a lower level, surely something I want to do again.

Actually, if everything goes well, my next instruction session will be in Holland sometime late next month.

onsdag, oktober 25, 2006

Dont trust your debugger

I just waisted a couple of hours because of a strange behaviour in the Visual Studio debugger.
Consider the following code:

object
obj = new String('a',1); //"a"
string str = new String('a',1); //"a"
Console.Out.WriteLine(obj == str); //ln1
Console.Out.WriteLine(str == obj); //ln2
Console.Out.WriteLine((string)obj == str);//ln3
Console.Out.WriteLine(str ==(string)obj); //ln4
Console.Out.WriteLine(obj.Equals(str)); //ln5
Console.Out.WriteLine(str.Equals(obj)); //ln6

Now, add breakpoints in Visulal Studio on line 1 to 6 - and make the debugger evaluate the expression before it is printet to the console.


What would you (the debugger) expect the output to be? The Visual Studio Debugger says:
true
true
true
true
true
true


This is however not the case. The actual output is:
false
false
true
true
true
true


There is really nothing strange about the result. The == operator does not just call the Equals method blindly and virtually as one might expect. It is actually an operator that compares references unless overridden.

By default the == operator compares for reference equality. So if == tests for reference equality, this would explain the behavior of the result of ln1 and ln2, but not ln 3 and 4. This is because the == operator has been overridden in the String class to call the Equals method, thus comparing the value of the string rather than its reference. (this explains ln 3 and 4).

The runtime system determines which operator to call based on the runtime type (the type of the reference rather than the type of the instance). In ln 1 and 2 the == operator of the Object class is used, where in ln3 and ln4 the operator as defined in the String class is used.

So much for the == operator. The strange thing however, is that the Visual Studio debugger does not seam to get this. (VS2003). I used a lot of time debugging an expression inside an 'if' statement, which evaluated to false (by the debugger) but the if - statement - body was entered anyway. Grrr – I’m a bit pissed at the debugger.

torsdag, august 31, 2006

Media Library Posts Removed

Sitecore has asked me to remove my Sitecore 5.3 Media Library Part 1 - 5 blog posts which gave a preview of the Media Library in Sitecore 5.3 beta because of changes in the final version. I will of course honor this request, whereas these posts no longer are available. For info on Sitecore – contact Sitecore

A Sitecore Core Developer goes solo

I made a decision a couple of months ago of going back to my old discipline of software consulting. This means that I have resigned my position at Sitecore as a Core Developer and QA manager, and have created a Software Consultancy firm called “Delegate ApS” (I know, quite C#’ish)

My decision has been a hard one and has nothing to do with me not being happy with working on this amazing product. I simply missed the kick of being around real customers and following projects through.

During the time of employment at Sitecore I have learned allot of hardcore stuff. Specially working with Ole and Jacob (Core Developers and innovators of Sitecore) has been extremely giving. Before working at Sitecore, I was a consultant and have therefore worked with allot of developers through the years. Without comparison, the guys at Sitecore are the most competent. I will truly miss the high level of abstraction there guys are able to discuss architecture on.

However, this will not be the end of my work with Sitecore. Sitecore will make sure that I become a Sitecore Certified Trainer as soon as possible and I have decided that my new firm (Delegate ApS ) is to become a certified Sitecore Partner within a month or so. This means that I will finally sit on the other end of the table and experience actually working with the product, instead of creating the product.

All the luck in the world to Sitecore here at the end of my voyage as an Sitecore employee.

tirsdag, maj 02, 2006

InPlaceEditExtender for April CTP release of ATLAS

Nikhil Kothari created a fine ATLAS control named InPlaceEditExtender. The control does not work on the April CTP of ATLAS, so I modified the javascript to comply with the April CTP release, as well as added some support for dropdowns.
Download the control from Nikhil's blog, and replace the javascript with the following javascript and you will have the InPlaceEditExtender control for April CTP:

Type.registerNamespace('nStuff.Samples.InPlaceEdit');

 

nStuff.Samples.InPlaceEdit.InPlaceEditBehavior = function() {

    nStuff.Samples.InPlaceEdit.InPlaceEditBehavior.initializeBase(this);

 

    var _labelCssClass;

    var _labelHoverCssClass;

 

    var _labelElement;

    var _isEditing = false;

    var _isInputControl = false;

 

    var _textBoxBlurHandler;

    var _labelFocusHandler;

    var _labelMouseOverHandler;

    var _labelMouseOutHandler;

    var _validatedHandler;

 

    this.get_isEditing = function() {

        return _isEditing;

    }

 

    this.get_labelCssClass = function() {

        return _labelCssClass;

    }

    this.set_labelCssClass = function(value) {

        _labelCssClass = value;

    }

 

    this.get_labelHoverCssClass = function() {

        return _labelHoverCssClass;

    }

    this.set_labelHoverCssClass = function(value) {

        _labelHoverCssClass = value;

    }

 

    this.beginEdit = function() {

        if (_isEditing) {

            return;

        }

 

        var textBoxElement = this.control.element;

        textBoxElement.style.display = '';

        _labelElement.style.display = 'none';

        if(!textBoxElement.disabled)

            textBoxElement.focus();

 

        _isEditing = true;

        this.raisePropertyChanged('isEditing');

    }

 

    this.dispose = function() {

        if (_labelElement) {

            _labelElement.detachEvent('onfocus', _labelFocusHandler);

            _labelElement.detachEvent('onmouseover', _labelMouseOverHandler);

            _labelElement.detachEvent('onmouseout', _labelMouseOutHandler);

 

            _labelElement = null;

            _labelFocusHandler = null;

            _labelMouseOverHandler = null;

            _labelMouseOutHandler = null;

        }

 

        if (_textBoxBlurHandler) {

            var textBoxElement = this.control.element;

            textBoxElement.detachEvent('onblur', _textBoxBlurHandler);

            _textBoxBlurHandler = null;

        }

 

        if (_validatedHandler) {

            this.control.validated.remove(_validatedHandler);

            _validatedHandler = null;

        }

 

        nStuff.Samples.InPlaceEdit.InPlaceEditBehavior.callBaseMethod(this, 'dispose');

    }

 

    this.endEdit = function() {

        if (!_isEditing) {

            return;

        }

        if (_isInputControl && this.control.get_isInvalid()) {

            return;

        }

 

        var textBoxElement = this.control.element;

        _labelElement.innerHTML = textBoxElement.value;

        _labelElement.style.display = 'block';

        textBoxElement.style.display = 'none';

 

        _isEditing = false;

        this.raisePropertyChanged('isEditing');

    }

 

    this.getDescriptor = function() {

        var td = nStuff.Samples.InPlaceEdit.InPlaceEditBehavior.callBaseMethod(this, 'getDescriptor');

 

        td.addProperty('isEditing', Boolean, /* readOnly */ true);

        td.addProperty('labelCssClass', String);

        td.addProperty('labelHoverCssClass', String);

        td.addMethod('beginEdit');

        td.addMethod('endEdit');

        return td;

    }

 

    this.initialize = function() {

        nStuff.Samples.InPlaceEdit.InPlaceEditBehavior.callBaseMethod(this, 'initialize');

 

        _labelElement = document.createElement('LABEL');

 

        var textBoxElement = this.control.element;

        var textBoxBounds = Sys.UI.Control.getBounds(textBoxElement);

        var containerElement = document.createElement('SPAN');

 

        textBoxElement.parentNode.insertBefore(containerElement, textBoxElement);

        containerElement.appendChild(textBoxElement);

        containerElement.appendChild(_labelElement);

 

        textBoxElement.style.display = 'none';

        if(textBoxElement.tagName == 'SELECT')

            _labelElement.innerHTML= textBoxElement.options[textBoxElement.selectedIndex].text;

        else

            _labelElement.innerHTML = textBoxElement.value;

        _labelElement.tabIndex = textBoxElement.tabIndex;

        _labelElement.className = _labelCssClass;

        _labelElement.style.display = 'block';

        _labelElement.style.width = textBoxBounds.width + 'px';

        _labelElement.style.height = textBoxBounds.height + 'px';

 

        _textBoxBlurHandler = Function.createDelegate(this, this._onTextBoxBlur);

        _labelFocusHandler = Function.createDelegate(this, this._onLabelFocus);

        _labelMouseOverHandler = Function.createDelegate(this, this._onLabelMouseOver);

        _labelMouseOutHandler = Function.createDelegate(this, this._onLabelMouseOut);

 

        textBoxElement.attachEvent('onblur', _textBoxBlurHandler);

        if (Sys.Runtime.get_hostType() == Sys.HostType.InternetExploreJ) {

            _labelElement.attachEvent('onfocus', _labelFocusHandler);

        }

        else {

            _labelElement.attachEvent('onclick', _labelFocusHandler);

        }

        _labelElement.attachEvent('onmouseover', _labelMouseOverHandler);

        _labelElement.attachEvent('onmouseout', _labelMouseOutHandler);

 

        if (Sys.UI.InputControl.isInstanceOfType(this.control)) {

            _isInputControl = true;

            _validatedHandler = Function.createDelegate(this, this._onValidated);

            this.control.validated.add(_validatedHandler);

        }

    }

 

    this._onLabelFocus = function() {

        if (_labelHoverCssClass && _labelHoverCssClass.length) {

            Sys.UI.Control.removeCssClass(_labelElement, _labelHoverCssClass);

        }

 

        this.beginEdit();       

    }

 

    this._onLabelMouseOut = function() {

        if (_labelHoverCssClass && _labelHoverCssClass.length) {

            Sys.UI.Control.removeCssClass(_labelElement, _labelHoverCssClass);

        }

    }

 

    this._onLabelMouseOver = function() {

        if (_labelHoverCssClass && _labelHoverCssClass.length) {

            Sys.UI.Control.addCssClass(_labelElement, _labelHoverCssClass);

        }

    }

 

    this._onTextBoxBlur = function() {

        this.endEdit();

    }

 

    this._onValidated = function(sender, eventArgs) {

        if (this.control.get_isInvalid()) {

            this.beginEdit();

        }

    }

}

//Type.registerSealedClass('nStuff.Samples.InPlaceEdit.InPlaceEditBehavior', Sys.UI.Behavior);

nStuff.Samples.InPlaceEdit.InPlaceEditBehavior.registerSealedClass('nStuff.Samples.InPlaceEdit.InPlaceEditBehavior', Sys.UI.Behavior);

Sys.TypeDescriptor.addType('nk', 'inPlaceEdit', nStuff.Samples.InPlaceEdit.InPlaceEditBehavior);

tirsdag, april 11, 2006

Sitecore performance

ScottGu posted a blog entry where he explains the danger of setting debug=true in production enviroments.

The consequenses include:

1) Compilation of pages takes longer
2) Code executes slower
3) More memory is used at runtime
4) Scripts and images from WebResources.axd are not cached.

This is specially Sitecore relevant.


debug="false" is our friend

For details, see Scott's blog post.

http://weblogs.asp.net/scottgu/archive/2006/04/11/442448.aspx

fredag, april 07, 2006

.NET Remoting in Sitecore

The upcoming release of Sitecore (I guess it will be named Sitecore V5.3) will include a lot of new cool features. One of my favorite new features Im working on is remote invocation of Sitecore objects through .NET Remoting - giving you remote access to almost the entire Sitecore API (SitecoreKernel.dll) from any .NET client.

Hopefully the Remoting features will be stable enough to make the final release.

To enable your non-sitecore project (for example a Forms application) to use Sitecore Remoting, simply add a reference to Sitecore.Kernel.dll and you are good to go.

Access to Sitecore API is achieved through the new Sitecore.Remoting namespace, where you will have to know about two new types: The RemoteFactory and RemotingClientConfigurator. Only one line of code is necessary in order to get a remote reference to Sitecore:

Sitecore.Remoting.RemotingClientConfigurator.Configure(_sitecoreurl, "admin", "");



This snippet sets up the connection to Sitecore at a given url, with the username 'admin' and the empty password.

To access Sitecore objects, simply use the new RemoteFactory object (a remoting enabled version of the Factory class):

RemoteFactory factory = new RemoteFactory();



You now have access to all Sitecore objects. For example:

factory.GetDatabase("master").GetRootItem()



This will get you the root item of the master database.

In a later post, I will show how Sitecore can be managed and scripted through Microsofts new shell: MONAD using the new Remoting features.

Hopefully other more or less useful programs will be developed as a result of the introduction of .NET Remoting in Sitecore. I talked to Alexy Rusakov (Sitecore developer from our Ukraine division) about creating an addin to the Google toolbar showing a list of items who's workflow step is assigned to a specific user.

Only your imagination is the limit :-)


Regards

tirsdag, marts 28, 2006

Atlas StopableTimer

I tried out the March CTP release of Microsofts new Ajax implementation Atlas. The library now has a "go live" license making it even more interesting for us real life programmers.

The TimerControl included in Atlas March CTP has a problem. It cannot be stopped ones started. I guess that this is intentional (that’s what the documentation says) but the fact remains. You often want to be able to update a page, only while some task is run on the server.

A user on the Atlas forum named Rama Krishna (that’s his username) came up with a clean and great solution to create a stopable timer control (see the post here). However, the posted control only worked on the January CTP release.

I took his control and modified and updated it for the March CTP release (All credit to Rama).

The control emits a client-side timer control (xml) and assigns an id to it. (The base TimerControl does not). Then a small piece of java script is registered to handle enabling and disabling the timer at startup.

First put the following in the App_Code folder:

using System;

using Microsoft.Web.UI.Controls;

 

namespace CustomControls {

 

    public class StopableTimer : TimerControl {

        public StopableTimer() {

        }

 

        protected override void OnPreRender(EventArgs e) {

            base.OnPreRender(e);

            if (Page.IsPostBack) {

              Page.ClientScript.RegisterStartupScript(

          Page.GetType(), "TimerStop",

                    "Sys.Application.findObject('" +

            UniqueID +

            "').set_enabled(" +

            (Enabled ? "true" : "false") +

            ");"

                    , true);

          }

        }

 

        protected override void RenderScript(Microsoft.Web.Script.ScriptTextWriter writer) {

            writer.WriteStartElement("timer");

            writer.WriteAttributeString("id", UniqueID);

            writer.WriteAttributeString("interval",

          Interval.ToString(System.Globalization.CultureInfo.InvariantCulture));

            writer.WriteAttributeString("enabled", Enabled.ToString());

            writer.WriteStartElement("tick");

            writer.WriteStartElement("postBack");

            writer.WriteAttributeString("target", UniqueID);

            writer.WriteAttributeString("eventArgument", string.Empty);

            writer.WriteEndElement();

            writer.WriteEndElement();

            writer.WriteEndElement();

        }

    }

}



When you have created the control, you only need to register it on you aspx page - and use it as you would use a TimerControl

<%@ Register Assembly="App_Code" Namespace="CustomControls" TagPrefix="AppCode" %>