lunes, 25 de noviembre de 2013

Obtener perfiles en un Gridivew

Saber quienes forman parte de nuestra aplicación es sencial, principalmente cuando deseamos hacer una "auditoria" de nuestro sistema. Cuando utilizamos el membership provider de asp.net podemos obtener esos usuarios en una lista para su identificación. Así que, veremos como podemos obtener esos usuarios en un gridivew. Algo tan sencillo como 2 líneas de código. Primeramente creamos una página asp.net y agregamos un gridview,


Ahora lo que a muchos les apasiciona el código, veamos como podemos llenar nuestro gridview. En el vento LOAD de nuestra página agregamos:

gvprofiles.DataSource = ProfileManager.GetAllProfiles(ProfileAuthenticationOption.Authenticated)
gvprofiles.DataBind();

Validar Textbox aceptar solo letras

Últimamente he recibido varias consultas via email sobre como hacer para validar un textbox para aceptar solo letras, así que, aquí les dejo el ejemplo Nuestro primer paso será crear la función JavaScript que hará el trabajo, para ello agregamos el javascript

function lettersOnly(evt) {
evt = (evt) ? evt : event;
var charCode = (evt.charCode) ? evt.charCode : ((evt.keyCode) ? evt.keyCode :
((evt.which) ? evt.which : 0));
if (charCode > 31 && (charCode < 65 || charCode > 90) &&
(charCode < 97 || charCode > 122)) {
alert("Ingrese solo letras.");
return false;
}
return true;
}



Por último iremos al code behind de la página y en el evento Load agregaremos un nuevo evento al textbox para que reconozca el script.


protected void Page_Load(object sender, EventArgs e)
{
txtnumeric.Attributes.Add("onkeypress", "javascript:return lettersOnly(event);");
}


Con esto, tenemos el textbox validado para aceptar solo letras.

Ejemplo del Código para descarga

Validar Textbox para aceptar solo números

Una de las necesidades más habituales en el desarrollo es poder validar los controles Textbox para que solo acepten valore numéricos. En este post eso es lo que haremos, nos apoyaremos en el lenguaje javascript para validar nuestro textbox del lado del cliente. Nuestro primer paso será crear la función JavaScript que hará el trabajo, para ello agregamos las etiquetas de javascript





Posteriormente dentro de esas etiquetas agregaremos el script que hará el trabajo

function ValidNum(e) {
var tecla= document.all ? tecla = e.keyCode : tecla = e.which;
return ((tecla > 47 && tecla < 58) || tecla == 46);
}


Por último iremos al code behind de la página y en el evento Load agregaremos un nuevo evento al textbox para que reconozca el script.

protected void Page_Load(object sender, EventArgs e)
{
TextBox1.Attributes.Add("onkeypress", "javascript:return ValidNum(event);");
}


Con esto, tenemos el textbox validado para aceptar solo números y el punto.

Ejemplo del Código para descarga

Encriptar QueryString en URL

Luego de varios días de trabajo pesado, nuevamente tengo tiempo para publicar en mi blog.

Para este post trataré de dar respuesta a una pregunta que se genera constantemente en los foros de MSDN, como encryptar los valores enviados a través del queryString en una URL.

Primero que nada he de decir que métodos de encriptación hay muchos, desde los personales hasta el MD5 y todos los conocidos. En nuestro ejemplo, trabajaremos con un código de encriptación utilizando el DESCryptoServiceProvider de asp.net más el método Left que se encuentra en la clase que publique en un post anterior

Funciones Con String

Para iniciar, debo comentar que para nuestra clase de encriptación crearemos dos métodos uno para encriptar y otro para desencriptar. Algunos se preguntaran para que el método de desencriptar. Pues sencillo, si estamos enviando valores por medio del QueryString en una URL, es porque esos valores los utilizaremos para realizar algún tipo de operación, entonces, que hacemos con unos valores encriptados? pues complicaríamos el trabajo un poco mas, así que, nuestros objetivos serán:

1. Encriptar los datos

2. Enviarlos encriptados por queryString

3.Recibirlos y desencriptarlos

4. Procesarlos.

Para empezar crearemos una nueva clase llamada Encryption, que contendrá nuestro métodos

Seguidamente, declararemos dos variables de Tipo byte que contendrán los datos que encriptemos y una de tipo string que contendrá los caracteres de encriptación

   
static byte[] key = { };
static byte[] IV = { 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef };
static string sEncryptionKey = "!#$a54?3"



Ahora, agregamos un nuevo método llamado Decrypt que será el encargado de desencriptar los datos enviados


public string Decrypt(string stringToDecrypt)
{
byte[] inputByteArray = new byte[stringToDecrypt.Length + 1];
try
{
key = System.Text.Encoding.UTF8.GetBytes(LeftRightMid.Left(sEncryptionKey, 8));
DESCryptoServiceProvider des = new DESCryptoServiceProvider();
inputByteArray = Convert.FromBase64String(stringToDecrypt);
MemoryStream ms = new MemoryStream();
CryptoStream cs = new CryptoStream(ms, des.CreateDecryptor(key, IV), CryptoStreamMode.Write);
cs.Write(inputByteArray, 0, inputByteArray.Length);
cs.FlushFinalBlock();
System.Text.Encoding encoding = System.Text.Encoding.UTF8;
return encoding.GetString(ms.ToArray());
}
catch (Exception e)
{
return e.Message;
}
}


Y por ultimo creamos el método mas importante, el de encriptación



public string Encrypt(string stringToEncrypt)
{
try
{
key = System.Text.Encoding.UTF8.GetBytes(LeftRightMid.Left(sEncryptionKey, 8));
DESCryptoServiceProvider des = new DESCryptoServiceProvider();
byte[] inputByteArray = Encoding.UTF8.GetBytes(stringToEncrypt);
MemoryStream ms = new MemoryStream();
CryptoStream cs = new CryptoStream(ms, des.CreateEncryptor(key, IV), CryptoStreamMode.Write);
cs.Write(inputByteArray, 0, inputByteArray.Length);
cs.FlushFinalBlock();
return Convert.ToBase64String(ms.ToArray());
}
catch (Exception e)
{
return e.Message;
}
}


Como vemos, el proceso de encriptación puede ser algo sencillo que realmente puede ayudar mucho a la seguridad de un sitio, especialmente cuando los datos que enviamos son de extremo cuidado.

Como siempre, para terminar el código de ejemplo

miércoles, 30 de octubre de 2013

Colorear celdas y filas en un Gridview

Últimamente he visto muchas consultas sobre como colorear las celdas o filas de un gridview basados en un determinado valor o condición.

Así que el objetivo de este post es mostrar como realizar este procedimiento, pero además añadiremos un elemento mas, que es como mostrar una imagen dependiendo de una condición.
Empezaremos trabajando en como cambiar el color de una fila del Gridview:

Supongamos que tenemos un Gridview que tiene un campo de tipo Literal en un TemplateField que muestra un total o cantidad y queremos con base a ese total colorear la fila completa.

    /**
     * SyntaxHighlighter
     */
    
         
            
            
    
Para lograr que nuestras celdas puedan cambiar de Color, utilizaremos el Evento OnRowDataBound el cual se ejecuta por cada celda del GridView , por tanto, dicho evento debe estar asociado a nuestro Gridview de lo contrario no se ejecutará
    /**
     * SyntaxHighlighter
     */
  
Una vez asociado el evento y creado el ItemTeplate, es hora de programar el evento RowDataBound desde el CodeBehind
    /**
     * SyntaxHighlighter
     */
    protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
    {
       if (e.Row.RowType == DataControlRowType.DataRow)
        {
          Literal tot =(Literal)e.Row.FindControl("ltltotal");
         Double total = Double.Parse(tot.Text);
         if (total == 500)
           {
             e.Row.BackColor = Color.FromName("#c6efce");
             //e.Row.Cells[2].BackColor = Color.FromName("#c6efce");
           }

        if (total >= 600)
           {
              e.Row.BackColor = Color.FromName("#ffeb9c");
           }

        if (total <300 e.row.backcolor="Color.FromName(" ffc7ce="" pre="">

Si examinamos el código anterior, vemos dos cosas importantes:

1. Accedemos al control en el GridView mediante el FindControl

2. Convertir,os ese objeto a double para poder hacer una comparación numérica.

El color a la fila (row) lo asignamos mediante la propiedad BackColor, si observamos con detenimiento, a esa propiedad le estamos asignando la propiedad Color.FromName(“numero de color”).
Por supuesto que esta no es la única forma de asignar el color, también podríamos hacerlo utilizando Color.NombreColor.
Una vez completado esto, nuestro gridview se vería de la siguiente forma
 
 
Ahora, nuestro segundo trabajo será hacer que el gridView también se coloreo pero esta vez no toda la fila sino únicamente las celdas. De igual forma, requerimos el evento RowDataBound, solo que esta vez la forma de asignar el color varia, pues se hace directamente sobre la celda.
    /**
     * SyntaxHighlighter
     */
  protected void GridView2_RowDataBound(object sender, GridViewRowEventArgs e)
   {
     if (e.Row.RowType == DataControlRowType.DataRow)
      {
         Literal tot = (Literal)e.Row.FindControl("ltltotal");
         Double total = Double.Parse(tot.Text);
         if (total == 500)
          {
             e.Row.Cells[3].BackColor = Color.FromName("#c6efce");
          }

        if (total >= 600)
         {
            e.Row.Cells[3].BackColor = Color.FromName("#ffeb9c");        
          }

       if (total < 300)
         {
            e.Row.Cells[3].BackColor = Color.FromName("#ffc7ce");      
         }
       }
   }
Al concluir nuestro GridView se vería así
Para terminar, haremos que nuestro gridview muestre una imagen distinta dependiendo de una condición. Esta vez haremos unos pequeños cambios: 1. Comparamos con base al valor aprobado, es decir un valor True/False para mostrar la imagen 2. Utilizamos la propiedad DataKeyNames del Gridview pues guardar el valor True/False, ya que la columna Aprobado no será mostrada sino únicamente la imagen. 3. Utilizaremos en control Image dentro de un ItemTemplate para mostrar la imagen nueva.
    /**
     * SyntaxHighlighter
     */
    
    /**
     * SyntaxHighlighter
     */
    
         
         
        
    
El evento rowDataBound
    /**
     * SyntaxHighlighter
     */
 protected void GridView3_RowDataBound(object sender, GridViewRowEventArgs e)
  {
    if (e.Row.RowType == DataControlRowType.DataRow)
      {  
         string KeyID = GridView3.DataKeys[e.Row.RowIndex].Value.ToString();
        System.Web.UI.WebControls.Image imagen = (System.Web.UI.WebControls.Image)e.Row.FindControl("imgestado");
        if (KeyID == "True")
          {
             imagen.ImageUrl = "GreenCircle5.jpg";       
          }

        if (KeyID == "False")
         {
            imagen.ImageUrl = "red-24.png";
          }  
       }
   }
En el código anterior lo mas importante, es la forma en que el valor del DataKeysNames es tomado, vemos que lo realizamos mediante el e.Row.RowIndex y lo convertimos a string para luego poder evaluarlo.

Por último les dejo el código de ejemplo
 

JqGrid y Asp.net, Maestro detalle con SubGrid (Parte 2)

Desde que escribí mi primer post sobre como utilizar JqGrid con asp.net, he recibido varias consultas sobre como realizar un maestro detalle utilizando este control de jquery.


Antes de comenzar debo mencionar que para mostrar un maestro detalle con JqGrid tenemos dos opciones:


1. Realizarlo con un subgrid

2. Utilizar dos JqGrid separados


Así que, teniendo esto en cuenta, el objetivo de este post será realizar el maestro detalle utilizando el Subgrid, que a mi parecer es mucho más agradable y por supuesto mas ordenado. Posteriormente en otro post veremos como hacerlo con 2 JqGrid separados.


Para este ejemplo, no voy a profundizar mucho en como esta formado JqGrid ni como llenar los datos, pues eso ya lo vimos en el anterior post y aplica exactamente de la misma forma para el grid padre como para el grid hijo, basicamente sería cambiar el nombre de la tabla y crea un nuevo stored procedure.


En lo que si nos vamos a enfocar es en como realizar la definición del subgrid.


Si recordamos un poco como esta conformado el JqGrid, veremos que al final de la definición del mismo este nos permite configurar las opciones adicionales que tendrá el control, como por ejemplo:

width: "850",
height: "100%


Es precisamente en esta serie de opciones donde tendremos que habilitar nuestro grid para que contenga un subgrid, esto lo hacemos agregando la opción:

subGrid: true

Luego de que hemos habilitado nuestro subgrid debemos crear la función subGridRowExpanded que será la encargada de mostrar nuestro subgrid cuando expandamos el grid padre, es precisamente dentro de esta función donde declararemos nuestro subgrid.

    /**
     * SyntaxHighlighter
     */
subGridRowExpanded: function (subgrid_id, row_id) {
         // we pass two parameters 
         // subgrid_id is a id of the div tag created whitin a table data 
         // the id of this elemenet is a combination of the "sg_" + id of the row 
         // the row_id is the id of the row 
         // If we wan to pass additinal parameters to the url we can use 
         // a method getRowData(row_id) - which returns associative array in type name-value 
         // here we can easy construct the flowing 
         var subgrid_table_id, pager_id;
         subgrid_table_id = subgrid_id + "_t";
         pager_id = "p_" + subgrid_table_id;
       $("#" + subgrid_id).html("
"); jQuery("#" + subgrid_table_id).jqGrid({ //este es mi subgrid datatype: function () { $.ajax( { url: "webservices/LoadChild.asmx/GetChilds", //PageMethod data: "{'pPageSize':'" + $("#" + subgrid_table_id).getGridParam("rowNum") + "','pCurrentPage':'" + $("#" + subgrid_table_id).getGridParam("page") + "','pSortColumn':'" + $("#" + subgrid_table_id).getGridParam("sortname") + "','id':'" + $("#" + subgrid_table_id).getGridParam("ajaxGridOptions") + "','pSortOrder':'" + $("#" + subgrid_table_id).getGridParam("sortorder") + "'}", //PageMethod Parametros de entrada dataType: "json", type: "post", contentType: "application/json; charset=utf-8", complete: function (jsondata, stat) { if (stat == "success") jQuery("#" + subgrid_table_id)[0].addJSONData(JSON.parse(jsondata.responseText).d); else alert(JSON.parse(jsondata.responseText).Message); } }); }, jsonReader: //Set the jsonReader to the JQGridJSonResponse squema to bind the data. { root: "Items", page: "CurrentPage", total: "PageCount", records: "RecordCount", repeatitems: true, cell: "Row", id: "ID" //index of the column with the PK in it }, colModel: [ { name: 'ChildId', index: 'ChildId', width: 40, align: 'left', editable: false, editrules: { edithidden: true }, hidden: true }, { name: 'ChildName', index: 'ChildName', width: 80, align: 'left', editable: true, edittype: 'text' }, { name: 'ChildLastName', index: 'ChildLastName', width: 200, align: 'left', editable: true, edittype: 'text', editoptions: { size: 20, maxlength: 30} }, { name: 'ChildBirthDate', index: 'ChildBirthDate', width: 300, align: 'left', editable: true, edittype: 'select', editoptions: { size: 20, maxlength: 30} }, { name: 'PersonId', index: 'PersonId', width: 200, align: 'left', editable: true, edittype: 'text', editoptions: { size: 20, maxlength: 30 }, formater: 'number'}], pager: pager_id, //Pager. loadtext: 'Cargando datos...', recordtext: "{0} - {1} de {2} elementos", emptyrecords: 'No hay resultados', pgtext: 'Pág: {0} de {1}', //Paging input control text format. rowNum: "10", // PageSize. ajaxGridOptions: row_id, rowList: [10, 20, 30], //Variable PageSize DropDownList. viewrecords: true, //Show the RecordCount in the pager. multiselect: false, sortname: "ChildName", //Default SortColumn sortorder: "asc", //Default SortOrder. width: "800", height: "100%", caption: "Invoice Detail" }); jQuery("#" + subgrid_table_id).jqGrid('navGrid', "#" + pager_id, { edit: false, add: false, del: false }) },
Si vemos el código anterior, la definición del subgrid es exactamente igual a como hemos realizado la definición del grid padre, solo que dentro de una función contenedora. 

 Finalmente, así se vería 

 

Por último el código de ejemplo 



Gracias a los comentarios de muchos, actualizo el post para agregar el Stored Procedure GetChilds, que lo disfruten


 
    /**
     * SyntaxHighlighter
     */
     USE [JQGrid]
 GO
 /****** Object:  StoredProcedure [dbo].[GetChilds]    Script Date: 07/27/2012 17:55:56 ******/
 SET ANSI_NULLS ON
 GO
SET QUOTED_IDENTIFIER ON
 GO
 -- GetPersons 3, 4, 'LastName', 'desc'
 ALTER procedure [dbo].[GetChilds]
 @PageSize int , 
 @CurrentPage int , 
 @SortColumn varchar(20), 
 @SortOrder varchar(4),
 @PersoId int
 as
 declare @RecordCount int
 declare @PageCount int
 declare @PageIndex int
 Select @RecordCount = count(ChildId)
 from Childs
 set @PageCount = Ceiling(cast (@RecordCount as float) / cast (@PageSize as float))
 if (@CurrentPage > @PageCount) set @CurrentPage = @PageCount
 set @PageIndex = @CurrentPage - 1
 Select RecordCount = @RecordCount, PageCount = @PageCount, CurrentPage = @CurrentPage
 declare @Query varchar(300)
 set @Query = 
    'Select ChildId, ChildName, ChildLastName, ChildBirthDate,PersonId, 
     RowNumber = ROW_NUMBER() OVER (ORDER BY ' + @SortColumn + ' ' + @SortOrder + ')
    from Childs' 
 set @Query = 
 'Select ChildId, ChildName, ChildLastName, ChildBirthDate,PersonId
  from (' + @Query + ' )as result 
 where PersonId='+ CAST(@PersoId as varchar(5)) +' and RowNumber BETWEEN ' + cast(@PageSize * @PageIndex + 1 as varchar(10)) + 'AND ' + cast(@PageSize * (@PageIndex + 1) as varchar(10)) 
   Exec (@Query)

martes, 29 de octubre de 2013

Menú Dinámico en MySql

Luego de varios días sin hacer post, hoy nuevamente retomo para mostrar un pequeño ejemplo de un tema que últimamente ha sido muy tocado en los foros de asp.net de MSDN. Cómo hacer un menú dinámico con MySql?

Antes de empezar a mostrar como crear el menú voy a explicar algunos problemas que encontré durante el desarrollo del ejemplo:

1. Para el ejemplo, utilizaremos la versión beta 6.5 del conector de .net para mysql, sin embargo, deben tomar en cuenta que este conector esta en desarrollo y aún carece de muchas funcionalidades que permitan implementar un mejor manejo de un menú dinámico.

2. En MySql lamentablemente no existe el Cache Dependency para poder monitorear los cambios en la base de datos y poder ver las actualizaciones del menú sin problemas. 

Por ello, con esta versión del .Net Connector, cada vez que agreguemos un nuevo ítem de menú a nuestra base de datos, tendremos que detener el servidor de desarrollo de visual studio y volver a iniciar para ver los cambios.

Sin embargo, aunque no sea posible por ahora con el conector monitorear el cambio (se puede hacer a código puro pero no vale la pena pues es mucho), este menú es una buena opción para poder organizar los accesos por roles.

Ahora sí, iniciemos:
Lo primero para nuestro menú, será descargar e instalar la última versión del conector .net para mysql (6.5 beta)


Entrando en el código, lo primero que realizaremos será crear una clase que herede se StaticSiteMapProvider para de esta manera poder contar con todas las opciones y métodos


    /**
     * SyntaxHighlighter
     */
    [MySqlClientPermission(SecurityAction.Demand,Unrestricted = true)]
    public class MySqlSiteMapProvider : StaticSiteMapProvider
    {
    }

Ahora, definimos una serie de variables Privadas (solo para la clase) que nos permitirán mostrar algunos mensajes de error predeterminado y almacenar los valores recuperados del web.config
    /**
     * SyntaxHighlighter
     */
    private const string _errmsg1 = "Missing node ID";
    private const string _errmsg2 = "Duplicate node ID";
    private const string _errmsg3 = "Missing parent ID";
    private const string _errmsg4 = "Invalid parent ID";
    private const string _errmsg5 = "Empty or missing connectionStringName";
    private const string _errmsg6 = "Missing connection string";
    private const string _errmsg7 = "Empty connection string";
    private string _connect;              // Cadena de conexión a  base de datos
    private int _indexId, _indexTitle, _indexUrl, _indexDesc, _indexRoles, _indexParent;
    private Dictionary _nodes = new Dictionary(16);
    private readonly object _lock = new object();
    private SiteMapNode _root;

En las definiciones anteriores, los mas importante sería el Dictionary llamado _nodes, pues será el que almacenara los datos recuperados para el menú. En el siguiente método, haremos un Override del método Initialize original y será en este en donde leamos el web.config y recuperemos todos los datos de la cadena de conexión y los proveedores

    /**
     * SyntaxHighlighter
     */
   public override void Initialize(string name, NameValueCollection config)
     {
        // Verificar que config no es null
         if (config == null)
             throw new ArgumentNullException("config");
         // Asignar al proveedor un nombre por defecto sino posee uno
        if (String.IsNullOrEmpty(name))
           name = "MySqlSiteMapProvider";
        // Add a default "description" attribute to config if the
        // attribute doesn’t exist or is empty
        if (string.IsNullOrEmpty(config["description"]))
         {
            config.Remove("description");
            config.Add("description", "SQL site map provider");
         }
        // Call the base class's Initialize method
        base.Initialize(name, config);
       // Initialize _connect
       string connect = config["connectionStringName"];
       if (String.IsNullOrEmpty(connect))
       throw new ProviderException(_errmsg5);
       config.Remove("connectionStringName");
        if (WebConfigurationManager.ConnectionStrings[connect] == null)
         throw new ProviderException(_errmsg6);
         _connect = WebConfigurationManager.ConnectionStrings[connect].ConnectionString;
         if (String.IsNullOrEmpty(_connect))
             throw new ProviderException(_errmsg7);
         if (config["securityTrimmingEnabled"] != null)
             config.Remove("securityTrimmingEnabled");
         // Throw an exception if unrecognized attributes remain
        if (config.Count > 0)
         {
           string attr = config.GetKey(0);
           if (!String.IsNullOrEmpty(attr))
              throw new ProviderException("Unrecognized attribute: " + attr);
         }
    }

El siguiente método al que vamos a realizar el Override sera el SiteMapNode, este es uno de los mas importantes pues será en el cual nos vamos a conectar a mysql, leer los datos y enviarlos a otro método para armar el menú

    /**
     * SyntaxHighlighter
     */
    public override SiteMapNode BuildSiteMap()
    {
        lock (_lock)
        {
           // Return immediately if this method has been called before
            if (_root != null)
               return _root;
            // Query the database for site map nodes
         MySqlConnection connection = new MySqlConnection(_connect);
          try
           {
             MySqlCommand command = new MySqlCommand("proc_GetSiteMap", connection);
             command.CommandType = CommandType.StoredProcedure;
             connection.Open();
             MySqlDataReader reader = command.ExecuteReader();
             _indexId = reader.GetOrdinal("ID");
             _indexUrl = reader.GetOrdinal("Url");
             _indexTitle = reader.GetOrdinal("Title");
             _indexDesc = reader.GetOrdinal("Description");
             _indexRoles = reader.GetOrdinal("Roles");
            _indexParent = reader.GetOrdinal("Parent");
         if (reader.Read())
             {
                 // Create the root SiteMapNode and add it to the site map
                 _root = CreateSiteMapNodeFromDataReader(reader);
                  AddNode(_root, null);
                  // Build a tree of SiteMapNodes underneath the root node
                  while (reader.Read())
                   {
                      // Create another site map node and add it to the site map
                      SiteMapNode node = CreateSiteMapNodeFromDataReader(reader);
                      AddNode(node, GetParentNodeFromDataReader(reader));
                    }
                }
            }
           finally
            {
               connection.Close();
            }
           // Return the root SiteMapNode
           return _root;
        }
   }

Los siguientes dos métodos no los voy a explicar en detalle, pero serán los encargados de tomar y extraer los roles y datos recuperados de la base de datos con el procedimiento anterior y crear cada SiteNode para el menú, almacenándolo en el Dictionay _nodes

    /**
     * SyntaxHighlighter
     */
    protected override SiteMapNode GetRootNodeCore()
    {
       lock (_lock)
        {
           BuildSiteMap();
           return _root;
        }
    }
    // Helper methods
    private SiteMapNode CreateSiteMapNodeFromDataReader(DbDataReader reader)
    {
       // Make sure the node ID is present
       if (reader.IsDBNull(_indexId))
       throw new ProviderException(_errmsg1);
       // Get the node ID from the DataReader
       int id = reader.GetInt32(_indexId);
       // Make sure the node ID is unique
       if (_nodes.ContainsKey(id))
            throw new ProviderException(_errmsg2);
      // Get title, URL, description, and roles from the DataReader
      string title = reader.IsDBNull(_indexTitle) ? null : reader.GetString(_indexTitle).Trim();
      string url = reader.IsDBNull(_indexUrl) ? null : reader.GetString(_indexUrl).Trim();
      string description = reader.IsDBNull(_indexDesc) ? null : reader.GetString(_indexDesc).Trim();
      string roles = reader.IsDBNull(_indexRoles) ? null : reader.GetString(_indexRoles).Trim();
      // If roles were specified, turn the list into a string array
      string[] rolelist = null;
        if (!String.IsNullOrEmpty(roles))
           rolelist = roles.Split(new char[] { ',', ';' }, 512);
        // Create a SiteMapNode
      SiteMapNode node = new SiteMapNode(this, id.ToString(), url, title, description, rolelist, null, null, null);
      // Record the node in the _nodes dictionary
      _nodes.Add(id, node);
      // Return the node       
      return node;
   }

El último método, se encargara de hacer accesibles o no cada uno de los nodos del menú, eso si, para que funcione la opción SecurityTrimming tiene que ser true en la configuración del SiteMapProvider del web.config

    /**
     * SyntaxHighlighter
     */
    private SiteMapNode GetParentNodeFromDataReader(DbDataReader reader)
    {
       // Make sure the parent ID is present
       if (reader.IsDBNull(_indexParent))
           throw new ProviderException(_errmsg3);

      // Get the parent ID from the DataReader
      int pid = reader.GetInt32(_indexParent);
      // Make sure the parent ID is valid

      if (!_nodes.ContainsKey(pid))
           throw new ProviderException(_errmsg4);

      // Return the parent SiteMapNode
      return _nodes[pid];
    }

Con lo anterior, ya tenemos la clase que se encargará del menu. Ahora veamos como se configura el web.config Entre las etiquetas se debe agregar la configuración del sitemap

    /**
     * SyntaxHighlighter
     */
    
      
       
      
   
Con esto, nuestro web.config ya estará preparado. Por supuesto no olviden cambiar el nombre de la cadena de conexión por la que tienen y el type que será el nombre de la clase Lo ultimo será el html en la pagina

    /**
     * SyntaxHighlighter
     */
    
       
        
          
          
          
          
          
          
         
     
Una vez agregado el html, nuestro menú estará listo. Y como siempre el código de ejemplo

Twitter Delicious Facebook Digg Stumbleupon Favorites More

 
Design by Free WordPress Themes | Bloggerized by Lasantha - Premium Blogger Themes | Hosted Desktops