Contact

admin

About Me · Send mail to the author(s) E-mail · Twitter

At GROSSWEBER we practice what we preach. We offer trainings for modern software technologies like Behavior Driven Development, Clean Code and Git. Our staff is fluent in a variety of languages, including English.

Feed Icon

Tags

Open Source Projects

Archives

Blogs of friends

Now playing [?]

Error retrieving information from external service.
Audioscrobbler/Last.fm

ClustrMap

Abschlussbericht zum .NET Wintercamp 2007

Posted in DNUG Leipzig at Wednesday, 28 March 2007 00:42 W. Europe Daylight Time

Marci hat einen abschließenden Bericht zum .NET Wintercamp 2007, der letzten Veranstaltung der .NET User Group Leipzig, veröffentlicht. Ich kann mich seinem positiven Resümee nur anschließen. Die ersten Bewertungen, die Torsten heute per E-Mail versendet hat sprechen ebenfalls für einen guten Eindruck der Teilnehmer. Immerhin gibt es unter allen Einsendern der Feedbackbögen auch noch etwas zu gewinnen. :-) Ich freue mich schon auf das .NET Summercamp 2007 welches im September stattfindet.

Um The IT Crowd weiter zur strapazieren: “I even like saying the word … team.” 

Das Team: Torsten Weber, Alexander Groß, Susanne Neuhaus und Marcel Hoyer

Now Playing [?]: CluesoOut of space

Folien meines Vortrags vom .NET Wintercamp 2007 in Leipzig

Posted in DNUG Leipzig | Presentations | Tools and Software at Thursday, 22 March 2007 19:34 W. Europe Standard Time

Der Foliensatz des heutigen Vortrags mit dem Titel Tools aus dem Basement kann nun heruntergeladen werden. Ich hoffe alle Teilnehmer hatten so viel Spaß wie ich. Für Rückfragen stehe ich natürlich per E-Mail oder Kommentarfunktion zur Verfügung. Noch einmal der Hinweis zu den orangefarbigen Links in der Präsentation: Das Kürzel einfach hinter den URL http://www.shrinkster.com/ setzen und Sie gelangen zur referenzierten Seite. Oder nutzen Sie alternativ einen der unten aufgeführten URLs.

Bisher schätze ich das .NET Wintercamp als sehr gelungene Veranstaltung ein, auch wenn ich aufgrund meiner Arbeit nur Abends anwesend sein kann. Gerade die gut besuchten Abendveranstaltungen, wie z. B. das Buffet der ECG Erdgas-Consult GmbH aus Leipzig, das Spanferkel, gesponsert durch Microsoft Deutschland und die gestrige Brauereiführung mit anschließendem Abendessen im Restaurant FELIS zeigen, dass es in Leipzig eine große Anzahl an .NET Technologien interessierter Entwickler und Studenten gibt. Ich freue mich auf Anmeldungen bei der .NET User Group Leipzig!

Links

Now Playing [?]: BonoboDays to comeIf you stayed over (featuring Fink)

Comparing and Synchronizing Subversion Folders With Total Commander

Posted in Tools and Software at Monday, 12 March 2007 01:58 W. Europe Standard Time

My Swiss Army knife for file operations is Windows Explorer. No, just kidding. In fact, I don't see a point in using Windows Explorer at all. It always feels like an insurmountable hassle to get this tool doing what I want quickly. (Yes, I know about Ctrl+A, Ctrl+C, Ctrl+V and their siblings.)

Anyway, I didn't want to bash Microsoft's premier file manager, instead I wanted to share a little goodie for Total Commander, a tool that deserves to be called Swiss Army knife. Total Commander is my tool of choice when it comes to doing anything with files. It's runs virtually all the time I'm in front of the computer. There's also a version for your USB stick and one for Windows Mobile and craploads of plugins to try out.

Total Commander comes with a powerful synchronization tool that allows you to compare and synchronize two directories. Because Total Commander handles zip files transparently, it allows to synchronize between a zip and a directory or between two zip files. Comparison features I've almost always enabled are the "Subdirs", "By content" and "Ignore date" checkboxes. This allows me to quickly see any differences between folders.

Synchronize Directories

If a folder contains .svn or _svn subfolders to accommodate Subversion's internal bookkeeping files, Total Commander will also compare these files. Of course this is pretty useless since these files will most likely not hold information you're interested in. The Synchronize Directories dialog provides a filter text box at the top that allows you to define a pattern for files to include and ignore in the search. The syntax is simple but the tiny input field doesn't assist you defining a filter, at least it remembers the last filters used.

Here's a filter definition leaving out all files related to Subversion, it came in handy a couple of times for me.

*.*|*.svn-base all-wcprops entries format dir-prop-base

Now Playing [?]: MetricLive it out – Monster hospital

Now Playing 2.3 Plugin for Windows Live Writer

Posted in Music | Now Playing at Sunday, 11 March 2007 02:27 W. Europe Standard Time

Time to release a major update for my Now Playing Plugin for Windows Live Writer. Over the last weeks some minor bugs surfaced, these have been fixed with the current release.

The %if syntax

One thing that has been bugging me was that metadata placeholders were included into the resulting markup regardless of the actual content. Imagine you have the Amazon plugin enabled and the %AmazonAlbumUrl% placeholder somewhere in your markup template:

<a href="%AmazonAlbumUrl%">%Album%</a>

Later, while you're writing a new blog post you're listening to a mixtape that's not listed on Amazon. Because the Amazon plugin cannot find information about your mixtape, Now Playing will leave the placeholder as-is, resulting in bad markup taking your visitors into HTTP Hell™ filled with lots of peculiar errors messages (I've already seen this happening).

<a href="%AmazonAlbumUrl%">My Mixtape</a>

The new %if statement helps eliminating this shortcoming: Wrap any content that is linked to the availability of a particular placeholder in an %if statement and Now Playing will create perfectly valid markup. The syntax is pretty easy:

%if(%placeholder%<content to insert if the placeholder holds a value>)

The example above, restructured to

%if(%AmazonAlbumUrl%<a href="%AmazonAlbumUrl%">)My Mixtape%if(%AmazonAlbumUrl%</a>)

yields

  • My Mixtape
    
    if the Amazon plugin could not find the album's URL or
  • <a href="http://www.amazon.com/…">My Mixtape</a>
    if the Amazon plugin was able to obtain a link to the album's page on Amazon.

Of course you can nest if statements to create dynamic templates. I work now with the following template:

<p class="nowPlaying">
    Now Playing [<a title="Find out about Now Playing" href="http://therightstuff.de/Projects/NowPlaying/" rel="previewlink">?</a>]:
    %if(%MusicMapArtistUrl%<a href="%MusicMapArtistUrl%" title="Display relations of %Artist% to other artists">)%Artist%%if(%MusicMapArtistUrl%</a>) &ndash;
    %if(%Album%%if(%AmazonAlbumUrl%<a href="%AmazonAlbumUrl%" title="Display Amazon page of the %Album% album">)%Album%%if(%AmazonAlbumUrl%</a>) &ndash; )
    %Title%
</p>

See the %if(%Album%%if(%AmazonAlbumUrl%… nested if statements in line 4? I use this to get rid of the whole album part if I'm listening to a song from my mixed playlist where the music has no album tag.

Now Playing's markup preview currently handles all placeholders as if they're holding values, so you may have to try a little the get your template working as you wish. In case you're having problems with the syntax, please leave a comment and I'll try to explain. 

Other features, fixed bugs and changes

Other little things I've fixed:

  • An important notice about the Windows Media Player Plugin: You need to install the Blogging Plug-In for WMP in order to query the track information. Windows Vista users, please download this plugin which provides the same functionality on Vista (where the Blogging Plug-In refuses to install).
  • The Amazon plugins allows you to set the search index (Amazon US, UK, Germany, France, Canada, Japan) you want use.
  • Amazon has introduced a new access identifier I wasn't aware of. You can now use your Amazon Access Key ID with Now Playing. The possibility to use an Amazon Subscription ID is provided for backward compatibility.
  • The iTunes plugin allows you to set if you want to start the iTunes application if it's not running. (iTunes has always been launched before.)
  • Fixed a minor plugin loading bug and added detailed error messages.
  • Code cleanup.

Download

Now Playing [?]: Wir sind HeldenVon hier an blind – Wütend genug

Sorting Visual Studio's "Add New Item" Dialog

Posted in PowerShell | Visual Studio at Saturday, 03 March 2007 18:33 W. Europe Standard Time

While browsing my ever increasing stack of unread The Daily Grind posts I came across a blog post by K. Scott Allen that describes how to sort Visual Studio's "Add New Item" dialog with PowerShell. Neat idea, as I always disliked the fact that Visual Studio has no way of sorting these items alphabetically but relies on a property inside vstemplate files.

Visual Studio Default Sort Order

After downloading and running the PowerShell script he provides on my machine, I was greeted with some error messages. Some WinFX templates were destroyed, as these have an App_Code subfolder inside the zip that the Scott's script doesn't handle well. Fortunately the script creates backups so it wasn't a dealbreaker but rather a point to start from revisiting the script and making it more compatible.

# sort-vsItems
# scott at OdeToCode dot com
# Modified by AlexanderGross at gmx dot de
#
# Use at your own risk!
# Script will make a backup of each template just in case.
 
# vjslib for .zip support.
[System.Reflection.Assembly]::Load("vjslib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a") | out-null
 
# Get list of VS installed templates.
$installDir = [System.IO.Path]::Combine((gp HKLM:Software\Microsoft\VisualStudio\8.0).InstallDir, "ItemTemplates")
$templateFiles = gci -recurse $installDir | ? {$_.extension -eq ".zip"}
 
# Append list of custom templates.
$installDir = [System.IO.Path]::Combine((gp "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders").Personal, "Visual Studio 2005\Templates\ItemTemplates")
$templateFiles += gci -recurse $installDir | ? {$_.extension -eq ".zip"}   # Sort all templates by filename. $templateFiles = $templateFiles | sort name   $i = 1 $count = 0 $tmpDir = new-item ([System.IO.Path]::Combine([System.IO.Path]::GetTempPath(), [System.IO.Path]::GetRandomFileName())) -type directory $buffer = new-object System.SByte[] (8192)   # Iterate through all template files. foreach($templateFile in $templateFiles) {     write-host "Processing" $templateFile.FullName       # Extract all files (no methods available to modify zip in place).     $zip = new-object java.util.zip.ZipFile($templateFile.FullName)     $entries = $zip.entries()     while($entries.hasMoreElements())     {         $zipEntry = $entries.nextElement()           # Ensure output directory exists.         $filename = [System.IO.Path]::Combine($tmpDir.FullName, $zipEntry.getName())           # $zipEntry.isDirectory() does not work for Microsoft zips (e.g. Web\CSharp\WinFxServiceItemTemplate.zip).         $directory = [System.IO.Path]::GetDirectoryName($filename)         if ([System.IO.Directory]::Exists($directory) -ne $true)         {             mkdir $directory | out-null               # In case the zip tells us it's a directory entry, skip the entry to prevent exceptions.             if ($zipEntry.isDirectory())             {                 continue             }         }           $in = $zip.getInputStream($zipEntry)         $out = new-object java.io.FileOutputStream($filename)           while(($count = $in.read($buffer, 0, $buffer.Count)) -gt 0)         {             $out.write($buffer, 0, $count)         }           $out.Close()         $in.Close()     }     $zip.Close()       # Tweak the sort order element.     $vst = gci -recurse $tmpDir | ? {$_.extension -eq ".vstemplate"}     if ($vst -eq $null)     {         # The zip file does not contain a vstemplate.           # Clean temporary directory for the next template file.         del $tmpDir\* -force -recurse         continue     }       $xmlDoc = new-object System.Xml.XmlDocument     $xmlDoc.Load($vst.FullName)     if ($xmlDoc.VSTemplate.TemplateData.SortOrder -ne $null)     {         # Sort by zip name. Sort order must be a multiple of 10.         $xmlDoc.VSTemplate.TemplateData.SortOrder = ($i++ * 10).ToString()           # Sort by item name in Visual Studio.         # Uncomment this line if you want to let Visual Studio sort by item name.         # $xmlDoc.VSTemplate.TemplateData.SortOrder = "10"           $xmlDoc.Save($vst.FullName)     }       # Backup existing zip file.     $backupName = $templateFile.FullName + ".bak"     if(test-path $backupName)     {         # Remove previous backups.         remove-item $backupName     }     move-item $templateFile.FullName $backupName       # Zip up modified version.     $zip = new-object java.util.zip.ZipOutputStream(new-object java.io.FileOutputStream($templateFile.FullName))     $files = gci -recurse $tmpDir     foreach($file in $files)     {         if ($file.Attributes -contains "Directory")         {             # Subfolders are created automatically with files residing in subfolders.             continue         }           # Create a file entry.         # Replacing the last backslash from $tmpDir.FullName is crucial, the zips would work with any other         # zip editor but Visual Studio doesn't like files with a leading backslash (though one doesn't see         # it in WinZip).         $zipEntry = new-object java.util.zip.ZipEntry($file.FullName.Replace($tmpDir.FullName + "\", ""))         $zip.putNextEntry($zipEntry)         $in = new-object java.io.FileInputStream($file.FullName)         while(($count = $in.read($buffer, 0, $buffer.Count)) -gt 0)         {             $zip.write($buffer, 0, $count)         }         $in.close()         $zip.closeEntry()       }     $zip.close()       # Clean temporary directory for the next template file.     del $tmpDir\* -force -recurse }   del $tmpDir -force -recurse   write-host "Running Visual Studio to refresh templates" $vstudio = (gp HKLM:Software\Microsoft\VisualStudio\8.0).InstallDir & $vstudio\devenv /setup

DownloadDownload the updated script.

Please note the part highlighted in red: If you leave that last red line commented, the item template entries will be sorted based on the zip file name. Just like Scott's original script did. As you can see in the screenshot below, this will get you some pseudo-grouping as all WinFX templates are at the bottom.

Sorted by Zip File Name

If you want to let Visual Studio do the sorting, uncomment the last red line and you'll get truly sorted item templates.

Sorted by Item Name

There's also another solution to the problem, but FixVsItemSortOrder 1.0.3.5361 has a bug that prevents "<Language>ProjectItems" folders from being sorted (so says the readme). Not sure what he means there because there's no ProjectItems folder, maybe he means the ProjectTemplates folder. FixVsItemSortOrder, in contrast to the PowerShell script above, also doesn't take user-specific item templates into account.

Now Playing [?]: AirThe Virgin Suicides O.S.T. – Bathroom girl

The Web Proxy Auto-Discovery Protocol (WPAD)

Posted in ASP.NET | Networking at Thursday, 01 March 2007 18:01 W. Europe Standard Time

The Web Proxy Auto Discovery Protocol, WPAD for short, simply does what its name implies. An application connecting to the internet may search the local network to find information about proxies and rules which proxy to use when connecting to specific (i.e. local or remote) servers. WPAD leverages a JavaScript file called wpad.dat that is located on a WPAD server. The file itself is retrieved using HTTP. WPAD has been implemented by Netscape in 1996 has not changed much since then.

Publishing WPAD Information

Basically there are two ways for an application to detect the URL to the WPAD server:

  • There is a DHCP option that tells DHCP clients where wpad.dat can be found on a network. By virtue of DHCP this information is only available to DHCP clients. The DHCP option 252 can be used to return an URL to the wpad.dat file, e.g. http://wpad/wpad.dat. Note that URLs specifying non-standard ports are also possible: http://wpad:79/wpad.dat.
  • The other way to retrieve the wpad.dat script is to do a DNS lookup for a host named WPAD and do a HTTP GET for /wpad.dat on this host. The DNS option, however, provides less information to the client application because it only specifies the server and has no way of transmitting information about the HTTP port to the client.

Different Clients

Although WPAD has not become an internet standard yet, both Internet Explorer and Firefox try to acquire the WPAD script if you configure automatic proxy configuration, but in a slightly different way. Internet Explorer prefers DHCP information over DNS whereas Firefox only uses DNS.

Also, Window's built-in WinHTTP Web Proxy Auto-Discovery Service uses either DHCP or DNS to obtain WPAD information.

Possible Problems

Typically, the wpad.dat script is generated and served served by firewalls and proxy servers like Microsoft ISA Server based on the network configuration (you could also write your own custom WPAD script). The WPAD HTTP server, like any other HTTP server,  listens on port 80 for incoming requests. Because this would lead to conflicting ports if you're running another ("workhorse") HTTP server on port 80 of the firewall/proxy, WPAD-enabled firewalls and proxies typically let you choose an alternative port to listen for WPAD requests. All you need to do is to change the DHCP URL accordingly.

But what about the DNS case? As stated above, DNS does not carry port information. A successful DNS lookup for the WPAD host is all to justify a subsequent HTTP request to the server on port 80. But there's not the WPAD server answering, it's the workhorse HTTP server not knowing about a file called wpad.dat: HTTP/404. Bummer.

Solutions

Of course, you could copy wpad.dat to your "real" workhorse web server. But if the firewall/proxy configuration changes, you would need to copy the file over and over again. Certainly nothing a good network administrator strives for.

  1. One solution I tried was enabling URL rewriting on the workhorse web server and redirect requests for /wpad.dat to the WPAD HTTP server running on the alternative port 79. Although Firefox understands HTTP redirects, they were ignored, presumably for security reasons. Does not work.
  2. proxiing redirect on the server would come in handy, but I couldn't find free ISAPI components doing this. If you like to spend some money, ISAPI_Rewrite may be your choice as it has the RewriteProxy directive. Works, if you are willing to spend money.

Wanting a free solution, I a proxy web site on the workhorse IIS with an ASP.NET IHttpHandler.

  1. Set up your WPAD configuration so that the WPAD HTTP server listens on a port that is not used by other applications.
  2. Create a host (A) DNS entry for the WPAD host, pointing to the IP address of your proxy/firewall that also hosts IIS.
  3. Set up option 252 on your DHCP server giving it a value of http://wpad/wpad.dat. The port can be omitted as we're proxiing requests to the real WPAD server.
  4. Create a new IIS web site on port 80, specify host headers wpad and wpad.your-domain. The web site should run as an ASP.NET 2.0 application.
  5. Add a script mapping for .dat files so that they are processed by %windir%\microsoft.net\framework\v2.0.50727\aspnet_isapi.dll. Be sure to uncheck the "Check that file exists" option.
  6. Put these files in the web site's root folder, allow NTFS read access for IUSR_<Machine Name> and NETWORK SERVICE.
  7. Open web.config with a text editor and adjust the URL to the real WPAD server in the only key of /configuration/appSettings.
  8. Test your WPAD configuration with wget:
    rem Test the real WPAD server, this is what the proxy web site uses.
    wget http://wpad:<alternative port>/wpad.dat
    rem Test the proxy WPAD server, this is what clients use.
    wget http://wpad/wpad.dat
    
  9. Test with Internet Explorer, Firefox and other clients. Take a look at the IIS log files if requests were served with HTTP status code 200.

Now Playing [?]: Fujiya & Miyagi – Cassettesingle