Documenting Web Projects |
This topic contains the following sections.
A question that comes up with some regularity is how to produce a help file from the XML comments in the code for a web project using Sandcastle. There are two types of web project: a web application project and a website project (both include a web service and an AJAX-enabled variant of the project type). A web application project is the simplest to document as it generates a single assembly with a fixed name much like any other non-web project. A website project, however, requires some extra effort to document and has a number of limitations:
It does not necessarily generate a single assembly.
It only generates assemblies when you actually publish the project.
The assembly names may vary from build to build depending on the options you use when publishing the website.
There is no project-level option to produce XML comments files. Instead, you have to add a section to the Web.config file to produce them.
Even after adding the option to produce XML comments files, there are limitations:
If you specify a single comments filename, only the comments from the last assembly compiled will be saved. The VB.NET compiler has a /doc+ option to work around this issue. However, the C# compiler does not so this makes it impossible to fully document a C# website project.
The comments files produced using the VB.NET /doc+ option are not placed in the folder to which the project was published. Instead, they are left in the system's temporary ASP.NET folder for the related .NET version (i.e. C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET files so you must locate and retrieve them after each build.
To work around the limitations present when documenting website projects, you can use the custom code providers made available with the Sandcastle tools installer (one for C# and one for VB.NET). By using these code providers, you can specify a folder to which the XML comments files should be copied. This saves you from having to locate and copy them manually and solves the issue of the C# compiler not being able to output one comments file per assembly. Below are instructions for documenting each type of web project and information about how the code providers work.
As noted, web applications are the easiest to document and do not require the use of the custom code providers. These projects are created in Visual Studio by selecting File | New | Project and then selecting ASP.NET Web Application or ASP.NET Web Service Application from the Web category of your preferred language. Note that these options are only available in Visual Studio 2005 after you install Service Pack 1.
You must enable the XML comments option in your application projects so that an XML comments file is produced when the projects are built. This is done as follows:
In the Solution Explorer, right click on the project and select Properties.
Select the Build property page (C#) or the Compile property page (VB.NET).
The XML comments filename is a per configuration option. As such, you can either select the All Configurations option at the top of the page to set the XML comments options for all configurations at the same time or select each configuration individually and repeat the next step for each one.
For C#, in the Output section, check the checkbox next to the XML documentation file text box and specify a name for the XML comments file. Although not required, a common convention is to name the XML comments file after the related assembly except with a .xml extension. The assembly name can be found on the Application property page.
For VB.NET, just check the Generate XML documentation file checkbox. It names the file after the assembly automatically.
If you have a solution with multiple web application or web service application projects that need to be documented, repeat the above steps for each project in the solution. If using the Sandcastle Help File Builder, be sure to give each project's XML comments file a unique name as they are copied to a common location for the build. Identically named files would overwrite each other and the documentation in the overwritten files would not appear in the help file.
Once the above has been done, Visual Studio will create the XML comments file each time the project is built. It is placed in the .\bin folder along with the assembly. These can be used in conjunction with your preferred documentation tool to produce a help file.
These projects are created in Visual Studio by selecting File | New | Web Site and then selecting ASP.NET Web Site or ASP.NET Web Service from the template dialog box. In order to create XML comments files, you must add the custom code providers to the Web.config file and publish the website. This is done as follows:
If your project does not yet contain one, add a Web.config configuration file.
Add the following <system.codedom> section to the <configuration> section as shown in the example below. You only need to add the <compiler> element for the language that you are using but it will not hurt anything if they are both present.
<configuration> <system.codedom> <compilers> <!-- For C# --> <compiler language="c#;cs;csharp" extension=".cs" compilerOptions="/docpath:C:\Publish\Docs" type="EWSoftware.CodeDom.CSharpCodeProviderWithDocs, EWSoftware.CodeDom, Version=1.1.0.0, Culture=neutral, PublicKeyToken=d633d7d5b41cbb65"> <!-- NOTE: Change value to "v3.5" for .NET 3.5 projects --> <providerOption name="CompilerVersion" value="v2.0"/> </compiler> <!-- For VB.NET --> <compiler language="vb;vbs;visualbasic;vbscript" extension=".vb" compilerOptions="/docpath:C:\Publish\Docs" type="EWSoftware.CodeDom.VBCodeProviderWithDocs, EWSoftware.CodeDom, Version=1.1.0.0, Culture=neutral, PublicKeyToken=d633d7d5b41cbb65"> <!-- NOTE: Change value to "v3.5" for .NET 3.5 projects --> <providerOption name="CompilerVersion" value="v2.0"/> </compiler> </compilers> </system.codedom> </configuration>
Instead of a /doc option, the custom code providers use a custom /docpath option in the compilerOptions attribute that specifies the fully qualified folder name into which the XML comments files are placed. The folder will be created by the code provider if it does not exist. Any other compiler options that you might need can also be specified in the attribute value separated by a space.
In order to use the code providers, the ASP.NET compiler must be able to find them. You can either copy the EWSoftware.CodeDom.dll assembly into your project's .\bin folder or you can register it in the Global Assembly Cache (GAC) so that it is available to any project. To do so, use the gacutil command line tool as follows replacing the path to the assembly to match the installed location on your system:
gacutil -i \DotNet\Web\WebCodeProviders\Bin\Release\EWSoftware.CodeDom.dll
To remove the assembly from the Global Assembly Cache, use the gacutil command line tool as follows:
gacutil -u EWSoftware.CodeDom
You can find a copy of the tool in the Visual Studio installation folder in the .\SDK\v2.0\bin subfolder.
Once the above has been done, you can publish your website. Right click on the project in the Solution Explorer, select Publish Web Site, set the options, and click OK to publish it. When finished, look in the location you specified in the /docpath option and you will find one XML comments file for each assembly that was built for your website. These can be used in conjunction with the assemblies and your preferred documentation tool to produce a help file.
As an alternative to publishing the website, you can use a web deployment project. Add-ins are available at the following locations:
The Sandcastle Help File Builder version 1.8.0.0 and later supports wildcard documentation sources. As such, just add one entry with the path set to [appPath]\bin\App_*.dll where [appPath] is the path to the published website and another entry with the path set to [docPath]\App_*.xml where [docPath] is the path to the XML comments files.
Since the code providers are not needed after the website is published, you can delete the system.codedom section from the published Web.Config file and delete the assembly from the .\bin folder if you added it to the project for publishing.
Using the aspnet_compiler tool, it is possible to automate the publishing of a website project. The tool is located in the .NET Framework folder. For .NET 2.0 through 3.5, this is usually C:\Windows\Microsoft.NET\Framework\v2.0.50727. To run it, issue a command similar to the following (lines wrapped for display purposes):
C:\Windows\Microsoft.NET\Framework\v2.0.50727\aspnet_compiler -f -v /MyWebSite -p C:\Path\To\MyWebsite C:\Publish\MyWebSite
The -f option tells it to delete any existing content in the target folder (C:\Publish\MyWebsite in the example above). The -v [path] option tells it the virtual path of the website to compile (i.e. the path you use to load it in the web browser). The -p [path] option tells it the physical location of the website related to the virtual path to compile. Using a script, you could for example publish the website, build the help file, replace the Web.config in the published website with one that has had the system.codedom section removed, and delete the code provider assembly if it was copied locally. This is left as an exercise for the reader. The web deployment add-ins noted above support post-build events so they may provide better support for such tasks.
The following are some known issues and things to be aware of when using the custom code providers.
If any part of the XML comments file path contains spaces, enclose it in " entities (i.e. compilerOptions="/docpath:"C:\My Path With Spaces"").
Do not use a relative path in the /docpath option. Always use a fully qualified path. When using the project's publish option, the ASP.NET compiler always runs in the .NET Framework folder so your XML comments files will end up in a location relative to it rather than your project's folder if you do.
You can specify any folder except one that is under the location to which you publish the website. The act of publishing the website clears the destination folder and, since the comments files are produced first, you will lose them if you place them under it.
The code providers will delete any "App_*.xml" files from the specified folder on the first use. This prevents lots of files from accumulating in the comments file folder that contain duplicate information when not using fixed names. It also means that you should publish each website's comments files to a unique folder so that they are not lost if you are publishing and documenting multiple projects.
Unless you are using fixed names when publishing, the assembly and comments filenames will change each time you publish the website. As such, use wildcards (App_*.dll and App_*.xml) to specify the files to use in your preferred documentation tool.
When using the VB.NET custom code provider, the commonly imported namespaces such as System and Microsoft.VisualBasic are not included automatically for some unknown reason. The custom code provider will add a /imports command line option automatically for most of the common namespaces to work around the problem. If publishing fails due to undefined types when using the custom code providers, simply add a /imports:[Namespace] option to the compilerOptions attribute where "[Namespace]" is the missing namespace. You can generally identify namespaces that may cause problems by checking Web.Config for <namespace> elements in the <pages> configuration section. See below for a list of the common namespaces added automatically by the VB.NET custom code provider. Another workaround to this issue is to add Imports statements to the code for each of the required namespaces rather than relying on the automatically included references.
Related to the item above, when the custom code providers are active in the Web.Config file, you may see lots of errors indicated by the red squiggly underline related to missing types while viewing VB.NET code. During development, you can comment out the custom code providers so that this does not happen. As noted, the other workaround is to add an Imports statement to the code that includes the missing namespace that contains the types.
The custom code providers are actually quite simple. Both the C# and VB.NET custom code providers are identical with the exception of their base class and an extra set of compiler options passed by the VB.NET version. The C# version is shown below.
public class CSharpCodeProviderWithDocs : CSharpCodeProvider { public override CompilerResults CompileAssemblyFromDom( CompilerParameters options, params CodeCompileUnit[] compilationUnits) { CodeProviderHelper.ReplaceDocPathOption(options, null); return base.CompileAssemblyFromDom(options, compilationUnits); } public override CompilerResults CompileAssemblyFromFile( CompilerParameters options, params string[] fileNames) { CodeProviderHelper.ReplaceDocPathOption(options, null); return base.CompileAssemblyFromFile(options, fileNames); } public override CompilerResults CompileAssemblyFromSource( CompilerParameters options, params string[] sources) { CodeProviderHelper.ReplaceDocPathOption(options, null); return base.CompileAssemblyFromSource(options, sources); } }
The derived version simply overrides three key methods and, prior to calling the base implementation, calls the CodeProviderHelper.ReplaceDocPathOption method which takes care of updating the compiler options to produce a unique XML comments file for the assembly in the specified folder. It is shown below.
internal static void ReplaceDocPathOption( CompilerParameters options, string[] additionalOptions) { Match m; string docPath, docFile; // Replace /docpath with /doc if(!String.IsNullOrEmpty(options.CompilerOptions)) { m = reDocPathOpt.Match(options.CompilerOptions); if(m.Success) { docPath = m.Groups[1].Value.Replace("\"", String.Empty); if(!Directory.Exists(docPath)) { Directory.CreateDirectory(docPath); docFilesPurged = true; } else if(!docFilesPurged) { // Purge the comments files from the folder // on the first call. foreach(string file in Directory.GetFiles( docPath, "App_*.xml")) File.Delete(file); docFilesPurged = true; } docFile = Path.Combine(docPath, Path.GetFileName( Path.ChangeExtension(options.OutputAssembly, ".xml"))); options.CompilerOptions = String.Format( "{0} /doc:\"{1}\"", reDocPathOpt.Replace( options.CompilerOptions, String.Empty), docFile); } } // Append the other options if(additionalOptions != null && additionalOptions.Length != 0) options.CompilerOptions = String.Concat( options.CompilerOptions, " ", String.Join(" ", additionalOptions)); }
A regular expression is used to locate the /docpath option. If found, it extracts the folder name and either creates it if it does not exist or deletes all existing App_*.xml files in it the first time it is called. It then combines the path with the output assembly's name and a .xml extension and replaces the /docpath option with a /doc command line option. If any additional options are passed to the method, they are also appended to the command line options. The VB.NET code provider passes in an extra /imports command line option to specify the following default import namespaces to work around the issue noted earlier:
System
System.Collections
System.Collections.Generic
System.Collections.ObjectModel
System.Configuration
System.Data
System.Web
System.Web.Configuration
System.Web.UI
System.Web.UI.HtmlControls
System.Web.UI.WebControls
System.Web.Util
System.Xml
Microsoft.VisualBasic
By using the custom code providers and the instructions above, you can now easily produce XML comments files for website projects in order to create help files for them.