Integrate XML code comments into Visual Studio 2005/2008 using Sandcastle and HTML Help 2.0

by Alexander Brütt on March 20th, 2008

Hi folks,
a few days ago I figured out how to create HTML help files from code comments and how
to integrate them into visual studio so pressing F1 on one of my classes opens the
generated help file.
Because I spent much time googleing the world getting all information I needed I decided
to write down how I did it:

1. Download and install tools

- Sandcatle

- Sandcastle Help File Builder

- HTML Help 2.0 compiler
The Help 2.0 compiler is integrated into the VS SDK (VS2005) (VC2008)

The compiler will be installed in the directory “%Program Files%\Common Files\Microsoft Shared\Help 2.0 Compiler\”.
Search for hxcomp.exe if you can’t locate it.

2. Configure Visual Studio to generate XML comment file

Open Project properties. Select Build tab and ensure that the checkbox “XML documentation file” is checked.
Then recompile your project.

3. Configure Sandcastle Help Builder

Create a new project and add your assembly to the project. Ensure that an xml file was found too. The added
entry should look like “MyAssembly.dll, MyAssembly.xml” and not like “MyAssembly.dll, Unknown.xml”. In this case
your xml documentation file was not found and a documentation cannot be build.

Lets go on with the settings:

Build > Help File Format: Enable HtmlHelp2x
Build > Dependencies: Add all assemblies your assembly depends on here.
Build > Framework Version: Select the .NET Framework version your assembly is build on.
Help File > Presentation Style: Select vs2005. This is not neccessary but pretty.
Paths > HtmlHelp2xCompilerPath: Give the path to the directory where hxcomp.exe is located.
Paths > SandcastpePath: Set it to the correct installed sandcastle path. In my case I had multiple versions
of sandcastle installed and had to specify where the newest version is installed.

4. Build help file

Now you should be able to build your help file. You cannot view Help 2 files without special viewers.
So build HTML Help 1.x files first until your output fits your needs. Play around with the
settings and define style, disable warning and define what you want to be documented.
Finally build a HTML help 2.0 file if your want to get it integrated into the Visual Studio
help system and go on with the next step.

5. Integrate help file into Visual Studio

Run Visual Studio.
Select File > New Project.
Select Other Project Types > Extensibility > Help Integration Wizard
In the first assistant step leave “Setup project” selected, chose your Visual Studio version and go next.
In the second assistant step add your Html Help 2 files (*.hxs).
Configure the last two steps as you wish.
Build the project.
Run the created setup which installes your help files into visual studio.

That’s it! Happy Easter!

Alexander

kick it on DotNetKicks.com

March 20th, 2008 12:52 pm | Comments (11)

Convert .sln to MSBuild file

by Tobias Hertkorn on March 19th, 2008

Just a quick note:

There is a way to convert a .sln to a msbuild file.

All you have to do is open the Visual Studio 2008 Command Prompt and set an environment variable - it's that simple. ;)

PLAIN:
  1. set MSBuildEmitSolution=1

and execute

PLAIN:
  1. msbuild solutionname.sln

After a successful compile there will be a solutionname.sln.proj file - which is a complete msbuild representation of the .sln.

March 19th, 2008 11:32 pm | Comments (1)

.NET continues to DoS attack me, seriously!

by Tobias Hertkorn on March 19th, 2008

Yeah, it does! And I don't necessarily mean denial of service - that would mean that I couldn't get any programming done. Nope, far from it - but it sure is denial of sleep attacking me. Come one, I am struggling to keep up with all the new runtimes, features, frameworks and best practices coming out of Redmond. It's awesome and actually fun; no doubt about it - but sometimes it is excruciating as well. And today I am going to talk about the excruciating experience of seeing another reinvented wheel hobble out of Microsoft.

Oh, remember the good old days? 2002/2003 when there was just a handful .NET developer, hardly any frameworks, except THE framework. No choice, but hey, no need to choose either. But let’s face it, most likely too little choice. Then around 2005 things started to pick up. There was one, maybe two high quality frameworks to support you in a particular area of your programming efforts.

And I loved it. Why? Simply because reviewing frameworks for a new direction of programming (like ORM or IoC) took me about half a day, maybe a day of intense work. And then I usually had a definitive favourite. And yes, most of these frameworks were true open source projects.

I don’t know when things changed, but lately I feel ... insecure. There is no better way to describe it. I have my definitive favourites, still. BUT all of those choices date back to approximately 2005. Before all those little “Microsoft certified” framiworkies. And I am NOT talking about WF, WCF, WPF and (pure, in memory) LINQ. Those are simply awesome on so many levels and SOMETHING NEW. No, I am talking about all these half-good, half-god, reinvent-the-wheel-but-this-time-elliptic framiworkies like LINQ to Entities, LINQ to SQL, Unity, ASP.NET MVC, … And let’s not even get started on tooling: MSBuild, MStest, ...

Why does the appearance of these Microsoft frameworks make me insecure all over sudden? Because: Every single one of those comes with the guaranteed "follow-the-herd-momentum": "We have to use it, because it’s *chant-as-mantra* Microsoft *chant-as-mantra* Microsoft *chant-as-mantra*". Oh, my. But here’s the sad part: It preys on my mind as well. Not because I like to chant mantras, but because one can argue that most newcomers to the .NET crowd might not take time to evaluate the alternatives and choose Microsoft(tm) by default. That means that the continuous stream of fresh minds might dry up for all those great open source projects out there. And that’s all they survive on. And THAT means - I HAVE to evaluate those Microsoft thingies and make up my mind which horse to bet on. That is a way harder decision than the 2005 "oh, that one is shiny" one. Because now it is "uh, that one is still so very, very shiny and clearly superior in my eyes" combined with a "there is a brass one out there which is almost as shiny AND it is attached to a marketing campaign proclaiming that brass is the new extra shiny". You see, it’s no longer about popping the hood and looking at the engine in order to decide. I have seen a weaker product win because of marketing one too many times to still think naively about those matters.

Why does Microsoft do that? Why did they have to come up with a "new" (there is nothing new here!!!) IoC instead of endorsing one of the established frameworks. And the sad part is: They did, they actually did. There are a couple of excellent guides from Microsoft e.g. on using NHibernate and Windsor. Why doesn’t Microsoft stick to that theme, it would be way better for the community, for my productivity and for my sleeping habits. ;-)

In all seriousness: From my point of view all those "alternatives" don’t increase diversity. Or to put it another way: Those new "alternatives" don’t increase my happiness. Quite the opposite is true. I see them as a nuisance and certainly an unnecessary one. Last night while I was evaluating Unity, I had to think about a talk I watched on google video about a year ago. It’s called "The Paradox of Choice - Why More Is Less".

Good people at Microsoft: I hope you will soon realize that less is sometimes more. Stop reinventing the wheel. It is bad on many different levels. I strongly believe that it actually hurts your efforts. Seriously, watch the video. It is quite the eye opener. And after doing so choose one open source product, dedicate 2 or 3 of your employees to it. That way my boss knows that support for that OS project won't go away. I can get some sleep because I don't have to evaluate the next not-so-new-but-with-a-twist project you throw out there. And you will notice that it saves you money and gives your company some Egoboo.

kick it on DotNetKicks.com

March 19th, 2008 1:38 am | Comments (16)

How to bind SharePoint event receivers to a custom list definition

by Alexander Brütt on March 12th, 2008

In most cases you want to create your own list definition with your own event receiver that sould only react on events of your custom list.

SharePoint ships with alot of list definitions with unique list type numbers:

100: Generic list
101: Document library
104: Announcements list
and many more.

You can create event receivers that react on events of these list types.

To create a custom list definition you should use the visual studio template "List Definition" shipped with the VSeWSS 1.1. If you create a custom list with base type "document library" its id will also be 101. It's just a copy of the template you selected.

First line of schema.xml after creating the custom list definition project:

XML:
  1. <List xmlns:ows="Microsoft SharePoint"
  2.   Title="List Definition1"
  3.   Direction="$Resources:Direction;"
  4.   Url="MyDocumentLibrary"
  5.   BaseType="1"
  6.   Name="MyDocumentLibrary"
  7.   Id="cc1b7796-28cb-4eeb-9ca5-fdacfadddecc"
  8.   Type="101" 
  9.   xmlns="http://schemas.microsoft.com/sharepoint/">

So what you should do ist change the Type value to a non-used number:

XML:
  1. <List xmlns:ows="Microsoft SharePoint"
  2.   Title="List Definition1"
  3.   Direction="$Resources:Direction;"
  4.   Url="MyDocumentLibrary"
  5.   BaseType="1"
  6.   Name="MyDocumentLibrary"
  7.   Id="cc1b7796-28cb-4eeb-9ca5-fdacfadddecc"
  8.   Type="999" 
  9.   xmlns="http://schemas.microsoft.com/sharepoint/">

You also have to modify the ListDefinition.xml

XML:
  1. <Elements Id="cc1b7796-28cb-4eeb-9ca5-fdacfadddecc" xmlns="http://schemas.microsoft.com/sharepoint/">
  2.   <ListTemplate Name="BskhDocumentLibrary"
  3.                 DisplayName="My Dokument Library"
  4.                 Description="Custom document library with custom event receiver doing cool things."
  5.                 BaseType="1"
  6.                 Type="999"
  7.                 OnQuickLaunch="TRUE"
  8.                 SecurityBits="11"
  9.                 Sequence="110"
  10.                 Image="/_layouts/images/itdl.gif"
  11.                 DocumentTemplate="101" />
  12. </Elements>

and the ItemEvntReceiver.xml

XML:
  1. <Elements Id="faca01fe-8478-4116-8b72-1e243bda6268" xmlns="http://schemas.microsoft.com/sharepoint/">
  2.   <Receivers ListTemplateOwner="cc1b7796-28cb-4eeb-9ca5-fdacfadddecc" ListTemplateId="999">
  3.     <Receiver>
  4.       <Name>ItemDeleted</Name>
  5.       <Type>ItemDeleted</Type>
  6.       <SequenceNumber>1</SequenceNumber>
  7.       <Class>faca01fe-8478-4116-8b72-1e243bda6268</Class>     
  8.     </Receiver>
  9.     <Receiver>
  10.       <Name>ItemAdded</Name>
  11.       <Type>ItemAdded</Type>
  12.       <SequenceNumber>1</SequenceNumber>
  13.       <Class>faca01fe-8478-4116-8b72-1e243bda6268</Class>
  14.     </Receiver>
  15.     <Receiver>
  16.       <Name>ItemUpdated</Name>
  17.       <Type>ItemUpdated</Type>
  18.       <SequenceNumber>1</SequenceNumber>
  19.       <Class>faca01fe-8478-4116-8b72-1e243bda6268</Class>
  20.     </Receiver>
  21.   </Receivers>
  22. </Elements>

Now your event receiver will be called only by MyDocumentLibrary lists and no longer by all document libraries.

March 12th, 2008 4:01 pm | Comments (20)

Howto safely move a file using C#

by Tobias Hertkorn on March 1st, 2008

If possible this version uses the special File.Replace on NTFS and graciously falls back on Delete+Move on any other file system. Nothing else to comment about here. I am just amazed that this kind of save moving is not supported by the framework itself. Instead the framework's move routine throws an exception if there is an file existing at the target location. Weird. ;)

Just a heads up: Don't use this in performance critical parts...

C#:
  1. using System;
  2. using System.IO;
  3.  
  4. namespace Com.Hertkorn.Helper.Filesystem
  5. {
  6.   public static class FileMover
  7.   {
  8.     /// <summary>
  9.     /// Securely moves a file to a new location. Overwrites any
  10.     /// preexisting file at new location (= replacing file).
  11.     /// </summary>
  12.     /// <remarks>
  13.     /// If NTFS is available this is done via File.Replace.
  14.     /// If NTFS is not available it will be moved via deleting
  15.     /// any preexisting file and moving. Do NOT rely on the
  16.     /// backupFile being there - or not - after the move process.
  17.     /// That is not predetermined. This method is clearly
  18.     /// optimized for the case that NTFS is available. Consider NOT
  19.     /// using it on any other filesystem, if performance is an issue!
  20.     /// </remarks>
  21.     /// <param name="sourceLocation">The file to be
  22.     /// moved.</param>
  23.     /// <param name="targetLocation">The new resting
  24.     /// place of the file.</param>
  25.     /// <param name="backupLocation">A backup location that is
  26.     /// used when replacing on NTFS.</param>
  27.     public static void FileMove(
  28.         FileInfo sourceLocation,
  29.         FileInfo targetLocation,
  30.         FileInfo backupLocation)
  31.     {
  32.       if (targetLocation.Exists)
  33.       {
  34.         try
  35.         {
  36.           File.Replace(
  37.               sourceLocation.FullName,
  38.               targetLocation.FullName,
  39.               backupLocation.FullName, true);
  40.         }
  41.         catch (PlatformNotSupportedException)
  42.         {
  43.           // Not operating on an NTFS volume
  44.           if (targetLocation.Exists)
  45.           {
  46.             targetLocation.Delete();
  47.           }
  48.           File.Move(sourceLocation.FullName, targetLocation.FullName);
  49.         }
  50.       }
  51.       else
  52.       {
  53.         File.Move(sourceLocation.FullName, targetLocation.FullName);
  54.       }
  55.     }
  56.   }
  57. }

kick it on DotNetKicks.com

March 1st, 2008 12:41 am | Comments (7)
Tobi + C# = T# - Blogged blogoscoop