Utilizar una maquina de Virtual PC en Hyper-V

Hola, ayer estaba pasando maquinas de Virtual PC a Hyper-V y tuve un problema que quiero comentar casi a modo recordatorio. Cuando arrancaba la maquina virtual desde Hyper-V iba perfecto exceptuando dos pequeños detalles, el primero no podía instalar Integration Serviuces de Hyper-V, este era sencillo de solucionar debía de desinstalar las Virtual Machine Additions desde el panel de Control como si fuese un programa mas y después instalar Integration services.

El segundo problema me costo un poco mas solucionarlo y era que mi maquina virtual no veía ninguna red y en las settings había configurado correctamente la red, el problema venia debido a que era una maquina de virtual PC y me di cuenta que el problema era debido a que Virtual Machine Bus Driver no estaba instalado correctamente , para conseguir que esta maquina viese las redes hay que realizar los siguientes pasos:

1. Ejecutar msconfig
2. ir a la pestaña Boot
3. click Advanced options
4. check Detect HAL
5. click OK
6. click OK
7. reboot la vm
8. aplicar Integration Services

Una vez realizado estos pasos por fin mi maquina virtual tenia conexión de red.

 

Hyper-V 2008 R2 Essentials
Microsoft Windows Server 2008 – Das Handbuch, 2. Auflage, erweitert f�r Hyper-V
Windows Server 2008 Hyper-V Unleashed

“The Path XXX Contains More Than the Allowed 259 Characters" in TFS

Hola, este es el error que me he encontrado cuando he ido a sincronizar uno de mis proyectos en el TFS, el cual me ha dejado descolocado por un momento que en un Windows 7 x64 se tenga esta limitación, pero supongo que será por mantener la compatibilidad hacia atrás con XP (maxpath). Concretamente el error es:

TF10128: The path <path> contains more than the allowed 259 characters. Type or select a shorter path.

Este error se me ha producido concretamente con las branchs del proyecto cuya nomenclatura hace que la profundidad del path sea grande

La verdad es que mapeados mis proyectos del TFS en el directorio por defecto de Visual Studio "C:UsersusernameDocumentsVisual Studio 2008Projects" con lo que pierdo + de 50 caracteres con lo que ya me veía que tenia que cambiar el mapeo de mis proyectos. Antes de realizar esta acción he investigado un poco y he visto que se podía realizar una entrada en el registro que hacia que este path se convirtiese en una sola letra sin tener que mover mis proyectos, algo asi como el comando SUBST.

He puesto en un fichero con extensión .reg las siguientes líneas

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINESYSTEMCurrentControlSetControlSession ManagerDOS Devices]"V:"=\DosDevices\C:\Users\username\Documents\Visual Studio 2008\Projects

Doble Click en el fichero y una vez reiniciado tenemos la letra V en vez de ese path

 

 

 

Inside the Microsoft Build Engine: Using MSBuild and Team Foundation Build
Team Foundation Server Recipes (Problem-Solution Approach)
Professional Team Foundation Server

Como tener una única instancia de mi aplicación en WPF


Un tema recurrente en WPF es como conseguir que solo haya una instancia de tu aplicación, existen varios métodos para ello que vamos a ir viendo.

1.Comprobando si existe el proceso.

Quizá sea la forma mas simple, en la lista de procesos chequeamos si ya existe

1 public partial class App : Application 2 { 3 protected override void OnStartup(StartupEventArgs e) 4 { 5 // Get Reference to the current Process 6 Process thisProc = Process.GetCurrentProcess(); 7 // Check how many total processes have the same name as the current one 8 if (Process.GetProcessesByName(thisProc.ProcessName).Length > 1) 9 { 10 // Si ya existe sacamos un mensaje. 11 MessageBox.Show("La aplicación ya se esta ejecutando."); 12 Application.Current.Shutdown(); 13 return; 14 } 15 16 base.OnStartup(e); 17 } 18 }

El único problema que tiene este método es que si a tu aplicación se le pasa argumentos no nos serviría.

 

2.Usando WindowsFormsApplicationBase

En la librería Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase existe una característica que  nos permite controlar si ya se esta ejecutando nuestra aplicación y soluciona el problema anterior. Realmente se utiliza igual que en Windows Forms, eliminamos los ficheros App.xaml y App.cs de manera que quitamos el punto de entrada de nuestra aplicación, añadimos la clase Main con el siguiente código.

1 class Program 2 { 3 [STAThread] 4 public static void Main(string[] args) 5 { 6 WindowsFormsApp wrapper = new WindowsFormsApp(); 7 wrapper.Run(args); 8 } 9 }

La clase Wrapper tendría el código:

 

1 class WindowsFormsApp : WindowsFormsApplicationBase 2 { 3 private App _wpfApp; 4 5 public WindowsFormsApp() 6 { 7 // habilitar una unica instancia 8 IsSingleInstance = true; 9 } 10 11 protected override bool OnStartup(StartupEventArgs e) 12 { 13 14 _wpfApp = new App(); 15 _wpfApp.Run(); 16 17 return false; 18 } 19 20 protected override void OnStartupNextInstance( 21 StartupNextInstanceEventArgs e) 22 { 23 if (e.CommandLine.Count > 0) 24 { 25 _wpfApp.ProcessArguments(e.CommandLine.ToArray()); 26 } 27 } 28 }

Por ultimo la clase App

 

1 class App : Application 2 { 3 protected override void OnStartup(StartupEventArgs e) 4 { 5 base.OnStartup(e); 6 7 MainWindow window = new MainWindow(); 8 window.Show(); 9 } 10 11 public void ProcessArguments(string[] args) 12 { 13 //Procesamos los parametros 14 15 } 16 }

Como veis sencillo, aunque a mi no me gusta, ya que metemos características de Winforms, tenemos que añadir librerías y es demasiado código para lo que queremos hacer.

3.Utilizando Mutex

Yo es la que utilizo siempre, es bastante sencilla de implementar y de mantener.

1 private static bool FirstInstance 2 { 3 get 4 { 5 bool created; 6 string name = Assembly.GetEntryAssembly().FullName; 7 8 Mutex mutex = new Mutex(true, name, out created); 9 return created; 10 } 11 }

Si recordamos como funciona Mutex, la primera instancia que lo crea pasa a ser propietaria del thread y con la variable created, controlamos si es la instancia que ha creado Mutex, sino es asi nos devolverá un false , de manera que nuestra App.Xaml.cs quedaría  

1 protected override void OnStartup(StartupEventArgs e) 2 { 3 if (FirstInstance) 4 base.OnStartup(e); 5 else 6 { 7 MessageBox.Show("Application is already running."); 8 Application.Current.Shutdown(); 9 } 10 }

Como veis mas sencillo que en el caso anterior y mucho mas elegante.

Libros de WPF recomendados

Pro Wpf in C# 2008: Windows Presentation Foundation with .Net 3.5
WPF 4 Unleashed
WPF Recipes in C# 2008: A Problem-Solution Approach

White Paper Cross Platform WPF Silverlight Windows Phone 7

  
Hoy en el lanzamiento oficial de Windows Phone, me he encontrado en el blog de ScootLogic un WhitePaper acerca de como unificar el desarrollo para estas tres tecnologías.

Puedes descargarlo desde aquí: WPF and Silverlight Cross Platform Development White Paper (PDF, 1.8 MBytes)

 

Es interesante de leer y son solo 16 paginas

 
 

 

 
Silverlight 4 in Action
 

 
Silverlight 4 Unleashed
 
Programming Windows Phone 7
 
   
 
 
 
 
     

   

WCF Modificar la respuesta SOAP antes de la Deserialización

  
Hola, después de mucho tiempo sin escribir debido a vacaciones, trabajo agobiante, prepararme para mi otra afición (correr)…, me he propuesto volver a escribir en el blog, quizás no con tanta periodicidad como antes pero no olvidarme de el.

Para este primer articulo después del kitkat, voy a hablar de un problema que he tenido recientemente.  La aplicación que estamos desarrollando es muy consumidora de servicios web de Java servidos por WebLogic 8. Recientemente la parte de WebLogic ha hecho una migración de la versión 8 a la 11 y han activado la multireferencia para los servicios Web (Consultar http://www.w3.org/TR/2000/NOTE-SOAP-20000508/#_Toc478383520), esto modificaba el mensaje SOAP devuelto por WebLogic (no puedo poner ninguno de ejemplo por confidencialidad) la teoría dice que no debía de afectar a los clientes porque era estándar.
Como siempre, yo me rio de los estándares que implementan las diferentes empresas, por supuesto los clientes .Net eran incapaces de deserializarlos ya que no entendían el mensaje SOAP, estos mensajes tenían en los campos que aplicaba la multireferencia el indicativo href on el valor ID_XXX y al final del mensaje venia el valor de esos campos

<xsd:int id="ID_7" xsi:type="xsd:int">62</xsd:int>

<xsd:int id="ID_73" xsi:type="xsd:int">104</xsd:int>

A la hora de deserializar WCF no devolvía ningún error sino que el valor de esos campos eran siempre 0.

WCF también implementa multireferencia y es capaz de deserializarla pero los mensajes SOAP que se generan son diferentes a los que generaba WebLogic 11.

La solución que encontré fue crear un behavior de WCF para el cliente, para crear un behavior os recomiendo que leáis esta entrada de Juanlu http://geeks.ms/blogs/jlguerrero/archive/2008/12/07/wcf-un-behavior-para-personalizar-cabeceras-http.aspx que indica como crear un behavior de WCF que personaliza las cabeceras SOAP para todos los mensajes enviados por el cliente.

Si os fijáis en el código del behavior el codifica el método BeforeSendRequest en el que puedes modificar el mensaje que envía el cliente al servidor, pero en este caso queríamos modificar lo que recibíamos del servidor para crear un mensaje SOAP que .NET podía deserializar, para ello debemos de codificar el método AfterReceiveReply , este método tiene un parámetro (reply) que es el mensaje enviado por el servidor, pero para tratarlo debemos de realizar unos cuantos pasos, primero debemos de saber que este mensaje puede ser leído solo una vez, si intentas leerlo una segunda vez te da una bonita excepción.

El primer paso es convertir este mensaje a un XmlDocument para poder tratarlo, el código seria el siguiente  

1 Message newMessage = null; 2 MessageBuffer msgbuf = reply.CreateBufferedCopy(int.MaxValue); 3 4 var copy = msgbuf.CreateMessage(); 5 6 7 XmlDocument doc = new XmlDocument(); 8 9 MemoryStream ms = new MemoryStream(); 10 11 XmlWriter writer = XmlWriter.Create(ms); 12 13 copy.WriteMessage(writer); 14 15 writer.Flush(); 16 17 ms.Position = 0; 18 19 doc.Load(ms);

Una vez que lo tenemos en formato XmlDocument, lo podemos tratar para cambiar las referencias de href por los valores correspondientes de manera que el servicio pudiera deserializarlos

1 /// <summary> 2 /// Se cambia el mensaje Soap, cambiando los atributos href por los valores correspondiente 3 /// </summary> 4 /// <param name="xmldoc"></param> 5 private void ChangeMessage(ref XmlDocument xmldoc) 6 { 7 //Se transforma a Xdocument para realizar LinQ 8 XDocument xdoc = ToXDocument(xmldoc); 9 10 11 List<string> href = new List<string>(); 12 Dictionary<string, string> id = new Dictionary<string, string>(); 13 Dictionary<string, XAttribute> type = new Dictionary<string, XAttribute>(); 14 15 //Se buscan los elementpos con atributo id 16 17 IEnumerable<XElement> elList = 18 from el in xdoc.Descendants() 19 where el.Attribute("id") != null 20 select el; 21 foreach (XElement el in elList) 22 { 23 if (el.Attribute("id").Value.StartsWith("ID_")) 24 { 25 id.Add(el.Attribute("id").Value.ToString(), el.Value); 26 type.Add(el.Attribute("id").Value.ToString(), el.Attribute("{http://www.w3.org/2001/XMLSchema-instance}type")); 27 } 28 } 29 30 //Se buscan los elementos con atributo href y se sustituye por el valor que se 31 IEnumerable<XElement> elListHref = 32 from el in xdoc.Descendants() 33 where el.Attribute("href") != null 34 select el; 35 foreach (XElement el in elListHref) 36 { 37 string value = id[el.Attribute("href").Value.ToString().Replace("#", "")]; 38 el.Add(new XAttribute(type[el.Attribute("href").Value.ToString().Replace("#", "")].Name, type[el.Attribute("href").Value.ToString().Replace("#", "")].Value)); 39 el.Attribute("href").Remove(); 40 el.Value = value; 41 } 42 xmldoc = ToXmlDocument(xdoc); 43 }

Una vez que tenemos el XMLDocument cambiado, la manera de asignarlo a la variable reply es a través de XMLReader,para ello transformamos el XMLDocument a XMLReader

1 ms.SetLength(0); 2 3 writer = XmlWriter.Create(ms); 4 5 doc.WriteTo(writer); 6 7 writer.Flush(); 8 9 ms.Position = 0; 10 11 XmlReader reader = XmlReader.Create(ms); 12 13 reply = Message.CreateMessage(reader, int.MaxValue, reply.Version);

De esta manera hemos cambiado el mensaje SOAP adaptándolo a nuestras necesidades

Libros recomendados para este tema

 
Professional WCF 4: Windows Communication Foundation with .NET 4 (Wrox Programmer to Programmer)
Pro WCF 4: Practical Microsoft SOA Implementation
Expert WCF 4: Maximizing Windows Communication Foundation