Aprende a utilizar el servicio de cloud storage de Windows Azure utilizando la API REST.
Esto puede ser muy útil cuando no puedes usar Windows Azure SDK o cuando no hay una versión del SDK disponible para el lenguaje o plataforma que manejas.
El video se hizo en WinRT + C# pero el mecanismo puede ser imitado desde otros lenguajes y frameworks.
En este video también se muestra como construir el header de autorización incluyendo como crear la firma con el Storage Key.
Acá el código fuente
using System;
using System.Globalization;
using System.IO;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using Windows.Security.Cryptography;
using Windows.Security.Cryptography.Core;
namespace App5.Storage
{
public class BlockBlobStorage
{
private const string X_MS_BLOCK_BLOB = "BlockBlob";
private const string X_MS_VERSION = "2012-02-12";
public string Account { get; set; }
public string Key { get; set; }
public BlockBlobStorage(string account, string key)
{
Account = account;
Key = key;
}
public async Task<HttpResponseMessage> UploadAsync(string blobname, Stream stream,
string mimetype = "application/octect-stream")
{
var httpClient = new HttpClient();
var content = new StreamContent(stream);
var tmpdate = RFC1123DateTime;
content.Headers.ContentType = new MediaTypeHeaderValue(mimetype);
httpClient.DefaultRequestHeaders.Add("x-ms-date", tmpdate);
httpClient.DefaultRequestHeaders.Add("x-ms-blob-type", X_MS_BLOCK_BLOB);
httpClient.DefaultRequestHeaders.Add("x-ms-version", X_MS_VERSION);
string signature = CreateSignature(
HTTPVerb: "PUT",
ContentLength: stream.Length.ToString(),
ContentType: mimetype,
CanonicalizedHeaders: "x-ms-blob-type:BlockBlob\nx-ms-date:" + tmpdate + "\nx-ms-version:2012-02-12",
CanonicalizedResource: string.Format("/{0}/{1}", Account, blobname)
);
httpClient.DefaultRequestHeaders.Add("Authorization",
string.Format("SharedKey {0}:{1}", Account, signature));
return await httpClient.PutAsync(
string.Format("http: content
);
}
private string CreateSignature(
string HTTPVerb = "",
string ContentEncoding = "",
string ContentLanguage = "",
string ContentLength = "",
string ContentMD5 = "",
string ContentType = "",
string Date = "",
string IfModifiedSince = "",
string IfMatch = "",
string IfNoneMatch = "",
string IfUnmodifiedSince = "",
string Range = "",
string CanonicalizedHeaders = "",
string CanonicalizedResource = ""
)
{
var sumstring = string.Format("{0}\n{1}\n{2}\n{3}\n{4}\n{5}\n{6}\n{7}\n{8}\n{9}\n{10}\n{11}\n{12}\n{13}",
HTTPVerb, ContentEncoding, ContentLanguage, ContentLength, ContentMD5,
ContentType, Date, IfModifiedSince, IfMatch, IfNoneMatch, IfUnmodifiedSince,
Range, CanonicalizedHeaders, CanonicalizedResource
);
return ComputeHMAC_SHA256(sumstring);
}
private string ComputeHMAC_SHA256(string input)
{
var alg = MacAlgorithmProvider.OpenAlgorithm("HMAC_SHA256");
var inputBuffer = CryptographicBuffer.ConvertStringToBinary(input, BinaryStringEncoding.Utf8);
var keybuffer = CryptographicBuffer.DecodeFromBase64String(Key);
var hmacKey = alg.CreateKey(keybuffer);
var signbuffer = CryptographicEngine.Sign(hmacKey, inputBuffer);
return CryptographicBuffer.EncodeToBase64String(signbuffer);
}
public string RFC1123DateTime { get { return DateTime.UtcNow.ToString("R", CultureInfo.InvariantCulture); } }
}
}var file = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx: var stream = await file.OpenStreamForReadAsync();
var blobUploader = new BlockBlobStorage("jk4freeusage", "Yk4KMu8b0FAzCuqJf4y3j5XSslLxqXYndfkReWg8YkLFVaQOzF1Ga4eAE8jy+rEyOMh9RP228rz0SB2uwkoOoQ==");
var rta = await blobUploader.UploadAsync("imagenes/chocorramo.jpg", stream, mimetype: "image/jpeg");
Este es el código completo que pueden descargar desde este Gist
Saludos
Introducción al tutorial
Hola, antes de comenzar con lo obvio quiero que se fijen en el titulo de este artículo, en los detalles.
El título normal de este artículo sería
Tutorial: Cómo crear un lector de RSS en WinRT
La diferencia desde mi punto de vista es que hacer un simple lector de RSS no vale mucho la pena, en especial si quienes crean la aplicación son los lectores de mi blog a quienes tengo en muy buen concepto.
Así que este artículo les enseñará a crear una aplicación para WinRT lo cual nos pide ser un poco más exigentes con los temas de calidad y en brindar una experiencia de usuario mucho más rica que realmente le de valor al usuario y pueda hacer de nuestra App una de las que brindan verdadero valor.
Let's begin
Qué es importante que tenga una aplicación lectora de RSS? hay muchas posibilidades y desde luego hay que darle un alcance justo, esta es mi propuesta para ese alcance:
- Debe conectarse con una fuente RSS que sea rica en contenido: imágenes, texto, audio ,video etc.; un feed de solo texto rara veces es lo que un usuario busca, es más lo que un usuario llamaría aburrido. Así que hay que seleccionar una buena fuente de información.
- La aplicación debe mostrar esa información al usuario de manera agradable, es decir la aplicación en su integridad debe seguir los lineamientos de la plataforma WinRT para tener una estética homogénea, fácil de usar incluso para el usuario novato.
- Hay que utilizar las funcionalidades que ofrece WinRT, la plataforma de manera nativa provee interfaces y lineamientos para las funcionalidades comunes, que si bien no es mandatorio implementarlas, si es mandatorio acoplarse al sistema cuando se requieran y no crear una funcionalidad a parte. Estas funcionalidades son:
- Settings
- Search
- Share
- Devices
Para este tutorial le daremos alcance solo a Settings
- Ser flexible estéticamente, la aplicación será utilizada en diversidad de dispositivos y en diversidad de orientaciones: vertical, horizontal, snapped, fill, full, vertical inv. y horizontal inv. por ende la aplicación debe ofrecer una funcionalidad consistente en cada una de estas posibilidades
- La aplicación debe ser resistente a fallos, por ejemplo sino hay conexión a internet debe seguir funcionando y no hacer crash, si la conexión a internet es requerida se debe informar al usuario que la app requiere esa conexión para funcionar adecuadamente, en todo caso la aplicación no debe reventar con errores.
- Ser confiable, es decir el usuario debe confirmar en lo servicios que brindamos y en la integridad de su privacidad, por ello la aplicación debe contar con política de privacidad.
De seguro que al revisar más en profundidad cada tema encontraremos muchos otros requisitos, sin embargo por alcance este tutorial solo cubrirá los puntos descritos
Indice General
Para cumplir con el alcance establecido he decidido fraccionar el proyecto en las siguientes partes:
- Tutorial: Cómo crear una aplicación lectora de RSS en WinRT - Parte 1
- Introducción al tutorial
- Let's begin
- Indice General
- Tutorial: Cómo crear una aplicación lectora de RSS en WinRT - Parte 2
- Tutorial: Cómo crear una aplicación lectora de RSS en WinRT - Parte 3
- Tutorial: Cómo crear una aplicación lectora de RSS en WinRT - Parte 4
- Consumiendo el RSS por medio de SyndicationClient
- CreateContent
- CreateSummary
- Find1stImageFromHtml
- Tutorial: Cómo crear una aplicación lectora de RSS en WinRT - Parte 5
- Inicializando la Aplicación e implementado el View-Model
- Cómo y desde donde llamar a Initialize
- Asociando el DataContext del View
- Tutorial: Cómo crear una aplicación lectora de RSS en WinRT - Parte 6
- Construyendo la UI - Parte 1
- Esquema principal de la App
- Creando elementos básicos
- El titulo
- Aplicar propiedades utilizando estilos
- El icono
- El artículo actual
- La Lista de Artículos
- Tutorial: Cómo crear una aplicación lectora de RSS en WinRT - Parte 7
- Vinculando la View con el ViewModel
- El artículo actual
- Tutorial: Cómo crear una aplicación lectora de RSS en WinRT - Parte 8
- Mejorando la experiencia de usuario - Parte 1
- Hacer que aparezca un articulo seleccionado por defecto
- Disminuir el tamaño de los títulos del ListView
- Disminuir el ancho del ListView
- Evitar que los resúmenes de los artículos en el ListView crezcan de manera descontrolada
- Colocar una imagen dummy en el Listview cuando no existan imágenes en el artículo
- Colocar la imagen adecuada cuando la única imagen del RSS es el aggbug
- Colocar una imagen dummy en el Listview cuando la imagen hallada en el artículo sea demasiado pequeña
- Mientras cargan los datos del feed da la impresión de que la App no esta haciendo nada
- Conclusión
- Tutorial: Cómo crear una aplicación lectora de RSS en WinRT - Parte 9
- Mejorar la apariencia de ListView
- Mejorar la apariencia del ProgressRing
- Mejorar la apariencia del WebView
- Soporte para Snapped View
- Imagen de Fondo
- Tutorial: Cómo crear una aplicación lectora de RSS en WinRT - Parte 10
- Mejorando la experiencia de usuario - Parte 2
- Detección de conexión a internet
- Adición de la política de privacidad
- Tareas adicionales
- FIN DEL TUTORIAL
WCF – El caso del wsdl con xsd:import schemalocation que no puede ser interpretado desde clientes PHP
o
El caso del wsdl con referencias externas que no puede ser usado en PHP
Este caso esta relacionado con el caso revisado en el artículo:
WCF – El caso del wsdl con referencias externas apuntando al servidor local
Por lo cual es otra anecdota de casos de consultoria
.
Supongamos que creamos un servicio WCF en http://my.webpage.com.co , como ya sabemos cuando creamos servicios con WCF el wsdl no muestra directamente los tipos de dato del servicio, sino que genera referencias a unos schemas xsd donde únicamente estan estos detalles, ejemplo:
|
1
2
3
4
5
6
7
8
9
10
|
<wsdl:types>
</xsd:schema>
</wsdl:types>
|
En otra oportunidad analizaremos el contenido de esas url, pero no es nada complejo.
El problema reside en que muchos clientes SOAP, sobre todo de tecnologías como PHP, no son capaces de interpretar este tipo de schemas xsd dentro de un wsdl, por lo cual la tarea de consumir el servicio WCF en ocasiones complicada
Los clientes SOAP para PHP en su mayoría requieren que el wsdl incorpore TODAS las especificaciones dentro de si, no soportan referencias externas, así que hay que 'aplanar' el wsdl para que todo quede en el mismo archivo.
Hay dos formas de solucionar este problema
- Forma fácil: Utiliza Framework 4.5, en el cual por defecto WCF incluye la opción de consultar el wsd así:http://my.webpage.com.co/MyService.svc?singlewsdl ,lo que es el mismo wsdl de siempre pero sin referencias externas, TODO EN UNO.
- Sino puedes pasarte a Framework 4.5, lo cual es muy probable en escenario empresariales, entonces continua leyendo este artículo.
Esta tarea requiere realizar algunas modificaciones a nivel de behaviors y endpoints, de hecho debes crear nuevos behaviors, no es nada del otro mundo, pero como todo, requiere tiempo, aprendizaje, pruebas etc. y si estas de afán multiplica este efecto por cien.
Por suerte existen personas que les gusta compartir conocimiento y este caso no es la excepción, en CodePlex, encontramos un proyecto llamado:
WCFExtras
Cuyo lema es: "WCF Soap Header support, Xml comments to WSDL annotation and more", a que te suena muy intereante! 
Bien, se los dejo como tema para revisar, este artículo no trata de conocer a fondo WCFExtras, tan solo una pequeña parte para solucionar nuestro lio.
Una de las funcionalidades de WCFExtras es "Single WSDL file", les suena familiar? en efecto esta funcionalidad nos permite 'aplanar' el wsdl para que no tenga referencias externas sino todo incorporado de una vez en un mismo archivo, justo lo que necesitamos.
Cómo se soluciona?
Lo primero que debemos hacer es bajar WCFExtras y compilar la dll, la agregamos al proyecto donde creamos nuestro servicio.
Seguidamente editamos el archivo app.config y adicionamos la siguiente extensión de behaviors
|
1
2
3
4
5
6
7
|
<system.serviceModel>
<extensions>
<behaviorExtensions>
<add name="wsdlExtensions" type="WCFExtras.Wsdl.WsdlExtensionsConfig, WCFExtras, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
</behaviorExtensions>
</extensions>
</system.serviceModel>
|
Esto ya nos garantiza que podemos acceder a los nuevos behaviors incorporados con WCFExtras. Así que ahora solo basta utilizarlos para nuestro caso puntual, esta es la forma más sencilla de generar un wsdl 'aplanado', simplemente agregamos un behavior en endpointBehaviors, el tipo del behavior es wsdlExtensions y le pasamos como parámetro singleFile=true
|
1
2
3
4
5
6
7
8
|
<behaviors>
<endpointBehaviors>
<behavior>
<wsdlExtensions singleFile="true"/>
</behavior>
</endpointBehaviors>
<serviceBehaviors>
</behaviors>
|
Eso es todo, hora de consultar el wsdl de nuevo y... ya no tenemos nada parecido a lo que vimos más arriba, en su lugar encontramos algo como esto inclusive para los tipos complejos:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
<wsdl:types>
<xs:schema attributeFormDefault="qualified"
elementFormDefault="qualified"
<xs:element name="anyType"
nillable="true"
type="xs:anyType"/>
<xs:element name="anyURI"
nillable="true"
type="xs:anyURI"/>
<xs:element name="boolean"
nillable="true"
type="xs:boolean"/>
<xs:element name="byte"
nillable="true"
type="xs:byte"/>
<xs:element name="dateTime"
nillable="true"
type="xs:dateTime"/>
</xs:schema>
</wsdl:types>
|
TODA la información ha sido consolidada en el mismo wsdl.
El caso del wsdl con xsd:import schemalocation apuntando a la url local en lugar de la pública
Dentro de mis labores como Arquitecto y Consultor me he encontrado con este caso que es digno de mencionar, y aunque algunos se sorprendan creanme que este escenario es más comun de lo que imaginan.
Supongamos que creamos un servicio WCF en http://my.webpage.com.co ,cuando creamos servicios con WCF el wsdl no muestra directamente los tipos de dato del servicio, sino que genera referencias a unos schemas xsd donde unicamente estan estos detalles, ejemplo:
|
1
2
3
4
5
6
7
8
9
10
|
<wsdl:types>
</xsd:schema>
</wsdl:types>
|
Vieron lo que sucede? las URL de los xsd no estan apuntando a http://my.webpage.com.co sino a la direccion de la red local http://myLocalServer.webpage.com.co .
A primera impresión es un problema de configuración del WCF, y en efecto al modificar algunos parametros podemos hacer que las URL del wsdl aparezcan solo como http://myLocalServer/MyService.svc , incluso podemos modificar la re esddfritura de URL desde el app.comfig para redireccionar este tipo de peticion es de manera correcta,pero no es un problema fácil de solucionar.
En algunas compañías lo que optan por hacer es modificar su firewall y/o configuracion de dominio público para que permita redireccionar las peticiones a la URL adecuada.
Aunque a primera impresión es un problema de WCF, la realidad es otra. Es un problema en la configuración de IIS.
WCF le pide al web server la dirección host principal para poder armar las rutas a los xsd, y allí es donde IIS le envia el nombre de la máquina local. Pero seamos justos... tampoco es un error de IIS.
Imaginate que tienes un servicio que solo se ejecuta dentro de tu empresa, en ese contexto IIS debe devolverte el nombre local de la máquina, ahora imagina que ese mismo servidor lo conectas a una IP púbica, es decir sin dejar de soportar aúnla URL corporativa, cuando WCF le pregunte al IIS el nombre del host le devolera el nombre local.
Cómo solucionarlo, como los profesionales?
Una de las ventajas que tiene haber iniciado mi carrera como profesional de IT antes de ser developer, es que me permite recordar que NO TODO lo debes resolver por código. IIS nos permite configurar los host names para cada sitio.
Vamos a nuestro sitio donde se publico el WCF, clic derecho propiedades, pestaña Web Site y damos clic en el boton advanced.

Damos doble clic sobre el host por defecto y lo editamos, dejando el nombre público correcto de nuestro servidor.

Y eso es todo! ahora las URL de los xsd referenciados desde el wsdl estan direccionadas correctamente.
Artículo publicado originalmente en
---
En el artículo anterior revisamos uno de los pilares de los patrones de Diseño Orientado a Objetos: "Inyección de Dependencias" en su forma más básica.
C# – INYECCIÓN DE DEPENDENCIAS
Como lo vimos la inyección de dependencias es una herramienta comúnmente utilizada en varios patrones de diseño orientado a objetos y consiste en inyectar comportamientos a componentes.
En este artículo formalizaremos un poco más su definición para de paso definir e implementar un conocido patrón de diseño llamado estrategia.
Los Robots
Imaginemos que tenemos una clase llamada Robot, cada Robot puede realizar una serie de operaciones fundamentales:
Desde luego hay muchas más pero esas serán suficientes para el ejemplo.
Iniciemos con el análisis, en primera instancia revisemos la característica Disparar. Si tenemos un conjunto de Robots donde todos ellos pueden disparar de manera diferente podemos pensar en crear una clase base llamada Robot la cual desde luego implementa la funcionalidad Disparar como virtual o abstract de tal forma que las implementaciones concretas puedan establecer una forma particular de disparar en cada caso.
Existen inicialmente 3 implementaciones de Robot
- RobotVigilante: Dispara como todos los Robot
- RobotMilitar: Dispara como todos los Robot
- RobotCasero: No dispara
Este es nuestro diagrama de clases

Y estas las implementaciones en código:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
public class Robot
{
public Robot()
{
}
public virtual void Disparar()
{
}
public virtual void Caminar()
{
}
}
public class RobotVigilante : Robot
{
}
public class RobotMilitar : Robot
{
}
public class RobotCasero : Robot
{
public override void Disparar()
{
}
}
|
Este esquema funciona 'bien' pero hay varios problemas que debemos afrontar si pensamos las cosas detenidamente.
- Cada vez que un Robot no dispare debemos sobrescribir el método virtual
- Pueden requerirse Robots que disparen de manera diferente, en cuyo caso también se requiere sobrescribir el método virtual
- Qué pasa con caminar? efectivamente pueden aparecer Robots que no caminen o Robots que lo hagan con un pie o con cuatro.
Teniendo este escenario nos damos cuenta que el propósito inicial por el cual se ha utilizado la herencia se ha desvirtuado, pues no es cierto que todos los Robot hagan las actividades de la misma forma, incluso pueden haber Robots que no hagan una determinada actividad.
La herencia en este punto se nos ha convertido en un problema, ¿ya vieron cual?, puede que no.
El problema es: MANTENIMIIENTO , todos sabemos que crear un programa es solo la primera parte, la segunda parte es mantener ese programa en el tiempo, hacerle mejoras , evolucionarlo etc. Y desde luego en el escenario de los Robots esto también es una necesidad, necesitaremos crear nuevos Robots y modificar los existentes.
Pero al haber utilizado herencia nos encontraremos que algunas cosas habrá que cambiarlas en la clase base y otras en las clases derivadas, peor aún puede haber un grupo de clases derivadas que no utilicen las funcionalidades de la clase base pero que entre ellas si comparten la misma funcionalidad, esto es : tendremos código redundante.
El problema realmente puede ser muy grueso.
La solución clásica
Lo primero que a uno se le viene a la mente para resolver el tema de los Robot que no Disparan o que no Caminan es utilizar interfaces, lo cual suele ser una muy buena idea, sobre todo teniendo en cuenta este principio de diseño.
Programe contra una interfaz no contra implementaciones concretas.
En este sentido hay que ser claro que este principio hace referencia a interfaces desde el punto de vista del diseño de software no de ningún lenguaje en particular y en este sentido entonces una interfaz puede ser en esencia un Súper Tipo:
- Clase Base
- Clase Abstracta
- Interfaz
Podemos crear dos interfaces para identificar que habilidades tiene cada Robot.
*Sorry por los nombres, mi creatividad en ese sentido es limitada.
Esto nos permitirá tener Robots que Caminen , Disparen, que no hagan nada o que solo hagan una de las dos cosas.

Y esta es la implementación...ligeramente más compleja
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
|
public interface ICaminable
{
void Caminar();
}
public interface IDisparable
{
void Disparar();
}
public class Robot
{
public Robot()
{
}
public virtual void MatarAJohnConnor()
{
}
}
public class RobotVigilante : Robot, ICaminable, IDisparable
{
public void Caminar()
{
}
public void Disparar()
{
}
}
public class RobotMilitar : Robot, ICaminable, IDisparable
{
public void Caminar()
{
}
public void Disparar()
{
}
}
public class RobotCasero : Robot, ICaminable
{
public void Caminar()
{
}
}
public class RobotDetectorDeJohnConnor : Robot, IDisparable
{
public void Disparar()
{
}
}
|
El tema de la complejidad... preocupante, pero más preocupante aún es el hecho que tenemos código redundante ya que aunque varios robots disparen de la misma forma, cada uno tiene su propia implementación.
Así que estamos usando uno de los principios de diseño de software pero algo anda un poco mal, vamos a solucionarlo.
Para los más experimentados el indicio de solución salta a la vista: encapsulamiento.
Pero pongámoslo en el marco del diseño de software, aquí existe otro principio fundamental:
Identificar los aspectos que cambian, y sepárelos de los que se mantienen iguales.
Eso precisamente se hace en POO haciendo uso de encapsulamiento, cosa que los cambios en este objeto no afecten el resto del código de la implementación.
Encapsular, en este caso implica necesariamente crear un objeto nuevo por cada funcionalidad 'que cambia', las funcionalidades que cambian en nuestros Robot son
Estas funcionalidades que cambian las llamaremos en adelante comportamientos, behaviors en inglés. Es tiempo de extraer estos comportamientos en nuevos objetos.
Cada acción ( caminar, disparar), tienen una serie de comportamientos posibles aunque exhiben la misma interfaz, es decir los mismos métodos con los mismos tipos de datos, así que podemos pensar en generalizar dicha interfaz, de tal forma que podamos crear diferentes comportamientos, por ejemplo al caminar:
- CaminarNormal
- CaminarDeMedioLado
O al disparar
- DispararNormal
- DispararAmetralladora
Queda la duda de ¿Qué hacer con los que no caminan o no disparan? esta es la parte más bella
Este es el diagrama de clases de nuestros comportamientos, y abajo la implementación de los Robots

Ahora veamos el código para los comportamientos
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
|
public interface IDispararBehavior
{
void Disparar();
}
public interface ICaminarBehavior
{
void Caminar();
}
public class CaminarNormal : ICaminarBehavior
{
public void Caminar()
{
}
}
public class CaminarDeMedioLado : ICaminarBehavior
{
public void Caminar()
{
}
}
public class NoCaminar : ICaminarBehavior
{
public void Caminar()
{
}
}
public class DispararNormal : IDispararBehavior
{
public void Disparar()
{
}
}
public class DispararAmetralladora : IDispararBehavior
{
public void Disparar()
{
}
}
public class NoDisparar : IDispararBehavior
{
public void Disparar()
{
}
}
|
Este es el código de implementación de los robots haciendo uso de los comportamientos creados.
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
|
public abstract class Robot
{
protected IDispararBehavior _disparador;
protected ICaminarBehavior _caminador;
public Robot()
{ }
public void Caminar()
{
_caminador.Caminar();
}
public void Disparar()
{
_disparador.Disparar();
}
public virtual void MatarAJohnConnor()
{
}
}
public class RobotVigilante : Robot
{
public RobotVigilante()
{
_disparador = new DispararNormal();
_caminador = new CaminarNormal();
}
}
public class RobotMilitar : Robot
{
public RobotMilitar()
{
_disparador = new DispararAmetralladora();
_caminador = new CaminarDeMedioLado();
}
}
public class RobotCasero : Robot
{
public RobotCasero()
{
_disparador = new NoDisparar();
_caminador = new CaminarNormal();
}
}
public class RobotDetectorDeJohnConnor : Robot
{
public RobotDetectorDeJohnConnor()
{
_disparador = new DispararAmetralladora();
_caminador = new NoCaminar();
}
}
|
Es una solución impecable, pero aún se puede hacer más! lo bueno de tener separados los comportamientos es que nada impide que podamos cambiar dichos comportamientos en tiempo de ejecución... hell yeeaahh!
Supongamos que queremos actualizar el Robot Detector De John Connor para que ahora pueda caminar, como hacerlo? gracias a que hemos programado contra interfaces y hemos encapsulado los comportamientos que cambian, es algo muy sencillo de hacer. Modificando la clase base, exponiendo de manera pública los comportamientos:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
public abstract class Robot
{
IDispararBehavior _disparador;
public IDispararBehavior Disparador
{
get { return _disparador; }
set { _disparador = value; }
}
ICaminarBehavior _caminador;
public ICaminarBehavior Caminador
{
get { return _caminador; }
set { _caminador = value; }
}
public Robot()
{ }
public void Caminar()
{
_caminador.Caminar();
}
public void Disparar()
{
_disparador.Disparar();
}
public virtual void MatarAJohnConnor()
{
}
}
|
Así expuestos podemos crear un objeto de cualquier tipo y modificar eso en tiempo de ejecución!.
|
1
2
3
4
5
6
7
8
9
10
11
|
public static class Programa
{
public static void Main()
{
var connorKiller = new RobotDetectorDeJohnConnor();
connorKiller.MatarAJohnConnor();
connorKiller.Caminador = new CaminarDeMedioLado();
Console.WriteLine("YEAH");
}
}
|
Digamos que ahora se nos ocurre ponernos un poco mas agresivos:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
public static class Programa
{
public class CaminadorAPropulsion : ICaminarBehavior
{
public void Caminar()
{
}
}
public static void Main()
{
var connorKiller = new RobotDetectorDeJohnConnor();
connorKiller.MatarAJohnConnor();
connorKiller.Caminador = new CaminarDeMedioLado();
connorKiller.Caminador = new CaminadorAPropulsion();
connorKiller.MatarAJohnConnor();
Console.WriteLine("YEEEEEEEEEEEEAHHHHHHHH");
}
}
|
Te desafío a igualar esto con herencia 
YEEEEEEEEEEEEAHHHHHHHH

Articulo Original tomado de
---
Qué es Inyección de dependencias
La inyección de dependencias o DI por sus siglas en inglés, es una herramienta comunmente utilizada en varios patrones de diseño orientado a objetos, consiste en inyectar comportamientos a componentes.
Esto no es más que extraer responsabilidades a un componente para delegarlas en otro, estableciendo un mecanismo a traves del cual el nuevo componente pueda ser cambiado en tiempo de ejecución. Es conveniente no confundir Inyección de dependencias (DI) con Inversion de Control (IoC) , error muy comunmente cometido que figura especialmente en la web. IoC es un tema para un próximo artículo.
Ejemplo y Explicación detallada
Imaginemos que estamos haciendo un videojuego en cual tenemos un personaje que es un robot, este robot puede realizar acciones de diferentes maneras, por lo cual su cabeza puede ser conectada a infinidad de cuerpos distintos.

Las soluciónes tradicionales desde el punto de vista de POO son diversas, ejemplo:
- Una clase base Robot con un atributo cuerpo, crear varias clases asugnando un atributo Cuerpo diferente en el constructor
- Una clase Robot con un atributo enumeación que le permita cambiar de cuerpo
- Muchas clases cuerpo que heredan de una clase Robot
Sin embargo a la final la responsabilidad del cuerpo y de la cabeza sigue siendo confusa, otro de mis principios favoritos de Diseño Orientado a Objetos es es de “Single Responsability” o mejor
“Un objeto una responsabilidad”
Claramente las soluciones clásicas al problema planteado no ofrecen esa opción.
Qué hacer? Inyección de dependencias tambien puede llamarse inyección de comportamientos, en todo caso es un nombre muy profesional y estilizado, lo cual puede ser intimidante, pero es un nombre preciso. Que sucede cuando te inyectan algo, una vacuna por ejemplo?. Depositan nuevos componentes en tu cuerpo, que pueden modificar el funcionamiento , sin que esto implique que vuelvas a nacer.
De eso mismo se trata la Inyección de Dependencias, colocar dentro de un objeto otros que puedan cambiar su comportamiento, sin que esto implique volver a crear el objeto.
Esto nos permite tener un objeto que puede hacer un conjunto de tareas, cada una de esas tareas es una responsabilidad, que puede ser ejecutada por otro objeto unicamente especialista y dedicado a ello [una responsabilidad], pero ahora tenemos otro diferenciador, El objeto responsable de ejecutar esa única tarea
Puede establecerse en tiempo de ejecución
La implementación habitual en programación es crear un método capaz de establecer el comportamiento, es decir capaz de cambiar el valor de un atributo asignandole una instancia de objeto diferente.
Esta seria una posible implementación de Robot que no utiliza Inyección de Dependencias
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
public class Robot
{
public Robot() { }
public void Caminar()
{
}
public void Disparar();
public void Volar();
public void BuscarAJhonConnor()
{
}
}
|
Ahora cambiemos la implementación por una que si haga Inyección de dependencias, primero creamos la clase Body la cual será la responsable de ejecutar las acciones del cuerpo:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
public class Body
{
public void Caminar()
{
}
public void Volar()
{
}
public void Disparar()
{
}
}
|
Seguidamente creamos un Robot que camina por medio de un Body, teniendo atención en delegar las responsabilidades a dicho objeto:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
public class Robot
{
public Body _body;
public Robot() { }
public void Caminar()
{
if(_body != null)
_body.Caminar();
}
public void Volar()
{
if (_body != null)
_body.Volar();
}
public void Disparar()
{
if (_body != null)
_body.Disparar();
}
public void BuscarAJhonConnor()
{
}
}
|
Como nos podemos dar cuenta el Robot hace todo lo que hacia antes aunque no tiene asignado aún un body, así que establecemos un mecanismo para hacer esto:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
public class Robot
{
public Body _body;
public void SetBody(Body newBody)
{
_body = newBody;
}
public Robot() { }
public void Caminar()
{
if(_body != null)
_body.Caminar();
}
public void Volar()
{
if (_body != null)
_body.Volar();
}
public void Disparar()
{
if (_body != null)
_body.Disparar();
}
public void BuscarAJhonConnor()
{
}
}
|
Bueno eso fué muy ‘java’, pongamonos serios y volvamoslo más elegante, fácil de leer y de mantener, más C#. Hagamos uso de propiedades y deshagamonos del private storage
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
public class Robot
{
public Body Cuerpo { get; set; }
public Robot() { }
public void Caminar()
{
if (Cuerpo != null)
Cuerpo.Caminar();
}
public void Volar()
{
if (Cuerpo != null)
Cuerpo.Volar();
}
public void Disparar()
{
if (Cuerpo != null)
Cuerpo.Disparar();
}
public void BuscarAJhonConnor()
{
}
}
|
Como se puede observar la clase Robot tiene la acción caminar, pero la responsabilidad es de la clase Body, tambien es claro que el valor de la propiedad Cuerpo lo podemos cambiar en tiempo de ejecución tan solo asignando una instancia diferente a la propiedad Cuerpo. Esta es una primera aproximación a la inyección de dependencias, siendo más formales incluso muchos comportamientos como Volar y Caminar incluso podrían llegar a estar en clases distintas.
Ahora subamos un poco el nivel, con lo aprendido podemos hablar del patrón de estrategia, el tema del próximo artículo. 
articulo original publicado en
-----
WCF – El caso del wsdl con xsd:import schemalocation que no puede ser interpretado desde clientes PHP
o
El caso del wsdl con referencias externas que no puede ser usado en PHP
Este caso esta relacionado con el caso revisado en el artículo:
WCF – El caso del wsdl con referencias externas apuntando al servidor local
Por lo cual es otra anecdota de casos de consultoria
.
Supongamos que creamos un servicio WCF en http://my.webpage.com.co , como ya sabemos cuando creamos servicios con WCF el wsdl no muestra directamente los tipos de dato del servicio, sino que genera referencias a unos schemas xsd donde únicamente estan estos detalles, ejemplo:
|
1
2
3
4
5
6
7
8
9
10
|
<wsdl:types>
</xsd:schema>
</wsdl:types>
|
En otra oportunidad analizaremos el contenido de esas url, pero no es nada complejo.
El problema reside en que muchos clientes SOAP, sobre todo de tecnologías como PHP, no son capaces de interpretar este tipo de schemas xsd dentro de un wsdl, por lo cual la tarea de consumir el servicio WCF en ocasiones complicada
Los clientes SOAP para PHP en su mayoría requieren que el wsdl incorpore TODAS las especificaciones dentro de si, no soportan referencias externas, así que hay que 'aplanar' el wsdl para que todo quede en el mismo archivo.
Hay dos formas de solucionar este problema
- Forma fácil: Utiliza Framework 4.5, en el cual por defecto WCF incluye la opción de consultar el wsd así:http://my.webpage.com.co/MyService.svc?singlewsdl ,lo que es el mismo wsdl de siempre pero sin referencias externas, TODO EN UNO.
- Sino puedes pasarte a Framework 4.5, lo cual es muy probable en escenario empresariales, entonces continua leyendo este artículo.
Esta tarea requiere realizar algunas modificaciones a nivel de behaviors y endpoints, de hecho debes crear nuevos behaviors, no es nada del otro mundo, pero como todo, requiere tiempo, aprendizaje, pruebas etc. y si estas de afán multiplica este efecto por cien.
Por suerte existen personas que les gusta compartir conocimiento y este caso no es la excepción, en CodePlex, encontramos un proyecto llamado:
WCFExtras
Cuyo lema es: "WCF Soap Header support, Xml comments to WSDL annotation and more", a que te suena muy intereante! 
Bien, se los dejo como tema para revisar, este artículo no trata de conocer a fondo WCFExtras, tan solo una pequeña parte para solucionar nuestro lio.
Una de las funcionalidades de WCFExtras es "Single WSDL file", les suena familiar? en efecto esta funcionalidad nos permite 'aplanar' el wsdl para que no tenga referencias externas sino todo incorporado de una vez en un mismo archivo, justo lo que necesitamos.
Cómo se soluciona?
Lo primero que debemos hacer es bajar WCFExtras y compilar la dll, la agregamos al proyecto donde creamos nuestro servicio.
Seguidamente editamos el archivo app.config y adicionamos la siguiente extensión de behaviors
|
1
2
3
4
5
6
7
|
<system.serviceModel>
<extensions>
<behaviorExtensions>
<add name="wsdlExtensions" type="WCFExtras.Wsdl.WsdlExtensionsConfig, WCFExtras, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
</behaviorExtensions>
</extensions>
</system.serviceModel>
|
Esto ya nos garantiza que podemos acceder a los nuevos behaviors incorporados con WCFExtras. Así que ahora solo basta utilizarlos para nuestro caso puntual, esta es la forma más sencilla de generar un wsdl 'aplanado', simplemente agregamos un behavior en endpointBehaviors, el tipo del behavior es wsdlExtensions y le pasamos como parámetro singleFile=true
|
1
2
3
4
5
6
7
8
|
<behaviors>
<endpointBehaviors>
<behavior>
<wsdlExtensions singleFile="true"/>
</behavior>
</endpointBehaviors>
<serviceBehaviors>
</behaviors>
|
Eso es todo, hora de consultar el wsdl de nuevo y... ya no tenemos nada parecido a lo que vimos más arriba, en su lugar encontramos algo como esto inclusive para los tipos complejos:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
<wsdl:types>
<xs:schema attributeFormDefault="qualified"
elementFormDefault="qualified"
<xs:element name="anyType"
nillable="true"
type="xs:anyType"/>
<xs:element name="anyURI"
nillable="true"
type="xs:anyURI"/>
<xs:element name="boolean"
nillable="true"
type="xs:boolean"/>
<xs:element name="byte"
nillable="true"
type="xs:byte"/>
<xs:element name="dateTime"
nillable="true"
type="xs:dateTime"/>
</xs:schema>
</wsdl:types>
|
TODA la información ha sido consolidada en el mismo wsdl.
Articulo tomado del original
---
WCF – El caso del wsdl con xsd:import schemalocation apuntando a la url local en lugar de la pública
o
El caso del wsdl con xsd:import schemalocation apuntando a la url local en lugar de la pública
Dentro de mis labores como Arquitecto y Consultor me he encontrado con este caso que es digno de mencionar, y aunque algunos se sorprendan creanme que este escenario es más comun de lo que imaginan.
Supongamos que creamos un servicio WCF en http://my.webpage.com.co ,cuando creamos servicios con WCF el wsdl no muestra directamente los tipos de dato del servicio, sino que genera referencias a unos schemas xsd donde unicamente estan estos detalles, ejemplo:
|
1
2
3
4
5
6
7
8
9
10
|
<wsdl:types>
</xsd:schema>
</wsdl:types>
|
Vieron lo que sucede? las URL de los xsd no estan apuntando a http://my.webpage.com.co sino a la direccion de la red local http://myLocalServer.webpage.com.co .
A primera impresión es un problema de configuración del WCF, y en efecto al modificar algunos parametros podemos hacer que las URL del wsdl aparezcan solo como http://myLocalServer/MyService.svc , incluso podemos modificar la re esddfritura de URL desde el app.comfig para redireccionar este tipo de peticion es de manera correcta,pero no es un problema fácil de solucionar.
En algunas compañías lo que optan por hacer es modificar su firewall y/o configuracion de dominio público para que permita redireccionar las peticiones a la URL adecuada.
Aunque a primera impresión es un problema de WCF, la realidad es otra. Es un problema en la configuración de IIS.
WCF le pide al web server la dirección host principal para poder armar las rutas a los xsd, y allí es donde IIS le envia el nombre de la máquina local. Pero seamos justos... tampoco es un error de IIS.
Imaginate que tienes un servicio que solo se ejecuta dentro de tu empresa, en ese contexto IIS debe devolverte el nombre local de la máquina, ahora imagina que ese mismo servidor lo conectas a una IP púbica, es decir sin dejar de soportar aúnla URL corporativa, cuando WCF le pregunte al IIS el nombre del host le devolera el nombre local.
Cómo solucionarlo, como los profesionales?
Una de las ventajas que tiene haber iniciado mi carrera como profesional de IT antes de ser developer, es que me permite recordar que NO TODO lo debes resolver por código. IIS nos permite configurar los host names para cada sitio.
Vamos a nuestro sitio donde se publico el WCF, clic derecho propiedades, pestaña Web Site y damos clic en el boton advanced.

Damos doble clic sobre el host por defecto y lo editamos, dejando el nombre público correcto de nuestro servidor.

Y eso es todo! ahora las URL de los xsd referenciados desde el wsdl estan direccionadas correctamente.
Articulo tomado de mi blog
Como aumentar el tiempo de carga de nuestras web – los iframe
-------------------------
El tiempo de carga de nuestros sitios web es un tema complejo, abordarlo completamente fácilmente podría ser tema de un solo blog… y no hablemos de las diferencias entre hacerlo con plataformas .Net o LAMP o lo que sea. Es un tema largo.
Así que siempre hay que abordarlo desde lo más grande hasta lo más pequeño. En la web moderna es frecuente encontrarse con iframes puesto que la integración con diversos servicios como redes sociales, mapas y demas gadgets suele hacerse por medio del tag <iframe> , lo cual en resumen es un marco que despliega contenidos alojados en otra web.
El problema con los iframes es que funcionan de manera síncrina, es decir nuestra web esta cargando normalmente, encuentra un iframe y comienza a cargarlo, solo cuando el iframe es cargado por completo continua la carga de los demas elementos de nuestra web.
Lo ideal entonces es hacer que la carga de éstos iframe sea asincónica o bien dilatarla para que inicien su carga solo cuando todo nuestro sitio haya sido desplegado, esto lo podemos hacer manipulando alguno de los eventos de carga de la pagina y luego escribiendo los tag del iframe dinámicamente.
Este es un código de prueba de un iframe
Para cargarlo dinamicamente lo primero que haremos es envolverlo dentro de un nuevo div al cual llamaremos “#map-container”
|
1
2
3
|
<div id="map-container">
</div>
|
Ahora haremos la parte del evento de carga de la página, a mi me gusta hacerlo con JQuery, pero ya sabes que puedes hacerlo con lo que desees. Colocamos el código dentro del evento ready de JQuery. El código es como sigue:
|
1
2
3
4
5
6
|
$(window).load(
function()
{
$("#map-container").html();
}
);
|
Así que ahora tomamos todo el contenido del tag <iframe> y lo enviamos como parámetro:
|
1
2
3
4
5
6
7
|
$(window).load(
function()
{
var iframeString ='<iframe id="Iframe2" name="gmap" width="100%" height="400" src="http://www.otraweb.com"></iframe>';
$("#map-container").html(iframeString);
}
);
|
Y eso es todo, en adelante el tiempo de carga de tu página es independiente del tiempo de carga de los iframe
.
Artículo tomado de mi blog
http://juank.black-byte.com/csharp-richeditbox-rtf-metro-formato/
------------------
Algunas veces cuando cargamos documentos RTF en un RichEditBox nos llevamos la no muy grata sorpresa de que aunque se muestra el texto correctamente los formatos aplicados a este, como color, negrita, itálica, etc. no son tenidos en cuenta.
Podemos abrir los RTF en editores comoWordpad y allí se muestran correctamente. Este problema se debe a que el controlRichEditBox no esta preparado en todo momento para aplicar dichos formatos, razón por la cual no es recomendable asignar el texto del documento hasta no estar 100% seguro de que el control ha cargado en su totalidad, por ende se debe evitar cargar texto en este control en el constructor de su clase contenedora, y en su lugar hacerlo en el evento Loaded, ejemplo:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
<common:LayoutAwarePage
x:Name="pageRoot"
x:Class="Test.GroupDetailPage"
xmlns:local="using:Test"
xmlns:data="using:Test.Data"
xmlns:common="using:Test.Common"
mc:Ignorable="d">
<RichEditBox x:Name="Richtest" Loaded="LoadedEventHandler"/>
</common:LayoutAwarePage>
|
Este es el code Behind
|
1
2
3
4
5
6
|
private void LoadedEventHandler(object sender, Windows.UI.Xaml.RoutedEventArgs e)
{
var cadena = @"{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033{\colortbl;\red255\green0\blue0;}{\cf1 Hello World }{\b nice text}{\par}}";
rich.Document.SetText(TextSetOptions.FormatRtf, cadena);
}
|
artículo tomado de mi blog
http://juank.black-byte.com/csharp-metro-mostrar-colores-rtf-richeditbox/
-----------------
Cuando cargamos documentos RTF en un RichEditBox esperamos que el formato siempre sea el adecuado, sin embargo en ocasiones, especialmente cuando nos entregan los RTF extraidos en una base de datos o en otros formatos diferentes de RTF, nos encontramos con que los textos coloreados no son procesados
EL color dentro de un archivo RTF se encuentra demarcado por medio de los ‘tag’ {\cf# donde # es un numero de color. De esta forma si buscamos dentro de un texto coloreado con RTF podemos encontrar un código como el que se ve a continuación:
|
1
|
{\cf1 Hola Mundo} \b nice text\b0
|
Donde cf1 hace referencia a un color determinado. Retomando el planteamiento inicial es posible en algunos escenarios que el texto sea mkjostrado sin el formato de color, esto se debe a que RTF requiere que se establezca previamente una paleta de colores que indique, por ejemplo, a que color equivale cf1.
Para ello, justo al inicio del documento establecemos la ‘etiqueta’ \colortbl la cual contiene una lista de entradas, donde cada una de estas entradas representa un color, la siguiente muestra una lista de 2 colores definidos, el azul y el rojo.
|
1
2
3
|
{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033
{\colortbl ;\red0\green0\blue255;\red255\green0\blue0;}
}
|
Este color creado en nuestra ‘paleta de colores’ puede ser referido en cualquier parte del documento como cf1, de tal forma si deseamos escribir “Hola Mundo” en color azul y rojo basta con hacer lo siguiente:
|
1
2
3
4
|
{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033
{\colortbl ;\red0\green0\blue255;\red255\green0\blue0;}
{\cf1 Hola}{\cf2 Mundo}
}
|
Si envias el documento (o sea la cadena de texto con la información) dentro de estos tag entonces al cargar la información dentro del RichEditBox debes asegurarte de indicarle el formato que debe aplicar, ejemplo:
|
1
2
3
4
5
|
string cadena = @"{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033
{\colortbl ;\red0\green0\blue255;\red255\green0\blue0;}
{\cf1 Hola}{\cf2 Mundo}
}";
MyRichEditBox.Document.SetText(TextSetOptions.FormatRtf, cadena);
|
De esta forma los documentos RTF cargados mostraran sus colores adecuadamente en un RichEditBox
Tomado de mi blog:
http://juank.black-byte.com/csharp-richeditbox-rtf-metro/
-------------------
En algunas ocasiones necesitamos cargar documentos RTF en un RichEditBox no direcamente desde archivo sino de otras fuentes, en estas ocasiones es común encontrarnos conque nuestro RTF se muestra de la siguiente manera
|
1
|
{\cf1 Hola Mundo} \b nice text\b0
|
Es decir nuestro RTF muestra el código pero el RichEditBox no es capaz de interpretarlo, este error se debe principalmente a que no se ha indicado el encabezado estandard de un documento RTF. Todo documento RTF debe estar contenido dentro de los siguintes tag omo mínimo:
Sin embargo es recomendable incluir información relacionada con la versión del documento, quedando de esta manera:
|
1
|
{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033 CONTENIDO }
|
Si envias el documento (o sea la cadena de texto con la información) dentro de estos tag entonces al cargar la información dentro del RichEditBox debes asegurarte de indicarle el formato que debe aplicar, ejemplo:
|
1
2
|
string cadena = @"{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033 Hello World\par}";
MyRichEditBox.Document.SetText(TextSetOptions.FormatRtf, cadena);
|
De esta forma ya no apreceran carácteres ‘basura’ el cargar tus datos RTF en un RichEditBox
Articulo tomado de mi blog:
http://juank.black-byte.com/csharp-archivo-configuracion-limpio/
-----------------
o Como reducir el archivo de configuración usando múltiples archivos .config
Como programadores siempre tenemos que lidiar con archivos de configuración, en mi opinión una hermosa forma de deshacernos de complejidad innecesaria en el código y desde luego una manera muy cool de crear aplicaciones fléxibles.
Sin embargo en aplicaciones de tipo empresarial comenzamos a tener detestables problemas con estos archivos. El notable aumento de complejidad en su estructura se convierte en una bomba de tiempo para el mantenimiento de las aplicaciones, es común encontrase con archivos de configuración que se miden en cientos de lineas y a veces en miles.
Cómo tener un archivo de configuración más limpio?
Por fortuna existe un mecanismo muy útil, a continuación les muestro un archivo de configuración que si bien no es uno precisamente enorme, ya comienza a mostrar problemasde legibilidad, en esta ocasión generados por la configuración de Unity Application Block , hablaremos de el en otro momento.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 | <?xml version="1.0"?>
<configuration>
<configSections>
<section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration" />
</configSections>
<typeAliases>
<typeAlias alias="singleton"
type="Microsoft.Practices.Unity.ContainerControlledLifetimeManager,
Microsoft.Practices.Unity" />
<typeAlias alias="external"
type="Microsoft.Practices.Unity.ExternallyControlledLifetimeManager,
Microsoft.Practices.Unity" />
<typeAlias alias="web_session"
type="Traversal.Utilities.Web.WebSessionLifetimeManager,
Traversal" />
<typeAlias alias="IDataContextWrapper" type="Domain.Core.Data.IDataContextWrapper`1, Domain.Core" />
<typeAlias alias="IParameterManager" type="Domain.Core.Repositories.IParameterManager, Domain.Core" />
<typeAlias alias="ILocalizationManager" type="Domain.Core.Repositories.ILocalizationManager, Domain.Core" />
<typeAlias alias="ContextWrapperSTE" type="Domain.Core.Data.ContextWrapperSTE`1, Domain.Core" />
<typeAlias alias="ContextWrapperEF" type="Domain.Core.Data.ContextWrapperEF`1, Domain.Core" />
<typeAlias alias="ParameterManager" type="Domain.Core.Repositories.ParameterManager, Domain.Core" />
<typeAlias alias="LocalizationManager" type="Domain.Core.Repositories.LocalizationManager, Domain.Core" />
<typeAlias alias="IEnteManager" type="Domain.wsldckm.Repositories.IEnteManager, Domain.oplkjsdfkpwe" />
<typeAlias alias="IEquipoManager" type="Domain.wsldckm.Repositories.IEquipoManager, Domain.oplkjsdfkpwe" />
<typeAlias alias="IEstadioManager" type="Domain.wsldckm.Repositories.IEstadioManager, Domain.oplkjsdfkpwe" />
<typeAlias alias="IEventoManager" type="Domain.wsldckm.Repositories.IEventoManager, Domain.oplkjsdfkpwe" />
<typeAlias alias="IPartidoManager" type="Domain.wsldckm.Repositories.IPartidoManager, Domain.oplkjsdfkpwe" />
<typeAlias alias="ITagManager" type="Domain.wsldckm.Repositories.ITagManager, Domain.oplkjsdfkpwe" />
<typeAlias alias="ITipoFormacionManager" type="Domain.wsldckm.Repositories.ITipoFormacionManager, Domain.oplkjsdfkpwe" />
<typeAlias alias="ITorneoEtapaManager" type="Domain.wsldckm.Repositories.ITorneoEtapaManager, Domain.oplkjsdfkpwe" />
<typeAlias alias="ITorneoNominaManager" type="Domain.wsldckm.Repositories.ITorneoNominaManager, Domain.oplkjsdfkpwe" />
<typeAlias alias="ITorneoManager" type="Domain.wsldckm.Repositories.ITorneoManager, Domain.oplkjsdfkpwe" />
<typeAlias alias="EnteManager" type="Domain.wsldckm.Repositories.EnteManager, Domain.oplkjsdfkpwe" />
<typeAlias alias="EquipoManager" type="Domain.wsldckm.Repositories.EquipoManager, Domain.oplkjsdfkpwe" />
<typeAlias alias="EstadioManager" type="Domain.wsldckm.Repositories.EstadioManager, Domain.oplkjsdfkpwe" />
<typeAlias alias="EventoManager" type="Domain.wsldckm.Repositories.EventoManager, Domain.oplkjsdfkpwe" />
<typeAlias alias="PartidoManager" type="Domain.wsldckm.Repositories.PartidoManager, Domain.oplkjsdfkpwe" />
<typeAlias alias="TagManager" type="Domain.wsldckm.Repositories.TagManager, Domain.oplkjsdfkpwe" />
<typeAlias alias="TipoFormacionManager" type="Domain.wsldckm.Repositories.TipoFormacionManager, Domain.oplkjsdfkpwe" />
<typeAlias alias="TorneoEtapaManager" type="Domain.wsldckm.Repositories.TorneoEtapaManager, Domain.oplkjsdfkpwe" />
<typeAlias alias="TorneoNominaManager" type="Domain.wsldckm.Repositories.TorneoNominaManager, Domain.oplkjsdfkpwe" />
<typeAlias alias="TorneoManager" type="Domain.wsldckm.Repositories.TorneoManager, Domain.oplkjsdfkpwe" />
</typeAliases>
<containers>
<container name="WebContainer">
<types>
<type type="IParameterManager" mapTo="ParameterManager" />
<type type="ILocalizationManager" mapTo="LocalizationManager" />
<type type="IDataContextWrapper" mapTo="ContextWrapperEF">
<lifetime type="web_session" />
</type>
<type type="IEnteManager" mapTo="EnteManager" />
<type type="IEquipoManager" mapTo="EquipoManager" />
<type type="IEstadioManager" mapTo="EstadioManager" />
<type type="IEventoManager" mapTo="EventoManager" />
<type type="IPartidoManager" mapTo="PartidoManager" />
<type type="ITagManager" mapTo="TagManager" />
<type type="ITipoFormacionManager" mapTo="TipoFormacionManager"/>
<type type="ITorneoEtapaManager" mapTo="TorneoEtapaManager" />
<type type="ITorneoNominaManager" mapTo="TorneoNominaManager" />
<type type="ITorneoManager" mapTo="TorneoManager" />
</types>
</container>
<container name="StandAloneContainer">
<types>
<type type="IParameterManager" mapTo="ParameterManager" />
<type type="ILocalizationManager" mapTo="LocalizationManager" />
<type type="IDataContextWrapper" mapTo="ContextWrapperEF" >
<lifetime type="singleton" />
</type>
</types>
</container>
</containers>
</unity>
<appSettings>
<add key="UnitySection" value="unity"/>
<add key="UnityContainer" value="WebContainer"/>
</appSettings>
<connectionStrings>
<add name="CoreContext"
connectionString="metadata=res://Data.Core/DataCoreModel.csdl|res://*/DataCoreModel.ssdl|res://*/DataCoreModel.msl; provider=System.Data.SqlClient;provider connection string="
data source=reveverv.database.windows.net;initial catalog=rrvr;
persist security info=True;user id=erverver;password=erverver;
multipleactiveresultsets=True;application name=EntityFramework""
providerName="System.Data.EntityClient" />
<add name="wdsefreContext" connectionString="metadata=res://Data.Core/erverModel.csdl|res://*/ervercvModel.ssdl|res://*/erverv.msl; provider=System.Data.SqlClient;provider connection string="
data source=erfververv.database.windows.net;initial catalog=rverv;
persist security info=True;user id=erververv;password=dfvdfv;
multipleactiveresultsets=True;application name=EntityFramework""
providerName="System.Data.EntityClient" />
<add name="ApplicationServices"
connectionString="data source=.\SQLEXPRESS;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|\aspnetdb.mdf;User Instance=true"
providerName="System.Data.SqlClient" />
</connectionStrings>
<system.web>
<compilation debug="true" targetFramework="4.0" />
<authentication mode="Forms">
<forms loginUrl="~/Account/Login.aspx" timeout="2880" />
</authentication>
<membership>
<providers>
<clear/>
<add name="AspNetSqlMembershipProvider" type="System.Web.Security.SqlMembershipProvider" connectionStringName="ApplicationServices"
enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="false"
maxInvalidPasswordAttempts="5" minRequiredPasswordLength="6" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10"
applicationName="/" />
</providers>
</membership>
<profile>
<providers>
<clear/>
<add name="AspNetSqlProfileProvider" type="System.Web.Profile.SqlProfileProvider" connectionStringName="ApplicationServices" applicationName="/"/>
</providers>
</profile>
<roleManager enabled="false">
<providers>
<clear/>
<add name="AspNetSqlRoleProvider" type="System.Web.Security.SqlRoleProvider" connectionStringName="ApplicationServices" applicationName="/" />
<add name="AspNetWindowsTokenRoleProvider" type="System.Web.Security.WindowsTokenRoleProvider" applicationName="/" />
</providers>
</roleManager>
</system.web>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>
|
Toda sección posee un atributo configSource en el cual se puede indicar la ruta donde se encuentra definido el XML, asi que podemos extraer toda la sección de Unity en un archivo Unity.config , incluyendo la etiqueta y sus atributos, y el archivo de configuración quedaria de la siguiente forma, bastante más legible y manteniendo toda su funcionalidad.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | <?xml version="1.0"?>
<configuration>
<configSections>
<section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration" />
</configSections>
<unity configSource="Unity.config" />
<appSettings>
<add key="UnitySection" value="unity"/>
<add key="UnityContainer" value="WebContainer"/>
</appSettings>
<connectionStrings>
<add name="CoreContext"
connectionString="metadata=res://Data.Core/DataCoreModel.csdl|res://*/DataCoreModel.ssdl|res://*/DataCoreModel.msl; provider=System.Data.SqlClient;provider connection string="
data source=reveverv.database.windows.net;initial catalog=rrvr;
persist security info=True;user id=erverver;password=erverver;
multipleactiveresultsets=True;application name=EntityFramework""
providerName="System.Data.EntityClient" />
<add name="wdsefreContext" connectionString="metadata=res://Data.Core/erverModel.csdl|res://*/ervercvModel.ssdl|res://*/erverv.msl; provider=System.Data.SqlClient;provider connection string="
data source=erfververv.database.windows.net;initial catalog=rverv;
persist security info=True;user id=erververv;password=dfvdfv;
multipleactiveresultsets=True;application name=EntityFramework""
providerName="System.Data.EntityClient" />
<add name="ApplicationServices"
connectionString="data source=.\SQLEXPRESS;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|\aspnetdb.mdf;User Instance=true"
providerName="System.Data.SqlClient" />
</connectionStrings>
<system.web>
<compilation debug="true" targetFramework="4.0" />
<authentication mode="Forms">
<forms loginUrl="~/Account/Login.aspx" timeout="2880" />
</authentication>
<membership>
<providers>
<clear/>
<add name="AspNetSqlMembershipProvider" type="System.Web.Security.SqlMembershipProvider" connectionStringName="ApplicationServices"
enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="false"
maxInvalidPasswordAttempts="5" minRequiredPasswordLength="6" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10"
applicationName="/" />
</providers>
</membership>
<profile>
<providers>
<clear/>
<add name="AspNetSqlProfileProvider" type="System.Web.Profile.SqlProfileProvider" connectionStringName="ApplicationServices" applicationName="/"/>
</providers>
</profile>
<roleManager enabled="false">
<providers>
<clear/>
<add name="AspNetSqlRoleProvider" type="System.Web.Security.SqlRoleProvider" connectionStringName="ApplicationServices" applicationName="/" />
<add name="AspNetWindowsTokenRoleProvider" type="System.Web.Security.WindowsTokenRoleProvider" applicationName="/" />
</providers>
</roleManager>
</system.web>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>
|
Y desde luego ese mismo atributo lo podemos usar en todas las secciones que superen un tamaño pequeño.
Enjoy it!
Artículo original de mi blog
http://juank.black-byte.com/varios-galardonado-como-microsoft-mvp-visual-c-2012-4to-ano-consecutivo/
------------

Hola,
hace un mes fui galardonado MVP por 4to año consecutivo. He tardado en hablar al respecto más que nada porque ando atravesando una etapa de mi vida bastante compleja en lo que a nivel laboral se refiere, sobrabundancia se podría llamar, y eso me ha obligado a reducir muchos de los espacios que tenía antes disponibles para todas estas actividades.
Tras 4 años es muy difícil no repetirse, eso o tengo muy mala imaginación.
Gracias a todos porque lograr esto no es fácil requiere del apoyo de muchos nerds o geeks como yo
.
con algo de suerte el año que viene puede que sea nombrado de nuevo, y de seguro tendre algo muy interesante para escribir.
Hasta pronto.
Artículo original de mi blog
http://juank.black-byte.com/sistemas_operativos-necesitan-programas-para-hacer-programas/
------------
Me preguntaron con que programa, se hacen los programas que hacen programas?
Si nos ponemos a pensar, parece ser un ciclo infinito, una paradoja. Se necesitan programas para hacer programas.
Pero este tema repasando un poco de historia es mucho más fácil de entender.
No pretendo en este artículo hacer un informe detallado y preciso de la historia de los lenguajes de programación, simplemente aportare los elementos mínimos para resolver esta paradoja: “ Se necesitan programas para hacer programas ”.
En un principio siempre se programaba en lenguaje de máquina, el lenguaje de maquina son opcodes, lenguajes de 1ra generación, es decir solo números en código binario, cada instrucción [opcode] tiene un equivalente mas nemotécnico en ensamblador, es decir por cada instrucción[numero de instrucción] que entiende el procesador existe una palabra que la representa y es mas fácil de recordar, esto es el lenguaje ensamblador.
Así que inicialmente se hicieron programas en opcode que al ‘ensamblarlos’ generaban un archivo binario con códigos de maquina. Ensamblador es entonces un lenguaje de 2da generación.
Después vinieron los lenguajes de 3ra generación: cobol y fortran por ejemplo, que con una instrucción podían representar varias instrucciones de Ensamblador, sin embargo los programas siguieron creciendo y hacer software se hizo difícil, así que se genero la necesidad de tener lenguajes que permitieran reusar más código y que fueran más fácil de entender, que estuvieran mejor estructurados.
Así nació el lenguaje C, luego de que Ritchie se diera cuenta de la gran cantidad de instrucciones repetitivas y de la enorme complejidad del software, decidió crear un lenguaje donde cada palabra representara varias instrucciones y estas además pudieran ser agrupadas de manera lógica(funciones) en componentes reutilizables. También pensó en que todas estas virtudes no deberían ser una limitante para manejar instrucciones de maquina a bajo nivel así que incluyo los apuntadores para acceso directo a memoria y le dio al lenguaje la capacidad de incluir fragmentos de ensamblador cuando fuera necesario,así creo los while, los if y los for del lenguaje C, las funciones. etc. C es uno de los lenguajes de 3ra generación, de hecho el lenguaje más popular de esa generación que incluso hoy día con nuevas generaciones y formas de hacer las cosas sigue vigente aunque ha cedido mucho terreno (casi todo) a C++.
Desde 3ra generación en adelante hay algunas variantes adicionales pero este es el resumen.
En los lenguajes 4ta generación tenemos lenguajes aún más orientados a objetos, con otras características que permiten que el desarrollador se preocupe más en el ‘que debo hacer‘ que en el ‘como se hace‘, por ello tenemos lenguajes con memoria administrada como Java, C# y Visual Basic entre otros que abstraen gran parte de las complejidades de la máquina en pro de enfocarse en el resultado.
Finalmente los lenguajes de 5ta generación, enfocados en gran parte a la inteligencia artificial pero no únicamente a ello, ya que también se ha abierto espacio para los lenguajes híbridos, como es el caso de C# que hoy día es POO pero también tienesentencias dinámicas funcionales que le dan un comportamiento muy similar a los lenguajes de 5ta generación.
F# es un lenguaje de 5ta generación así como Lisp y Prolog estos últimos con un intenso uso en temas de inteligencia artificial.
Con esto queda resuelta la paradoja de Se necesitan programas para hacer programas. Los primeros programas creados se hicieron directamente en lenguaje de máquina, y según el software se fue haciendo más complejo se generó la necesidad de tener programas que permitieran escribir de forma más natural, inicialmente ensamblador donde cada instrucción del lenguaje equivalía a una instrucción de la máquina, y luego con lenguajes de nivel superior donde una instrucción correspondía a muchas instrucciones de la maquina, esa tarea de traducir de un lenguaje más ‘natural’ al lenguaje de máquina sed hace por medio de programas llamados compiladores, los cuales no solo traducen sino que analizan el conjunto del programa escrito para escribir la misma versión del programa en lenguaje de máquina con tan pocas instrucciones como sea posible.
Como se darán cuenta no todo tiempo pasado fue mejor, cosas tan habituales el día de hoy como procesar el evento clic de un botón pueden tener tras de sí miles de instrucciones ya en el lenguaje de máquina, instrucción es que antes debían escribir los desarrolladores una y otra vez.
Por suerte los ingenieros y desarrolladores hemos sido muy ingeniosos y aunque el resto de la industria se ha dedicado a mejorar a costa de funcionalidades más y más complejas hemos sabido jugar nuestras fichas, hemos mejorado nuestras herramientas con nuestros propios programas y hoy día hacemos en un clic lo que antes nos tomaba semanas, o incluso meses.
Artículo tomado de http://juank.black-byte.com/varios/uncategorized-volcados-memoria-server-2008-r2-adplus/
El caso de los volcados de memoria en Windows Server 2008 R2 con adplus.vbs
----------
Hace tiempos que no necesitaba hacer una sesión de depuración, y esta vez realizando consultoria con uno de mis clientes me reportaron un problema ejecutando adplus.vbs.
Lo primero que me encontré es que adplus.vbs ahora fue reemplazado con adplus_old.vbs ya que en su lugar hay una nueva versión de adplus que es un .exe que se ejecuta con powershell. Eso ya es una tarea para aprender.
Sin embargo una vez subsanado esto me di cuenta que tampoco funcionaba, al tratar de generar el volcado ejecute esta instrucción arrojándome el resultado que se ve a continuación:
adplus_old.vbs -hang -pn w3wp.exe -o c:\volcado
Attaching the debugger to: W3WP.EXE_-DefaultAppPool-_-v_-v2.0-_-l_-webengine4.dll-_-a_-.-pipe-iisipm06ba2546-4f31-46b0-8 953-d2ce72ddb19e_-h_-C-inetpub-temp-apppools-DefaultAppPool-DefaultAppPool.config-_-w_–_-m_0_-t_20 (Process ID: 1008) Error creating file: c:\volcado\Hang_Mode__Date_02-07-2012__Time_09-51-11m.\CDBScripts\PID-1008__W3WP.EXE_-DefaultAppPoo l-_-v_-v2.0-_-l_-webengine4.dll-_-a_-.-pipe-iisipm06ba2546-4f31-46b0-8953-d2ce72ddb19e_-h_-C-inetpub-temp-apppools-Defau ltAppPool-DefaultAppPool.config-_-w_–_-m_0_-t_20.cfg Error: 76 – Ruta de acceso no encontrada
Se me hizo raro, verifique que el directorio al que hacia referencia existiera y que tuviese los persmisos necesarios, y todo esraba OK.
Digamos que me quede barado, pero decidí hecharle un vistazo al código, pues adplus es un archivo .vbs ( visual basic script ), así que no debería ser muy complicado.
Me detuve a analizar el error y vi "Attaching the debugger to:" lo cual esta un poco antes de "Error creating file:" así que abri el archivo adplus_old.vbs desde el editor y busqué ese trozo de código
Todo parecia normal, no encontraba nada en el código que mmostrara un error. Así que regrese al nombre del archivo demasiado largo se veia, eso si. Conte los caracteres y el resultado fué 273… OOOOps se supone que el path máximo son 255 caracteres, así que decidí acortar el path.
La ruta a la carpeta no la puedo modificar, debe ser tan autonoma como sea posible, pero el nombre del paquete si lo puedo modificar, y es fácil hacerlo ya que justo despues de "Attaching the debugger to:" se hace referencia a strPackageNamesimplemente lo deje de 25 caracteres ya que está demasiado grande.
Así que inmediatamente despues de "Attaching the debugger to:" adicione este trozo de código:
1 2 3 | If LEN(strPackageName)>25 then
strPackageName=LEFT(strPackageName,25)
End If
|
Procedí a ejecutar nuevamente el proceso y…. Funciona todo OK
Attaching the debugger to: W3WP.EXE_-DefaultAppPool-_-v_-v2.0-_-l_-webengine4.dll-_-a_-.-pipe-iisipmdd4ec914-7997-4b58-9
2ec-330e042592d7_-h_-C-inetpub-temp-apppools-DefaultAppPool-DefaultAppPool.config-_-w_–_-m_0_-t_20
(Process ID: 2764)
Caso Cerrado!
Articulo originalmente escrito en el blog: http://juank.black-byte.com/varios-caso-problemas-live-writer-wordpress/
Sigueme en Twitter: @JuanKRuiz
-------------------------------------------------------
Como de seguro a muchos de mis lectores les sucede Live Writer se ha convertido e una herramienta fundamental.
Live Writer es una de las herramientas por excelencia para los blogueros más avanzados.
Por mucho tiempo fue mi herramienta infaltable hasta que un día… no se que paso, ni como ni donde ni porqué… pero lo cierto es que dejo de funcionar.
Lo acepto, me dio pereza utilizar mis super poderes de developer, así que busque en foros , blogs, amigos etc. sin éxito y comencé a hacerlo de nuevo en el blog de notas… probé otros blog writers, sin quedar satisfecho.
Hasta que en un día de Junio me harté.
Respire, mire a mis adentros y me dije, es hora de utilizar mis super poderes y lo solucione.
Esta es la historia.
El error
Cada vez que trataba de hacer algo con mi blog desde Live Writer me salía este error

Así que decidí volver a inscribir el blog en Live Writer con tan mala suerte que sucedió exactamente lo mismo y ya nunca más funciono.

En busca de soluciones
El Log
Como pueden ver el mensaje de error sirve para poco y nada.
"Error al intentar conectar con tu servicio de blog:
Respuesta de servidor no válida –
La respuesta al método blogger.getUsersBlogs recibida desde el servidor de blogs no era válida:
Invalid response document returned from XmlRpc server Intenta solucionar el problema y, a continuación, inténtalo de nuevo."
Me pregunto que $#%#$ es blogger.getUsersBlogs y que tiene que ver con WordPress :S
Así que era el momento de buscar logs.
El log de Live Writer en Windows Vista y Windows 7 esta en "%localappdata%\Windows Live Writer" , en el caso de XP y otras versiones de Windows puede variar.
Allí esta el archivo "Windows Live Writer.log" el cual podemos revisar.

Lo primero que notamos es que vuelve a aparecer el tema de XmlRpc lo cual aún no nos dice nada, pero algo si es muy importante: "La respuesta del servidor no es válida" aunque hasta el momento eso tampoco nos sirve de nada.
Este es uno de esos momentos en que te das por vencido esperando que alguna vez WordPress o Live Writer corrijan un bug en su código… si algún día.
Salvo que uses tus super poderes de developer.
Buscando en internet encontré muchos problemas diferentes de Live Writer los cuales para solucionarlos hay que revisar el archivo xmlrpc.php de WordPress, sin embargo para no comer entero busqué de donde salía ese archivo.
Lo usual es que podemos cambiar el inicio de Live Writer para que el log sea más detallado, eso se hace llamando al ejecutable de Live Writer así
WindowsLiveWriter.exe /verbose
Una vez hecho de esa manera, debes replicar el error y de nuevo revisar el log el cual ahora es más detallado, en mi caso encontré esto:

La palabra clave es Request y la URL de dicho Request … así llegamos al archivo xmlrpc.php de WordPress.
http://juank.black-byte.com/wordpress/xmlrpc.php
Con esta información podemos suponer que ese Request esta devolviendo una respuesta incorrecta.
Al revisar el archivo xmlrpc.php de WordPress me pregunte ¿Cómo es que de la noche a la mañana ahí hay algo mal si yo nunca le he hecho nada?
Gran pregunta, pero sospeche de los plugin, por lo cual desactive todos ellos y taraaaaaaaaaaaaaaaan: no paso nada, el error persistia. #Fail
Revise el código meticulosamente, pero no encontré nada extraño.
Toco sacar el developer super sayayin nivel 2.
Revisando el request
Al ingresar http://juank.black-byte.com/wordpress/xmlrpc.php por el explorador web, obtengo la respuesta
XML-RPC server accepts POST requests only.
así que tenia que hacer un Request vía POST y de seguro comenzar a obtener tanta información como pudiera de su respuesta.
Comencé a indagar en internet acerca de como hacer un Request a una URL sin necesidad de hacer mi propio programa, lo cual era de una vez mi plan B. De esta forma encontré una herramienta llamada Feedler la cual tiene un nombre bastante self explained: "Feedler Web Debugging Proxy".
Lo pueden obtener acá: http://www.fiddler2.com/fiddler2/
No entrare en detalles de como hace feedler para funcionar, pero el que lo desee puede investigarlo.
Así que uso feedler para hacer un Request a http://juank.black-byte.com/wordpress/xmlrpc.php .
Voy a la pestaña "Request Builder" donde configuro la URL y el método del Request el cual es POST:

Le doy execute e inmediatamente obtengo esto:

Content-Length mismatch: Response Header indicated 386 bytes, but server sent 389 bytes.
Bingo!! mm no tan rápido.
Doy doble clic sobre el Request fallido, recién hecho, para examinar sus detalles, estos detalles de la respuesta salen a la derecha en la parte inferior, aparentemente no dice nada del otro mundo pero entonces me voy a la pestaña Raw para ver la respuesta sin procesar, tal como es enviada por el servidor.

Tampoco veo nada anómalo, entro en depresión. (jejeje)
De repente veo la pestaña HexView la cual es aún más Raw (jejeje), ahora si estamos hablando el mismo idioma: bytes.
Comparando la vista Raw con la Hexa me doy cuenta que puedo diferenciar fácilmente el header del Response de su contenido, sumado a que en la vista Hexa Feedler me pone el header de color verde como se ve aquí:

Todo va bien hasta que comienzo a ver los bytes traspasar por mi cuerpo y lo veo allí…
Neo: Hiya, fellas.
Agent Johnson: It’s him.
Agent Thompson: The anomaly.
Agent Jackson: Do we proceed?
Agent Johnson: Yes…
Agent Thompson: …he is still…
Agent Jackson: …only human.
Estos 3 caracteres  son los 3 primeros caracteres después de los header.
Desconozco los detalles de longitud de los headers, pero el error anterior era claro: "en el header se indican 386 bytes, pero el servidor envió 389 bytes".
La diferencia según el mensaje son 3 bytes y casualmente ‘la anomalía’ es de 3 bytes. Te tengo!
Como muchos de ustedes pueden saber y sino de una vez les cuento PHP tiene la particularidad de que si se incluyen líneas en blanco antes o después de los tag <?php … ?> se pueden generar resultados inesperados… que belleza.
Procedí, entonces a revisar el archivo xmlrpc.php para eliminar dichos espacios, pero para mi sorpresa no había ninguno.
Como es de suponerse las funcionalidades de ese archivo son llamadas desde otros archivos así que por descarte escogí los archivos de WordPress que yo si había modificado: los de el tema actual del blog, los revise uno por uno y encontré varios con líneas en blanco al inicio o al final… o en ambos casos.
Procedí a eliminarlos pero al probar Live Writer… no había funcionado.
Nuevamente me quede sin opciones.No había podido solucionar el problema. #fail
A debugguear! o algo así.
Solución … a medias pero solución
Estaba seguro que el problema estaba en los 3 bytes, eso era un hecho, para descartar fui a xmlrpc.php de WordPress y verificando sus referencias llegue a class-wp-xmlrpc-server.php y a class-IXR.php.
Para mi alegre sorpresa encontré que class-wp-xmlrpc-server.php esta repleto de llamados a métodos llamados getUsersBlogs y que casualmente cuando se llama a wp_getUsersBlog aparece esto
1 2 3 4 5 6 7 8 9 10 | function wp_getUsersBlogs( $args )
{
global $current_site;
if ( !is_multisite() )
{
array_unshift( $args, 1 );
return $this->blogger_getUsersBlogs( $args );
}
}
|
De allí se origina el error que al inicio del blog nos arrojaba el Live Writer. Continúe con mi búsqueda revisando en donde se escribían los headers exactamente el header de la longitud del Response, pero no lo encontré, por lo cual supuse que era una funcionalidad heredada.
Verificando el código línea a línea llegue a class-IXR.php y allí estaba:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | function output($xml)
{
$xml = '<?xml version="1.0"?>'."\n".$xml;
$length = strlen($xml);
header('Connection: close');
header('Content-Length: '.$length);
header('Content-Type: text/xml');
header('Date: '.date('r'));
echo $xml;
exit;
}
|
Lo revise meticulosamente y en apariencia no había nada que hiciera que el header "Content-Length" reportara un tamaño incorrecto.
Así que nada más por descartar en la parte donde se establece el tamaño, en el encabezado, le sume 3 bytes.
Ejecuté Live Writer y FUNCIONO!!
Ok, pero esta no es una solución decente, porque si me volvía a pasar que debería hacer?
modificar todas las veces este fuente y forzar que el conteo sea el correcto.
Eso no es nada profesional… y por demás… dónde se genera la anomalía?
Hasta acá no tenia idea de que más hacer y ya se había hecho bastante
Pero bueno, podemos ser super saiyayin nivel 3.
Buscando la anomalía, desde sus raíces – BOM .
Los bytes anómalos son EF BB BF respectivamente: 
Inicie mi búsqueda por internet con los caracteres anómalos y aunque habían algunas pistas no me llevaba a nada concreto, así que busque por los valores hexa y el primer artículo que salió era de Wikipedia:
Byte order mark : http://en.wikipedia.org/wiki/Byte_order_mark
Resulta que exactamente estos tres caracteres (BOM) son una marca de bytes utilizada en archivos de texto de manera opcional para indicar que codificación trae el archivo, si lo trae el archivo es un archivo codificado en UTF-8 sin lugar a duda… pero BOM ya es poco usado porque se presta para malas interpretaciones.
Esos caracteres BOM pudieron haber sido agregados a cualquier archivo de php dentro de mi WordPress, de hecho mi problema original era con 6 caracteres y no con 3 como lo he explicado para simplificar un poco el problema, lo cual me hacia pensar que como mínimo habían dos archivos con ese problema.
El problema con BOM es que muchos editores no muestran esos caracteres porque precisamente saben que son BOM y que no se muestran sino que se usan como guía para saber que tipo de codificación tiene el archivo. Así que no es cuestión de abrir los archivos y editarlos.
Estas imagen muestran como se ve un archivo con BOM en un editor de texto y como se ve en un editor binario:


Potencialmente cualquier archivo .php en mi WordPress podría tener ese problema pero revisar algo así como 1000 archivos en modo binario desde Visual Studio para remover 3 bytes en cada uno podría ser dispendioso, más aún cuando no en todos debería quitar esos 3 bytes sino solo en los que tuviesen BOM.
Deshice los cambios que sumaban 3 bytes en el header.
De nuevo hacer un programa por mi cuenta era el plan B. Buscando por Internet Llegué a esta herramienta gratuita
Replace Pioner http://www.mind-pioneer.com/
Debo admitir… es un enrredo internamente muy bueno pero una UI de la vieja guardia.
Les diré como usarlo para este problema puntual. Lo primero es que baje mi sitio de WordPress a carpeta local.
- Abrimos replace pioner
- Vamos a Tools>_Batch Runner
- Como no sabemos cuantos archivos de nuestra instalación de WordPress tienen ese problema usamos la opción Search Files y filtramos todos los archivos .php del directorio y subdirectorios de WordPress

- Clic en Search y listo tenemos listados todos los archivos .php
- Cerramos el dialogo
- En la parte inferior de Batch Runner tenemos el botón "Fast Replace" lo presionamos.
- En el dialogo que se abre seleccionamos el template de "binary file — remove utf-8 BOM"
- Presionamos Add
- Seguidamente Start

Tomara unos segundos y podemos ver el log de los cambios realizados, eso nos permitirá saber que archivos eran los culpables.
Una vez finalice el proceso copiamos los archivos de nuevo a nuestro sitio, vamos a Windows Live Writer y BINGO!!
Ahora si todo funcionando y de la manera más profesional posible.
Como prevenirlo
En algún lugar de la web encontré algo ingenioso.
Si bien puedes ser prevenido y siempre desde tu editor darle "guardar como" y seleccionar todo menos UTF-8 un truco es que al menos en los comentarios incluyan una letra que no sea de UTF-8 por ejemplo la ‘ñ’ con esto automáticamente el editor no hará uso del BOM ni nada similar.
Estoy seguro que este artículo les habrá encantado.
Byte!
Tomado de
El bucle de mensajes - message loop - WndProc
-------------------
Debido a que este es un tema recurrente en este blog, he decidido extraer este pequeño aporte hecho en otro artículo para poder referenciarlo puntualmente cuando se requiera.
Las ventanas – y los demás controles – funcionan gracias a un bucle de mensajes, todo lo que manejamos nosotros como eventos : click del mouse, mover, cerrar, cambiar tamaño, maximizar etc, realmente es controlado por un bucle en donde se envían diferentes mensajes a la ventana, esta a su vez tiene un procedimiento que recibe estos mensajes y con base a los mensajes recibidos puede hacer una u otra cosa según se programe.
Si, para algunos esto ya debe estar sonando a cuento, pero las cosas son así por debajo de lo que usamos tradicionalmente. El tema del artículo no es explicar como funciona un ciclo de mensajes así que por el momento lo dejaremos hasta allí y quien quiera profundizar puede consultar esta fuente en internet
http://www.winprog.org/tutorial/message_loop.html
Esta es una copia cruzada de mi blog original.
Puedes leer el articulo original con código coloreado y demás utilidades en
C# - Como obtener un manejador (handle) para una ventana de WPF
-------------------------------------
WPF es una parte del .Net Framework muy robusta pensada para ser multiplataforma, pero a veces necesitamos que nuestra aplicación interactue con aspectos más relacionados con el sistema operativo donde se ejecuta. En estos casos requerimos el menejador ( handle ) de la ventana el cual no es expuesto por WPF.
Para obtenerlo debemos hacer uso de una clase utilitaria llamada WindowInteropHelper la cual tiene un elemento muy importante, la propiedad Handle que no es ni más menos que el manejador a la ventana de WPF. Su uso es muy sencillo:
[csharp]
Window miVentana = this;
WindowInteropHelper interopHelper = new WindowInteropHelper(miVentana);
IntPtr manejadorVentana = interopHelper.Handle;
[/csharp]
El código esta así por claridad, dentro del código de una ventana de WPF a la que querramos obtenerle el manejador basta con hacer:
[csharp]
WindowInteropHelper interopHelper = new WindowInteropHelper(this);
IntPtr manejadorVentana = interopHelper.Handle;
[/csharp]
Ya teniendo el manejador de la ventana podemos acceder a muchas otras funcionalidades fuertemente atadas con el SO como por ejemplo las expuestas en Win32Api o equivalente en otras plataformas
Esta es una copia cruzada de mi blog original.
Puedes leer el articulo original con código coloreado y demás utilidades en
C# - usar el WndProc en una Ventana WPF
----------------------------------
WPF es una parte del .Net Framework muy robusta pensada para ser multiplataforma, pero a veces necesitamos que nuestra aplicación interactue con aspectos más relacionados con el sistema operativo donde se ejecuta. En estos casos requerimos interceptar mensajes en el WndProc.
Para lograr acceder al WndProc debemos obtener un manejador (handle) para la ventana WPF y seguidamente utilizar la clase utilitaria HwndSource para crear el Hook, allí creamos un delegado el cual hara las veces de WndProc de nuestra ventana.
[csharp]
WindowInteropHelper interopHelper;
private void Window_Loaded(object sender, RoutedEventArgs e)
{
//Conseguir el Handle de la ventana
interopHelper = new WindowInteropHelper(this);
//Crear un hook al WndProc
HwndSource sourceWindow = HwndSource.FromHwnd(interopHelper.Handle);
sourceWindow.AddHook(WndProc);
}
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
//Hacer algo...
return IntPtr.Zero;
}[/csharp]
Y eso es todo ;)
More Posts
Next page »