Hack-a-thon, repaso a las novedades de networking de Windows Phone 7

Este fin de semana en Málaga se ha celebrado el Hack-a-thon un evento de Microsoft para incentivar el desarrollo de aplicaciones de Windows Phone 7 en entornos universitarios. Es todo un fin de semana de programación de apps y entre medias los desarrolladores pueden elegir las charlas que quieres escuchar. Así que es un agenda dinámica que se decide en base a las valoraciones.

Yo es la segunda vez que participo en un evento de este tipo y en mi caso la charla que me ha tocado es la de Networking. Así que estando ahora mismo en el evento aprovecho para hacer un repaso de las novedades de Windows Phone 7.1 (Mango) en el apartado de comunicaciones.

clip_image002

Peticiones HTTP

Dentro de apartado de peticiones HTTP de toda la vida, WP7 tiene dos clases para realizar este trabajo: WebClient y HttpWebRequest (+Response). Las dos API se distinguen una de la otra por la simplicidad y opciones que ofrecen.

Hay que recordad que todas las comunicaciones en WP7 son asíncronas.

WebClient

WebClient es la API más sencilla para hacer peticiones HTTP, simplemente hay que crear una instancia de esta clase, suscribirse al evento deseado, por ejemplo, DownloadStringCompleted y llamar al método DownloadStringAsync(Uri) para descargarse el contenido de una URI como un string.

public partial class MainPage : PhoneApplicationPage
{
WebClient client;

// Constructor
public MainPage()
{
InitializeComponent();

client = new WebClient();
client.DownloadStringCompleted +=
new DownloadStringCompletedEventHandler(
client_DownloadStringCompleted);
}

void client_DownloadStringCompleted(object sender,
DownloadStringCompletedEventArgs e)
{
if (e.Error == null)
{
XElement twitterElements = XElement.Parse(e.Result);


var postList =
from tweet in twitterElements.Descendants("status")
select new TwitterPost
{
UserImage = tweet.Element("user").Element("profile_image_url").Value,
PostText = tweet.Element("text").Value,
DatePosted = tweet.Element("created_at").Value
};

tweetsListBox.ItemsSource = postList;
}
}

private void loadButton_Click(object sender, RoutedEventArgs e)
{
string url = "http://twitter.com/statuses/user_timeline/" +
nameTextBox.Text + ".xml";
client.DownloadStringAsync(new Uri(url));
}
}

En este ejemplo podemos ver como en los argumentos DownloadStringCompletedEventArgs podemos obtener una propiedad llamada Result que contiene el string con el contenido de la petición.

En este tipo de peticiones no podemos añadir cookies ni configurar ningún otro tipo de propiedad para la petición.

Las opciones de personalización son:

  • Añadir cabeceras en la petición y leer las cabeceras de la respuesta.
  • Configurar credenciales para autenticación de usuarios.
  • Permitir la lectura buffereada del contenido de la lectura y de la escritura.
  • Codificación usada para lectura y escritura.

HttpWebRequest

HttpWebRequest es la clase de bajo nivel que permite hacer peticiones HTTP configurando todas las opciones que queramos, es mucho más flexible, pero más complejo de consumir. Estas API utiliza el APM (Asychonous Programming Model) de .NET lo que significa que utiliza para las notificaciones asíncronas IAsyncResult.

Estas son las características:

  • Acceso a todas las cabeceras.
  • Podemos agregar cookies en las peticiones y leer las cookies de respuesta.
  • Podemos especificar el método de la petición (GET o POST)
  • Podemos escribir en el cuerpo de la petición.

Así tenemos un ejemplo completo de peticiones usando HttpWebRequest:

public class ComplexRestRequest : BaseRequestProcessor
{
public override void ProcessRequest(Uri uri, string body)
{
content = body;

request = HttpWebRequest.Create(uri);
request.Method = "POST";

request.Headers["Authorization"] = AuthorizationService.AuthorizationToken.Token;
request.Headers["IsComplex"] = "true";
request.BeginGetRequestStream(new AsyncCallback(OnBeginGetRequestStream), null);

}

private void OnBeginGetRequestStream(IAsyncResult result)
{
Stream stream = request.EndGetRequestStream(result);
byte[] buff = System.Text.Encoding.UTF8.GetBytes(content);
stream.Write(buff, 0, buff.Length);
buff = null;

request.BeginGetResponse(OnBeginGetResponse, null);
}

private void OnBeginGetResponse(IAsyncResult result)
{
try
{
response = request.EndGetResponse(result);
string authorizationHeader = response.Headers["Authorization"];
if (!string.IsNullOrEmpty(authorizationHeader))
{
AuthorizationService.UpdateAuthorizationToken(authorizationHeader);
}
string content = null;
if (response.ContentLength > 0L)
{
using (Stream stream = response.GetResponseStream())
{
using (StreamReader reader = new StreamReader(stream, Encoding.UTF8, true))
{
content = reader.ReadToEnd();
}
}
}

FireEndRequestCompleted(new HttpResult(content, false, null));
}
catch (Exception ex)
{
Trace.WriteLine(ex.ToString());
FireEndRequestCompleted(new HttpResult(null, true, ex));
}
}

private WebRequest request;
private WebResponse response;
private string content;
}

Socket

La siguiente gran funcionalidad de comunicaciones, muy esperada, en Windows Phone 7 son los sockets. Los sockets permiten una comunicación más directa en un canal de comunicación orientado a conexión (TCP) o no orientado a conexión (UDP y multicasting).

clip_image004

Windows Phone 7 soporta direcciones IPv4 pero no soporta IPv6. Toda la API es asíncrona.

Background file transfers

Si tenemos que descargar o subir ficheros al isolated storage de nuestra aplicación, pero queremos que esa descarga se haga cuando el usuario no esté usando la conexión a internet de su dispositivo móvil, podemos usar Background file transfers.

Esta API permite programar la descarga de un fichero al almacenamiento aislado de Windows Phone 7 incluso si nuestra aplicación no está ejecutándose. Soporta HTTP y HTTPS pero no FTP. Alguna de las cabeceras HTTP están reservadas, principalmente las de control de cache.

Estos son los valores de cuota:

  • Tamaño máximo de subida: 5MB
  • Tamaño máximo de descarga sobre 2G/3G: 20 MB
  • Tamaño máximo de descarga sobre WiFi: 100MB

API de información de comunicaciones

Todas las aplicaciones que utilicen recursos online deberán de ser tolerantes a faltas de conectividad por parte del usuario en su dispositivo. Si el usuario está modo avión, no tiene cobertura ni Wifi, la aplicación no debería de fallar y cerrarse, sino que debería de ofrecer la posibilidad de reconectarse de nuevo.

Para eso necesitamos saber cuál es el estado de las comunicaciones del dispositivo.

  • Consulta del operador móvil
    • DeviceNetworkInformation.CellularMobileOperator
  • Consulta si hay red disponible
    • DeviceNetworkInformation.IsNetworkAvailable
  • Consulta si hay red celular 2G/3G
    • DeviceNetworkInformation.IsCellularDataEnabled
  • Consulta si el romaing está habilitado
    • DeviceNetworkInformation.IsCellularDataRoamingEnabled
  • Consulta si el WiFi está habilitado
    • DeviceNetworkInformation.IsWiFiEnabled

Eligiendo la mejor serialización para aplicaciones móviles

Cuando desarrollamos aplicaciones móviles tenemos que tener en cuenta el tamaño de los datos que enviamos al cliente. Por eso tenemos que elegir la serialización que permite utilizar el menor tamaño para enviar los datos. Aquí tenemos una comparativa de los diferentes formatos para los mismos datos envíados.

Wire Serialization Format

Size in Bytes

ASMX SOAP – DataSet (XML)

39670

ODATA XML

73786

ODATA JSON

34030

REST + JSON

15540

REST + JSON GZip

8680

Luis Guerrero.