Tip #2 - Do More with More

by Nicolás Ferreira 16. August 2007 00:00

Leyendo MCPmag me encuentro con un artículo llamado "Do More with More". Estando en la ventana de comandos si abrimos paréntesis "(" y presionamos Enter vamos a obtener algo así:

C:\>(
More?

Podemos escribir un comando por línea. Cuando terminamos escribimos ")" y presionamos Enter para que todos los comandos que fueron escritos se ejecuten. Por ejemplo:

C:\>(
More? ECHO %OS%
More? ECHO Hello World
More? )

Esto produce:

Windows_NT
Hello World

Esto puede ser de gran utilidad cuando lo que queremos es mostrar varias listas de archivos y subdirectorios de varios directorios y redirigir la salida a un archivo. Por ejemplo:

C:\>(
More? TIME /T
More? DIR C:\*.EXE
More? DIR C:\WINDOWS\*.EXE
More? ) >C:\Resultados.txt

C:\>

Tags:

off-topic

Supervisión de estado

by Nicolás Ferreira 15. August 2007 00:00

Pregúntele a su programador ASP.NET favorito por cómo haría para recibir una notificación por E-Mail en el caso de que alguien no autorizado intente acceder a un recurso protegido que se encuentra dentro de su aplicación Web. Probablemente no le pueda responder.
La realidad es que ASP.NET trae un sistema de supervisión de estado que mediante los siguientes eventos nos permite administrar las aplicaciones Web:

WebApplicationLifetimeEvent – Representa un evento significativo en el período de duración de una aplicación.
WebAuditEvent – Actúa como clase base para todos los eventos de auditoría de supervisión del estado de ASP.NET.
WebAuthenticationFailureAuditEvent – Proporciona información sobre los errores de autenticación en ASP.NET.
WebAuthenticationSuccessAuditEvent – Proporciona información sobre los eventos de autenticación correctos.
WebBaseErrorEvent – Sirve de clase base para todos los eventos de error de supervisión de estado.
WebBaseEvent – Define la clase base para los eventos de supervisión de estado de ASP.NET.
WebErrorEvent – Proporciona información sobre los errores sistémicos.
WebFailureAuditEvent – Proporciona información sobre los errores de seguridad.
WebHeartbeatEvent – Define los eventos de supervisión de estado que se producen periódicamente.
WebManagementEvent – Define la clase base para los eventos que contienen información de la aplicación e información de procesos.
WebRequestErrorEvent – Define el evento que incluye información sobre los errores de solicitud Web.
WebRequestEvent – Define la clase base para los eventos que proporcionan información sobre solicitudes Web.
WebSuccessAuditEvent – Proporciona información de los eventos de seguridad correctos.
WebViewStateFailureAuditEvent – Proporciona información de errores relacionados con el estado de vista de las aplicaciones Web.

Junto a estos eventos, tenemos los siguientes proveedores:

EventLogWebEventProvider – Implementa un proveedor de eventos que registra los eventos de supervisión de estado de ASP.NET en el registro de eventos de aplicación para Windows.
SqlWebEventProvider – Implementa un proveedor de eventos que guarda las notificaciones de eventos en una base de datos SQL.
WmiWebEventProvider – Implementa un proveedor de eventos que asigna los eventos de supervisión del estado de ASP.NET a los eventos de Windows Management Instrumentation (WMI).
SimpleMailWebEventProvider – Implementa un proveedor de eventos que envía mensajes de correo electrónico para las notificaciones de eventos.
TemplatedMailWebEventProvider – Implementa un proveedor de eventos que utiliza las plantillas para definir y dar formato a los mensajes de correo electrónico que envía para las notificaciones de eventos.
TraceWebEventProvider – Implementa un proveedor de eventos que envía los eventos de supervisión de estado de ASP.NET como mensajes de seguimiento.

Además podemos crear nuestros propios eventos y nuestros propios proveedores. En esta ocasión, lo que voy a hacer simplemente es configurar en el archivo de configuración Web el evento WebFailureAuditEvent con el proveedor SqlWebEventProvider para almacenar en una base de datos de SQL Server información en el caso de que alguien intente acceder a un recurso protegido y no se encuentre autorizado:

<?xml version="1.0" ?>
<configuration>
  <connectionStrings>
    <remove name="SqlConnectionString" />
    <add connectionString="Data Source=;Initial Catalog=aspnetdb;Integrated Security=True"
         name="SqlConnectionString" providerName="System.Data.SqlClient" />
  </connectionStrings>
  <system.web>
    <healthMonitoring enabled="true" heartbeatInterval="0">
      <bufferModes>
        <remove name="Critical Notification" />
        <add name="Critical Notification" maxBufferSize="100" maxFlushSize="20"
             urgentFlushThreshold="1" regularFlushInterval="Infinite"
             urgentFlushInterval="00:01:00" maxBufferThreads="1" />
      </bufferModes>
      <providers>
        <remove name="SqlWebEventProvider" />
        <add name="SqlWebEventProvider"
             type="System.Web.Management.SqlWebEventProvider,System.Web,Version=2.0.0.0,Culture=neutral,PublicKeyToken=b03f5f7f11d50a3a" connectionStringName="SqlConnectionString" maxEventDetailsLength="1073741823" buffer="true" bufferMode="Critical Notification" />
      </providers>
      <eventMappings>
        <remove name="FailureAuditEvent" />
        <add name="FailureAuditEvent"
             type="System.Web.Management.WebFailureAuditEvent,System.Web,Version=2.0.0.0,Culture=neutral,PublicKeyToken=b03f5f7f11d50a3a" />
      </eventMappings>
      <profiles>
        <remove name="Critical" />
        <add name="Critical" minInstances="1" maxLimit="Infinite" minInterval="00:00:00" custom="" />
      </profiles>
      <rules>
        <remove name="FailureAuditEvent" />
        <add eventName="FailureAuditEvent" name="FailureAuditRule"
             provider="SqlWebEventProvider" profile="Critical" />
      </rules>
    </healthMonitoring>
    <compilation debug="true" />
  </system.web>
</configuration>

Lo importante a destacar de todo esto es:

urgentFlushInterval (bufferModes): tiempo mínimo que puede transcurrir entre vaciados del búfer.
maxEventDetailsLength (providers): se aplica sólo al atributo SQLWebEventProvider. Especifica la longitud máxima, en caracteres, de la información detallada que se permite para cada evento.
minInterval (profiles): intervalo de tiempo mínimo entre dos eventos del mismo tipo.

La base de datos "aspnetdb" la pueden crear utilizando "Aspnet_regsql".

Tags:

.NET Development

Tip #1 – FormsAuthentication

by Nicolás Ferreira 15. August 2007 00:00

Puede que nuestra aplicación Web vaya a utilizar autenticación de formularios pero como estamos en la etapa inicial y lo único que tenemos es un formulario llamado Login.aspx, no estemos dispuestos a implementar el sistema de validación de credenciales desde el comienzo. Aún así, queremos dejar a nuestro jefe contento y darle un usuario y contraseña. La solución es poner lo siguiente en nuestro Web.config:

<configuration>
  <system.web>
    <authentication mode="Forms">
      <forms>
        <credentials passwordFormat="Clear">
          <user name="Usuario" password="Contraseña"/>
        </credentials>
      </forms>
    </authentication>
  </system.web>
</configuration>

En Login.aspx ponemos un control de Login cuyo código de marcas se vea así:

<asp:Login ID="Login1" runat="server" OnAuthenticate="Login1_Authenticate"/>

Y en el code-behind de Login.aspx ponemos lo siguiente:

        protected void Login1_Authenticate(object sender, AuthenticateEventArgs e)
        {
            e.Authenticated = FormsAuthentication.Authenticate
                (this.Login1.UserName, this.Login1.Password);
        }

Nota: "passwordFormat" está en "Clear". Podemos aplicar un algoritmo hash a la contraseña utilizando "MD5" o "SHA1" de la siguiente manera:

FormsAuthentication.HashPasswordForStoringInConfigFile("ContraseñaAAPlicarHash", "MD5");
FormsAuthentication.HashPasswordForStoringInConfigFile("ContraseñaAAPlicarHash", "SHA1");

Lo que devuelve el método HashPasswordForStoringInConfigFile es lo que luego tenemos que poner en el atributo password del elemento user del elemento credentials.

Finalmente para probar si todo este invento funciona podemos poner lo siguiente en el Web.config:

<authorization>
  <deny users="?"/>
</authorization>

Tags:

.NET Development

GridView: TemplateField

by Nicolás Ferreira 9. August 2007 00:00

Hoy llegué al trabajo y me encontré con que tenía que hacer una página que mostrara información tabular. El problema por así decirlo era que el texto que se iba a mostrar en una columna tenía que tener un color de fuente dependiendo de la información. Por ejemplo, si el texto era "Satisfactorio", entonces el color del texto tenía que ser verde. Si el texto era "Error", entonces el color del texto tenía que ser rojo.

El sitio Web en el cual tenía que poner la página tenía una carpeta ASP.NET de temas (App_Themes) con un tema (Theme1). Lo primero que vamos a hacer es definir en un archivo skin (SkinFile.skin) lo siguiente:

        <asp:Label ID="Label1" SkinID="LabelRojo" runat="server" Font-Names="Arial" Font-Size="11px"
            ForeColor="Red" />
        <asp:Label ID="Label2" SkinID="LabelVerde" runat="server" Font-Names="Arial" Font-Size="11px"
            ForeColor="Green" />

La propiedad StylesheetTheme de la página la establecemos en "Theme1".

Para esta prueba vamos a crear una clase llamada "Demostracion" de la siguiente manera:

    public class Demostracion
    {
        private string _Estado;

        public string Estado
        {
            get { return _Estado; }
            set { _Estado = value; }
        }
        public Demostracion(string pEstado)
        {
            Estado = pEstado;
        }
    }

En el code-behind de la página ponemos lo siguiente:

        protected object ObtenerSpanEstado(string pEstado)
        {
            string lSpanEstado = string.Empty;
            Label lLabelEstado = new Label();
            lLabelEstado.Text = pEstado;
            if (pEstado == "Satisfactorio")
            {
                lLabelEstado.SkinID = "LabelVerde";
            }
            else if (pEstado == "Error")
            {
                lLabelEstado.SkinID = "LabelRojo";
            }
            lLabelEstado.ApplyStyleSheetSkin(this.Page);
            StringWriter lHTMLRenderizado = new StringWriter();
            HtmlTextWriter lHtmlTextWriter = new HtmlTextWriter(lHTMLRenderizado);
            lLabelEstado.RenderControl(lHtmlTextWriter);
            return lHTMLRenderizado.ToString();
        }

Y en el GridView creamos una columna de tipo TemplateField. De HeaderText le ponemos algo como "Estado". La propiedad AutoGenerateColumns del GridView la establecemos en False. En el código de marcas de la página, dentro del elemento asp:TemplateField (que fue la columna que creamos), ponemos lo siguiente:

        <ItemTemplate>
            <%# ObtenerSpanEstado((string)Eval("Estado")) %>
        </ItemTemplate>

Y para ir terminando, vamos a poblar el GridView en el Page_Load:

        protected void Page_Load(object sender, EventArgs e)
        {
            List<Demostracion> lDemostraciones = new List<Demostracion>();
            lDemostraciones.Add(new Demostracion("Satisfactorio"));
            lDemostraciones.Add(new Demostracion("Error"));
            lDemostraciones.Add(new Demostracion("Satisfactorio"));
            lDemostraciones.Add(new Demostracion("Error"));
            lDemostraciones.Add(new Demostracion("Satisfactorio"));
            this.GridView1.DataSource = lDemostraciones;
            this.GridView1.DataBind();
        }

Lo importante aquí es ObtenerSpanEstado. Cuando el GridView se encuentra atando la información, al nosotros haber definido en la plantilla que permite mostrar un elemento en un control enlazado a datos lo siguiente:

            <%# ObtenerSpanEstado((string)Eval("Estado")) %>

Se va a llamar a ObtenerSpanEstado que va a recibir como parámetro el valor de la propiedad "Estado" del objeto de tipo "Demostracion" que el GridView se encuentre atando en ese momento (mediante reflexión hecha por el método Eval). Eval lo que hace es "Proporciona compatibilidad para analizar y evaluar una expresión de enlace de datos con respecto a un objeto en tiempo de ejecución". ObtenerSpanEstado devuelve el HTML que se va a insertar. Después a lLabelEstado le asignamos el ID de la máscara y llamamos a ApplyStyleSheetSkin que "Aplica al control las propiedades de estilo definidas en la hoja de estilos de página". Tenemos que llamar a ApplyStyleSheetSkin ya que el control Label lo creamos de manera programática. Finalmente RenderControl "Representa el control HtmlForm en el objeto HtmlTextWriter especificado" que al estar el HtmlTextWriter "enlazado" al StringWriter, nos va a permitir obtener la cadena HTML del Label.

Tags:

.NET Development