[Enlace] Remover RID Lookup de tus planes de ejecución

Despues de varios años varios cabezazos contra la mesa vamos aprendiendo un poco los índices y planes de ejecución.

En esa oportunidad solo quiero mencionar a la operación RID Lookup, esta operación es muy costosa y afecta el rendimiento de la consulta, por eso debemos tratar de removerlo de nuestro plan de ejecución. El siguiente caso se hace un update a una tabla:

UPDATE dbo.Producto_Bulk SET Valido=0, ErrorMensaje=’Codigo Invalido’ WHERE ProveedorID = @pID AND ArchivoCargaID=@logID AND Valido=1 AND Codigo = ”

Existía un índice non-clustered para ProveedorID y para ArchivoCargaID, pero el campo Valido y el campo Codigo no estaban dentro del indice, se estaba generando la operación RID Lookup. Es una aplicación de carga masiva de productos que se venía abajo debido al maldito RID Lookup, se carga entre 30,000 productos a 200,000 por archivo, y además de la validación de vacíos también hay validación de repetidos, en el update de repetidos hay hasta dos RID Lookup, y este punto es donde la consulta no daba mas si quieres actualizalo tu, que yo no lo voy hacer, y se generaba el queridísimo timeout.

Después de seguir las recomendaciones de mi amigo Pinal Dave, pueden remover las operaciones RID Lookup del plan de ejecución, y salvar sus aplicaciones… bueno por el momento… hombre, que el mantenimiento de base de datos no tiene fin

Fuente: SQL SERVER – Query Optimization – Remove Bookmark Lookup – Remove RID Lookup – Remove Key Lookup.

Saludos,

[CodeSnipeet] Usar el atributo Obsolete (.NET: ObsoleteAttribute Class)

Entre cada versión de un producto, siempre puede ocurrir la mejora de alguna clase o método creando una versión con un nuevo nombre, pero también existe el tema de afectar lo menos posible a aplicaciones que usen la versión antigua. Es como usar la clase ConfigurationSettings.AppSettings en .Net 2.0, cuando podemos usar ConfigurationManager.AppSettings, siempre encontramos esos códigos que dices después lo cambio que por temas de tiempo todavía no se han podido actualizar.

El uso del atributo Obsolete, además de ser útil cuando distribuimos librerías a terceros, también podemos usarla en nuestros equipos internos. Siempre debemos tratar de que el código sea mantenible independiente del desarrollador actual, ¿cómo le decimos al siguiente desarrollador?: “Tío no uses este método, usa este nuevo método, no borre al anterior porque tengo miedo que no funcione la aplicación, si quieres tu lo puedes borrar”. Usando el atributo Obsolete.

¿Cómo podemos usar el atributo Obsolete?

   1: [Obsolete]

   2: [Obsolete("BuildPostList was disabled in BEv2.5")]

   3: [Obsolete("BuildPostList was disabled in BEv2.5", true)]

   4: private static void BuildPostList()

   5: {

   6:     var number = Math.Min(BlogSettings.Instance.NumberOfRecentPosts, Post.Posts.Count);

   7:  

   8:     Posts.Clear();

   9:     foreach (var post in Post.Posts.Where(post => post.IsVisibleToPublic).Take(number))

  10:     {

  11:         Posts.Add(post);

  12:     }    

  13: }

Podemos usarlo en tres versiones, la primera sólo indica que el método esta obsoleto, la segunda además de mostrar un mensaje de obsoleto muestra un mensaje personalizado, y la tercera además del mensaje muestra un error en tiempo de compilación:

Ver: Entrada original.

Saludos,

Geeks.ms en la Tienda de Nokia (Ovi Store)

Geeks.ms en OviStore

 

Nokia, cuenta con una aplicación llamada Nokia App Wizard, la cual permite crear aplicaciones, de una manera sencilla, y que funcionan en los siguientes dispositivos: S40, Symbiam, y MeeGo (eso dice en la portada).

El asistente al inicio solicita la fuente de información, y la más sencilla es una fuente de RSS, los siguientes pasos son de personalización y opciones de la aplicación, como el costo de la misma. El proceso de validación y aprobación demora unos días, tened paciencia. Y nada, Geeks.ms ya está disponible en la tienda de Nokia, Ovi Store: Geeks.ms en OviStore.

Nokia App Wizard

Saludos,

 

Proveedores de Alojamiento (Hosting): WinHost, ASP.NET Hosting

Desde hace unos meses que vengo usando WinHost para mi sitio Web personal, y hasta ahora todo va muy bien. Antes tenía otro proveedor que me hacía dos facturaciones una por el alojamiento del sitio web y otra por el alojamiento de la base de datos. Pero como lo que tengo es un sitio personal, de vez en cuando subo algunos prototipos, buscaba una opción más económica y que el uso de base de datos este incluida dentro del mismo plan, y WinHost cumplía con eso.

Algunas de sus características, a mi parecer básicas para tomar una decisión, son las siguientes:

  • IIS 7 Web Hosting
  • Acceso remoto a través de IIS 7 Manager
  • Incluye una base datos SQL Server y MySql
  • Acceso remoto a la base de datos desde SQL Management Studio
  • ASP.NET en todas sus versiones, y sus add-ins ASP.NET MVC, Silverlight, etc.
  • Y para el correo el uso de SmarterMail

Tiene un panel de control simple y práctico:

WinHost Demo Control Panel

Saludos,

Descargas: Plantillas de diseño para ASP.NET (ASP.NET 2.0 Design Templates)

Hace algunos años, existía un excelente recurso en MSDN para ASP.NET llamado: ASP.NET 2.0 Design Templates, bajo la siguiente url: http://msdn.microsoft.com/asp.net/reference/design/templates/default.aspx. No pude encontrar este recurso en otro lado, si alguien tiene el dato, por favor lo deja en los comentarios.

Aunque la página web mencionada no esta disponible, las plantillas como descargas si lo están. Gracias a mi amigo: flysun0311, por guardar los enlaces en esta entrada: 符合Web标准的ASP .NET 2.0 Starter Kit模板下载.

Todas estas descargas son compatibles para cualquier versión de ASP.NET, es más se pueden usar con cualquier otro lenguaje Php, Jsp, etc, el diseño es uno solo para todos Html y CSS.

P.D.: Si algún enlace no esta disponible, me avisan por los comentarios tengo un bakcup de todos estos archivos en la nube.

Html – Div y Table – “Basic Design Template” – Descarga

ST2 Basic Web Template

Html – Div y Table – “Fun Design Template” – Descarga

Html – Div y Table – “Grid Design Tamplte” – Descarga

Html – Div y Table – “Rounded Design Template” – Descarga

Html – Div y Table – “Simple Design Template” – Descarga

ASP.NET – Web Commerce Design – C# y VB

ASP.NET – Web Corporate Design – C# y VB

ASP.NET – Web Personal Design – C# y VB

ASP.NET – Web Small Business Design – C# y VB

Saludos,

[CodeSnipeet] C# Detección personaliza de un navegador móvil

Fácilmente  podríamos detectarlo usando la siguiente propiedad: Request.Browser.IsMobileDevice.

Pero esta propiedad no satisface algunos casos, por ejemplo con Opera Mini en un equipo Nokia. Si queremos crear nuestro propio método, podemos usar el siguiente código, extraído del artículo: Detecting a mobile browser in ASP.NET:

   1:  protected Boolean IsCustomMobileBrowser()
   2:  {
   3:      //GETS THE CURRENT USER CONTEXT
   4:      HttpContext context = HttpContext.Current;
   5:   
   6:      //FIRST TRY BUILT IN ASP.NT CHECK
   7:      if (context.Request.Browser.IsMobileDevice)
   8:      {
   9:          return true;
  10:      }
  11:      //THEN TRY CHECKING FOR THE HTTP_X_WAP_PROFILE HEADER
  12:      if (context.Request.ServerVariables["HTTP_X_WAP_PROFILE"] != null)
  13:      {
  14:          return true;
  15:      }
  16:      //THEN TRY CHECKING THAT HTTP_ACCEPT EXISTS AND CONTAINS WAP
  17:      if (context.Request.ServerVariables["HTTP_ACCEPT"] != null &&
  18:          context.Request.ServerVariables["HTTP_ACCEPT"].ToLower().Contains("wap"))
  19:      {
  20:          return true;
  21:      }
  22:      //AND FINALLY CHECK THE HTTP_USER_AGENT 
  23:      //HEADER VARIABLE FOR ANY ONE OF THE FOLLOWING
  24:      if (context.Request.ServerVariables["HTTP_USER_AGENT"] != null)
  25:      {
  26:          //Create a list of all mobile types
  27:          String[] mobiles =
  28:              new String[]
  29:              {
  30:                  "midp", "j2me", "avant", "docomo", 
  31:                  "novarra", "palmos", "palmsource", 
  32:                  "240x320", "opwv", "chtml",
  33:                  "pda", "windows ce", "mmp/", 
  34:                  "blackberry", "mib/", "symbian", 
  35:                  "wireless", "nokia", "hand", "mobi",
  36:                  "phone", "cdm", "up.b", "audio", 
  37:                  "SIE-", "SEC-", "samsung", "HTC", 
  38:                  "mot-", "mitsu", "sagem", "sony"
  39:                  , "alcatel", "lg", "eric", "vx", 
  40:                  "NEC", "philips", "mmm", "xx", 
  41:                  "panasonic", "sharp", "wap", "sch",
  42:                  "rover", "pocket", "benq", "java", 
  43:                  "pt", "pg", "vox", "amoi", 
  44:                  "bird", "compal", "kg", "voda",
  45:                  "sany", "kdd", "dbt", "sendo", 
  46:                  "sgh", "gradi", "jb", "dddi", 
  47:                  "moto", "iphone"
  48:              };
  49:   
  50:          //Loop through each item in the list created above 
  51:          //and check if the header contains that text
  52:          foreach (string s in mobiles)
  53:          {
  54:              if (context.Request.ServerVariables["HTTP_USER_AGENT"].
  55:                              ToLower().Contains(s.ToLower()))
  56:              {
  57:                  return true;
  58:              }
  59:          }
  60:      }
  61:   
  62:      return false;
  63:  }

P.D.: Si tienen algún dispositivo que no funciona en este código, nos dejan un comentario para actualizar el código.

Los detalles de la aplicación de este código, lo podemos ver en la siguiente página: http://sergiot2.com/browserInformation.aspx

Vamos a usar un navegador Wap para Windows, WinWap, para mostrar algunas páginas en su versión para móvil:

Si ingresamos a la página desarrollada:

Si ingresamos a Facebook vemos la redirección:

En Google presentan contenido de acuerdo al dispositivo:

Microsoft al parecer ya no tiene pensado soportar Wap:

Ingresando directamente a la dirección móvil:

Otros enlaces:

Saludos,

[CodeSnippet] C# Obtener los programas instalados en Windows (Plus: Export to CSV)

Existen dos formas, una es a través del registro y la otra usando WMI. En esta oportunidad mostrare el código usando WMI, porque el registro también devuelve las actualizaciones instaladas.

Enlaces:

 

Notas del código:

  • Si quieren saber que otros campos pueden visualizar de este objeto puede revisar el siguiente enlace: Win32_Product Class.
  • Usamos el CodePage 1252, para no tener problemas con caracteres especiales (ñ) al escribir en el archivo.
  •  

   1:  static void Main(string[] args)
   2:  {
   3:      DisplayInstalledApplications2();
   4:      ExporToCSV();
   5:   
   6:      Console.WriteLine("... ENTER FOR EXIT");
   7:      Console.ReadLine();
   8:  }
   9:   
  10:  static void DisplayInstalledApplications2()
  11:  {
  12:      ManagementObjectSearcher mos = new ManagementObjectSearcher(
  13:                  "SELECT * FROM Win32_Product");
  14:      foreach (ManagementObject mo in mos.Get())
  15:      {
  16:          Console.WriteLine(mo["Name"]);
  17:      }           
  18:   
  19:  }
  20:   
  21:  static void ExporToCSV()
  22:  {
  23:      ManagementObjectSearcher mos = new ManagementObjectSearcher(
  24:                  "SELECT * FROM Win32_Product");
  25:   
  26:      String fileName = "InstalledSoftware_" + DateTime.Now.ToString("yyyy-MM-dd") + ".csv";
  27:   
  28:      if ( File.Exists(fileName) ) File.Delete(fileName);
  29:   
  30:      StringBuilder sbText = new StringBuilder();
  31:      sbText.AppendLine("Name,InstallDate");
  32:      foreach (ManagementObject mo in mos.Get())
  33:      {               
  34:          sbText.AppendFormat(@"""{0}"",""{1}""", mo["Name"], mo["InstallDate"]);
  35:          sbText.AppendLine("");                
  36:      }
  37:   
  38:      using (StreamWriter wr = new StreamWriter(fileName, true, Encoding.GetEncoding(1252)))
  39:      {
  40:          wr.WriteLine(sbText.ToString());
  41:      }
  42:  }

Saludos,

Proveedores de Alojamiento (Hosting): myLittleAdmin, una herramienta para SQL Server via Web

Uno de los clientes, tiene alojada su Web en un proveedor de Hosting, el proveedor te da la opción de conectarte directamente desde un SQL Management Studio a la base de datos remotamente.

Pero que pasa si, por alguna razón:

  • No tenemos instalado SQL Management Studio
  • Estamos en la partición Linux y hay un problema que resolver
  • Estamos en algún cliente y sólo tenemos acceso a internet
  • Da mucha lata levantar la virtual con las herramientas “Developer Ranger”

Pero por suerte, si nuestro proveedor soporta myLittleAdmin estamos salvado. Antes de todo, unos screenshots unas pantallas:

1. Modelo de Objetos

2. Crear una tabla

3. Crear un Registro

4. Hacer un “Abrir Tabla” (Open Table)

 

myLittleAdmin, es una herramienta como SQL Management Studio pero vía Web, es como el phpMyAdmin de MySql. Debido al costo de licencia su mayor ventaja se da en los proveedores de hosting. Si hay dos proveedores de hosting de ASP.NET y sólo uno de ellos soporta myLittleAdmin, es altamente recomendable que seleccionen el que soporta myLittleAdmin.

Enlaces myLittleAdmin:

P.D.: No hay beneficio por recomendar esta herramienta, lo cual si sucediera no me enojaría, es sólo que me gusto y a veces prefiero usar esta en lugar del SQL Management Studio.

Saludos,

Reciente vulnerabilidad de ASP.NET y BlogEngine.Net

Vamos a listar las noticias en orden cronológico, para intentar entender la vulnerabilidad:

Y así estamos…

Si no quieren leer todos los enlaces, el resumen de David Salgado sobre la vulnerabilidad:

En resumen… explota una vulnerabilidad relacionada con el algoritmo de cifrado que se utiliza en la autenticación por Forms. Va probando diferentes entradas y detectando la diferencia de respuesta de la aplicación para aprender y finalmente dar con una clave que da acceso.

Y si no queda claro aún, puede ver el video con la demo completa. Y la solución que se tiene ahora, pasa por evitar “responder” a los intentos de usar esta vulnerabilidad. ¿Cómo?. Evitar que los atacantes obtengan información usando los errores personalizados de ASP.NET (customErrors element, web.config).

 

La vulnerabilidad y BlogEngine:

No hay una respuesta oficial de BlogEngine, pero podemos hacer lo siguiente (para dormir tranquilos) hasta tener alguna respuesta oficial. Referencia: The Asp.Net Vulnerability and DotNetBlogEngine.Net.

1. Cambiar el elemento customErrors en el archivo web.config:

   1: <customErrors mode="RemoteOnly" defaultRedirect="~/error404.aspx" />

   2:    <error statusCode="404" redirect="error404.aspx" />

   3: </customErrors>

Por el siguiente:

   1: <customErrors mode="On" redirectMode="ResponseRewrite" 

   2:      defaultRedirect="~/fail.aspx" />

2. Crear la siguiente página ASPX, y subirla a la carpeta root de BlogEngine:

   1: <%@ Page Language="C#" AutoEventWireup="true" %>

   2: <%@ Import Namespace="System.Security.Cryptography" %>

   3: <%@ Import Namespace="System.Threading" %>

   4:  

   5: <script runat="server">

   6:    void Page_Load() {

   7:       byte[] delay = new byte[1];

   8:       RandomNumberGenerator prng = new RNGCryptoServiceProvider();

   9:  

  10:       prng.GetBytes(delay);

  11:       Thread.Sleep((int)delay[0]);

  12:         

  13:       IDisposable disposable = prng as IDisposable;

  14:       if (disposable != null) { disposable.Dispose(); }

  15:     }

  16:   < /script>

  17: <html>

  18: <head runat="server">

  19:     <title>Error</title>

  20: </head>

  21: <body>

  22:     <div>

  23:         An error occurred while processing your request.

  24:     </div>

  25: </body>

  26: </html>

A estar pendientes en estos días, para ver que pasa con esta vulnerabilidad.

 

Saludos,

[Ejemplo] Usando la API Apache Log4Net

Estaba dando mantenimiento a un proyecto que fue desarrollado con Java (Struts), y en el  código vi el uso de la API Apache Logging Services, puntualmente log4j, para registrar información de rastreo en un archivo.

Pero también hay una versión .Net de esta API: Log4net. Existen muchos otras APIs similares, hay para todos los gustos y colores. En esta entada mostraremos como usar la mencionada API:

Después de descargar Log4Net, y extraer el contenido hacemos lo siguiente:

1. Agregamos la referencia a nuestro proyecto (VS2005, VS2008, VS2010):

 

2. Configuramos que tipo de proveedor vamos a usar para guardar la información, puede ser un archivo de texto, SQL Server, Oracle, enviar emails, entre otros. Son dos partes principales: la declaración de la sección, y la definición de la sección misma. Si queremos agregar proveedores usamos el elemento appender:

   1: <?xml version="1.0"?>

   2: <configuration>

   3:   <configSections>

   4:     <section name="log4net" 

   5:              type="log4net.Config.Log4NetConfigurationSectionHandler,log4net" />    

   6:   </configSections>

   7:   <log4net>  

   8:     <root>

   9:       <level value="ALL"/>

  10:       <appender-ref ref="AdoNetAppender" />

  11:     </root>

  12:     <appender name="FileAppender" 

  13:          type="log4net.appender.FileAppender">...</appender>

  14:     <appender name="AdoNetAppender" 

  15:         type="log4net.Appender.AdoNetAppender">...</appender>    

  16:   </log4net>  

  17: </configuration>

3. Escribimos el código para guardar los mensajes:

   1: class Program

   2:   {

   3:  

   4:     static void ConfigureLog()

   5:     {

   6:       //Configurar Log, de acuerdo a la archivo app.config

   7:       log4net.Config.XmlConfigurator.Configure();          

   8:     }

   9:  

  10:     static void Main(string[] args)

  11:     {

  12:       //SET UP, Configure Log

  13:       ConfigureLog();

  14:  

  15:       log4net.ILog logger = log4net.LogManager.GetLogger(typeof(Program));

  16:  

  17:       logger.Debug("Here is a debug log.");

  18:       logger.Info("... and an Info log.");

  19:       logger.Warn("... and a warning.");

  20:       logger.Error("... and an error.");

  21:       logger.Fatal("... and a fatal error.");

  22:  

  23:       Console.WriteLine("END --- PRESS ENTER");

  24:       Console.ReadLine();

  25:     }    

  26:   }

4. Log en archivo de texto: , Log en Base de datos:

 

Nota: Para el tipo FileAppender, podemos establecer el patrón de como se guardará la información:

   1: <appender name="FileAppender" type="log4net.appender.FileAppender">

   2:    <param name="File" value="C:tempmiPrimerLog4Net.txt" />

   3:    <param name="AppendToFile" value="true" />

   4:    <layout type="log4net.Layout.PatternLayout">

   5:      <param name="ConversionPattern" value="%d [%t] %-2p %c [%x] - %m%n" />

   6:    </layout>

   7: </appender>

¿Ustedes qué usan para el Logging, alguna API pública o tienen sus propias clases?

Enlaces relacionados:

Saludos,