10.15.2006
¿De que se trata Windows Communication Foundation (WCF)?
Windows Communication Foundation (WCF) permite el reuso de funcionalidad y la integración de sistemas distribuidos con una facilidad de desarrollo, operación y mantenimiento antes imposible.
El esquema WCF combina un lenguaje de dominio específico (LDE) con una librería de clases para permitir el desarrollo ágil de software orientado a servicios. El LDE es el modelo de servicio y la librería de clases es la capa de canal.
Un lenguaje de dominio específico permite definir software de una manera más específica y precisa que un lenguaje de modelado general, pero únicamente dentro de un dominio específico. Por ejemplo, UML es un lenguaje de modelado general y el diseñador de Windows Forms es un lenguaje de dominio específico dirigido a la librería de clases System.Windows.Forms .
El modelo de servicio de WCF consiste de clases dentro del namespace ServiceModel y de un lenguaje de configuración basado en XML. La capa de canal se compone de clases dentro del namespace System.ServiceModel.Channel
Como desarrolladores diseñamos la comunicación de nuestros programas utilizando el modelo de servicio y los componentes de comunicación que usaremos son generados a partir de la capa de canal. Si el mecanismo de comunicación que requerimos no existe ya en la capa de canal, es posible extenderla con nuestros propios componentes de comunicación.
9.29.2006
Mapas de Windows Live (Gratis) en tus Aplicaciones Windows Forms o WPF
Si necesitan hacer una aplicación que incorpore mapas que no requiere necesariamente de que todo México esté al detalle en los mapas, les recomiendo el SDK de Virtual Earth. Se trata de un control pensado para web que se manipula con JavaScript. Sin embargo, con un mínimo de ingenio lo pueden utilizar en cualquier aplicación Windows Forms o WPF al hostear (sic) un web browser control en un UserControl de Windows Forms. O mejor aún, pueden tomar este código que hice ayer para esos fines y simplemente usarlo:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
///
<summary>
/// Encapsulamiento (incompleto pero funcional del control de mapas de Virtual Earth
/// para su uso desde Windows Forms o WPF
/// (Requiere VS2005)
/// Software libre por Héctor Obregón http://msdnfan.blogspot.com
///
</summary>
namespace WindowsLiveControl
{
public
partial
class
WindowsLiveMapControl : UserControl
{
///
<summary>
/// Constructor publico.
///
</summary>
public WindowsLiveMapControl()
{
InitializeComponent();
this.webBrowser.DocumentText = "<html><head><title></title><meta http-equiv=\"Content-Type\"content=\"text/html; charset=utf-8\">" +
"<script src=\"http://dev.virtualearth.net/mapcontrol/v3/mapcontrol.js\"></script> <script> var map = null;" +
"function GetMap() { map = new VEMap('myMap'); map.LoadMap(new VELatLong(" +
m_dMapCenterLatitude.ToString() + ", " + m_dMapCenterLongitude.ToString() + "), " + m_iMapZoom.ToString() + ", '" + m_chMapStyle.ToString() + "' ," +
m_bMapFixed.ToString().ToLower() + "); } " +
"function AddPushPin( PinID, Latitude, Longitude, Title, Details, IconURL ) { var Pin = new VEPushpin( PinID, new VELatLong( Latitude, Longitude ), " +
"IconURL, Title, Details ); " +
"map.AddPushpin(Pin); }" +
"function SetCenter( Latitude, Longitude ) { map.SetCenter( new VELatLong( Latitude, Longitude )); } " +
"function RemovePushPin( ID ) { map.DeletePushpin( ID ); } " +
"function DeleteAllPushPins() { map.DeleteAllPushpins(); } " +
"function ZoomIn() { map.ZoomIn(); } " +
"function ZoomOut() { map.ZoomOut(); } " +
"function HideControl() { map.HideDashboard(); } " +
"function ShowControl() { map.ShowDashboard(); } " +
"function SetMapStyle( mapStyle ) { map.SetMapStyle( mapStyle ); } " +
"function SetMapZoom( level ) { map.SetZoomLevel( level ); } " +
"function SetBestMap( LatitudeArray, LongitudeArray, Count ) { " +
"var locs = new Array;" +
"for (i=0; i < Count; i++){" +
"var loc = new VELatLong( LatitudeArray[i], LongitudeArray[i] );" +
"locs.push( loc );" +
"}" +
"map.SetMapView( locs );" +
"} " +
"function SetBestMap2( lMin, loMin, lMax, loMax ) { " +
"var locs = new Array;" +
"var loc = new VELatLong( lMin, loMin );" +
"locs.push( loc );" +
"var loc = new VELatLong( lMax, loMax );" +
"locs.push( loc );" +
"map.SetMapView( locs );" +
"} " +
"</script> </head> <body onload=\"GetMap();\">" +
"<div id='myMap' style=\"position:relative; width:" + this.ClientSize.Width.ToString() + "px; height:" + this.ClientSize.Height.ToString() + "px;\"></div> </body></html>";
this.ClientSizeChanged += new
EventHandler(WindowsLiveMapControl_ClientSizeChanged);
webBrowser.SizeChanged += new
EventHandler(WindowsLiveMapControl_ClientSizeChanged);
}
///
<summary>
/// Para que ajuste automáticamente el tamaño del mapa al
/// cambiar el tamaño del control.
///
</summary>
///
<param name="sender"></param>
///
<param name="e"></param>
void WindowsLiveMapControl_ClientSizeChanged(object sender, EventArgs e)
{
this.webBrowser.DocumentText = "<html><head><title></title><meta http-equiv=\"Content-Type\"content=\"text/html; charset=utf-8\">" +
"<script src=\"http://dev.virtualearth.net/mapcontrol/v3/mapcontrol.js\"></script> <script> var map = null;" +
"function GetMap() { map = new VEMap('myMap'); map.LoadMap(new VELatLong(" +
m_dMapCenterLatitude.ToString() + ", " + m_dMapCenterLongitude.ToString() + "), " + m_iMapZoom.ToString() + ", '" + m_chMapStyle.ToString() + "' ," +
m_bMapFixed.ToString().ToLower() + "); } " +
"function AddPushPin( PinID, Latitude, Longitude, Title, Details, IconURL ) { var Pin = new VEPushpin( PinID, new VELatLong( Latitude, Longitude ), " +
"IconURL, Title, Details ); " +
"map.AddPushpin(Pin); }" +
"function SetCenter( Latitude, Longitude ) { map.SetCenter( new VELatLong( Latitude, Longitude )); } " +
"function RemovePushPin( ID ) { map.DeletePushpin( ID ); } " +
"function DeleteAllPushPins() { map.DeleteAllPushpins(); } " +
"function ZoomIn() { map.ZoomIn(); } " +
"function ZoomOut() { map.ZoomOut(); } " +
"function HideControl() { map.HideDashboard(); } " +
"function ShowControl() { map.ShowDashboard(); } " +
"function SetMapStyle( mapStyle ) { map.SetMapStyle( mapStyle ); } " +
"function SetMapZoom( level ) { map.SetZoomLevel( level ); } " +
"function SetBestMap( LatitudeArray, LongitudeArray, Count ) { " +
"var locs = new Array;" +
"for (i=0; i < Count; i++){" +
"var loc = new VELatLong( LatitudeArray[i], LongitudeArray[i] );" +
"locs.push( loc );" +
"}" +
"map.SetMapView( locs );" +
"} " +
"function SetBestMap2( lMin, loMin, lMax, loMax ) { " +
"var locs = new Array;" +
"var loc = new VELatLong( lMin, loMin );" +
"locs.push( loc );" +
"var loc = new VELatLong( lMax, loMax );" +
"locs.push( loc );" +
"map.SetMapView( locs );" +
"} " +
"</script> </head> <body onload=\"GetMap();\">" +
"<div id='myMap' style=\"position:relative; width:" + this.ClientSize.Width.ToString() + "px; height:" + this.ClientSize.Height.ToString() + "px;\"></div> </body></html>";
}
///
<summary>
/// Constructor con parámetros para inicializar el control.
///
</summary>
///
<param name="Latitude"></param>
///
<param name="Longitude"></param>
///
<param name="Zoom">De 1 a 19</param>
///
<param name="Style"></param>
///
<param name="Fixed"></param>
public WindowsLiveMapControl( double Latitude, double Longitude, int Zoom, MapStyle Style, bool Fixed):this()
{
m_dMapCenterLatitude = Latitude;
m_dMapCenterLongitude = Longitude;
m_iMapZoom = Zoom;
this.Style = Style;
m_bMapFixed = Fixed;
}
///
<summary>
/// Agrega un pin estándar al control
///
</summary>
///
<param name="Pin"></param>
public
void AddPushPin(PushPin Pin)
{
m_dictPins.Add(Pin.PinID, Pin);
object[] args = new
object[6];
args[0] = Pin.PinID;
args[1] = Pin.Latitude;
args[2] = Pin.Longitude;
args[3] = Pin.Title;
args[4] = Pin.Details;
args[5] = Pin.IconURL;
webBrowser.Document.InvokeScript( "AddPushPin", args );
}
///
<summary>
/// Centra el mapa.
///
</summary>
///
<param name="Latitude"></param>
///
<param name="Longitude"></param>
public
void SetCenter(double Latitude, double Longitude)
{
m_dMapCenterLatitude = Latitude;
m_dMapCenterLongitude = Longitude;
CenterMap();
}
///
<summary>
/// Centra el mapa en su última posición.
///
</summary>
public
void CenterMap()
{
object[] args = new
object[2];
args[0] = m_dMapCenterLatitude;
args[1] = m_dMapCenterLongitude;
webBrowser.Document.InvokeScript("SetCenter", args);
}
///
<summary>
/// Ajusta el mapa automáticamente
/// para que se vean todos los pushpins definidos.
///
</summary>
public
void FitBestMap()
{
double dMinLat = 90.0;
double dMinLong = 180.0;
double dMaxLat = -90.0;
double dMaxLong = -180.0;
foreach (PushPin p in m_dictPins.Values)
{
if (p.Latitude < dMinLat)
dMinLat = p.Latitude;
if (p.Latitude > dMaxLat)
dMaxLat = p.Latitude;
if (p.Longitude < dMinLong)
dMinLong = p.Longitude;
if (p.Longitude > dMaxLong)
dMaxLong = p.Longitude;
}
object[] args = new
object[4];
args[0] = dMinLat;
args[1] = dMinLong;
args[2] = dMaxLat;
args[3] = dMaxLong;
webBrowser.Document.InvokeScript("SetBestMap2", args);
}
///
<summary>
/// Quita un pushpin (Duh!)
///
</summary>
///
<param name="ID"></param>
public
void RemovePushPin(int ID)
{
PushPin pin;
if (m_dictPins.TryGetValue(ID, out pin))
{
object[] args = new
object[1];
args[0] = pin.PinID;
webBrowser.Document.InvokeScript("RemovePushPin", args);
}
}
public
void RemovePushPin(PushPin Pin)
{
RemovePushPin(Pin.PinID);
}
public
void DeleteAllPushPins()
{
m_dictPins.Clear();
webBrowser.Document.InvokeScript("DeleteAllPushPins");
}
public
void ZoomIn()
{
webBrowser.Document.InvokeScript("ZoomIn");
if (m_iMapZoom < 19)
++m_iMapZoom;
}
public
void ZoomOut()
{
webBrowser.Document.InvokeScript("ZoomOut");
if (m_iMapZoom > 1)
--m_iMapZoom;
}
public
void ShowNavigation()
{
webBrowser.Document.InvokeScript("ShowControl");
}
public
void HideNavigation()
{
webBrowser.Document.InvokeScript("HideControl");
}
private
void SetMapStyle()
{
object[] args = new
object[1];
args[0] = m_chMapStyle.ToString();
webBrowser.Document.InvokeScript("SetMapStyle", args);
}
private
void SetMapZoom()
{
object[] args = new
object[1];
args[0] = m_iMapZoom;
webBrowser.Document.InvokeScript("SetMapZoom", args);
}
private
double m_dMapCenterLatitude = 19.7;
public
double MapCenterLatitude
{
get { return m_dMapCenterLatitude; }
set { m_dMapCenterLatitude = value;
CenterMap();
}
}
private
double m_dMapCenterLongitude = -99.46;
public
double MapCenterLongitude
{
get { return m_dMapCenterLongitude; }
set { m_dMapCenterLongitude = value;
CenterMap();
}
}
private
int m_iMapZoom = 10;
public
int MapZoom
{
get { return m_iMapZoom; }
set {
m_iMapZoom = value;
SetMapZoom();
}
}
private
bool m_bMapFixed = false;
public
bool MapFixed
{
get { return m_bMapFixed; }
set { m_bMapFixed = value; }
}
public
enum
MapStyle { Aerial = 1, Hybrid, Oblique, Road }
private
char m_chMapStyle = 'r';
private
Dictionary<int, PushPin> m_dictPins = new
Dictionary<int, PushPin>();
public
MapStyle Style
{
set
{
if (value == MapStyle.Aerial)
m_chMapStyle = 'a';
if (value == MapStyle.Hybrid)
m_chMapStyle = 'h';
if (value == MapStyle.Oblique)
m_chMapStyle = 'o';
if (value == MapStyle.Road)
m_chMapStyle = 'r';
SetMapStyle();
}
get
{
if (m_chMapStyle == 'a')
return
MapStyle.Aerial;
if (m_chMapStyle == 'h')
return
MapStyle.Hybrid;
if (m_chMapStyle == 'o')
return
MapStyle.Oblique;
return
MapStyle.Road;
}
}
}
///
<summary>
/// Representa un PushPin...
///
</summary>
public
class
PushPin
{
private
int m_intPinID;
public
int PinID
{
get { return m_intPinID; }
set { m_intPinID = value; }
}
private
string m_strTitle;
public
string Title
{
get { return m_strTitle; }
set { m_strTitle = value; }
}
private
string m_strDetails;
public
string Details
{
get { return m_strDetails; }
set { m_strDetails = value; }
}
private
double m_dLatitude;
public
double Latitude
{
get { return m_dLatitude; }
set { m_dLatitude = value; }
}
private
double m_dLongitude;
public
double Longitude
{
get { return m_dLongitude; }
set { m_dLongitude = value; }
}
private
string m_strIconURL;
public
string IconURL
{
get { return m_strIconURL; }
set { m_strIconURL = value; }
}
public PushPin( int ID, double Latitude, double Longitude)
{
m_intPinID = ID;
m_dLatitude = Latitude;
m_dLongitude = Longitude;
}
public PushPin(int ID, double Latitude, double Longitude, string Title)
{
m_intPinID = ID;
m_dLatitude = Latitude;
m_dLongitude = Longitude;
m_strTitle = Title;
}
public PushPin(int ID, double Latitude, double Longitude, string Title, string Details)
{
m_intPinID = ID;
m_dLatitude = Latitude;
m_dLongitude = Longitude;
m_strTitle = Title;
m_strDetails = Details;
}
public PushPin(int ID, double Latitude, double Longitude, string Title, string Details, string IconURL)
{
m_intPinID = ID;
m_dLatitude = Latitude;
m_dLongitude = Longitude;
m_strTitle = Title;
m_strDetails = Details;
m_strIconURL = IconURL;
}
}
}
Y este el archivo generado por el diseñador de Windows Forms…
namespace WindowsLiveControl
{
partial
class
WindowsLiveMapControl
{
///
<summary>
/// Required designer variable.
///
</summary>
private System.ComponentModel.IContainer components = null;
///
<summary>
/// Clean up any resources being used.
///
</summary>
///
<param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected
override
void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
///
<summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
///
</summary>
private
void InitializeComponent()
{
this.webBrowser = new System.Windows.Forms.WebBrowser();
this.SuspendLayout();
//
// webBrowser
//
this.webBrowser.Dock = System.Windows.Forms.DockStyle.Fill;
this.webBrowser.Location = new System.Drawing.Point(0, 0);
this.webBrowser.MinimumSize = new System.Drawing.Size(20, 20);
this.webBrowser.Name = "webBrowser";
this.webBrowser.Size = new System.Drawing.Size(655, 484);
this.webBrowser.TabIndex = 0;
//
// WindowsLiveMapControl
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.Controls.Add(this.webBrowser);
this.Name = "WindowsLiveMapControl";
this.Size = new System.Drawing.Size(655, 484);
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.WebBrowser webBrowser;
}
}
Por si lo quieren usar en XAML hay que agregar la referencia al control de Windows Forms en su proyecto WPF y luego agregar esto en la definición inicial de namespaces de su archivo….
xmlns:wfmap="clr-namespace:WindowsLiveControl;assembly=WindowsLiveControl"
y luego incluirlo así donde quieran…
<WindowsFormsHost
Name="mapHost">
<wfmap:WindowsLiveMapControl
Name="mapControl"/>
</WindowsFormsHost>
Una solución fácil para incorporar mapas simples en sus aplicaciones. Hasta la próxima…..
9.10.2006
Instalando Vista RC1 (5600)
Ya instalé Windows Vista RC1 en mi Inspiron 9400. Mucho, mucho mejor que el CTP de Julio que había instalado antes. Hasta donde he podido checar, todo funcionó a la primera (audio, video, DVD+R, ranura SD). También el desempeño está significativamente mejorado. La instalación no tomo más de 35 mins. (increíble)
Llevo todo el día en esto y ya instalé VS 2005, Office 2003, Office 2007 Beta 2, y una variedad de utilerías básicas. Todo bien.
Vista RC1 se puede obtener del sitio de suscriptores de MSDN. Las utilerías para desarrollar para .NET 3.0 RC1 las pueden obtener aquí http://msdn.microsoft.com/windowsvista/downloads/products/getthebeta/default.aspx . En esa página faltan las utilerías “Orcas” para WPF que están aquí: http://www.microsoft.com/downloads/details.aspx?FamilyID=935aabf9-d1d0-4fc9-b443-877d8ea6eab8&DisplayLang=en
Por cierto, estoy escribiendo este post desde la funcionalidad de “Blog Post” que trae Word 2007. Se conecta a blogger sin problemas y está bastante cómodo para escribir los posts cuando estás off-line.
Si me da tiempo hoy voy a instalar Vista RC1 también en una XPS 600. Espero que todo salga bien, los mantengo informados.
8.30.2006
Llegaron Nuevos Libros
Hoy me llegaron 5 libros de Amazon que pedí para echarme un clavado a fondo en .NET 3.0. Voy a empezar por Applications = Code + Markup de Charles Petzold (Microsoft Press). El estilo de Petzold me gusta mucho porque te lleva de la mano de una manera muy sencilla pero al mismo tiempo toca todos los temas relevantes con profundidad. Voy en la página 30 y me parece muy bueno, espero terminarlo en unos días y pondré aquí mis comentarios finales en un futuro post. También encargué Presenting Windows Workflow Foundation (SAMS), Programming Windows Presentation Foundation(O’Reilly), Microsoft Windows Communication Foundation Hands On! (SAMS), y Software Engineering with Microsoft Visual Studio Team System (Addison-Wesley).
.NET 3.0 es tan amplio que es difícil (y cansado) lograr un entendimiento global razonable sólo de leer artículos en Internet. Creo que los libros son una mejor opción para adentrarse en un tema tan amplio e innovador como este. Además, estoy participando en un proyecto para desarrollar un libro donde desarrollemos una aplicación concreta basada en .NET 3.0 y contar con el apoyo teórico me parece indispensable por decir lo menos.
8.20.2006
¡Podemos desarrollar sobre Xbox 360!
Microsoft acaba de lanzar una versión XNA Game Studio Express de sus herramientas de desarrollo para Xbox que cualquiera puede bajar sin costo. Me parece que este no es un evento menor. Hay millones de consolas Xbox en hogares de todo el mundo. El Xbox ha logrado un posicionamiento dentro de la sala de casa que están muy lejos de alcanzar dispositivos como las PCs con Windows Media Center.
La oferta de Microsoft permite que ejecutes aplicaciones XNA en tu PC sin ningún costo. Para correrlas en tu Xbox hay un servicio de desarrollo que cuesta
Me falta entender cómo podríamos distribuir nuestro software para Xbox. De cualquier manera, a reserva de probar está tecnología próximamente, me parece que como plataforma la Xbox es muy atractiva para aspectos más allá de los juegos. Por ejemplo, empresas que ofrecen contenido en línea pudieran ver a la Xbox como un mecanismo legítimo de distribución y acceso hacia sus clientes. El beta estará disponible a finales de mes. Con éste puedes desarrollar juegos para Windows (con cualquier fin) y para Xbox (sin fines comerciales). A principios de 2007 saldrá una versión con costo que te permitirá comercializar tus juegos también.
Para registrarte al beta puedes visitar connect.microsoft.com .
Ya veremos….
8.09.2006
¡Finalmente! Windows Vista July CTP (5472) en Inspiron 9400 (Finally! - Windows Vista July CTP (5472) on Dell Inspiron 9400)
Cuando instalé Vista 5472 en mi Dell Inspiron 9400 no reconoció la tarjeta de video (una SigmaTel 97xx integrada). Encontraba un "dispositivo S/PDIF" pero no se escuchaba nada. Windows Update tampoco encontraba nada.
Bajé los drivers de XP del sitio de Dell y todo parecía estar bien (se escuchaba el audio) pero... resulta que el driver provocaba serias inestabilidades en Vista:
1. El explorer se congela al abrir el panel de control.
2. La búsqueda de Vista se pasma.
3. El "Network and Sharing Center" se pasma.
Encontré estos drivers para un build anterior que son unos para Realtek '97 modificados. Parece ser que ahora todo funciona. Puedes encontrar los drivers aquí.
------------------------------------------------------------------------
When I installed Vista 5472 on my Dell Inspiron 9400 my sound card was not recognized. The OS found some sort of S/PDIF device but I had no sound at all. Windows Update found nothing either.
I tried downloading drivers from support.dell.com for Windows XP. I got sound but some serious instability ensued as explorer hung when opening Control Panel, when using search with the Windows key and when opening Network and Sharing Center.
After much searching I found this modded Realtek 97 drivers and everything now seems to work fine. You can find the drivers here.
7.25.2006
Conceptos Básicos de Windows Workflow Foundation
Un flujo de trabajo de WWF siempre está compuesto de un conjunto de actividades. Estas son ejecutadas de manera asíncrona por un motor de ejecución provisto por WWF. Las actividades pueden ser simples o compuestas. Una actividad compuesta integra a más de una actividad simple. WWF provee un conjunto de actividades predefinidas y además permite que nosotros definamos cualquier otra con la funcionalidad que necesitemos.
WWF soporta dos tipos de flujos de trabajo:
· Flujo Secuencial: Es aquel donde se ejecutan una serie de actividades en una secuencia predefinida. Esta secuencia puede incluir operadores de control de flujo similares a los que han existido durante años en lenguajes de programación. Por ejemplo, operadores de decisión (if…else) o de iteración (while). Se utiliza para flujos donde nos interesa que el control lo tanga primordialmente el proceso definido.
· Flujo de Máquina de Estados: En este flujo las actividades se ejecutan dependiendo de el estado en el que se encuentre una máquina de estados, así como de las transiciones entre estos estados (que pueden ser iniciadas por las actividades mismas). Se utiliza normalmente para flujos donde se prefiere que el control recaiga mayormente en los usuarios del sistema.
Si quieren saber más, ojalá puedan asistir este próximo Viernes al WTC piso 35 en la Ciudad de México dónde voy a dar una platica nivel 100 de introducción a este tema.
7.18.2006
Reuniones de la Comunidad .NET del D.F.
La siguiente es el próximo Viernes 28 de Julio. Vamos a tener muchas platicas interesantes. Recuerden que no tiene costo y que no les tratamos de vender nada.
En esta ocasión voy a dar una plática de Windows Workflow Foundation.
Los esperamos.
Introducción al .NET Framework 3.0
1. Componentes comunes nuevos para desarrollar la capa de presentación (normalmente la interfaz de usuario) de nuestra aplicación que permite la construcción de experiencias interactivas mucho más atractivas y fáciles de usar. A esta parte de la plataforma Microsoft le llama Windows Presentation Foundation. También se conoce como WPF.
2. Un conjunto de elementos que facilitan enormemente el desarrollo de sistemas distribuidos e interconectados. Estos elementos van más allá de los servicios web para facilitar la comunicación entre desarrolladores. A esta parte de la plataforma Microsoft le llama Windows Communications Foundation. También se conoce como WCF.
3. Servicios de plataforma para sostener el desarrollo acelerado de aplicaciones con elementos de flujo de trabajo. Estos servicios administran el flujo de información para un proceso de trabajo sin imponer ninguna condición sobre los requerimientos de negocio de este. A esta parte de la plataforma Microsoft le llama Windows Workflow Foundation. También se conoce como WWF.
En los próximos meses estaré participando en el desarrollo de una aplicación sobre esta plataforma y voy a estar bloggeando (me comprometo una vez a la semana) sobre este tema.
Si quieren ir experimentando junto conmigo les recomiendo instalar:
· Windows Vista Beta 2.
· Los componentes de ejecución de WinFX Beta 2.
· Visual Studio 2005
· El SDK del WinFX Beta 2
· Las herramientas de desarrollo “Orcas” para WPF Beta 2.
· Las herramientas de desarrollo “Orcas” para WWF Beta 2.
· SQL Server 2005 Express Edition SP1
Nos estamos comunicando por aquí....
5.25.2006
Impresiones Iniciales de Windows Vista Beta 2
- Este ya lo pude instalar en mi Dell XPS600 con RAID 0 (NVIDIA ya sacó los drivers necesarios).
- El performance es mucho mejor.
- La interfaz se ve mucho más acabada.
- El sidebar funciona bien y trae más gadgets.
- La instalación es más rápida (ayer instalé en una partición limpia).
También instalé el Beta 2 de Office 2007 pero he jugado poco con el. El Outlook al menos jaló bien. Lo demás no lo he visto, pero de un primer vistazo a Excel veo que no me va a ser tan fácil acostumbrarme a la nueva interfaz.
Me gustó tanto que hoy decidí hacer un respaldo de mi partición de Windows XP e intentar instalar Vista sobre XP. En este momento está aparentemente detenido en Gathering Files (99%) pero no se ha caído, así que le voy a tener paciencia un rato más.
Aventuras en un Framework de Seguridad en .NET (3)
El método Authorize es el siguiente:
///
/// Evaluates the specified authority against the specified context.
///
/// Must be an
/// The name of the rule to evaluate.
///
/// otherwise
private bool Authorize(IPrincipal principal, string c, out Behavior b, out bool Evaluated)
{
Evaluated = false;
if (principal == null) throw new ArgumentNullException("principal");
if (c == null ) throw new ArgumentNullException("Control");
BooleanExpression booleanExpression = GetParsedControlExpression(m_strFormName,
c, out b, out Evaluated);
if (booleanExpression == null)
{
Evaluated = false;
return true;
}
bool result = booleanExpression.Evaluate(principal);
return result;
}
La clave aquí es la llamada a booleanExpression.Evaluate(principal) que es un muy útil evaluador de expresiones que viene incluído en el Enterprise Library 2.0. Esta función utiliza el método IsInRole del Principal para evaluar la expresión conforme a las reglas que se le pasan en la cadena c.
Otro aspecto que buscamos en esta librería, es que se pueda utilizar también en el .NET Compact Framework 2.0.
Para esto, la estrategia tiene algunos cambios con respecto al control de escritorio. Los principales son:
1. La evaluación de las expresiones no la hace el dispositivo móvil, sino un servidor a través de un servicio web. esto se debe a que en el caso de un dispositivo móvil, debemos de ser cuidadosos con el consumo de recursos o el desempeño de nuestra aplicación podría verse severamente afectado.
2. Los metodos que nos permiten utilizar reflection para ver que función nos está llamando en AuthorizeMethod no existen en el Compact Framework, por lo que necesitamos pasar explícitamente el nombre del método.
5.03.2006
Aventuras en un Framework de Seguridad en .NET (2)
Recordemos brevemente:
1. Que los programadores puedan implementar la seguridad sin programar.
2. Que podamos hacer visibles/invisibles o habilitados/deshabilitados elementos de la IU de manera totalmente declarativa, ya sea en una BD o en XML.
Para satisfacer el punto 1, podemos desarrollar un control gráfico, que simplemente se arrastre con drag and drop a cada forma del proyecto en la que se desea tener seguridad (aquí estamos hablando de Windows Forms).
Mi primera intención fue crear un componente no gráfico (heredando de System.Windows.Forms.Component) ya que este implementador de seguridad no requiere de una interfaz gráfica para si mismo. Sin embargo, me enfrenté a la dificultad de que un componente de este tipo no puede determinar en tiempo de ejecución a que forma pertenece. Existen algunos trucos para determinar esto en tiempo de diseño pero no me gustaron ya que quedaría una solución frágil ante renombramientos y cambios de ese tipo.
Por lo tanto opté por desarrollar un control (heredando de System.Windows.Forms.UserControl) que se vuelve invisible en tiempo de ejecución. No tan elegante como quisiera pero funcional. Se parece al viejo timer de VB6, ¿se acuerdan?
Para que este control pueda encargarse de configurar la interfaz en tiempo de ejecución, necesita analizar al correr todos los elementos gráficos de la forma e ir encendiendo/apagando/habilitando/deshabilitando los elementos de la IU conforme a las reglas de seguridad declaradas. Sin embargo, no es suficiente con hacer esto al cargar la forma. ¿Qué pasa si el código del programador enciende o habilita programáticamente un control que no debería para el usuario firmado? Por esta razón es necesario también establecer manejadores de los eventos OnEnabledChanged y OnVisibleChanged de los controles bloqueados para poder levantar una excepción de seguridad en caso necesario.
El código que itera sobre los controles se ve más o menos así:
private void AuthorizeControls( Control main)
{
IPrincipal iprin = Thread.CurrentPrincipal;
Behavior b;
bool bEvaluated = false;
foreach (Control c in main.Controls)
{
if (c.Controls.Count > 0)
AuthorizeControls(c);
if (!Authorize(iprin, c.Name, out b, out bEvaluated))
{
switch (b)
{
case Behavior.Enabled:
c.Enabled = false;
c.EnabledChanged += new EventHandler(c_EnabledChanged);
break;
case Behavior.Visible:
c.Visible = false;
c.VisibleChanged += new EventHandler(c_VisibleChanged);
break;
case Behavior.Both:
c.Enabled = false;
c.EnabledChanged += new EventHandler(c_EnabledChanged);
c.Visible = false;
c.VisibleChanged += new EventHandler(c_VisibleChanged);
break;
}
}
else
{
if (bEvaluated)
{
switch (b)
{
case Behavior.Enabled:
c.Enabled = true;
c.EnabledChanged -= new EventHandler(c_EnabledChanged);
break;
case Behavior.Visible:
c.Visible = true;
c.VisibleChanged -= new EventHandler(c_VisibleChanged);
break;
case Behavior.Both:
c.Enabled = true;
c.EnabledChanged -= new EventHandler(c_EnabledChanged);
c.Visible = true;
c.VisibleChanged -= new EventHandler(c_VisibleChanged);
break;
}
}
}
}
}
void c_VisibleChanged(object sender, EventArgs e)
{
throw new System.Security.SecurityException
(m_strUISecurityException);
}
void c_EnabledChanged(object sender, EventArgs e)
{
throw new System.Security.SecurityException
(m_strUISecurityException);
}
Este código está un poco simplificado. Para completarlo hay que contemplar la posibilidad de manejar controles que viven dentro de objetos ToolStrip. Desafortunadamente estos contenedores no tienen a sus controles "hijos" en una colección Controls sino en Items por lo que hay que considerar esa diferencia también.
En la siguiente actualización voy a hablar de como se autorizan los controles (como funciona el método Authorize.
4.21.2006
Aventuras en un Framework de Seguridad en .NET (1)
1. Que los programadores puedan implementar la seguridad sin programar.
2. Que podamos hacer visibles/invisibles o habilitados/deshabilitados elementos de la IU de una manera totalmente declarativa, ya sea en una BD o en XML.
3. Que esto funcione también en el .NET Compact Framework (v 2.0)
4. Que me pueda integrar a distintos proveedores de autentificación y membresía como los de ASP.NET 2.0 o el ActiveDirectory.
5. Que podamos validar si un método o proceso está autorizado para ejecutarse.
6. Que tengamos reglas simples con excpresiones de autorización.
Ya tengo bastante avance sobre este tema. Antes de empezar, evalué el Enterprise Library de Microsoft. Me pareció demasiado complejo, por lo que tomé algunas ideas de allí para hacer algo más simple. En particular, me gustó mucho el evaluador de expresiones booleanas que tiene para definir autorización. Sin embargo, no me gusta que todo el profiling se tiene que seguir haciendo en código. Quiero algo declarativo.
Lo que tengo listo hasta ahora es:
1. Un control gráfico que con hacer drag and drop en una forma se encarga de habilitar/deshabilitar cualquier control mediante reflection con base en las reglas declaradas para el usuario firmado.
2. La posibilidad de autorizar un método con una sóla función (AuthorizeMethod).
3. Flexibilidad para operar con el Membershipprovider de ASP.NET 2.0 o con Active Directory.
4. Ya funciona en Compact Framework.
4.04.2006
Primera Reunión de la Comunidad de Usuarios de .NET de México D.F. en el 2006
Estoy muy satisfechos con los resultados de la reunión. Además de las pláticas técnicas creo que sentamos las bases de una buena participación de los miembros de la comunidad.
Nos vamos a reunir el último Viernes de cada mes en el mismo lugar.
Me interesa mucho tu retroalimentación.
¿Que opinas de la reunión?
¿Qué te gustaría ver en reuniones futuras?
¿Te gustaría hablar de algún tema?
3.22.2006
Impresiones de Mix06
En orden de más a menos, estos son los temas que me perecieron más interesantes:
1. ASP.NET Atlas
Atlas es un marco para desarrollar rápidamente aplicaciones con el modelo AJAX. Esta tecnología ya tiene una licencia GoLive! para usarse en sitios públicos. Me parece de aplicabilidad inmediata para mejorar la interactividad y respuesta de sitios web.
2. WPF
Windows Presentation Foundation es un nuevo motor para definición y presentación de la capa de interfaz de usuario en aplicaciones. WPF simplemente va a modificar dramáticamente las expectativas de los usuarios de aplicaciones tradicionales (Smart Client). La interfaz se puede definir en código tradicional o en un nuevo lenguaje declarativo llamado XAML. La introducción de este lenguaje declarativo facilita enormemente la cooperación entre diseñadores y desarrolladores en un proyecto de smart client. WPF en mi opinión va a revolucionar la facilidad de uso de nuestras aplicaciones. También creo que un conocimiento temprano de WPF puede ser un factor diferenciador muy importante cuando todo mundo continua haciendo aplicaciones basadas en formas.
3. WPF/E
Este es un subconjunto de WPF (la /E significa "Everywhere") para multiplataforma. Esta tecnología, aunque interesante, me parece que no es muy relevante por ahora ya que se liberará hasta principios (¿mediados?) de 2007. Para sitios públicos creo que va a ser difícil y va a tomar mucho tiempo para que se utilice esta tecnología en lugar de Flash por ejemplo.
Se presentaron algunas otras cosas interesantes como el Expression Intercative Designer con el cual diseñadores pueden crear interfases y contenido para WPF de una manera muy simple y poderosa. También son atractivos el API de Windows Media Center de Vista y los servicios de Windows Live.
2.27.2006
Reflexiones sobre Mis Viajes a Taiwán
Taiwán es muy diferente a México. Es un país donde el ingreso per capita es el doble que en México y el porcentaje de población que vive por debajo de la línea de pobreza es menor al 1%. Las diferencias en el nivel de ingreso son mucho menos marcadas que en México y el nivel de educación promedio es mucho mayor. La población en su mayoría es étnicamente china, de los Chinos que perdieron en la revolución comunista de la China continental.
Viniendo acá parece que salieron ganando con lo que han logrado hacer en esta isla. Este es un país que en los sesentas soñaba con alcanzar el nivel de desarrollo que México tenía en ese momento. Apostaron al futuro (a la industria de las tecnologías de información) y tomaron las medidas necesarias para convertirse en uno de los “tigres asiáticos” y hoy prácticamente son ya una economía desarrollada.
En mi experiencia tratar con un Taiwanés es siempre agradable, independientemente de si es para temas de negocios o simple amistad. He hecho un par de buenos amigos aquí. Siempre son amables y tienen muestran una humildad muy particular. Eso sí, trabajan como locos, toman muy pocas vacaciones y muestran una tenacidad pertinaz para todo lo que sea negocio. Una experiencia que me impactó fue conocer a un tipo dueño de una empresa de tecnología de buen tamaño que me presumía de cómo en 20 años sólo había tomado tres días de vacaciones y tenía una casa de 5 millones de dólares (¿para que puede alguien querer una casa de ese precio si nunca toma vacaciones?).
El éxito económico de Taiwán es innegable. Aún así, como Mexicano relativamente afortunado que soy de vivir con bastante comodidad (y que toma mucho más vacaciones), al hacer una comparación entre nuestras sociedades prefiero evitar saltar a la tan mentada conclusión sobre como tenemos que aprender de los tigres asiáticos. En ciertos aspectos sin duda habrá mucho que aprender, pero ¿hay que vivir para trabajar o trabajar para vivir?
2.16.2006
Seguridad en Nuestros Desarrollos
La realidad es que la mayor parte de los problemas de seguridad pueden evitarse con adecuadas técnicas de programación e incorporando la seguridad como un requerimiento de diseño en nuestros proyectos.
El día de hoy tuve la oportunidad de ofrecer un par de talleres dentro del evento WebSec. El primero sobre desarrollo seguro con C++ y C# y el segundo sobre desarrollo seguro con .NET. Las láminas de las presentaciones de estas pláticas están disponibles aquí y aquí en el sitio de emLink, empresa donde trabajo.
¿Ustedes qué opinan? ¿Por qué nos es tan difícil como programadores poner atención al asunto de la seguridad en nuestros desarrollos?