Sandcastle y los Tags XML para los comentarios en código.

Hola a tod@s,


 El siguiente artículo ya lo publiqué hace bastante tiempo en mi antiguo blog.


En el siguiente artículo os voy a explicar como agregar comentarios de forma sencilla con Visual Studio 2005 y luego con la herramienta Sandcastle generar una documentación en formato htm o chm. La finalidad es que si nos acostumbramos a que cada vez que hagamos una clase le añadamos comentarios siguiendo las reglas de los tags XML, podamos generar mas tarde una documentación completamente actualizada y de manera bastante rápida de nuestro proyecto. Y en caso de que usemos un generador de código, todavía es mas sencillo hacerlo.

Si estamos haciendo un proyecto en C# 2005 cuando queremos incorporar un comentario sabemos que se tiene que hacer con «//» pero si añadimos una barra mas nos aparecerá un menú contextual con etiquetas xml que tienen una característica especial:

/// <summary>
/// Esta clase hace una importante función. 
/// </summary>
public class MiClase{}

Los distintos tags que hay por ahora son:

<c> <code> <example> <exception> <include> <list>
<para> <param> <paramref> <permission> <remarks> <returns>
<see> <seealso> <summary> <typeparam> <typeparamref> <value>

Lo que voy a hacer ahora es poneros un ejemplo de como usar estas etiquetas en una clase. He construido una clase con 2 constructores, 5 propiedades y 4 métodos. No he usado todas las etiquetas, pero creo que con este ejemplo os bastará para coger conocimientos sobre el tema y si queréis profundizar siempre podréis seguir la MSDN.

Para poder llevar a cabo este ejemplo he tenido que instalarme la herramienta Sandcastle y luego usar un programa que facilita la tarea SandcastleGUI, he optado por este programa debido a su sencillez y porque es gratuito, para obtenerlo solo hay que registrarse.

Para mas información sobre como usar Sandcastle, herramientas que lo usan, etc. visitad este enlace: http://www.sandcastledocs.com/Wiki%20Pages/Home.aspx

Nota: Otra herramienta que está muy bien es la que podéis encontrar en http://www.codeplex.com/SHFB, lo único que es algo mas compleja que la que yo he usado en este ejemplo y no he encontrado la opción para poder incluir un logo. Lo bueno es que te deja parametrizar mas e incluso tiene una opción para que algunos textos aparezcan en español (pero esta opción no está muy lograda).

Mi clase con los comentarios añadidos me ha quedado así:

using System;
using System.Collections.Generic;
using System.Text;

namespace comentarios
{
    /// <summary>
    /// Clase de ejemplo
    /// </summary>
    /// <remarks>
    /// <para>Con esta clase aprenderemos los pasos básicos para <br/>
    /// crear una buena documentación con Sandcastle.</para>
    /// <img src=»Class1.png» mce_src=»Class1.png»></img>
    ///</remarks>
    public class Class1
    {
        /// <summary>
        /// Constructor principal de la clase.
        /// </summary>
        /// <remarks>
        /// <para>El constructor principal no admite parámetros.</para>
        /// </remarks>
        /// <seealso cref=»Class1(String, String, Boolean, Int32, DateTime)»/>
        public Class1()
        {
        }

        /// <summary>
        /// Sobrecarga del Constructor en el que se inicializan las propiedades.
        /// </summary>
        /// <example>
        /// <code>
        /// Class1 miClase = new Class1(«uno», «dos», 3, true, DateTime.Today);
        /// string p1 = miClase.Propiedad1;
        /// string p2= miClase.Propiedad2;       
        /// </code>
        /// </example>
        /// <remarks>
        /// Este segundo constructor necesita 5 parámetros, los dos primeros de tipo cadena <br/>
        /// el tercero de tipo booleano, el cuarto de tipo entero y el quinto de tipo fecha.
        /// </remarks>
        /// <param name=»prop1″>Propiedad 1 de tipo cadena</param>
        /// <param name=»prop2″>Propiedad 2 de tipo cadena</param>
        /// <param name=»prop3″>Propiedad 3 de tipo booleano</param>
        /// <param name=»prop4″>Propiedad 4 de tipo entero</param>
        /// <param name=»prop5″>Propiedad 5 de tipo fecha</param>
        /// <seealso cref=»Class1()»/>
        public Class1(string prop1, string prop2, bool prop3, Int32 prop4, DateTime prop5)
        {
            _sPropiedad1 = prop1;
            _sPropiedad2 = prop2;
            _bPropiedad3 = prop3;
            _iPropiedad4 = prop4;
            _dPropiedad5 = prop5;
        }

        /// <summary>
        /// Campo privado de tipo cadena, propiedad 1.
        /// </summary>
        private string _sPropiedad1 = string.Empty;
        /// <summary>
        /// Campo privado de tipo cadena, propiedad 2.
        /// </summary>
        private string _sPropiedad2 = string.Empty;
        /// <summary>
        /// Campo privado de tipo booleano, propiedad 3.
        /// </summary>
        private bool _bPropiedad3 = false;
        /// <summary>
        /// Campo privado de tipo entero, propiedad 4.
        /// </summary>
        private Int32 _iPropiedad4 = 0;
        /// <summary>
        /// Campo privado de tipo fecha, propiedad 5.
        /// </summary>
        private DateTime _dPropiedad5 = DateTime.MinValue;

        /// <summary>
        /// Propiedad pública que obtiene o establece el valor de <c>_sPropiedad1</c>.
        /// </summary>
        /// <remarks>Propiedad pública que obtiene o establece el valor de <c>_sPropiedad1</c></remarks>
        /// <value>Obtiene o establece el valor del miembro _sPropiedad1.</value>
        /// <seealso cref=»_sPropiedad1″/>
        public string Propiedad1
        {
            get {
                return _sPropiedad1;
            }
            set{
                _sPropiedad1 = value;
            }
        }

        /// <summary>
        /// Propiedad pública que obtiene o establece el valor de <c>_sPropiedad2</c>.
        /// </summary>
        /// <remarks>Propiedad pública que obtiene o establece el valor de <c>_sPropiedad2</c></remarks>
        /// <value>Obtiene o establece el valor del miembro _sPropiedad2.</value>
        /// <seealso cref=»_sPropiedad2″/>
        public string Propiedad2
        {
            get {
                return _sPropiedad2;
            }
            set {
                _sPropiedad2 = value;
            }
        }

        /// <summary>
        /// Propiedad pública que obtiene o establece el valor de <c>_bPropiedad3</c>.
        /// </summary>
        /// <remarks>Propiedad pública que obtiene o establece el valor de <c>_bPropiedad3</c></remarks>
        /// <value>Obtiene o establece el valor del miembro _bPropiedad3.</value>
        /// <seealso cref=»_bPropiedad3″/>
        public bool Propiedad3
        {
            get {
                return _bPropiedad3;
            }
            set
            {
                _bPropiedad3 = value;
            }
        }

        /// <summary>
        /// Propiedad pública que obtiene o establece el valor de <c>_iPropiedad4</c>.
        /// </summary>
        /// <remarks>Propiedad pública que obtiene o establece el valor de <c>_iPropiedad4</c></remarks>
        /// <value>Obtiene o establece el valor del miembro _iPropiedad4.</value>
        /// <seealso cref=»_iPropiedad4″/>
        public Int32 Propiedad4
        {
            get { return _iPropiedad4; }
            set { _iPropiedad4 = value; }
        }

        /// <summary>
        /// Propiedad pública que obtiene o establece el valor de <c>_dPropiedad5</c>.
        /// </summary>
        /// <remarks>Propiedad pública que obtiene o establece el valor de <c>_dPropiedad5</c></remarks>
        /// <value>Obtiene o establece el valor del miembro _dPropiedad5.</value>
        /// <seealso cref=»_dPropiedad5″/>
        public DateTime Propiedad5
        {
            get { return _dPropiedad5; }
            set { _dPropiedad5 = value; }
        }

        /// <summary>
        /// Método público que devuelve un booleano al comparar la longitud <br/>
        /// de los miembros  _sPropiedad1 y _sPropiedad2
        /// </summary>
        /// <returns>Devuelve un booleano</returns>
        public bool Metodo1()
        {
            return (_sPropiedad1.Length < _sPropiedad2.Length);
        }

        /// <summary>
        /// Método privado que establece el valor del miembro _iPropiedad4 <br/>
        /// a la suma de los 2 parámetros pasados.
        /// </summary>
        /// <param name=»x»>Primer parámetro entero</param>
        /// <param name=»y»>Segundo parámetro entero</param>
        private void Metodo2(Int32 x, Int32 y)
        {
            _iPropiedad4 = x + y;
        }

        /// <summary>
        /// Método público que llama al método privado Metodo2.
        /// </summary>
        /// <param name=»x»>Primer parámetro entero</param>
        /// <param name=»y»>Segundo parámetro entero</param>
        public void Metodo3(Int32 x, Int32 y)
        {
            Metodo2(x, y);           
        }

        /// <summary>
        /// Método públic que devuelve un valor doble obtenido <br/>
        /// a través de la división de dos enteros pasados como parametros.
        /// </summary>
        /// <param name=»x»>Primer parámetro entero</param>
        /// <param name=»y»>Segundo parámetro entero.</param>
        /// <returns>Devuelve un doble a partir de división de enteros.</returns>
        /// <exception cref=»System.Exception»>Se produce una excepción cuando intentamos dividir por cero.</exception>
        public Double Metodo4(Int32 x, Int32 y)
        {
            try
            {
                return x / y;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
    }
}

Una vez que tenemos el proyecto con los comentarios pertinentes tenemos que habilitar la opción de que al compilar se cree el fichero XML con los comentarios.

Nota: Es muy importante tener en cuenta que si nuestro proyecto hace referencia a otros assemblies, para que se genere correctamente, dichos assemblies tienen que tener asociado su XML de documentación correspondiente, en caso contrario no garantizo que la documentación creada esté correcta.

art9_01

Generamos la solución y ya podemos utilizar el Sandcastle a través del programa SandcastleGUI para generarnos nuestra documentación.

art9_02

Como podemos observar en la figura anterior vamos rellenando la información requerida sobre nuestro proyecto.

En la zona «General» rellenamos la primera casilla con la ruta donde se encuentra/n nuestra/s assembly/is, en la segunda casilla le decimos donde queremos que nos deje la documentación generada, la tercera casilla es para que en caso de que añadamos archivos adjuntos como imágenes las pueda encontrar, en mi caso he incluido la imagen del diagrama de la clase que he creado, en la cuarta casilla le indicamos el/los namespace/s que queremos documentar.
En la zona «Custom» indicamos el nombre del programa, la linea de copyright y en caso de que queramos un logo su ruta.
En la zona «Compilation» le indicamos si sigue una sintaxis de C#, VB o C++ manegado, si queremos que los ficheros generados (cuando es un Website) tengan nombres «amigables» o no (es decir, que los nombres de los htm generados tengan algún significado como F_comentarios_Class1__bPropiedad3.htm o que sea un nombre como si estuviera encriptado), si queremos que nos muestre las propiedades, métodos, etc privados (Document internals), que nos formatee a la sintaxis de C# los ejemplos, si queremos tener enlaces a la MSDN para las clases usadas del framework, y por último en qué formato lo queremos, para el ejemplo que he creado quiero un Website con plantilla Hana y que me cree el árbol de contenidos a la izquierda.
El motivo de que haya querido un Website es que te da la posibilidad de tener un buscador.

Una vez que hayamos puesto todas las opciones con las que queremos que se genere nuestra documentación pulsamos el botón «Start documenting» y eso hace que nos aparezca una ventana de lineas de comando haciendo un montón de cosas.

art9_03

Cuando se cierra la ventana de lineas de comando ya tenemos generada nuestra documentación, para la opción Website, abrimos con un navegador el archivo index.htm (que es el principal).

art9_04

Si navegamos a través de los constructores, métodos y propiedades que hemos comentado veremos como se ha formateado las líneas de comentario escritas en el proyecto en esta estupenda documentación. Por ejemplo, aunque no se vea muy bien, gracias a lo que hemos escrito en las etiquetas <sumary> se puede ver reflejado en la descripción de los miembros de la clase:

art9_05

También podemos usar etiquetas típicas de HTML (pero tratando de hacerlo como si de XML se tratara, por ejemplo la etiqueta <BR> no tiene / final, pero aquí se debe poner quedando <BR/>), e incluso podemos insertar imágenes como se puede apreciar en el siguiente dibujo (ver el código de la clase, los comentarios creados en la declaración de la clase Class1):

art9_06

Podemos aumentar la calidad de nuestra documentación añadiendo ejemplos prácticos (con las etiquetas <example> y <code>) y que al generarse se nos permite copiar el código como vemos en la siguiente imagen (ver el código de la clase, los comentarios creados en la declaración del segundo constructor):

art9_07

También se puede mostrar las excepciones que se pueden producir en un método. (ver el código de la clase, los comentarios creados en el método 4).

art9_09

Como os había comentado, tenemos un buscador que al poner palabras para buscar, en caso de que las encuentre nos indica donde y nos las marca en amarillo:

art9_08

Para que os quede mas claro, podéis crearos un proyecto, usar la clase que he definido y generar la documentación como os he ensañado, de esta forma podréis navegar por la documentación y ver el por qué de los comentarios que he usado.

Espero que os haya parecido interesante.

15 comentarios sobre “Sandcastle y los Tags XML para los comentarios en código.”

  1. Hombre yo creo que está bastante clarito, pero si quieres mas información siempre puedes echar un vistazo en los siguientes enlaces

    http://www.inchl.nl/SandcastleGUI/

    http://www.sandcastledocs.com/Wiki%20Pages/Home.aspx

    Y por supuesto, lo que mas conocimiento da sobre el tema es hacer un ejemplo como el que he hecho en el artículo y luego ir haciendo pruebas usando unas veces unas opciones y luego otras y ver las diferencias entre la documentación generada en cada caso.

  2. Perfecto, he descargado el programita de Stephan, sencillo, como bien dices, lo pongo a funcionar, esta trabajando un ratillo, termina, voy a la carpeta donde tiene que estar la salida, y veo un monton de graficos, vale, unos js, perfecto, para mi sorpresa también veo el exe de mi proyecto, y sin embargo ningun html.
    Durante la ejecución he visto que se hacia referencia al vs sdk 2005, el cual tengo instalado, asi como el html help workshop, que el programa no es capaz de encontrar.
    Donde debo colocar el archivo que he bajado, hay algun tipo de requisitos para que el programa funcione correctamente. LLevo 2 dias peleandome con el tema de la documentación y estoy ya un poco liado.
    Otra cosa, he observado que en tu entorno, en la pestaña de compilar, el check que marcas en rojo, yo no lo tengo, pero el xml se me genera, automaticamente cuando genero la aplicacion, con el nombre del proyecto. No se si esto puede influir en algo, estoy utilizando VS2005 Professional Edition con el SP 1.
    Gracias

  3. Hola Pablo,

    Creo recordar que cuando estuve haciendo pruebas con esto me pasaba lo mismo que a tí y que una de las veces era porque no tenía puesto bien el namespace del assembly que quería documentar y otra vez era porque no tenía chequeada la generación del xml en el visual studio.

    Mira a ver si tienes en propiedades del proyecto pestaña compile la opción «generate xml documentation file» (ten cuidado con las opciones debug y release) y despues de compilar mira si el xml que ha generado tiene los comentarios que has puesto en el código.

    Me cuentas a ver que tal te ha ido.

    Un saludo.

  4. He procurado hacer las cosas con el maximo cuidado posible y sigue sin funcionar, estoy desesperado ya. He probado tanto con proyectos en vb con c# y nada, nada de nada. He probado cambiando las carpetas del bin, usando tanto la de debug como la de release, y nada. El xml me lo genera bien, sin problemas. Por cierto, lo del check, si que lo tenia marcado, estaba por ahi escondido y no lo veia, pero estaba marcado y se generaba el xml.
    ¿Se genera algún tipo de log de la generación?
    En fin, de todas formas muchas gracias.

  5. Pues la verdad es que no lo sé. En mi caso enseguida generé la documentación y no lo necesité.

    Prueba también a volver a instalarlo de nuevo.

    Otra cosa que no he probado todavía es a generarlo con Vista, en mi caso siempre lo he hecho con XP.

  6. Conseguido, despues de todo no ha sido tan duro. He utilizado el Sandcastle Help File Builder, al principio también me fallaba, por la version del Sandcastle, la que usa el Visual Studio 2005 SDK 1.44 no vale, he bajado la ultimisima y ha funcionado a la primera.
    Ahora sólo queda echar un vistazo a los Tags, 🙂

  7. Pues no lo he probado, pero supongo que de igual manera excepto por la parte HTML del ASP, porque lo que es un webservice no creo que haya problemas, de todas formas lo miraré.

  8. A ver, el pesado de Pablo otra vez. Te comento lo que me pasa. El tema es que cuando cuando desarrollamos ASP creamos sitios, no aplicaciones. Diferencias entre ambos, basicamente que una aplicacion web crea una assembly y un sitio web no. Pasa lo mismo con los servcios web. Mas diferencias, un sitio web se puede publicar desde el menu contextual del sitio, y la aplicacion web no, hay que subir los aspx y la carpeta bin a la carpeta del sitio, esto no lo he probado aun, pero lo hacia asi con el vs2003.
    Asi que voy a crearme unas aplicaciones nuevas, y a agregar los archivos que ya tengo creados, y ver que es lo que pasa, si todo me sigue funcionando igual, a partir de ahora trabajaremos asi.
    Gracias por aguantarme.
    Un Saludo

  9. Necesito que alguien me diga como poder personalizar las plantillas del sandcastle para que no me muestre los metodos que son propios de .net.

    por favor

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *