Custom tool warning: Cannot import wsdl:portType

Hoy mientras desarrollaba la aplicación de Windows Phone que tengo en mente me he encontrado con un error que ha hecho que este dos horas buscando la solución. El problema me ha surgido cuando desde mi aplicación de Windows Phone he hecho referencia a un servicio WCF que tengo en otro proyecto de la solución.  El error era el siguiente

Warning    22    Custom tool warning: Cannot import wsdl:portType
Detail: An exception was thrown while running a WSDL import extension: System.ServiceModel.Description.DataContractSerializerMessageContractImporter
Error: Could not load type ‘System.Runtime.Serialization.DataContractSet’ from assembly ‘System.Runtime.Serialization, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e’.
XPath to Error Source: //wsdl:definitions[@targetNamespace=’http://tempuri.org/’]/wsdl:portType[@name=’IVerblijfService’]    C:UsersNicoDocumentsVisual Studio 2010ProjectsTestAppl1Phone7 – kopieTestAppl1Phone7Service ReferencesVerblijfServiceReference.svcmap    1    1    TestAppl1Phone7
—————————–

Lo que hacia que fuera imposible generar la clase proxy que consumiese el servicio web. Después de navegar un rato por Internet he descubierto que este error se producía cuando el VS2010 se ejecuta en modo administrador,tan solo he tenido que ejecutar el VS2010 en modo “normal” y lo he podido referenciar correctamente el servicio WCF.

Es un error reportado a connect lo podéis ver aquí https://connect.microsoft.com/VisualStudio/feedback/details/624984/error-warnings-when-adding-web-reference-on-windows-phone-7-project?wa=wsignin1.0.

 

Espero que os ayude a no perder tanto tiempo como me paso a mi.

Windows Phone–Tutorial XIV – Usando datos en Windows Phone 7–Servicios REST

En el anterior post vimos como utilizar un servicio SOAP, en este vamos a consumir un servicio REST, para ello vamos a aprovecharnos de todo el código anterior y utilizaremos el servicio de Google de traducción que es de tipo REST.

En nuestro caso recoger los lenguajes que nos permite traducir no es posible ya que Google no lo proporciona para ello

1 private void GetLanguagesGoogle() 2 { 3 Language la = new Language(); 4 la.Code = "en"; 5 la.Name = "English"; 6 _languages.Add(la); 7 8 la = new Language(); 9 la.Code = "es"; 10 la.Name = "Spanish"; 11 _languages.Add(la); 12 13 la = new Language(); 14 la.Code = "ar"; 15 la.Name = "Arabic"; 16 _languages.Add(la); 17 } 18

Para utilizar la traducción de Google llamaremos a la url https://www.googleapis.com/language/translate/v2?key=YOUR-API-KEY&source=en&target=es&q=Hello

Para conseguir tu key debes de registrarte en https://code.google.com/apis/console/?pli=1#welcome

Definimos una variable con la url

1 private readonly string SERVICE_URL = @"https://www.googleapis.com/language/translate/v2?key=YOUR-API-KEY&source={0}&target={1}&q={2}";

Para llamar a un servicio REST debemos de utilizar el objeto WebClient por lo que en nuestro método Traslate

1 private void Translate() 2 { 3 WebClient _proxy = new WebClient(); 4 _proxy.DownloadStringCompleted += new DownloadStringCompletedEventHandler(_proxy_DownloadStringCompleted); 5 string googleTranslateUrl = string.Format(SERVICE_URL, 6 LanguageFromSelected.Code, LanguageToSelected.Code, LanguageFrom); 7 _proxy.DownloadStringAsync(new Uri(googleTranslateUrl)); 8 } 9

Observáis como componemos la URL con los datos y llamamos al método DownloadStringAsync , para recoger el resultado debemos parsearlo ya que al no ser un servicio SOAP nos va a devolver un XML o JSON, para ello utilizaremos DataContractJsonSerializer, en el ejemplo que voy a poner voy a utilizar la v1 de la API de Google en la que no hace falta la API key que os he explicado antes, la url es

https://ajax.googleapis.com/ajax/services/language/translate?v=1.0&q={0}&langpair={1}|{2}
Un ejemplo seria
https://ajax.googleapis.com/ajax/services/language/translate?v=1.0&q=Hello,%20my%20friend!&langpair=en%7Ces
La respuesta que obtendríamos en el navegador es
{
  "responseData": {
    "translatedText": "Hola, mi amigo!"
  },
  "responseDetails": null,
  "responseStatus": 200
}

Con DataContractJsonSerializer deberíamos crear una clase en el model que refleje los datos JSON que vamos a serializar, yo voy a crear dos clases TranslationResponse y ResponseData estas clases deben de estar decoradas con los atributos DataContract y DataMember

1 [DataContract(Name = "translateResponse")] 2 public class TranslationResponse 3 { 4 5 [DataMember(Name = "responseData")] 6 public ResponseData ResponseData { get; set; } 7 8 9 [DataMember(Name = "responseDetails")] 10 public string ResponseDetails { get; set; } 11 12 13 [DataMember(Name = "responseStatus")] 14 public int ResponseStatus { get; set; } 15 }

 
1 [DataContract(Name = "translations")] 2 public class ResponseData 3 { 4 5 [DataMember(Name = "translatedText")] 6 public string TranslatedText { get; set; } 7 8 9 [DataMember(Name = "detectedSourceLanguage")] 10 public string DetectedSourceLanguage { get; set; } 11 }

Ahora para deserializar la respuesta es tan sencillo como el código que tenéis abajo

 

1 void _proxy_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e) 2 { 3 4 DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(TranslationResponse)); 5 MemoryStream ms = new MemoryStream(Encoding. UTF8.GetBytes(e.Result)); 6 7 TranslationResponse t = (TranslationResponse)serializer.ReadObject(ms); 8 9 LanguageTo = t.ResponseData.TranslatedText; 10 11 }

El resultado sería

image

 

Os dejo el código, no os asustéis del nombre del proyecto ya que he reutilizado el anterior, pero en vez de bing es el de Google

 

Nuevo Libro de Windows Phone 7

Hoy Reyes me he encontrado en el blog de Rob Miles  que han publicado un curso de programación para Windows Phone 7 en Microsoft Faculty Center.

Windows Phone 7 Blue Book

Este libro es una introducción para Windows Phone 7 no esperéis conceptos avanzados. Tiene los capítulos

  1. WP7, Introducción a Silverlight
  2. Introducción a Visual Studio 2010,
  3. Interfaces con Silverlight
  4. Consumo de servicios
  5. XNA
  6. Creando aplicaciones para WP7
  7. Windows Phone Marketplace

Podéis descárgalo a través de este enlace.

Windows Phone–Tutorial XIII – Usando datos en Windows Phone 7–Web Services

En Windows Phone 7 no existe una base de datos como en compact framework, existen algunas no oficiales como Sterling aunque al final lo que utilizan por debajo es  IsolatedStorage como ya vimos. No se si Microsoft en futuras versiones nos ofrecerá esta posibilidad pero en mi opinión no creo que sea una característica por la que debemos rasgarnos las vestiduras aunque necesaria si Microsoft quiere que Windows Phone tenga éxito en el ámbito empresarial, aunque ahora mismola única manera de obtener datos y manejarlos es a través de servicios. En este articulo vamos a ver varios tipos de acceso a datos.

El primer tipo que voy a explicar es como acceder a través de un servicio SOAP, para ello vamos a utilizar el servicio Translator de Bing con lo que creamos nuestro proyecto para WindowsPhone y como siempre utilizando MVVM

 

Para utilizar la API de Bing debemos de hacer referencia la servicio http://api.microsofttranslator.com/V2/Soap.svc, para ello en “References” pulsamos botón derecho del ratón y en el menu "Add service reference", añadimos la url anterior.

image

Nos va a generar la referencia al servicio web de Bing

 

image

 

Vamos a crear un modelo con las propiedades Code y Name de los lenguajes

1 namespace BingTranslatorMVVM.Model 2 { 3 public class Language 4 { 5 public string Code { get; set; } 6 public string Name { get; set; } 7 } 8 }

 

Ahora en nuestra ViewModel vamos a utilizar el servicio web que hemos referenciado de Bing para ello  añadimos el using

1 using BingTranslatorMVVM.BingTranslatorService;

Creamos la instancia de la clase LanguageServiceClient que expone el servicio web y llamamos al método para traernos los lenguajes, debemos recordar que al igual que en Silverlight las llamadas a los servicios web son asíncronas. El código para realizar las llamadas para recoger los lenguajes sería

1 private void GetLanguages() 2 { 3 LanguageServiceClient proxy = new LanguageServiceClient(); 4 proxy.GetLanguagesForTranslateAsync(APPID); 5 proxy.GetLanguagesForTranslateCompleted += new System.EventHandler<GetLanguagesForTranslateCompletedEventArgs>(proxy_GetLanguagesForTranslateCompleted); 6 } 7 8 void proxy_GetLanguagesForTranslateCompleted(object sender, GetLanguagesForTranslateCompletedEventArgs e) 9 { 10 11 _codes = e.Result.ToList(); 12 LanguageServiceClient proxy = new LanguageServiceClient(); 13 proxy.GetLanguageNamesCompleted += new System.EventHandler<GetLanguageNamesCompletedEventArgs>(proxy_GetLanguageNamesCompleted); 14 proxy.GetLanguageNamesAsync(APPID, "en", e.Result); 15 } 16 17 void proxy_GetLanguageNamesCompleted(object sender, GetLanguageNamesCompletedEventArgs e) 18 { 19 _names = e.Result.ToList(); 20 LoadLanguages(); 21 } 22 23 private void LoadLanguages() 24 { 25 for (int index = 0; index < _codes.Count; index++) 26 { 27 _languages.Add(new Language 28 { 29 Code = _codes[index], 30 Name = _names[index] 31 }); 32 } 33 }

Como podéis observar hemos tenido que llamar a dos métodos del web service para recuperar los lenguajes que nos da bing para la traducción.

El XAML nos quedaría

1 <Grid x:Name="ContentGrid" 2 Grid.Row="1"> 3 <StackPanel Orientation="Vertical"> 4 <StackPanel Orientation="Horizontal" HorizontalAlignment="Center"> 5 <StackPanel Orientation="Vertical"> 6 <TextBlock TextAlignment="Center">From</TextBlock> 7 <ListBox Name="lbxFrom" Height="140" ItemsSource="{Binding Languages}" Margin="0,3,0,0"> 8 <ListBox.ItemTemplate> 9 <DataTemplate> 10 <TextBlock Text="{Binding Name}" FontSize="20" /> 11 </DataTemplate> 12 </ListBox.ItemTemplate> 13 </ListBox> 14 </StackPanel> 15 <StackPanel Orientation="Vertical" Margin="5,0,0,0"> 16 <TextBlock Margin="10,0,0,0" TextAlignment="Center">To</TextBlock> 17 <ListBox Name="lbxTo" Height="140" ItemsSource="{Binding Languages}" Margin="0,3,0,0"> 18 <ListBox.ItemTemplate> 19 <DataTemplate> 20 <TextBlock Text="{Binding Name}" FontSize="20" /> 21 </DataTemplate> 22 </ListBox.ItemTemplate> 23 </ListBox> 24 </StackPanel> 25 </StackPanel> 26 <TextBox Name="txtInput" Text="{Binding LanguageFrom}" Height="180" /> 27 <Button Name="btnTranslate" Content="Translate"/> 28 <TextBox Name="txtOutput" Text="{Binding LanguageTo}" Height="180" /> 29 </StackPanel> 30 </Grid> 31 </Grid> 32

Me gustaría antes de seguir adelante que os fijaseis en los controles ListBox, en Windows Phone no existe la propiedad SelectedValuePath para indicar la propiedad que contiene el código del item de cada fila.

Si ejecutamos la aplicación tendríamos por el momento

 

image

 

Ahora debemos de recoger los idiomas que seleccione el usuario, para saber el item seleccionado utilizando el patrón MVVM es muy sencillo en nuestra ViewModel crearemos una propiedad del tipo que hacemos binding y la enlazamos mediante DataBinding a la propiedad SelectedItem.

1 private Language _languageFromSelected; 2 public Language LanguageFromSelected 3 { 4 get { return _languageFromSelected; } 5 6 set 7 { 8 _languageFromSelected = value; 9 RaisePropertyChanged("LanguageFromSelected"); 10 } 11 } 12

El código XAML

 

1 <ListBox Name="lbxFrom" Height="140" ItemsSource="{Binding Languages}" SelectedItem="{Binding LanguageFromSelected, Mode=TwoWay}" Margin="0,3,0,0"> 2 <ListBox.ItemTemplate> 3 <DataTemplate> 4 <TextBlock Text="{Binding Name}" FontSize="20" /> 5 </DataTemplate> 6 </ListBox.ItemTemplate> 7 </ListBox>

Una vez que sabemos los idiomas a traducir solo tenemos que llamar al método de traducción con los parámetros correctos.

 

1 private void Translate() 2 { 3 LanguageServiceClient proxy = new LanguageServiceClient(); 4 proxy.TranslateCompleted += new System.EventHandler<TranslateCompletedEventArgs>(proxy_TranslateCompleted); 5 proxy.TranslateAsync(APPID, LanguageFrom, LanguageFromSelected.Code, LanguageToSelected.Code); 6 } 7 8 void proxy_TranslateCompleted(object sender, TranslateCompletedEventArgs e) 9 { 10 LanguageTo = e.Result; 11 } 12

Ejecutamos nuestra aplicación y ya tenemos nuestro traductor

image

 

Os dejo el código, os recuerdo si queréis ejecutarlo debéis de crear vuestra key en Bing Developer Center

 

En el siguiente post veremos como utilizar un servicio REST

Debug DataBinding con PresentationTraceSources.TraceLevel en VS2010

Si recordáis mi articulo de http://geeks.ms/blogs/oalvarez/archive/2009/07/22/debugeando-los-binding-de-wpf.aspx en el que os explicaba como debugear bindings en wpf había una opción en la que nos permitía tracear los bindings en la ventana de Output

 

“PresentationTraceSources.TraceLevel es una clase que te permite enviar a la ventana de Output mucha mas información del DataBinding, podemos monitorizar todos los pasos que se producen en un Binding, para habilitarlo tenemos que añadir el namespace System.Diagnostics y en el binding añadir PresentationTraceSources.TraceLevel=High. Esta opción aparece a partir de la versión 3.5”

1 <Window x:Class="DebugBindings.Window1"... xmlns:trace="clr-namespace:System.Diagnostics;assembly=WindowsBase"> 2 <StackPanel> 3 <TextBox Text="{Binding ElementName=slider, Path=Value, Mode=OneWay, trace:PresentationTraceSources.TraceLevel=High}" Height="30" Width="100" Margin="10"/> 4 <Slider Minimum="0" Maximum="100" Value="20" Margin="10" x:Name="slider" /> 5 StackPanel> 6 Window>

En VS2010 no funciona correctamente y es debido a que a la hora de instalarse el VS2010 las settings con las que se instala no se activa esta opción, para activarla vamos a Tools, Options, Debugging, Output Window, WPF Trace Settings, Data Binding y lo cambiamos al valor Warning

 

ToolsOptionsDataBinding

Este tip esta sacado de Karl on WPF y me ha venido muy bien para unas pruebas que estoy realizando.