Maarten Balliauw {blog}

ASP.NET MVC, Microsoft Azure, PHP, web development ...

NAVIGATION - SEARCH

Automatically generate SandCastle documentation using CruiseControl.NET or VSTS Team Build

Earlier this week, I was playing around with SandCastle, and found that the SandCastle Help File Builder (SHFB) was a great tool to quickly create SandCastle documentation. No more XML writing, just a few clicks and documentation is compiled into a HTML Help file or as a MSDN-style website.

Next to the GUI being quite handy, there's also a command-line tool in the download of SHFB... Now wouldn't it be nice if you could just create a configuration file using SHFB, and automatically compile documentation on your build server every weekend? Here's a short how-to, for both CruiseControl.NET (ccnet) and VSTS Team Build!

Shared steps

Get the right tools

First of all, download and install the right tools on your build machine:

This should not be difficult, right?

Fix a small bug...

In the 1.5.0.1 release of SHFB, there is a small bug... Navigate to the file C:\Program Files\EWSoftware\Sandcastle Help File Builder\Templates\MRefBuilder.config, open it with Notepad, and replace %DXROOT% with {@SandcastlePath} on line 4.

Setup your project file the right way

Next, make sure that your application build outputs XML code comment files. To do this, open your project file's property dialog, and enable "XML documentation file".

Create a SHFB configuration file

Now, create a SHFB configuration file for your solution. Make sure you include the necessary libraries and XML comment files. Also, try building the configuration file you just created. It often occurs you need to add a link to another assembly in your configuration too. If that assembly does not have any XML comments, you can use this one: Unknown.XML (right-click, Save As...).

Use the "Namespaces" button on the top-right of the SHFB screen to include/exclude specific namespaces (useful for external assemblies!), and to provide a short description of those namespaces for use in the help file.

In my case, I added this file (and Unknown.XML) to a SourceSafe repository, which will be used by ccnet to always fetch the latest documentation configuration file.

One thing to keep in mind: references to assemblies that should be documented, must be located from the build server's perspective! This means that when your build folder is C:\builds\, your assembly paths must resolve to that location somehow (relative or absolute). 

CruiseControl.NET

If you are using ccnet as your build server, the following steps are required to add a documentation build to your build server!

Locate your ccnet.config file, and add a new project:

[code:xml]

<cruisecontrol>
  <project name="SandCastle_Documentation">
    <workingDirectory>C:\SandCastle_Documentation\</workingDirectory>
    <artifactDirectory>C:\SandCastle_Documentation\Generated\</artifactDirectory>
    <modificationDelaySeconds>0</modificationDelaySeconds>
    <sourcecontrol>
      <!-- ... Fetch Documentation.shfb here! ... -->
    </sourcecontrol>
    <triggers>
      <scheduleTrigger time="21:00" buildCondition="ForceBuild">
        <weekDays>
          <weekDay>Sunday</weekDay>
        </weekDays>
      </scheduleTrigger>
    </triggers>
    <tasks>
      <exec>
        <executable>C:\Program Files\EWSoftware\Sandcastle Help File Builder\SandcastleBuilderConsole.exe</executable>
        <baseDirectory>C:\SandCastle_Documentation\</baseDirectory>
        <buildArgs>"C:\SandCastle_Documentation\Documentation.shfb"</buildArgs>
        <buildTimeoutSeconds>10800</buildTimeoutSeconds> <!-- 3 hours -->
      </exec>
      <exec>
        <executable>xcopy</executable>
        <buildArgs>"C:\SandCastle_Documentation\Generated" "C:\Inetpub\wwwroot\SandCastle_Documentation" /E /Q /H /R /Y</buildArgs>
        <buildTimeoutSeconds>3600</buildTimeoutSeconds> <!-- 1 hour -->
      </exec>
    </tasks>
    <publishers>
      <xmllogger logDir="c:\Program Files\CruiseControl.NET\Log" />
    </publishers>
  </project>
</cruisecontrol>

[/code]

There are two notheworthy steps here, located inside the <tasks> element. The first task you see there is used to call the SHFB command line tool and instruct it to generate documentation. Now since I want to create a MSDN-style documentation website, I added a second step, copying the deliverables to a folder in my wwwroot. For both steps, make sure you extend the default <buildTimeoutSeconds>! Over here, the thing takes a hour and a half to complete both steps, you see I have configured a larger amount of time there...

Finished? Restart the CruiseControl.NET system service, and you are ready to build SandCastle documentation automatically! 

VSTS Team Build

If you are using VSTS Team Build as your build server, the following steps are required to add a documentation build to your build server!

Locate your TFSbuild.proj file, check it out, and add a build target at the end of the file:

[code:xml]

<Target Name="AfterCompile">
    <Exec Command="&quot;C:\Program Files\EWSoftware\Sandcastle Help File Builder\SandcastleBuilderConsole.exe&quot; &quot;C:\SandCastle_Documentation\Documentation.shfb&quot;" />
    <Exec Command="xcopy &quot;C:\SandCastle_Documentation\Generated&quot; &quot;C:\Inetpub\wwwroot\SandCastle_Documentation&quot;  /E /Q /H /R /Y" />
</Target>

[/code]

There is one notheworthy step here: the first target task you see is used to call the SHFB command line tool and instruct it to generate documentation. Now since I want to create a MSDN-style documentation website, I added a second task, copying the deliverables to a folder in my wwwroot.

Check-in the build file, and build the solution! SandCastle documentation will now be integrated in your build process.

PackageExplorer, not only great for OpenXML...

The last few days, I've been working with Wouter to discuss some new features and ideas for his PackageExplorer. PE is an editor for OpenXML packages, enabling you to view the contents and relations of different parts in a package, to validate XML against OpenXML schemes, ...

One of the cool things we discussed was a HTML start page. Since Visual Studio has one, we decided PE should have one too. After creating a simple mock for this, Wouter was first to Google for a way to embed images and HTML in a resource file, and display it in a fancy start page (second price, for slow Google searchers: I designed the page [<:o)]). You can see the code and build steps required over at Wouter's.

Next cool thing: a new splash screen model. Always wanted to do things right with threads? No more white gaps in your screen due to a blocked UI thread? I suggest you read the eventing and threading explanation at (again) Wouter's blog.

Next suggestion: download PE, even if you don't know a thing about OpenXML. Want to learn how to use OO patterns? Always wanted to provide add-in functionality for your own application? PE's code gives a lot of answers on those questions!

Microsoft Tafiti just released

I'm sure you have already heared of SilverLight before, right? If not: it's Microsoft's answer to Adobe Flash, providing the same features + XAML-like markup + easier databinding + ... Now you're up to date: the Redmond people have just released a new site, Microsoft Tafiti, which is basically Live Search combined with a rich SilverLight interface. Tafiti means "do research" in Swahili. Don't think I'm a native Swahili speaker though, I found this here 8-)

The screenshot I made was first rendered in FireFox. No need to worry your SilverLight application not going to work on other systems than Windows + IE!

If this is the way the web is evolving, I like it! Slick graphics, but not the "feeling" you are working in a browser plugin.

TFS Team Build and ASP.NET websites

Here's one I'd really like to share with everyone trying to build ASP.NET websites using TFS Build. First of all, a little story about the project setup...

A VS2005 solution was created a few weeks ago. This solution included some projects, namely ASP.NET website, Domain Layer class library, Business Layer class library and DAL class library. The ASP.NET website uses project references to the class libraries, enabling automatic updates of all references on build. So far, so good. As a test case, this project was added to a new TFS project, and created a build for. That specific build kept failing forever, ignoring all tips I found on various websites.

20070816buildok Two dozen cups of coffee later, an amazing thing happened: my build completed successfully! Colleagues were giving me strange looks when I jumped around the office, yelling around this great news, but hey: it is great news after all!

Here's how I did this: first of all, check out your Solution File (.sln), and open it up with any editor that pleases you (notepad.exe will do). Locate the line containing Release.AspNetCompiler.PhysicalPath. By default, it is set to the web project's name. Change this to ".\WebProjectName\":

Release.AspNetCompiler.PhysicalPath = ".\MyProject.Web\"
==>
Release.AspNetCompiler.PhysicalPath = ".\MyProject.Web\"

20070816solutionexplorer Save the file, and check it in. Second step: make sure the MyProject.Web\Bin folder under source control is EMPTY. The screenshot you see on the right illustrates a non-empty Bin folder. Fire up your Source Control Explorer, navigate to the web project's Bin folder, select all files in there, press the delete key, and check in pending changes.

Third step: BUILD! If magic happens for you, join my club. If it doesn't, try one of the things mentioned earlier in this blog post (in the story-part). There are people who get things working in one of those 4 ways, so it might be your success story too...

Open XML Developer workshop content

Over the last few months, Doug, Wouter, Brian and lots of other people delivered a series of OpenXML workshops around the globe. Those who were there, and those who weren't, can now download all content of these workshops from OpenXMLdeveloper.org.

There are some interesting slideshows available for those of you who never heared about OpenXML before, as well as some nice code samples to get you started developing in C# or Java.

As a side note: I also spotted a good article on OpenXML, explaining the Open Packaging Conventions with a self-created file format (based on OpenXML).

PHP zip:// and parse_url...

After having a few months of problems using PHP and fopen('zip://something.xlsx#xl/worksheets/sheet1.xml', 'r'), I finally found the reason of that exact line of code giving errors on some PC's... Assuming this uses a call to parse_url under the hood, I tried parsing this, resulting in the following URL parts:

Array
(
   [scheme] => zip
   [host] => something.xlsx#xl
   [path] => /worksheets/sheet1.xml
)

That's just not correct... Parsing should return the following:

Conclusion: beware when using parse_url and the zip file wrapper!

My job?

Seems that, according to this Wikipedia entry, I work at Microsoft:

To clarify this: I do not work at Microsoft, but at Dolmen, one of the top Belgian IT firms. I do work with Microsoft technology and tend to promote their technology too, but no job at Microsoft.

(Thank you Wouter for showing me this)