Saltar al contenido

En la entrada anterior veíamos como habilitar la compresión gzip de salida de HTTP con Apache, en esta entrada explicaré de manera resumida realizar la misma acción pero para IIS 6.

1. el primer paso para habilitar la compresión es agregar una "Extensión de servicio". Para ello locarizaremos en el administrador de IIS la carpeta "Extensiones de servicio web" y haremos click sobre "Nueva extensión".

iis6

2. en la ventana de "Nueva extensión de servicio web" le pondremos un nombre, como "gzip" o "compresión" y agregaremos la librería gzip.dll ubicada en c:\Windows\System32\inetsrv\gzip.dll

Es importante seleccionar el check "Establecer el estado de extensión a Permitido".

3. Una vez agregada la extensión, solo tenemos que ir a nuestros "Sitios Web" y en sus propiedades de Servicio habilitar "Comprimir archivos de aplicación" y "Comprimir archivos estáticos"

4. Para finalizar la configuración de la compresión tendremos que modificar el fichero "Metabase.xml", antes deberemos haberle habilitado su modificación (bloqueado por defecto por IIS).  Para ello iremos a "Admnistración de Internet Information Server" > Propiedades y "Habilitar la modificación directa de archivos de metabase"

habilitar metabase.xml

Ahora ya podemos editar el fichero “Metabase.xml”, normalmente ubicado en "%windir%\SYSTEM32\inetsrv\".

Del fichero en cuestión lo que nos interesa para la compresión http es la sección de“<;IIsCompressionScheme Location="/LM/W3SVC/Filters/Compression/gzip">;”. Podemos abrir el fichero con el bloc de notas.

HcDoDynamicCompression="TRUE", La compresión esta habilitada para ficheros dinamicos.

HcDoOnDemandCompression="TRUE", la compresión esta habilitada para ficheros estaticos

HcDynamicCompressionLevel="10", establece el nivel de compresión de los archivos dinámicos; números altos significan mayores niveles de compresión, pero también implican mayor uso de CPU y de memoria (0-10), pero es evaluar como nuestro servidor funciona mejor.

HcFileExtensions="htm html txt"

Extensiones de archivos estáticos, por ejemplo: htm, html, txt, doc, pdf, etc. que serán comprimidas si está habilitada la compresión estática.

HcScriptFileExtensions="asp
dll
exe
aspx
htm"

Extensiones de archivos dinámicos. En mi caso tengo puesto como dinámico el htm ya que mi servidor utiliza rewrite y por ello considero que una htm es una pagina dinámica.

HcOnDemandCompLevel="10", establece el nivel de compresión de los archivos estáticos cuando la compresión en demanda está activada, números altos significan mayores niveles de compresión, pero también implican mayor uso de CPU y de memoria (0-10).
Algunas de las propiedades que aparecen aquí también pueden ser modificadas desde la consola de administración:

HcCompressionDirectory="%windir%\IIS Temporary Compressed Files", indica el directorio en donde serán guardados los archivos temporales comprimidos.

HcDoDiskSpaceLimiting="FALSE", cuando está en False no limita el espacio de los archivos temporales comprimidos.

HcExpiresHeader="Wed, 01 Jan 1991 12:00:00 GMT", se coloca una fecha obsoleta para que los proxys no guarden en caché el archivo.

HcMaxDiskSpaceUsage="99614720", tamaño máximo en bytes que pueden ocupar las copias comprimidas de los archivos estáticos.

Después de toda esta configuración lo único que nos quedara será reiniciar el IIS 6.0

Para reiniciarlo por consola de comandos (cmd) Inicio, ejecutar, cmd: iisrestart

Si tienes IIS 7 consulta el siguiente enlace (no creo que varie mucho de la versión 6): http://technet.microsoft.com/en-us/library/cc771003(v=WS.10).aspx

Siempre es bueno reciclar métodos y funciones a lo largo de la vida útil del software, en ocasiones con el paso del tiempo o de actualizaciones se deben utilizar las funciones nuevas. Una forma útil de marcar las viejas para que nos lo muestre el intellisense de Visual Studio es utilizando la marca "Obsolete" arriba de los métodos.

< Obsolete("Este método se encuentra obsoleto") > _
Private Sub NombreFuncionObsoleta()

De la misma forma, también se puede marcar en C#

Existen una serie de métodos de C# que no tienen conversión a LINQ. Bueno, más bien que no tengan conversión es que no introducimos la sintaxis correcta. Yo me he topado con el error: "El método 'System.String ToShortDateString()' no admite la conversión a SQL."

En la siguiente consulta:

var variable= (from x in storage.Tabla
where  x.Fecha.ToShortDateString() == otrostring
select x).Any();

La solución es la siguiente:

var variable= (from x in storage.Tabla<strong>.AsEnumerable()</strong>
where x.Fecha<strong>.ToShortDateString()</strong>  == otrostring
select x).Any();

En la siguiente entrada dispones de más información del método AsEnumerable(), que básicamente lo que realiza es no forzar la traducción instantánea de LINQ a SQL y trabaja localmente con LINQ to Objects.


Para obtener los parámetros que se le pasan por consola a un programa se puede utilizar este código, por ejemplo en la consola pondríamos:

>Programa.exe argumento1

y se recogerían así:

var x = Environment.GetCommandLineArgs();
 if (x.Length > 0)
 {
 // x[0] es el nombre del programa -> resultado : Programa.exe
 Console.WriteLine(x[1]); // -> resultado: argumento1
 }

Os dejo el enlace:

http://msdn.microsoft.com/es-es/windowsphone/hh307892

 

 

 

 

 

 

 

Estos días he estado bastante liado ya que el proceso que teníamos de carga de XML realizaba una precarga en memoria del archivo (método Load()), la solución que hay es bastante sencilla con un XMLReader, os pongo un fragmento que seguro se entiende:

using (XmlReader reader = XmlReader.Create(directoryTemp + fichero))
{
 reader.MoveToContent();
 
 int count = 0; // una variable contador XElement nombretabla = null; // un XElement auxiliar
 
 while (!reader.EOF)
 {
 switch (reader.NodeType)
 {
 case XmlNodeType.Element: // se puede filtrar por tipo de XmlNodeType...
 if (count == 0)
 {
 // CUALQUIER CONDICION
 count++;
 reader.Read();
 
 } else if (count == 1)
 {
 nombretabla = new XElement((XName)reader.Name); // esto para crear un XELEMENT con el nombre del Reader actual
 count++;
 reader.Read();
 } else
 {
 if (string.IsNullOrEmpty(nodoReg)) nodoReg = reader.Name; // condicion para omitir anidados..
 
 if (nodoReg == reader.Name)
 {
 count++;
 nombretabla.Add(XElement.ReadFrom(reader) as XElement);
 
 // INSERCION .. cada X lanzo una inserción en BD
 if (count % numInserciones == 0)
 {
 nombrecondicionado.Add(nombretabla);
 docaux.Add(nombrecondicionado);
 
 // VALIDACION ...
 validado = ValidarEsquema(docaux, esquema);
 
 if (validado)
 {
 nreg += cond.Insertar(docaux, delete);
 delete = false;
 
 // vacio contenidos
 nombretabla.Elements().Remove();
 nombrecondicionado.Elements().Remove();
 docaux.Elements().Remove();
 }
 else
 {
 OnReportInformation(string.Format("ERROR fichero{0} no valido.", fichero), ReportLevel.Error);
 EstadoCarga = 2;
 }
 }
 
 }
 
 }
 break;
 
 default :
 reader.Read();
 break;
 
 }
 
 }
 // INSERCION DE LOS ULTIMOS QUE NO ENTRAN EN EL ÚLTIMO WHILE
 nombrecondicionado.Add(nombretabla);
 docaux.Add(nombrecondicionado);
 
 // VALIDACION
 validado = ValidarEsquema(docaux, esquema);
 
 if (validado)
 {
 nreg += cond.Insertar(docaux, delete);
 
 // vacio contenidos
 nombretabla.Elements().Remove();
 nombrecondicionado.Elements().Remove();
 docaux.Elements().Remove();
 }
 else
 {
 OnReportInformation(string.Format("ERROR fichero{0} no valido.", fichero), ReportLevel.Error);
 EstadoCarga = 2;
 }
 
}

La diferencia es sencilla, mientra Descendants() cuenta todos los nodos (anidados incluidos), Elements() solo cuenta los del mismo nivel.

string xml = @"
                <Root>
                    <Item>
                        <id>1</id>
                    </Item>
                    <Item>
                        <id>2</id>
                    </Item>
                    <Item>
                        <id>3</id>
                        <Items>
                            <Item>
                                <id>5</id>
                            </Item>
                            <Item>
                                <id>6</id>
                            </Item>                            
                        </Items>
                    </Item>
                    <Item>
                        <id>4</id>
                    </Item>
                </Root>";
 
            XDocument doc1 = XDocument.Parse(xml);
 
            var q1 = from e in doc1.Root.Descendants("Item")
                     select e;
 
            var q2 = from e in doc1.Root.Elements("Item")
                     select e;
 
            int c1 = q1.Count(); //6
            int c2 = q2.Count(); //4

1

Siempre cargaba los documentos XML del streamReader de esta forma:

XDocument myXmlDocument = XDocument.Load(myReader, LoadOptions.None);

Hasta que hace unos días me salía un error con un documento que decía:

'.', valor hexadecimal 0x00, es un carácter no válido. Línea XXX, posición XX. (casualmente siempre me indicaba la última línea)

Bueno... y como podía ser esto posible... si yo veía el XML correcto, muy bien a ciencia cierta no lo se pero encontré una solución que al menos lo que hace es eliminar todos los caracteres hexadecimales de la cadena de carga de XML.

 

Utilizando esta función en mi caso:

public static string CleanInvalidXmlChars(string text)        {           
// From xml spec valid chars:             
// #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]                 
// any Unicode character, excluding the surrogate blocks, FFFE, and FFFF.             
string re = @"[^x09x0Ax0Dx20-xD7FFxE000-xFFFDx10000-x10FFFF]";            
return Regex.Replace(text, re, "");        
}

Y cambiando el Load por el Parse:

XDocument myXmlDocument = XDocument.Parse( CleanInvalidXmlChars(myReader.ReadToEnd()), LoadOptions.None);

1 -Descargar el Reactive Extensions de .NET (Rx) para 3.5:
http://msdn.microsoft.com/en-us/devlabs/ee794896.aspx

2 - Instalar el paquete .msi

3 - Importar Referencia al proyecto que queramos utilizar, la ruta donde esta instalado es:

C:Program Files (x86)Microsoft Cloud ProgrammabilityReactive Extensionsv1.0.2856.0Net35System.Threading.dll

4- Incluir los using:

using System.Threading;
using System.Threading.Tasks;

5- Documentación MSDN de Parallel:
http://msdn.microsoft.com/es-es/library/system.threading.tasks.parallel.aspx

A veces por motivos de seguridad o eficiencia hay que configurar las llamadas WCF REST por GET o por POST, es altamente recomendable que las peticiones GET al servidor se hagan por GET y las SET por POST, por motivos de seguridad sobretodo. Por eficiencia es siempre mejor el GET.

[ServiceContract]
public interface IGasPriceService
{
    [OperationContract]
    [WebGet // ESTO ES PARA UN GET
        (RequestFormat = WebMessageFormat.Xml,
        ResponseFormat = WebMessageFormat.Xml,
        BodyStyle = WebMessageBodyStyle.Bare,
        UriTemplate = "/GetGasPrice/For/City/{city}"
        )]
    GasPriceData GetPriceDataForCity(string city);

    [OperationContract]
    [WebInvoke // ESTO PARA UN POST
        (Method = "POST",
        RequestFormat = WebMessageFormat.Xml,
        UriTemplate = "/SetGasPrice/For/ZipCode/{zipCode}/Price/{price}"
        )]
    void SetPriceDataForZipCode(string zipCode, string price);
}