19 Dezember 2009

AssemblyAttributes

This is a cute little helper class that is useful for almost every .NET or Silverlight application that displays some information about itself (think “About Box”). It retrieves the values of the following assembly attributes in an easy and consistent manner:
  • Title
  • Product
  • Copyright
  • Company
  • Description
  • Trademark
  • Configuration
  • Version
  • FileVersion
  • InformationalVersion

Doing so is a piece of cake for every experienced developer but getting these information for the 100th time manually through reflection is quite cumbersome. And junior developers sometimes don’t know where to start and get lost in learning about reflection and attributes.
With the help of generics and lambdas you can code an elegant class that solves this problem one and for all. Usage is like this:

AssemblyAttributes assembly = new AssemblyAttributes();

string title = assembly.Title;
string version = assembly.Version;

And this is the full source:

/// <summary>
/// Easy access to common Assembly attributes.
/// </summary>
public class AssemblyAttributes
{
    readonly Assembly _assembly;

    public AssemblyAttributes() : this(Assembly.GetCallingAssembly())
    {}

    public AssemblyAttributes(Assembly assembly)
    {
        _assembly = assembly;
    }

    public string Title
    {
        get { return GetValue<AssemblyTitleAttribute>(a => a.Title); }
    }

    public string Product
    {
        get { return GetValue<AssemblyProductAttribute>(a => a.Product); }
    }

    public string Copyright
    {
        get { return GetValue<AssemblyCopyrightAttribute>(a => a.Copyright); }
    }

    public string Company
    {
        get { return GetValue<AssemblyCompanyAttribute>(a => a.Company); }
    }

    public string Description
    {
        get { return GetValue<AssemblyDescriptionAttribute>(a => a.Description); }
    }    
    
    public string Trademark
    {
        get { return GetValue<AssemblyTrademarkAttribute>(a => a.Trademark); }
    }   
    
    public string Configuration
    {
        get { return GetValue<AssemblyConfigurationAttribute>(a => a.Configuration); }
    }

    public string Version
    {
        get
        {
#if !SILVERLIGHT
            return _assembly.GetName().Version.ToString();
#else
            return _assembly.FullName.Split(',')[1].Split('=')[1]; // workaround for silverlight
#endif
        }
    }

    public string FileVersion
    {
        get { return GetValue<AssemblyFileVersionAttribute>(a => a.Version); }
    }

    public string InformationalVersion
    {
        get { return GetValue<AssemblyInformationalVersionAttribute>(a => a.InformationalVersion); }
    }

    /// <summary>
    /// Returns the value of attribute T or String.Empty if no value is available.
    /// </summary>
    string GetValue<T>(Func<T, string> getValue) where T : Attribute
    {
        T a = (T)Attribute.GetCustomAttribute(_assembly, typeof(T));
        return a == null ? "" : getValue(a);
    }

}

The real workhorse of this class is the GetValue<T> method. It gets an arbitrary custom attribute from an assembly. If it exists, it returns the result of applying the getValue delegate on it. If the attributes does not exist, it returns the empty string.


The full article with downloads is posted at CodeProject.

14 Dezember 2009

Improve performance through using FileAccess.Write

At work I’m implementing a little app that copies video files from cameras to network folders. The size of a video file is usually several hundred megabytes. The target file is written with the standard .NET FileStream class. The strange thing I noticed was that calling Close on the stream took between 15 and 20 seconds. Even if I flushed the stream Close call took ages. I created the stream like this

var output = new FileStream(path, FileMode.Create);

After playing with the available constructor overloads I found a better solution:

var output = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read);

Using this overload, the Close call took only 1 millisecond! That means a performance boost of factor 20000 just by using the right FileAccess Options.

Tip: Always use the “Read” or “Write” if you don’t need “ReadWrite”. This will give you a performance boost on network files.

12 Dezember 2009

Open Xaml file in Xml view without loading the Designer

I use Expression Blend almost always as a design tool for my WPF projects. If I want to do quick modifications inside the xaml code from Visual Studio, I find the designer loading time quite annoying. But VS offers you the possibility to open xaml files in the xml/xaml view by default. Just open Tools –> Options –> Text Editor –> XAML –> Miscellaneous and tick “Always open documents in full XAML view” check. 
full_xaml_view_vs2008

08 Dezember 2009

WiX Lessons Part 2

Today I did some localization of my WiX based installer and learned, that Windows Installer must have a very old code base. While localization with WiX is really easy it inherits some limitations that you don’t expect nowadays. First you cannot use UTF8 or Unicode to define your string tables. No, you need to specify windows codepages that should be used for a concrete language. Unicode is not supported. So you have to dig in old documentation for appropriate codepages (Luckily I can use Windows-1252 for West European Languages). Second you cannot simply build one msi for all languages. You must build a msi package for every language. Then you can either use a bootstrapper to decide which msi to start, or you can use some black magic on the command line which uses transformations at runtime to morph one msi into the appropriate language. Multi Language packages are not built into Windows Installer.

I had another strange behavior today regarding the usage of WiX library. I made a simple library with some very minimalistic installer gui which needs three images. projectThe three images are located inside an Images folder. See attached picture for the project structure. The files are referenced like this:

<Binary Id="Banner" SourceFile="Images\banner.bmp" />

First build succeeded than it always failed, saying that it could not find “Images\banner.bmp”. It seems some tool in the chain needs an absolute path because I fixed the build by adding the $(sys.CURRENTDIR) preprocessor directives:

SourceFile="$(sys.CURRENTDIR)Images\banner.bmp"

And you need to check “Bind files into the library file” on the Build page of the project properties. Else the library contains only the filenames and every project using the library must have access to the absolute path of the images. By default this is unchecked which imho corrupts the meaning of a redistributable library.

23 November 2009

Windows 7 Upgrade

Last week I have upgraded my business notebook from Vista to Windows 7. I have lots of stuff installed on this machine and I wanted to save time reinstalling every little tool I need. And it worked!

I started the setup in the afternoon and when it said “This can take several hours” decided to go home early this day. In the next morning it prompted for the serial key and wow Windows 7 was ready! In only needed to adjust the desktop resolution and was able to continue working without interruption. Every shortcut, every app was just working. This was the fastest and most impressive OS update I have experienced in the last twenty years.

And working with Windows 7 is really more effective! All those subtle changes that you begin using without noticing. Working feels much fluffier now and I instantly became  addictive. Must upgrade all other PC’s now …

29 Oktober 2009

WiX Lessons Learned

The last week I was playing around with the Windows Installer XML to create a simple setup for a very simple product implemented with .NET. All I needed to do was to copy some files, install a service under a custom account, let the user enter the address of some web services.
These features are hot:
  • open source
  • frontend for the built-in windows installer
  • done by people who know windows installer inside out
  • simple declaration of files and actions in xml
  • simple install/deinstall of services with properties like windows account or description
  • custom actions can done with .net very easily, they have read/write access to properties via a session object (see tutorial)
  • you can use managed custom actions for easy validation of custom dialogs
  • can easily integrated into automatic msbuild builds
  • very good logging capabilities which helps you on debugging
  • property based, declarative style
  • property values can be changed by administrators to support customized automatic install on clients
  • support for commit/rollback and repair/maintenance mode
But this is what bites me:
  • Bringing new Custom Dialogs (e.g. query user/password) into the dialog chain is really a pain in the ass. The chaining is done through adding event-actions to the next/back buttons which open new dialogs. Adding some conditional logic if a dialog should be shown or not has to be done by attaching conditions on the adding of event actions of the Next button of the previous dialog and the Back button of the following dialog. An you have to deal with this because on Repair/Maintenance Mode your need probably another dialog sequence.
  • Managed Custom Actions don’t seem to work in elevated mode. The bad thing is, that the installation succeeds without an error, and the custom action is ignored (that is unless you look into the log file).
  • There is no easy way to manipulate files, say app.config on the fly during installation. There is an XmlConfig extension you can use, but using it is rather crude, if you know how to do it in managed code.
  • The GUI support is very limited, you can have edit, password, combobox, listbox, check and radio controls, but layouting is done by entering x and y coordinates by hand. Browsing for a file is impossible, you can browse only for directories.
Other things:
  • You need the WiX tutorial or you are lost
  • You need DTF (Deployment Tools Foundation) for managed custom actions
    • it is included in the WiX package
    • the documentation is hidden in the doc folder of you installation … it is neither linked from the WiX documentation nor to be easily found on the internet

  • If you are a mortal .NET developer you have to do bend your mind to understand it, the windows installer technology sometimes feels like C64 basic with line numbers. Don’t be afraid, after one or two frustrating days you will get it.

20 Oktober 2009

IE8 Kompatibilitätsansicht für Intranetsites

Nachdem ich nun dem Table Layout abgeschworen habe und ins CSS Lager gewechselt bin, habe ich am Wochenende auch mein Hobbyprojekt SvnQuery auf CSS umgestellt. Das hat zwar etwas Mühe gekostet, aber dafür habe ich wieder etwas gelernt, das html hat eine klare Struktur und nebenbei wurden noch einige andere html Fehler beseitigt.

Zurück in der Arbeit aktualisierte ich auch die Suche der Firmenrepositories. Doch gleich bei der ersten Suche der Schock: Fette Scrollbalken schon auf der Startseite, offensichtlich wurde das Layout 200% breit statt wie gewünscht 100%. Und das auf dem IE8 gegen den ich hauptsächlich getestet hatte. Hatte ich schlecht getestet? Warum war mir das daheim nicht aufgefallen?

Also schnell das Projekt heruntergeladen, lokal installiert und ausprobiert. Und siehe da, das Layout war wie erwartet. Aber was war das Problem? Irgendwo musste es einen Unterschied geben. Entwickelt hatte ich gegen den ASP.NET Development Server, in der Firma läuft ein IIS6. Also schnell die Seite auf dem lokalen IIS gehostet. Doch auch hier wurde die Seite einwandfrei dargestellt. Jetzt wurde es mysteriös. Der einzige Unterschied, der noch blieb, war, dass auf meinem Enwicklungsrechner ein deutsches Vista mit IIS7 lief, und der Produktivserver mit einem englischen Windows Server 2003 und IIS6 arbeitete. Vielleicht ein Lokalisierungsproblem im IIS oder IE8? Ein Vergleich der Quelltexte von beiden Quellen zeigte zumindestens, dass der ASP.NET DataPager ein paar Texte lokalisierte (First ~ Erste, Next ~ Nächste, ...). Nachdem dies gefixt war, gab es aber auch hier keine Unterschiede mehr ... bis auf die Adressen der verlinkten CSS Stylesheets und Javscripts. Nun lernte ich, dass ASP.NET Scripts an dynamischen Adressen zum Nachladen generiert :
script src="/search/WebResource.axd?d=UV3-E5OwNGFcSb3I84w2&t=6391349351841...
Diese Scripte sind immerhin ca 20k groß und ihre Adresse ändert sich bei jedem Aufruf der Webseite. Vielleicht lag hier das Problem. Also speicherte ich die funktionierende Seite in ein lokales html file und bog händisch Schritt für Schritt die Links von der funktionierenden Quelle auf die nicht funktionierende um, in der Hoffnung irgendwann eine Seite mit dem zerstörten Layout zu erreichen.
Am Ende hatte ich jedoch eine lokale Seite mit Scripten und Stylesheets vom nicht funktionierenden Server, die immer noch das korrekte Layout anzeigte. Jetzt war ich völlig perplex!

Ich lud nun die beiden Seiten, funktionierend und defekt, in zwei Tabs des IE8. Während ich versuchte, mir eine neue Hypothese für dieses seltsame Verhalten auszudenken, schaltete ich immer zwischen beiden Tabs hin und her ... bis mir etwas auffiel. Es gab Unterschiede, aber außerhalb des eigentlichen Darstellungsbereiches. Das Symbol für die Kompatibilitätsansicht im IE8 war im defekten Layout nicht sichtbar! Warum nicht? Der andere Unterschied war in der Statusleiste zu sehen, die funktionierende Seite kam von "Computer" die andere von "Lokales Intranet". Hatte es etwas mit dem berüchtigten Zonenmodell zu tun? Ich konnte im Menüpunkt "Internetoptionen" nichts finden. Aber im Menü "Seite" gibt es den Punkt "'Einstellungen der Kompatibilitätsansicht" und dort gibt es die Option "Intranetsites in Kompatibilitätsansicht darstellen".
D.h. alle Seiten aus dem Intranet (wo sich auch das Firmenrepository befindet) werden in der Kompatibilitätsansicht dargestellt, und in der Kompatibilitätsansicht geht das Layout kaputt! Seiten vom lokalen Computer (localhost, Dateisystem) und aus dem Internet werden im neuen, standardkonformen Modus angezeigt! Offensichtlich ist dies die Standard Einstellung des IE8, wobei mir der Sinn dieser Option wirklich schleierhaft ist. Noch merkwürdiger, dass sie  standardmäßig aktiviert ist.





PS: Der Grund für das defekte Layout in der Kompatibilitätsansicht war übrigens ein absolut positioniertes Element, dessen Style die folgenden Attribute fehlten:
right: 1px;
top: 1px;
width: auto;
overflow: hidden;


11 Oktober 2009

Homepage Redesign mit Expression Web und Subversion

Gestern und heute habe ich mit einem Design für meine Homepage begonnen. Diese hatte ich mal vor Urzeiten (ca 2003) nach einem Provider Wechsel neu angelegt aber dann wegen Hochzeit, Kindern etc. nie wieder angefasst. Um den Lachanfällen von Frau, Kollegen und Nachbarn ein Ende zu setzen musste etwas passieren. Und eine gute Gelegenheit mal wieder meine Html Kenntnisse aufzupolieren. Und am besten gleich mal Expression Web 3 ausprobieren. Gesagt getan, rein ins Vergnügen.

Erste Erkenntnis, Table Layout ist out, CSS funktioniert tatsächlich, und nach einer halben Stunde Template Erforschung hatte ich dann a) ein funktionierendes neues Layout mit Navigation und b) endlich verstanden was das Cascading bedeutet. Und das man das Separation of Concerns Prinzip auch auf Stylesheets anwenden kann. Im Vergleich zu Frontpage oder gar dem Html Editor vom Visual Studio ist Expression Web um Lichtjahre besser. Kaum wartet man ein paar Jahre, schon geht alles viel leichter :-)

Doch dann bekam ich Probleme als ich versuchte mein Homepage Projekt unter Versionskontrolle zu stellen, konkret mit Subversion. Expression Web hat ja erstaunlicherweise keine eingebaute Unterstützung für Versionskontrolle außer für Microsofts TFS, welches außerhalb von großen Unternehmen kaum verbreitet sein dürfte. Mit Subversion bekommt man die größten Probleme, wenn Dateien oder gar Verzeichnisse umbenannt oder verschoben werden. Dies muss man unbedingt mit einem Subversion Client machen. Nun sind jedoch genau diese Operationen beim Aufbau einer neuen Struktur nicht gerade selten. Mit Expression Web läßt sich das alles sehr einfach und bequem erledigen, alle Hyperlinks werden automatisch angepasst, etc. Doch danach ist die Subversion Working Copy erst einmal Schrott. OK, dann verschiebe und benamse ich mittels TortoiseSVN. Hat man dabei jedoch Expression Web offen, hatte ich öfters das Problem, das plötzlich Dateien mit altem Inhalt überschrieben wurden, Links kaputt waren und am Ende das Programm behauptete meine Homepage wäre kein gültiges WebSite Projekt mehr.

Grund waren geheime (versteckte) _vti_* Verzeichnisse, deren Inhalt von TortoiseSvn logischerweise nicht upgedatet werden konnte. Letztendlich habe ich meine Homepage wieder aus der Versionskontrolle entfernt und mache jetzt wieder händische Backups des kompletten Verzeichnisses.

Ich frage mich nun, ob überhaupt jemand dieses Programm zu professionellen Web Design hernehmen kann, bzw. wo es Microsoft positioniert? Ohne funktionierende Versionskontrolle kann man doch nicht guten Gewissens arbeiten? Oder arbeiten Web Site Entwickler etwa noch ohne Versionskontrolle? Ich meine ein Versionkontroll Plugin Konzept wäre im Vergleich zu den vielen tollen anderen Features wirklich trivial gewesen. Es muss doch nur eine Benachrichtung übers Anlegen, Ändern, Löschen, Umbenennen, und Verschieben gesendet werden.

Wirklich schade, ohne dieses "fehlende Feature" ist Expression Web 3 wirklich ein tolles Produkt.

06 Oktober 2009

Don't forget to run aspnet_regiis and ServiceModelReg

Every few month I run into weird installation problems on IIS so that ASP.NET applications (including .svc WCF services and Silverlight applications) don't run with misleading error messages. Today I was running into this problem again. Seems that I hadn't the correct permissions to download a .xap file from the ClientBin silverlight folder. After fiddling around for half an hour or so I eventually remembered to run aspnet_regiis.exe -i to reregister the current .net framework. This solved the problem immediately.
Even if this tool is located in "%windir%\Microsoft.NET\Framework\v2.0.50727" it seems to reregister the newest installed framework (in my case .NET 3.5 and Silverlight).

A similar problem can occur for WCF services with the .svc extension. In this case you need to run ServiceModelReg.exe -i again. This tool is located in "%windir%\Microsoft.NET\Framework\v3.0\Windows Communication Foundation"

30 September 2009

My recent transformation from hating code generators to loving them

For a long time now I believed that code generators were evil. When I discussed this topic I mainly gave these reasons:
  • a strong believe that you could pack every code into a class and just use it from there
  • a chapter from The Pragmatic Programmer I wrongly remembered as "Beware of evil code wizards"
  • bad experience with MFC Wizards(VS 4.2) for database based data entry / viewing dialogs
It didn't came to my mind until now that I was already using code generators everyday:
  • Automatically add using references when typing still unreferenced types
  • Using Resharper's Complete Code to insert delegates or create method stubs
  • using Resharper's Live Templates to insert unit testing stubs
Perhaps they were so small and convenient that I didn't recognize them as code generators. Lateley I had to do a lot of WCF programming. First I totally rejected the recommended way of using Web References because they generated tons of code I didn't understand. I wanted to do it like Juval Löwy, that means
  • refactor all contracts into a ServiceContract dll
  • reference this dll from the server and the client
  • let the client use a ChannelFactory to create a proxy on the fly from the service interface
This was an elegant and easy to understand solution. Additionaly I would got compiler errors if I changed an interface and forgot to change the client. This is absolutely necessary if you use Continous Integration. Then I needed to think more and more about cross cutting concerns with WCF proxies like
  • retrying failed service calls
  • authentication
  • central exception handling

Some of these things cannot be simply refactored into another class and just used. Basically, often you need to wrap every method into a try-catch block or do some common initialization. You have to do the same thing over and over again, and if every member in your team has to do it also it becomes a nightmare to ensure that everyone is doing it in the same way. In parallel I needed to do some Silverlight clients for the same WCF services. This should be easy, but with Silverlight you can't reference the ServiceContract dll generated by normal .net (because it uses a different runtime version) and even worse you need to use the asnychronous communication modell, which means you need another interface with other methods. Combined with the additional needed cross cutting concerns and soon you have a very unmaintainable code base.

In this situation I started to think of a code generator that could generate proxies for silverlight and .net with allthe special cross cutting stuff from one single source. I started to develop it, and a day later I had a protypegenerating working proxies. I spent another day with integrating it into Visual Studio and the automatic build and then it was obvious to me that this was the right solution to my problems. Integrating cross cutting concerns is really simple, all the special knowledge is encapsulated inseid the proxy generator, proxies get regenerated on every automatic build with the newest proxy generator, team members just add a custom service generation step and start using the proxies. No more code reviews and no more search and replace through the whole code base if a cross cutting concern changes.

After this experience I have now reread the chapter about evil wizards and learned that my understanding mutated over the years. Actually the pragamatic programmer encourages you to build code generators to automate repetive tasks. The evil is not the code generation itself. The evil is, that you get code that you don't understandand that you must modify it, because it is like a framework. After a modification you cannot regenerateit without loosing your modifications.

Having this remembered and extended my understanding I can now happily say that generating code from file A to file B in a repeatable way is always safe. Its just like a compiler for a DSL stored in file A. Just don't modify B. Creating method stubs or unit test hull is also safe, even if you need to modify them, because they are small and understandable. But keep aware of run-once-wizards which generate complex application frameworks that you don't understand.

18 September 2009

Eintrag Eins

So, nun versuche ich mich auch mal als Blogger. Ich möchte hier Dinge aufschreiben die ich mit Mühe herausgefunden habe und die ich irgendwann einmal via google wiederfinden möchte. Manchmal brauche ich nämlich Jahre später Sachen die ich bereits gelöst wurden, aber oft vergesse ich all die vielen Probleme, die ich nur einmal gelöst habe ;-) . Ich habe es mir zur Gewohnheit gemacht vor jedem Problem *immer* zu googeln, um zu schauen ob vielleicht jemand anderes das gleiche oder ein ähnliche Problem gelöst hat. Und wenn meine Gedanken und Ideen für Google sichtbar sind, brauche ich nur einmal suchen :-) Ein Frage stellt sich mir noch, schreibe ich lieber in Englisch oder in Deutsch? Deutsch geht deutlich flüssiger, aber bei vielen technischen Problemen sucht man eh nach den englischen Keywords. Dann werde ich die Beitrage am besten gleich in Englisch schreiben.