Hi Alex!

by Tobias Hertkorn on February 28th, 2008

Hey there, just a quick personal note: Alexander Brütt joined us here at this blog. He is our absolute go-to guy when it comes to SharePoint development – even though that’s not really developing, right Alex? :) Check out his first post: Visual Studio 2005 Project Template for SharePoint 2007 Timer Jobs. Cool stuff. Good to have you here, Alex!

February 28th, 2008 11:00 pm | Comments Off

Visual Studio 2005 Project Template for SharePoint 2007 Timer Jobs

by Alexander Brütt on February 27th, 2008

What are SharePoint Timer Jobs?
SharePoint timer jobs are tasks executed on a scheduled basis by the SharePoint Timer service.

SharePoint comes by default with a lot of timer jobs, like profile synchronisation between Active Directory and SharePoint. To see all currently installed timer jobs go to Central Administration > Operations > Timer Job Definitions.

Developing your own SharePoint Timer Job
To create your own SharePoint 2007 timer job you have to perform the following steps:

  1. Create a class library project.
  2. Create a class derrived from SPJobDefinition that contains the business logic.
  3. Create a class derrived from SPFeatureReceiver that can be deployed and functions as an installer for the timer job.
  4. Create a feature description file: feature.xml
  5. Create a solution description file: manifest.xml
  6. Create build description files for makecab.exe to build a .wsp (cab) file: .ddf and .Targets
  7. Build the wsp file.
  8. Add the solution to SharePoint.
  9. Deploy the solution.
  10. Activate the feature.

Nobody wants to do all these steps for each new timer job. So in order to make it simpler to start a new timer job project, I created a visual studio template containing all the neccessary stuff you need.

Visual Studio 2005 Project Template
Andrew Connell wrote a good article on his blog on how to create a SharePoint timer job and to modify the visual studio project to get a deployable .wsp file after building the project. Based on his article I created a reusable visual studio template. In addition I included a setup.bat file that can deploy and undeploy the .wsp file.

How to use the template

  1. Download the template and save it in MyDocuments\Visual Studio 2005\Templates\Visual C#.
  2. Create a new project using the “Custom SharePoint Job” template (Be careful to not use a dot in the project name).
  3. Write your logic inside the Execute method.
  4. Build the project.
  5. Run the setup.bat in your project folder to install, deploy and activate your job (Do not copy it into your bin folder, just run it. Everything is taken care for you. :) ).

If no errors are shown your timer job is listed in the Timer Job Definition list of the central administration. Navigating to Timer job status you can find out if your job was executed and if there were any errors. In case of an error exception messages are written to the EventLog by SharePoint.

Tip: Before you start customizing your project (namespace, assembly version, file names) look inside every file to get an overview on how everything fits together.

Good luck on making good (timer-)jobs,
Alexander Brütt

Download: CustomSharePointJob.zip

Deploying the timer on a SharePoint Farm:
I had problems deploying the timer job on a farm. The following commands deployed the timer on the farm correctly:

1. Add the solution
stsadm -o addsolution -filename {WSPFILENAME}
2. Deploy the solution
stsadm -o deploysolution -name {WSPFILENAME} -url {SITEURL}
3. Install the feature
stsadm -o installfeature -filename {FeatureFolder}\feature.xml
4. Activate the feature
stsadm -o activatefeature -id {FEATUREID} -url {SITEURL} -force

kick it on DotNetKicks.com

February 27th, 2008 8:44 pm | Comments Off

Downgrade a VS 2008 .sln or .csproj to VS 2005

by Tobias Hertkorn on February 15th, 2008

I just had to convert a Visual Studio 2008 Solution and Project to Visual Studio 2005, because we had to exchange sources with somebody who did not use VS 2008 yet.

Even though Microsoft (of course :( ) did not provide a wizard or automated tool for it, converting the solution is possible to do, if you know what you are doing. It is actually pretty straight forward. At least in my case... I really can't tell if it is always that easy.

All I had to do in the .sln file:
change

XML:
  1. Microsoft Visual Studio Solution File, Format Version 10.00

to

XML:
  1. Microsoft Visual Studio Solution File, Format Version 9.00

The .csproj is more complicated (showing changes as diff):

XML:
  1. +++ C:/vsone/source/SoundEx.the/SoundEx.the/SoundEx.the.csproj.2005 
  2. --- C:/vsone/source/SoundEx.the/SoundEx.the/SoundEx.the.csproj.2008
  3. @@ -1,14 +1,17 @@
  4. +<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  5. -<?xml version="1.0" encoding="utf-8"?>
  6. -<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  7.    <PropertyGroup>
  8.      <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
  9.      <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
  10. +    <ProductVersion>8.0.50727</ProductVersion>
  11. -    <ProductVersion>9.0.21022</ProductVersion>
  12.      <SchemaVersion>2.0</SchemaVersion>
  13.      <ProjectGuid>{94E2C393-2BE5-411C-BAFF-892F2C049E06}</ProjectGuid>
  14.      <OutputType>Library</OutputType>
  15.      <AppDesignerFolder>Properties</AppDesignerFolder>
  16.      <RootNamespace>SoundEx.the</RootNamespace>
  17.      <AssemblyName>SoundEx.the</AssemblyName>   
  18. -    <TargetFrameworkVersion>v2.0</TargetFrameworkVersion>
  19. -    <FileAlignment>512</FileAlignment>
  20.    </PropertyGroup>
  21.    <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
  22.      <DebugSymbols>true</DebugSymbols>
  23. @@ -44,7 +47,7 @@
  24.      <Compile Include="Properties\AssemblyInfo.cs" />
  25.      <Compile Include="SoundexSystem.cs" />
  26.    </ItemGroup>
  27. <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
  28. <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
  29.    <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
  30.         Other similar extension points exist, see Microsoft.Common.targets.
  31.    <Target Name="BeforeBuild">

The "-" at the start of a line means remove from 2008 version and a "+" means add to 2005 version. For more explanation see Diff Section "unified format".

Hope this helps in case you need to do the same.

kick it on DotNetKicks.com

February 15th, 2008 7:00 pm | Comments (10)

Source Structure (Part 3): Be aware of long project names, or …

by Tobias Hertkorn on February 14th, 2008

... why 260 chars really is not that much.

Have you ever seen this error message, while starting a new project?

SvnPlanning - Exceeds maximum path length allowed

"The length of the full path for the solution, project or item you are creating exceeds the maximum path length allowed by the system. You must reduce the length of the name or the location."

I remember sitting in front of my first Win95 installation, wondering how they did that damn thing with the long filenames. And what a waste. 8.3 was enough. So I started naming all my new word documents something totally silly. Like "The Abstract Reflection Regarding Catcher In The Rye After Careful Consideration Disregarded.doc", or something similar in German. And I thought, wow, that's just 97 chars. 260 chars will last me forever! Little did I know...

A source of constant tweaking

How could it possibly be that 260 chars are not enough? Surprisingly 260 chars get used up surprisingly quickly when creating solutions in Visual Studio. Let's look at the default structure Visual Studio creates for me when I create a new solution:

<solution name>
               \_
                 <solution name>.sln
                 <solution name>
                                \_
                                  <solution name>.csproj
                                  Class1.cs
                                  ...
                                  bin
                                     \_
                                       Release
                                              \_
                                                <solution name>.dll
                                                <solution name>.pdb

(I hearts me ascii drawing)

That means a solution to create the dll "Com.Hertkorn.Framework.SampleFramework.dll" will result in a total path named:
C:\test\Com.Hertkorn.Framework.SampleFramework\Com.Hertkorn.Framework.SampleFramework\bin\
Release\Com.Hertkorn.Framework.SampleFramework.dll

That's a whopping 139 chars!

Hmm. Actually it seems as if the above error gets displayed at a total path name length of about 199 chars. Oh, well. Who cares what the actual number is. I guess the programmers of Visual Studio played it save and allowed for some leeway. Anyway, so we see, using the default strategy, Visual Studio creates a lot of file path bloat - which results in an obstacle, because it does limit the way we name dlls, which is directly connected with the default namespace, etc. and the way we structure the global structure of our subversion.
So the desire to have nice dll names and namespaces plus still being able to create deep directory structures creates, at least for me, a source of constant tweaking. Because either I create a solution with a short name and modify the namespace and dll name to represent the long name, or I start with the long name and shorten the subdirectories. Either way, it's an additional step that I would like to eliminate. And don't get me started on adding new projects to a solution.

What I currently do by hand are the following steps:

  • I create a solution using the full name of the target dll name in a test folder.
  • Close the solution.
  • Rename subdirectories to use a short name, usually removing redundant information.
  • Move the directory tree into my svn tree.
  • Reopen the solution.
  • Fix the paths to the projects.
  • Reload the projects.
  • If necessary tweak the namespaces.

That certainly is a number of steps that I can automate.

What we need to automate these steps

A tool automating these steps needs

  • The name of the target dll (full project description name).
  • The name of the target namespace.
  • The short name for the directory.
  • The filepath of the directory, where the solution structure will get created.
  • The information if both a solution and a project should get created, or if the newly created project should get attached to an existing solution.

Now we can create a structure like this:

c:\dev\Projects\Com.Hertkorn.Framework\
<short name>
            \_
              <full project description name>.sln
              <short name>
                          \_
                            <full project description name>.csproj
                            Class1.cs
                            ...
                            bin
                               \_
                                 Release
                                        \_
                                          <full project description name>.dll
                                          <full project description name>.pdb

This results in a file path:
c:\dev\Projects\Com.Hertkorn.Framework\SampleFramework\SampleFramework\bin\Release\
Com.Hertkorn.Framework.SampleFramework.dll and even with a deep folder structure it results in 126 chars. That is even less than with the default behaviour and flat folder sturcture.

Namespace (sometimes) != dll name

Plus this method allows for the additional freedom of easily choosing the namespace independant of the dll name. That is sometimes desirable, for example in a situation where types, typically interfaces should be shared between different dlls usually unifying components.

So component A which lives in the dll and namespace Com.Hertkorn.Infrastructure.ComponentA and component B which lives in the dll and namespace Com.Hertkorn.Infrastructure.ComponentB should share types. Ideally their shared types live in a component Com.Hertkorn.Infrastructure.SharedTypes.dll but the root namespace should differ. I would argue the root namespace should be Com.Hertkorn.Infrastructure. That way a subdirectory ComponentA or ComponentB would result in a namespace complementing the namespace they want to unify. It is kind of an exotic situation that needs a lot of discussion if the team wants to live with the consequences. But it could happen. ;)

What needs tweaking in the .sln or .csproj

Within the .sln we need to tweak the file path of the resulting .csproj, which should be quite straight forward.

The changes within the .csproj are located in these two lines:

XML:
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  3.   <PropertyGroup>
  4.     [...]
  5.     <RootNamespace>SvnPlanning.WpfSampleApplication</RootNamespace>
  6.     <AssemblyName>SvnPlanning.WpfSampleApplication</AssemblyName>
  7.     [...]
  8.   </PropertyGroup>
  9.   [...]
  10. </Project>

February 14th, 2008 12:41 am | Comments (3)

Startups: Who should you fire?

by Tobias Hertkorn on February 12th, 2008

I just came across a pretty funny, or sad (?) post by Mike. Startups: Fire Your Dev Teams. Yeah, that's what I thought.

To tell you the truth - he has some very valid points, indeed:

Seriously. The minute you’re successful, plan to rewrite your software from scratch.

That is a very good point. Even though, as the whole post does, even this quote does overshoot the target. There are EXTREMLY good points against rewriting from scratch. Nonono. Don't. It should read: "Seriously. The minute you’re successful, plan to rewrite your software. FULL STOP". Not from scratch, use refactoring techniques.

But the next sentence was the killer:

Plan to hire enterprise quality developers.

Now THAT's a WTF. Hahaha. I laugh, because it is so tragic. "enterprise"-anything is a marketing term. enterprise != quality. I am seriously getting allergic to that word and the misconception it carries along. Buzzword bingo galore! Well, what did I expect on a blog called "agile thinking". What is particularly funny is that he states "I’ve worked for two startups and consulted at several more.". All while he is seriously bashing startup developer AND suggesting that he does indeed know better. Now that is tragically funny. :) Just my kind of humor.

The sad part is that most symptoms he describes are actually management related. Not developer related. No developer enjoys the death march before a presentation. Those death marches are usually managment induced. Lack of requirements, incomplete feature lists, last minute changes, lack of sticking to decisions, ...

The requirements for developer don't change that dramatically going from a startup to a enterprise. What does change dramatically are the requirements for management. Going from 10 developer to 20 is a huge step. Going to 100 is different world. All the while it is true, not all developer that "have been with us all the time" should get promoted. But even that is a management decision. It's not the developer's fault. Move them to those team that should open up new business areas. That's where they belong and where they will most likely be most satisfied. And make a team of (newly hired!) quality asssurance professionals bundled with some (newly hired!) senior architects work on the legacy code base.

Good points:

  • There is a difference in business goals between startups and enterprises.
  • When you know you found your market, harden your business by hardening your codebase.
  • Not all developers are bound to become lead-anything.

Ugly stuff:

  • The title.
  • Overuse of the buzz word "enterprise".
  • Blaming the developer for most of these flaws.
  • Doing a complete rewrite without the old developers, that's the evil himself.
  • The three tests if you are "enterprise" or not are quite a lot of fun for all the wrong reasons.
February 12th, 2008 1:52 am | Comments Off

Source Structure (Part 2): The reference problem, or …

by Tobias Hertkorn on February 10th, 2008

... trying to make up for yesterday's post.

Sorry, for yesterday's first part. I guess it does actually represent pretty well how torn I am. Even the damn post is non-linear. ;)

So, I guess I really do have to write down all the options, all the pitfalls and all the optimizations I see. Maybe that will clear up my vision. Oh, and I would love to hear from you, how you solve this mesh of interdependency not just between projects, but also between tools - and all that under the strict goal to maximize productivity and obstruct the flexibility as little as possible. And flexibility in my sense of the word means as well that it should enable me, if needed, to improve on dependant frameworks as closely as possible (direct project reference in my solution) and if not needed allows me to save build time by reference a specific version of said framework by assembly reference.

Since this reference problem is as good a starting point as any other of the problems I see when thinking about source structures and source management, I'll start my discussion right here, work my way through this problem set and come up with followup problems.

The reference problem

I guess it is time for some images to accompany my requirements. What did I mean by direct project reference versus assembly reference. Pretty simple:

Direct project reference:

SvnPlanning - Direct project referencing

Assembly reference:

SvnPlanning - assembly referencing

So, direct project referencing allows me to make any changes to the framework directly, without switching to a different Visual Studio. This situation is ideal for starting the development of the framework or for hunting down bugs. It will greatly improve my productivity in those two scenarios, because here I can closely look at the relationship between my application code and the framework code. And altering the framework code and observing the effect on the application is as easy as can be.

But since it is a framework it should be a slowly changing part of your overall application and assembly landscape. That's why I need the second mode as well, where I just want to reference a precompiled assembly. That has two reasons: One it saves on compile time, because the IDE does not have to check if anything changed, etc. Thus improving my productivity while developing my application. And two it prevents me from accidentely modifying a framework or compiling against an old version or the trunk version, just because I did not pay close attention to what I checked out of source control. Don't underestimate the second argument! Anybody who has spent time hunting down a weird bug - until discovering that he didn't check out the correct version of a framework, will tell you about sever self-inflicted bruises from banging heads on desks, etc. So I believe the second argument is actually the stronger one of the two, because it saves me from wasting time and energy on checking and rechecking if I use the right framework. Plus it is there simply because I am worried about my (and your) health.

Can we automate that transition? Digging into the .sln and .csproj files.

Please don't pay any attention to the file paths here. I will discuss it later, why these filepaths displayed here are actually very, very evil.

Direct project reference:

This results in following SvnPlanning.WpfSampleApplication.sln:

XML:
  1. Microsoft Visual Studio Solution File, Format Version 10.00
  2. # Visual Studio 2008
  3. Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SvnPlanning.WpfSampleApplication", "SvnPlanning.WpfSampleApplication\SvnPlanning.WpfSampleApplication.csproj", "{A9CDAFB6-9224-4064-9A04-01C68C957633}"
  4. EndProject
  5. Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "_Framework", "_Framework", "{25121969-C024-446A-9CED-92ABD1200DE5}"
  6. EndProject
  7. Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Com.Hertkorn.Framework.SampleFramework", "..\Com.Hertkorn.Framework\Com.Hertkorn.Framework.SampleFramework\Com.Hertkorn.Framework.SampleFramework\Com.Hertkorn.Framework.SampleFramework.csproj", "{8EEAC483-B09F-4771-8A29-EFCC01B029FA}"
  8. EndProject
  9. Global
  10.     GlobalSection(SolutionConfigurationPlatforms) = preSolution
  11.         Debug|Any CPU = Debug|Any CPU
  12.         Release|Any CPU = Release|Any CPU
  13.     EndGlobalSection
  14.     GlobalSection(ProjectConfigurationPlatforms) = postSolution
  15.         {A9CDAFB6-9224-4064-9A04-01C68C957633}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
  16.         {A9CDAFB6-9224-4064-9A04-01C68C957633}.Debug|Any CPU.Build.0 = Debug|Any CPU
  17.         {A9CDAFB6-9224-4064-9A04-01C68C957633}.Release|Any CPU.ActiveCfg = Release|Any CPU
  18.         {A9CDAFB6-9224-4064-9A04-01C68C957633}.Release|Any CPU.Build.0 = Release|Any CPU
  19.         {8EEAC483-B09F-4771-8A29-EFCC01B029FA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
  20.         {8EEAC483-B09F-4771-8A29-EFCC01B029FA}.Debug|Any CPU.Build.0 = Debug|Any CPU
  21.         {8EEAC483-B09F-4771-8A29-EFCC01B029FA}.Release|Any CPU.ActiveCfg = Release|Any CPU
  22.         {8EEAC483-B09F-4771-8A29-EFCC01B029FA}.Release|Any CPU.Build.0 = Release|Any CPU
  23.     EndGlobalSection
  24.     GlobalSection(SolutionProperties) = preSolution
  25.         HideSolutionNode = FALSE
  26.     EndGlobalSection
  27.     GlobalSection(NestedProjects) = preSolution
  28.         {8EEAC483-B09F-4771-8A29-EFCC01B029FA} = {25121969-C024-446A-9CED-92ABD1200DE5}
  29.     EndGlobalSection
  30. EndGlobal

And following SvnPlanning.WpfSampleApplication.csproj:
(I skipped unnecessary parts. They are marked by [...])

XML:
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  3.   [...]
  4.   <ItemGroup>
  5.     <Reference Include="System" />
  6.     <Reference Include="System.Core">
  7.       <RequiredTargetFramework>3.5</RequiredTargetFramework>
  8.     </Reference>
  9.     <Reference Include="System.Xml.Linq">
  10.       <RequiredTargetFramework>3.5</RequiredTargetFramework>
  11.     </Reference>
  12.     [...]
  13.   </ItemGroup>
  14.   <ItemGroup>
  15.     <ProjectReference Include="..\..\..\Com.Hertkorn.Framework\Com.Hertkorn.Framework.SampleFramework\Com.Hertkorn.Framework.SampleFramework\Com.Hertkorn.Framework.SampleFramework.csproj">
  16.       <Project>{8EEAC483-B09F-4771-8A29-EFCC01B029FA}</Project>
  17.       <Name>Com.Hertkorn.Framework.SampleFramework</Name>
  18.     </ProjectReference>
  19.   </ItemGroup>
  20.   [...]
  21. </Project>

Assembly reference:

This results in following SvnPlanning.WpfSampleApplication.sln:

XML:
  1. Microsoft Visual Studio Solution File, Format Version 10.00
  2. # Visual Studio 2008
  3. Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SvnPlanning.WpfSampleApplication", "SvnPlanning.WpfSampleApplication\SvnPlanning.WpfSampleApplication.csproj", "{A9CDAFB6-9224-4064-9A04-01C68C957633}"
  4. EndProject
  5. Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "_Framework", "_Framework", "{25121969-C024-446A-9CED-92ABD1200DE5}"
  6. EndProject
  7. Global
  8.     GlobalSection(SolutionConfigurationPlatforms) = preSolution
  9.         Debug|Any CPU = Debug|Any CPU
  10.         Release|Any CPU = Release|Any CPU
  11.     EndGlobalSection
  12.     GlobalSection(ProjectConfigurationPlatforms) = postSolution
  13.         {A9CDAFB6-9224-4064-9A04-01C68C957633}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
  14.         {A9CDAFB6-9224-4064-9A04-01C68C957633}.Debug|Any CPU.Build.0 = Debug|Any CPU
  15.         {A9CDAFB6-9224-4064-9A04-01C68C957633}.Release|Any CPU.ActiveCfg = Release|Any CPU
  16.         {A9CDAFB6-9224-4064-9A04-01C68C957633}.Release|Any CPU.Build.0 = Release|Any CPU
  17.     EndGlobalSection
  18.     GlobalSection(SolutionProperties) = preSolution
  19.         HideSolutionNode = FALSE
  20.     EndGlobalSection
  21. EndGlobal

And following SvnPlanning.WpfSampleApplication.csproj:

XML:
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  3.   [...]
  4.   <ItemGroup>
  5.     <Reference Include="Com.Hertkorn.Framework.SampleFramework, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
  6.       <SpecificVersion>False</SpecificVersion>
  7.       <HintPath>..\..\Com.Hertkorn.Framework\Com.Hertkorn.Framework.SampleFramework\Com.Hertkorn.Framework.SampleFramework\bin\Debug\Com.Hertkorn.Framework.SampleFramework.dll</HintPath>
  8.     </Reference>
  9.     <Reference Include="System" />
  10.     <Reference Include="System.Core">
  11.       <RequiredTargetFramework>3.5</RequiredTargetFramework>
  12.     </Reference>
  13.     <Reference Include="System.Xml.Linq">
  14.       <RequiredTargetFramework>3.5</RequiredTargetFramework>
  15.     </Reference>
  16.     [...]
  17.   </ItemGroup>
  18.   [...]
  19. </Project>

As you can see, it is quite straight forward to switch between the two modes. When switching from direct referencing to assembly referencing the tool has to remove stuff from the .sln and remove a ProjectReference and add a Reference in the .csproj. The switch from assembly referencing to direct referencing is equally straight forward. Btw: Right now I don't care about Visual Studio integration of the tool, I am fine with unloading the solution, running the tool to switch mode and re-opening the solution.

From looking at the stuff that needs to change between the two mode we can derive what the tool needs to know:

  • The location of the .sln
  • The location of the two .csproj
  • The GUIDs of the two .csproj
  • The mapping that SvnPlanning.WpfSampleApplication.sln contains "{A9CDAFB6-9224-4064-9A04-01C68C957633}" (SvnPlanning.WpfSampleApplication.csproj)
  • The mapping that version a.b.c.d of "{A9CDAFB6-9224-4064-9A04-01C68C957633}" depends on version e.f.g.h of "{8EEAC483-B09F-4771-8A29-EFCC01B029FA}" (Com.Hertkorn.Framework.SampleFramework.csproj")

With that information alone it could tailor the .sln and the .csproj to either reflect mode A or mode B.

Decisions necessary to support this tool (= TODO list)

  • Do we check in the ever changing .sln and .csproj files into subversion?
  • Do we only check in the meta data that is needed to create the .sln and .csproj files?
  • Do we only check in .sln and .csproj in a certain mode, e.g. only in assembly reference mode?

Related decisions

  • Where should the precompiled assemblies of the framework lie, directly inside the application path, e.g. in a lib directory or in a special assemblies folder structure?
  • Do we use the GAC as a very special assembly folder structure?
  • Who is responsible for making sure that those assemblies exist, are up to date and contain the latest bugfixes?
  • How does this play out on the continuous integration server?
  • Can we get debugging information even for precompiled assemblies?
February 10th, 2008 7:09 pm | Comments (2)

Where is a reasonably elegant .Net Source Structure setup tool, or …

by Tobias Hertkorn on February 9th, 2008

... why putting everything together is damn hard.

The current situation...

At work we are currently working on a nice and big project. But sometimes we have to implementing smallish products on the side. They tend to look quite similar, they all share some common self-coded frameworks and they usually have some external libraries they depend on (Castle, NHibernate, EntLib, ...). Then they have to be checked into SVN, they should be built and tested on our continuous integration, so an appropriate project should get created there, ... Then we need a handful of Domain Objects to do some persisting, usually fairly simple stuff, some services that exposes the "server-side" and finally a GUI.

As you can see even if only setting up a simple solution that is under source control and using continuous integration, even that already takes three totally different tools too setup. Creating the solution in VS, doing a initial checkin via tortoiseSVN and going to your build server via remote desktop and tweaking the configuration files. During all this I tend to make errors, because I am still thinking about an interesting function in the nice and big project. And I am hurrying along, since I want to get back to it. So ... I make small errors. Every projects looks the same, but is slightly different. And me being a physicist, I know that a small disturbance repeatedly applied can sometimes lead to severe consequences. ;)

So, now I created my basic simple solution, but it still lacks the Domain. So, I start adding a project for the domain, choose the right name in order to have a consistent , put all domain objects in the folder DomainObjects. Create the hmb.xml (first remember the syntax again), write the class, write the filtering, write the service, set up basic unit tests, ...

I hear you scream: Tobi, all you need here is code generation. Ha, but that's what I was waiting for, because that means ... I need a FOURTH tool.

And we are not done here. Because now we get into the area of external dependencies and common frameworks. Do I put all external libraries in a lib folder under my solution? What about my frameworks? Do I include precompiled assemblies? How will bugfixes in those frameworks propagate into my solution? Will I have two Visual Studios open while improving the framework for the current solution, one for the framework and one for the solution? Or will I put a direct project reference into my solution? How will that decision affect continuous integration? So now I go for msbuild or NAnt. A fifth tool.

Hmm, now I ranted for a couple of pages - and the conclusion is: Even setting up a simple project and starting performing very basic coding tasks is a quite lengthy and errorprone process. BUT it is quite a lot of boilerplate code/configuration that varies very little between different solutions.

What do I want...
... which most likely not what I need! We all know that problem.

<insertion topic="YAY for tooling">

Give me six hours to chop down a tree and I will spend the first four sharpening the axe.
Abraham Lincoln

I am inherently lazy, well actually not lazy, lazy, but I strive to maximize my efficiency. If I know I will have to do a task more than three times and implementing a solution will cut the time in half that I will spend on doing said task, I am going to invest in that solution. Did you notice that I didn't say how much time I invest in implementing that solution? ;) Well sometimes, ... No. Actually it never, EVER takes more time than brute forcing my way through the boring repetitive task. Ever! And it's more fun and I learn a lot! Ha! So there you have it, three great points in favour of implementing tooling:

  1. ... never takes more time than the boring repetitive task!
  2. ... is fun!
  3. ... teaches a lot! (sometimes how not to do it...)

</insertion>

Anyway, back on topic: I want to supply a product name, if applicable dependencies, one or more service names and associated domain objects.

Taking that information a tool automatically sets up a source tree, consistently adds those dependencies, creates the service, domain and tests for the service. It generates the build script necessary for an automated build and test, performes the initial checkin and adds the new project to the continuous integration server.

Right now I don't see any way around improving on the tools we started writing ourselfs. Because I have not come across a tool that would do these tasks in an efficient way. Maybe I am mistaken?

I have looked at a long list of available tools, but it seems none of them have the capabilities to span across multiple problem domains. Plus most of the available tools have hidious addin APIs. Is it just me, or does anybody else share the feeling that XML is in no way suited for process-based, procedural scripting, such as build scripts. They tend to get very ugly, hard to read and maintain.

Well, do you have any suggestions?

Read on:
Assembly referencing versus direct referencing
And there is more: Be aware of long project names, or ...

February 9th, 2008 2:49 am | Comments Off

Quick, get more Germans on the internet, it just might save the world!

by Tobias Hertkorn on February 1st, 2008

I am serious, it might be the only way to stop global warming. In the spirit of the statistically significant inverse relationship between pirates and global temperature I present you the proof that we need to get more German citizens on the internet since that actually decreases the carbon dioxide emission per capita. See for yourself:

German citizens on the internet actually decreases the carbon dioxide emission per capita

I am not kidding! :) I found that out while I watched the video over at Gapminder and toying with their statistics. Awesome stuff! Very cool way to present statistics.

February 1st, 2008 9:59 pm | Comments Off
Tobi + C# = T# - Blogged blogoscoop