Categorías
asp.net

Inyeccíon de dependencia en asp.net

En el ámbito del desarrollo de software, siempre es bueno eliminar dependencias. En otros términos, bajar el nivel de acoplamiento.

Hay casos en que se logra más directamente y otros en que no es tan simple.

Para estos últimos contamos con un pattern llamado Dependency Injection,Inyección de Dependencia, término por primera vez usado por Martin Fowler. Si te interesa ir a la fuente, acá está su documento sobre Dependency Injection.

En este post voy a intentar explicar que viene a resolver este patrón y sus distintas implementaciones.

Cuando tenemos un objeto que necesita de otro para funcionar correctamente, tenemos definida una dependencia. Esta dependecia puede ser altamente acopladatight coupling, o levemente acopladaloose coupling. Si el acoplamiento es bajo el objeto independiente es fácilmente reemplazable, si, en cambio el acoplamiento es alto, el reemplazo no es fácil y se dificulta el diseño de tests unitarios.

Supongamos que tenemos una clase que define un producto, que necesita un componente, este componente puede provenir de distintos fabricantes, en general cubren las mismas funciones. Los productos son varios y alternativamente pueden valerse del componente de cualquier fabricante.

Si instanciamos uno de los componentes en forma directa necesitamos referenciarlo. Si el mercado nos exige cambiar de componente, tendríamos que eliminar la referencia anterior, crear la nueva, revisar si los métodos, funciones y propiedades son homogéneos, si no lo son, corregir el código donde sea necesario… Si a esto le agregamos que valdría la pena tener una versión con el primer componente y otra con el segundo, la situación empeora. Si hubiera cincuenta componentes alternativos, la situación ya sería inmanejable.

Acá es donde la necesidad del patrón Dependency Injection se hace evidente.

Supongamos que este conjunto de componentes ejecuta básicamente cuatro métodos, que son los que nosotros necesitamos: Initialize, Shutdown, Prepare y DoIt.

Entonces comencemos por escribir una interface que defina estos cuatro métodos:

[VB]

Public Interface ISomeHardware
Sub Initialization()
Sub Shutdown()
Sub Prepare()
Sub DoIt()
End Interface

[C#]

public interface ISomeHardware
{
void Initialization();
void Shutdown();
void Prepare();
void DoIt();
}

Las clases que definan los componentes deben implementar la interfaceISomeHardware. En nuestro ejemplo, ComponentA y ComponentB:

[VB]

Public Class ComponentA
Implements ISomeHardware
Public Sub InitializationBegin() ImplementsISomeHardware.Initialization

End Sub
Public Sub ShutdownBegin() Implements ISomeHardware.Shutdown

End Sub
Public Sub PrepareBegin() Implements ISomeHardware.Prepare

End Sub
Public Sub DoItBegin() Implements ISomeHardware.DoIt

End Sub
End Class

Public Class ComponentB
Implements ISomeHardware

Public Sub InitializationBegin() ImplementsISomeHardware.Initialization

End Sub
Public Sub ShutdownBegin() Implements ISomeHardware.Shutdown

End Sub
Public Sub PrepareBegin() Implements ISomeHardware.Prepare

End Sub
Public Sub DoItBegin() Implements ISomeHardware.DoIt

End Sub
End Class

[C#]

class ComponentA : ISomeHardware
{
public void Initialization() { }
public void Shutdown() { }
public void Prepare() { }
public void DoIt() { }
}

class ComponentB : ISomeHardware
{
public void Initialization() { }
public void Shutdown() { }
public void Prepare() { }
public void DoIt() { }
}

Aclaración: Acá hago una simplificación a efecto didáctico. Las clases que definen ComponentA y ComponentB, en realidad debieran ser wrappers de las dll’s provistas por los fabricantes. Para no complicar inútilmente las dejaré así.

Veremos tres implementaciones del patrón Dependency Injectionpor Constructorpor Setter por Interface.

POR CONSTRUCTOR:

Ahora voy a usar otro patrón llamado Facade o Fachada, la idea es encapsular todos los aspectos complejos de un subsistema de clases en una única y simple interface. En nuestro caso, ProductFacade:

[VB]

Public Class ProductFacade
Private SomeHardware As ISomeHardware
Public Sub New(ByVal pSomeHardware As ISomeHardware)
SomeHardware = pSomeHardware
End Sub
End Class

[C#]

public class ProductFacade
{
private ISomeHardware SomeHardware;
public ProductFacade(ISomeHardware SomeHardware)
{
this.SomeHardware = SomeHardware;
}
}

En esta clase se implementa la Inyección de Dependencia por medio delconstructor, que acepta un parámetro de entrada de tipo de interfaceISomeHardware. Este punto es determinante. Cualquier clase que implemente la interface ISomeHardware es aceptada como parámetro del constructor de ProductFacade. Este es todo el secreto.

Entonces, para inyectar la dependencia de un componente de un fabricante u otro por Constructor, se hace así:

[VB]

Dim ComponentA As ISomeHardware = New ComponentA
Dim Product01 As ProductFacade = New ProductFacade(ComponentA)
 
Dim ComponentB As ISomeHardware = New ComponentB
Dim Product02 As ProductFacade = New ProductFacade(ComponentB)

[C#]

ISomeHardware componentA = new ComponentA();
ProductFacade product01 = new ProductFacade(componentA);
 
ISomeHardware componentB = new ComponentB();
ProductFacade product02 = new ProductFacade(componentB);

Realmente elegante.

Para las siguientes dos implementaciones del patrón, usaremos la misma interface ISomeHardware y la definición de las clases ComponentA yComponentB.

Las variaciones estarán en la Fachada y en la Inyección de Dependencia.

POR SETTER:

En este caso la Inyección de Dependencia se efectiviza a través de unapropiedad definida en la Fachada.

[VB]

Public Class ProductFacade
Private mSomeHardware As ISomeHardware
 
Public Property SomeHardware() As ISomeHardware
Get
Return mSomeHardware
End Get
Set(ByVal value As ISomeHardware)
mSomeHardware = value
End Set
End Property
End Class

[C#]

public class ProductFacade
{
private ISomeHardware SomeHardware;
public ISomeHardware Component
{
get
{
return SomeHardware;
}
set
{
SomeHardware = value;
}

}

}

Para el caso de Setter, la Inyección de Dependencia queda determinada así:

[VB]

Dim ComponentA As ISomeHardware = New ComponentA
Dim Product01 As ProductFacade = New ProductFacade()
Product01.SomeHardware = ComponentA

Dim ComponentB As ISomeHardware = New ComponentB
Dim Product02 As ProductFacade = New ProductFacade()
Product02.SomeHardware = ComponentB

[C#]

ISomeHardware componentA = new ComponentA();
ProductFacade product01 = new ProductFacade();
product01.Component = componentA;
ISomeHardware componentB = new ComponentB();
ProductFacade product02 = new ProductFacade();
product02.Component = componentB; 

POR INTERFACE:

Ahora la Inyección de Dependencia está implementada sobre un métodoque acepta un parámetro de tipo de interface ISomeHardware.

[VB]

Public Class ProductFacade
Private mSomeHardware As ISomeHardware
Public Sub SetComponent(ByVal pSomeHardware As ISomeHardware)
mSomeHardware = pSomeHardware
End Sub
End Class

[C#]

public class ProductFacade
{
private ISomeHardware SomeHardware;
public void SetComponent(ISomeHardware SomeHardware)
{
this.SomeHardware = SomeHardware;
}
}

Cuando la Inyección de Dependencia es por Interface, se invoca de esta forma:

[VB]

Dim ComponentA As ISomeHardware = New ComponentA
Dim Product01 As ProductFacade = New ProductFacade()
Product01.SetComponent(ComponentA)
 
Dim ComponentB As ISomeHardware = New ComponentB
Dim Product02 As ProductFacade = New ProductFacade()
Product02.SetComponent(ComponentB)

[C#]

ISomeHardware componentA = new ComponentA();
ProductFacade product01 = new ProductFacade();
product01.SetComponent(componentA);
 
ISomeHardware componentB = new ComponentB();
ProductFacade product02 = new ProductFacade();
product02.SetComponent(componentB);

Las tres implementaciones difieren sutilmente entre si. La diferencia más importante que yo encuentro es que, Por Constructor, nos obliga a inyectar al crear la clase, mientras que las otras modalidades, la difieren para más adelante.

La diferencia entre estas dos últimas está en si se prefiere inyectar la dependencia en el set de una propiedad, Por Setter, o como argumento de un parámetro de entrada a un método o función, Por Interface. Cuestión de gusto sintáctico.

Categorías
ASP

¿Como evitar SQL Inyection en asp?

<%
Dim BlackList, ErrorPage, s

BlackList = Array("--", ";", "/*", "*/", "@@", "@",_
"char", "nchar", "varchar", "nvarchar",_
"alter", "begin", "cast", "create", "cursor",_
"declare", "delete", "drop", "end", "exec",_
"execute", "fetch", "insert", "kill", "open",_
"select", "sys", "sysobjects", "syscolumns",_
"table", "update")

' Populate the error page you want to redirect to in case the check fails.
ErrorPage = "/ErrorPage.asp"

' This function does not check for encoded characters since we do not know the form of encoding your application uses. Add the appropriate logic to deal with encoded characters in here
'''''''''''''''''''''''''''''''''''''''''''''''''''
Function CheckStringForSQL(str)
On Error Resume Next

Dim lstr

' If the string is empty, return true
If ( IsEmpty(str) ) Then
CheckStringForSQL = false
Exit Function
ElseIf ( StrComp(str, "") = 0 ) Then
CheckStringForSQL = false
Exit Function
End If

lstr = LCase(str)

' Check if the string contains any patterns in our black list
For Each s in BlackList

If ( InStr (lstr, s) <> 0 ) Then
CheckStringForSQL = true
Exit Function
End If

Next

CheckStringForSQL = false

End Function

' Check forms data
For Each s in Request.Form
If ( CheckStringForSQL(Request.Form(s)) ) Then

' Redirect to an error page
Response.Redirect(ErrorPage)

End If
Next

' Check query string
For Each s in Request.QueryString
If ( CheckStringForSQL(Request.QueryString(s)) ) Then

' Redirect to error page
Response.Redirect(ErrorPage)

End If

Next

' Check cookies
For Each s in Request.Cookies
If ( CheckStringForSQL(Request.Cookies(s)) ) Then
' Redirect to error page
Response.Redirect(ErrorPage)
End If
Next
%>
Categorías
ASP

Función en asp para convertir a url amigables con expresiones regulares

function convertirURLfriendly(cadena)
    if not isNull(cadena) then
    ' Eliminamos los espacios a ambos lados de la cadena
        strCadena = Trim(lCase(cadena))
        ' Reemplazamos carácteres especiales
        strCadena = replace(replace(strCadena,"'",""),"""","")
        strCadena = replace(replace(strCadena,"&quot;",""),vbcrlf,"")
        strCadena = replace(replace(strCadena,"<br>","")," ","-")
        set expReg = New RegExp
        ' Todas las ocurrencias
        expReg.Global = True
        expReg.Pattern = "[àáâãäå]"
        strCadena = expReg.Replace(strCadena, "a")
        expReg.Pattern = "[èéêë]"
        strCadena = expReg.Replace(strCadena, "e")
        expReg.Pattern = "[ìíîï]"
        strCadena = expReg.Replace(strCadena, "i")
        expReg.Pattern = "[òóôõö]"
        strCadena = expReg.Replace(strCadena, "o")
        expReg.Pattern = "[ùúûü]"
        strCadena = expReg.Replace(strCadena, "u")
        expReg.Pattern = "[ñ]"
        strCadena = expReg.Replace(strCadena, "n")
        expReg.Pattern = "[ç]"
        strCadena = expReg.Replace(strCadena, "c")
        ' Todo lo que no cumpla este patron
        expReg.Pattern = "[^a-z0-9-]"
        strCadena = expReg.Replace(strCadena, "")
        set expReg = nothing
        convertirAURLfriendly = left(strCadena,256)
    else
        convertirAURLfriendly = ""
    end if
end function
Categorías
Programación

Expresiones regulares

Validar una URL

¿Quieres saber si una dirección web es válida? No hay problema con esta expresión regular lo tendremos muy fácil:

/^(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \?=.-]*)*\/?$/

Validar un E-mail

En muchas ocasiones necesitaremos saber si un e-mail con el que se trata de registrar un usuario es válido:

^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,3})$

Comprobar la seguridad de una contraseña

Para aquellos que necesitáis sugerir / comprobar la fortaleza de una contraseña:

(?=^.{8,}$)((?=.*\d)|(?=.*\W+))(?![.\n])(?=.*[A-Z])(?=.*[a-z]).*$

De esta forma comprobaremos:

  • Contraseñas que contengan al menos una letra mayúscula.
  • Contraseñas que contengan al menos una letra minúscula.
  • Contraseñas que contengan al menos un número o caracter especial.
  • Contraseñas cuya longitud sea como mínimo 8 caracteres.
  • Contraseñas cuya longitud máxima no debe ser arbitrariamente limitada.

Validar un número de teléfono

Con esta expresión se validarán todos los número de teléfono pertenecientes a los listados en la Wikipedia:

^\+?\d{1,3}?[- .]?\(?(?:\d{2,3})\)?[- .]?\d\d\d[- .]?\d\d\d\d$

Validar número de tarjeta de crédito

Ahora que tan de moda está el e-commerce seguro que esto le vendrá bien a más de uno:

^((67\d{2})|(4\d{3})|(5[1-5]\d{2})|(6011))(-?\s?\d{4}){3}|(3[4,7])\ d{2}-?\s?\d{6}-?\s?\d{5}$

Recoger ID de un vídeo de Youtube

Si necesitas recoger el ID de un vídeo de Youtube en sus múltiples combinaciones, esta es tu expresión regular:

/http:\/\/(?:youtu\.be\/|(?:[a-z]{2,3}\.)?youtube\.com\/watch(?:\?|#\!)v=)([\w-]{11}).*/gi

Validar todas las etiquetas de imagen sin cerrar

Ahora que prácticamente todos empleamos xHTML es interesante comprobar que todas nuestras etiquetas de imagen están correctamente cerradas.

<img([^>]+)(\s*[^\/])></img([^>

Validar una dirección IP

Si necesitas validar una dirección IP introducida por un usuario, esto te será de gran ayuda.

/^(([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]).){3}([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/

Validar código postal

En muchas ocasiones necesitamos recoger en los formularios de alta el código postal.

^([1-9]{2}|[0-9][1-9]|[1-9][0-9])[0-9]{3}$

Validar un nombre de usuario

Si por ejemplo quisiésemos validar un nombre de usuario con un mínimo de 4 caracteres y un máximo de 15 haríamos lo siguiente:

/^[a-z\d_]{4,15}$/i

Además el nombre estaría utilizando sólo caracteres de la A-z y números.

Categorías
ASP

Forzar la codificación UTF-8 en ASP

Código asp:

Response.ContentType = "text/html"
Response.AddHeader "Content-Type", "text/html;charset=UTF-8"
Response.CodePage = 65001
Response.CharSet = "UTF-8"
Categorías
ASP

Cómo evitar que las paginas asp sean cacheadas

Para evitar la cache de las paginas asp asignaremos las siguientes addHeader

Response.Expires = -1
Response.AddHeader "Cache-Control", "no-cache"
Response.AddHeader "Cache-Control", "private"
Response.AddHeader "Cache-Control", "no-store"
Response.AddHeader "Cache-Control", "must-revalidate"
Response.AddHeader "Cache-Control", "max-stale=0"
Response.AddHeader "Cache-Control", "post-check=0"
Response.AddHeader "Cache-Control", "pre-check=0"
Response.AddHeader "Pragma", "no-cache"
Response.AddHeader "Keep-Alive", "timeout=3, max=993"
Response.AddHeader "Expires", "Thu, 10 Ene 2012 05:00:00 GMT"
Categorías
ASP

Response.CacheControl

Para evitar que páginas con contenidos personales se puedan mandar a otras personas distintas de su dueño por culpa de los servidores proxy está la propiedad Response.CacheControl.

Si le asignamos el valor «Private» la página no será guardada por los servidores proxy.
Si le asignamos el valor «Public» las páginas si que se almacenarán en los servidores proxy y podrán ser enviadas a otras personas.
Si le asignamos el valor «No-cache» las páginas no se almacenan en los servidores proxy, ni para el mismo cliente.
Si le asignamos el valor «No-store» las páginas no se almacenan en ningun caso.

Response.CacheControl = "Public" 
Response.CacheControl = "Private"
Response.CacheControl = "No-cache"
Response.CacheControl = "No-store"
Categorías
ASP

Perdida de Memoria en ASP o Memory Leak en ASP

Una fuga de memoria o en inglés memory leak es un error de software que ocurre cuando un bloque de memoria reservada no es liberada en un programa de computación.

Comúnmente ocurre porque se pierden todas las referencias a esa área de memoria antes de haberse liberado.

Dependiendo de la cantidad de memoria perdida y el tiempo que el programa siga en ejecución, este problema puede llevar al agotamiento de la memoria disponible en la computadora.

Este problema se da principalmente en aquellos lenguajes de programación en los que el manejo de memoria es manual (C o C++ principalmente), y por lo tanto es el programador el que debe saber en qué momento exacto puede liberar la memoria.

Otros lenguajes utilizan un recolector de basura o conteo de referencias que automáticamente efectúa esta liberación.

Sin embargo todavía es posible la existencia de fugas en estos lenguajes si el programa acumula referencias a objetos, impidiendo así que el recolector llegue a considerarlos en desuso.

Como evitar la fuga de memoria o memory leak en asp:

  • Cerrar los registros de base de datos
  • Cerrar las conexiones de base de datos
  • Cerrar todos los otros objetos que hayan creado
  • En caso de utilizar en response.redirect hacer todo lo anterior antes de llamarlo.

Causas para producir una fuga de memoria en IIS w3wp.exe

Podría ser un millón de cosas: las conexiones de base de datos no se han cerrado, objetos ADO no está correctamente destruidos … a menos que sólo hay unos pocos sitios en el servidor que va a tener un montón de problemas rastrear cuál es el culpable.

Herramientas para encontrar una fuga de memoria en el IIS w3wp.exe

Utilizar un depurador del w3wp.exe cuando está al 100%, determine qué código se está ejecutando actualmente y masticar ciclos de CPU, y fijar ese código para no masticar CPU.

Debug Diagnostic Tool

Herramienta diseñada para ayudar en la solución de problemas tales como cuelges, bajo rendimiento, pérdida de memoria o de fragmentación, y se estrella en cualquier proceso de modo de usuario.

La herramienta incluye secuencias de comandos de depuración adicionales centradas en Internet Information Services (IIS), los datos de las aplicaciones web de componentes de acceso, COM + y relacionadas con tecnologías de Microsoft.

Debug Diagnostic Tool proporciona un modelo de objetos extensible en forma de objetos COM y proporciona todo tipo script con un marco de información integrado.

Se compone de los siguientes 3 componentes: un servicio de depuración, un host del depurador, y la interfaz de usuario.

El Servicio de Depuración El servicio del depurador (DbgSvc.exe) realiza las siguientes tareas:

  • Conectar / Desconectar el anfitrión a los procesos
  • Recoger datos de rendimiento del monitor
  • Implementar mesa de ping HTTP para detectar cuelges
  • Inyectar monitor de fugas en los procesos en ejecución
  • Recopilar información de estado de sesión de depuración
  • Muestra el estado de cada regla definida

El host del depurador (DbgHost.exe) acoge el motor de Windows Depurador simbólico (dbgeng.dll) para unir a los procesos y generar volcados de memoria.

También alberga el módulo analizador principal para analizar volcados de memoria. Dbghost.exe no tiene ninguna dependencia en el servicio «DbgSvc.exe» y puede ser utilizado por separado.

La interfaz de usuario de las interfaces de usuario (DebugDiag.exe y DebugDiagAnalysisOnly.exe) presentan una interfaz para analizar volcados de memoria, automatizar la creación de secuencias de comandos de control y para mostrar el estado de los procesos en ejecución, incluidos los servicios.

Se compone de tres puntos de vista:

  • Reglas: Crea script de control para el host del depurador a través de un asistente. El script se encuentra en el directorio \ scripts.
  • Análisis Avanzado: Se ejecuta un seleccionado «Script Análisis» en contra de uno o más volcados de memoria.
  • Procesos: Muestra el estado de los procesos en ejecución / servicios.