Categories
.NET Utilidades Windows Forms

Habilitar la corrección de ortografía en Windows Live Writer

Si algunos usan la versión en inglés de Windows Live Writer y un sistema operativo en español para escribir textos (en inglés obviamente), se habrán dado cuenta que la corrección de ortografía no funciona bajo estas condiciones.

Para solucionar este problema, lo único que tienen que hacer es crear una pequeña aplicación que ejecute Windows Live Writer en un dominio de aplicación personalizado:

csharp:

using System.Globalization;
using System.Threading;

class Program
{
        static void Main()
        {
                string exe = @"C:\Archivos de programa\Windows Live Writer\WindowsLiveWriter.exe";
               
                System.AppDomain app = System.AppDomain.CreateDomain(exe);
                Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
               
                app.ExecuteAssembly(exe);
        }
}

Si alguien quiere ahorrarse un poco de tiempo, puede descargar el ejecutable que preparó Roy Osherove.

Categories
.NET ASP.NET Seguridad Web

10 errores más comunes que pueden causar problemas de seguridad en ASP.NET

Brian Sullivan, comenta los 10 errores más comunes que se cometen al configurar aplicaciones ASP.NET, estas configuraciones mal hechas podrían ayudar a los atacantes a vulnerar nuestras aplicaciones Web.

  1. Custom Errors deshabilitado: Al tener deshabilitado esta opción, los errores que se producen en la aplicación se muestran a todos. Los valores adecuados son On y RemoteOnly, en el primero se puede especificar páginas personalizadas para mostrar mensajes de error más amigables.
  2. Dejar habilitado el seguimiento de página (Tracing): Esta característica de ASP.NET contiene información bastante detallada de todo lo que pasa en la aplicación (registro de instrucciones relacionadas con el principio y el final de métodos de la ejecución, como Init, Render y PreRender; variables o encabezados de formulario y objetos QueryString, jerarquía de controles, estado de sesión y estado de aplicación). Un atacante puede utilizar toda esta información - accediendo simplemente a trace.axd - para lograr vulnerar nuestras aplicaciones, el valor adecuado para esta opción es:
    xml:

    <trace enabled="false" localOnly="true">
  3. Depuración habilitada: Tener esta opción habilitada, no sólo afecta al rendimiento de la aplicación, sino también que se muestran errores más detallados.
  4. Cookies accesibles desde código de cliente: Esto básicamente se refiere al uso de cookies del tipo HttpOnly, técnica que mitiga de algún modo el robo de cookies. Hay que tener en cuenta que esta característica no es la panacea para asegurar nuestra aplicación, además si se habilita esta opción a nivel de la aplicación, puede traer ciertos problemas al momento de trabajar con cookies en código de cliente.
  5. Cookies de estado de sesión enviadas por Url: El autor recomienda usar cookies para almacenar el ID de la sesión, de este modo se evitaría que un atacante suplante a un usuario válido al robar este valor usando algún sniffer - personalmente no veo mucha diferencia entre usar uno u otro método.
  6. Cookies de autenticación enviadas por Url: Ídem al anterior.
  7. No usar SSL para transmitir las cookies de autenticación: El uso de SSL en teoría permite la comunicación segura de datos.
  8. Uso de slidingExpiration en la autenticación: El tener este valor habilitado (<forms slidingExpiration="true">), permite que el tiempo de vida de la sesión vaya cambiando a medida que el usuario vaya interactuando con la aplicación. Sin embargo, con esta opción deshabilitada sólo se dispone de un tiempo fijo para la sesión, de esta manera si alguien suplanta a usuarios legítimos sólo tendrá un espacio de tiempo limitado.
  9. Cookies de autenticación no únicas: EL autor se refiere a usar diferentes valores para el nombre de la cookie de autenticación (<forms name="otro_valor">) en aplicaciones ASP.NET diferentes (para los casos en los que existen más de 2 aplicaciones en un mismo dominio)
  10. Almacenar las credenciales de usuario en Web.config:

Para mayores detalles pueden visitar los artículos originales.

Categories
.NET PostgreSQL Software Libre

Tipos personalizados de PostgreSQL y Npgsql

A raíz de una pregunta en la lista de discusión en español de PostgreSQL en el que hacían la siguiente pregunta:

Hola, tengo una función definida en mi BD postgresql que recive un array de un elementos de un tipo definido en la BD. (este tipo es un bigint y un character varying). Ahora mi duda es si el conector npgsql (Conector para .NET) soporta la posibilidad de llamar a una funcion con estas características.

Estos tipos compuestos en PostgreSQL se crean con la sentencia CREATE TYPE:

code:

test=> CREATE TYPE complex AS (
test(>     r       double precision,
test(>     i       double precision
test(> );
CREATE TYPE
test=> create table foo (item complex);
CREATE TABLE
test=> insert into foo values(ROW(5.2,1.6));
INSERT 0 1
test=> insert into foo values(ROW(2,-1));
INSERT 0 1
test=> select * from foo;
   item
-----------
 (5.2,1.6)
 (2,-1)
(2 filas)

Npgsql trae soporte sólo para los tipos de datos nativos que ofrece PostgreSQL, y trata a estos tipos compuestos como una cadena de caracteres. Si bien es cierto que se podría trabajar solamente con cadenas tanto para insertar como para recuperar este tipo de datos, esto probablemente causaría algunos problemas en la etapa de desarrollo, porque estos valores no serían comprobados en tiempo de compilación (más detalles); puesto que disponemos del código de Npgsql, es posible extenderlo sin mayores problemas para que soporte los tipos de datos que usemos en una aplicación X.

Lo primero, es definir una clase que represente el tipo que hayamos definido en la base de datos:

csharp:

public struct NpgsqlComplex
{
        private double _r;
        private double _i;

        public double I
        {
                get { return _i; }
                set { _i = value; }
        }

        public double R
        {
                get { return _r; }
                set { _r = value; }
        }

        public NpgsqlComplex(double r, double i)
        {
                _r = r;
                _i = i;
        }       
}

Luego se tiene que registrar esta clase en el método VerifyDefaultTypesMap de la clase NpgsqlTypesHelper:

csharp:

NativeTypeMapping.AddType("complex", NpgsqlDbType.Complex, DbType.Object, true,
        new ConvertNativeToBackendHandler(ExtendedNativeToBackendTypeConverter.ToComplex));

NativeTypeMapping.AddTypeAlias("complex", typeof(NpgsqlComplex));

y agregar un nuevo elemento a la variable TypeInfoList ubicado en el método CreateAndLoadInitialTypesMapping de la misma clase:

csharp:

new NpgsqlBackendTypeInfo(0, "complex", NpgsqlDbType.Complex, DbType.Object, typeof(NpgsqlComplex),
                        new ConvertBackendToNativeHandler(ExtendedBackendToNativeTypeConverter.ToComplex)),

Los métodos ExtendedNativeToBackendTypeConverter.ToComplex y ExtendedBackendToNativeTypeConverter.ToComplex se usan para convertir estos tipos compuestos desde .NET a PostgreSQL y desde PostgreSQL a .NET respectivamente

csharp:

// clase ExtendedNativeToBackendTypeConverter
private static readonly Regex complexRegex = new Regex(@"\(([-+]?\b[0-9]*\.?[0-9]+(?:[eE][-+]?[0-9]+)?\b),([-+]?\b[0-9]*\.?[0-9]+(?:[eE][-+]?[0-9]+)?\b)\)", RegexOptions.Compiled);
internal static Object ToComplex(NpgsqlBackendTypeInfo TypeInfo, String BackendData, Int16 TypeSize, Int32 TypeModifier)
{
        Match m = complexRegex.Match(BackendData);

        return new NpgsqlComplex(
                        Double.Parse(m.Groups[1].ToString(), NumberStyles.Any,
                                                 CultureInfo.InvariantCulture.NumberFormat),
                        Double.Parse(m.Groups[2].ToString(), NumberStyles.Any,
                                                 CultureInfo.InvariantCulture.NumberFormat));
}

// clase ExtendedBackendToNativeTypeConverter
internal static String ToComplex(NpgsqlNativeTypeInfo TypeInfo, Object NativeData)
{
        if (NativeData is NpgsqlComplex)
        {
                NpgsqlComplex complex = (NpgsqlComplex)NativeData;
                return String.Format(CultureInfo.InvariantCulture, "({0},{1})", complex.R, complex.I);
        }
        else
        {
                throw new InvalidCastException("Unable to cast data to NpgsqlComplex type");
        }
}

Finalmente, la clase de prueba para ver si todo funciona como debería:

csharp:

using System;
using System.Collections.Generic;
using System.Text;
using Npgsql;
using NpgsqlTypes;

namespace Demo
{
    class Program
    {
        static void Main(string[] args)
        {
            using (NpgsqlCommand command = new NpgsqlCommand("SELECT item FROM foo LIMIT 1", new NpgsqlConnection("server=192.168.1.20;uid=alex;database=test")))
            {
                command.Connection.Open();

                NpgsqlDataReader reader = command.ExecuteReader();
                while (reader.Read())
                {
                    NpgsqlComplex num = (NpgsqlComplex)reader["item"];
                    Console.WriteLine("{0} + {1}i", num.R, num.I);
                }
                reader.Close();

                command.CommandText = "INSERT INTO foo VALUES (@item)";
                command.Parameters.Add("@item", NpgsqlDbType.Complex);
                command.Parameters["@item"].Value = new NpgsqlComplex(15.5, -5);

                command.ExecuteNonQuery();
            }
        }
    }
}

Aunque el ejemplo es bastante trivial y tiene poco o nulo valor en aplicaciones reales, este ejemplo intenta mostrar uno de los beneficios del uso de Software Libre: el hecho de poder acomodar a nuestras necesidades las cosas que usemos.

Nota: Si alguien le interesa el ejemplo mostrado, puede descargar una versión modificada de Npgsql (para Visual Studio 2005) más el proyecto de prueba.

Categories
.NET Miniposts

NHibernate 1.2

NHibernate 1.2 está listo para ser usado en producción, las cosas que mencionan en las notas de la versión son:

  • Support for generic collections (soporte nativo para generics)
  • Custom SQL, including stored procedures (se puede personalizar la consulta SQL usada para persistir las entidades, también existe soporte para procedimientos almacenados)
  • Improved legacy database support
  • Subselect fetching
  • Enhancements to Criteria API
  • Filters (filtrar datos de acuerdo a ciertos criterios definidos)
  • Enhanced user types support
  • Update batching on MS SQL Server (ejecutar en conjunto, consultas UPDATE/INSERT/DELETE)
  • Multi-queries (algo parecido al anterior pero esta característica es para recuperar datos)
  • SysCache2 (cache de segundo nivel en el que se puede hacer uso del denominado "cache invalidation" para refrescar los datos de acuerdo a algunos eventos producidos en la base de datos)
  • Database dialects (soporte para nuevas bases de datos Ingres, Informix, Sybase ASA, Microsoft SQL Server 2005 y SQL Server CE. Ahora es posible usar SetFirstResult/SetMaxResults en SQL Server 2005)

Fuente: Ayende

Categories
.NET Expresiones Regulares

Expresiones regulares más entendibles en .NET – II

En la primera parte en el que recomendaba el uso de comentarios y la asignación de nombres a los grupos que se definían en la expresión regular, Eber Irigoyen comentó otra alternativa, que también había visto antes 🙂 , donde se hace uso del patrón Fluent Interface para que las expresiones regulares sean más fáciles de entender, este conjunto de clases es obra de Joshua Flanagan:

El siguiente ejemplo muestra un equivalente a la siguiente expresión regular: <(?<tag>[a-zA-Z][a-zA-Z]*)[^>]*>(?<innerHTML>.*?)</\k<tag>>

csharp:

using System;
using FlimFlan.ReadableRex;
using System.Text.RegularExpressions;

class Program
{
    static void Main(string[] args)
    {
        //Regex htmlTag = new Regex(@"<(?<tag>[a-zA-Z][a-zA-Z]*)[^>]*>(?<innerHTML>.*?)</\k<tag>>");

        Pattern pattern =
            Pattern.With.Literal("<"). // <
            NamedGroup("tag", Pattern.With.Set(Range.AnyLetter).Set(Range.AnyLetter).Repeat.ZeroOrMore). // (?<tag>[a-zA-Z][a-zA-Z]*)
                NegatedSet(Pattern.With.Literal(">")).Repeat.ZeroOrMore.Literal(">"). // [^>]*>
            NamedGroup("innerHTML", Pattern.With.Anything.Repeat.Lazy.ZeroOrMore). // (?<innerHTML>.*?)
            RegEx(@"</\k<tag>>"); // </\k<tag>>

        Match match = Regex.Match(@"<a href=""http://www.buayacorp.com"">Enlace</a>", pattern.ToString());

        Console.WriteLine("Patrón: {0}\nGrupo innerHTML: {1}", pattern.ToString(), match.Groups["innerHTML"].Value);
    }
}

Esta última alternativa es más adecuada para aquellos que no están tan familiarizados con las expresiones regulares, pero es bastante fastidioso cuando se requiere expresar un patrón más largo y complejo; en todo caso el uso de uno u otro método, dependerá de las prácticas que se sigan en cada empresa -o proyecto.