Friday, November 26, 2010

Nuevos blogs y productos de Spenta


Este no es un post técnico, pero sí que es muy interesante para mí porque me toca de cerca.


Empiezo haciendo un poco de publicidad a dos blogs.


  • El primero de ellos de uno de un crack con muchísima experiencia en SharePoint y que por fin se ha animado a compartir su sabiduría con el mundo: sharejoint.blogspot.com. El propio título lo dice todo... comparte tu... ejem... joint :-)

  • El segundo es de una visionaria, una diseñadora con mayúsculas que convierte una página web en un recital para la vista: bymadeinmind.blogspot.com. Ella es en gran parte la responsable del nuevo producto de la casa en la que trabajo...



StreetCare, de Spenta. Es el nuevo producto de crowdsourcing (cómo mola el palabro) para el report de incidencias en un ayuntamiento por parte de los propios ciudadanos. Echadle un vistazo al vídeo y a la página web, porque no tiene desperdicio.

Espero postear durante el finde algo más técnico.

Tuesday, November 16, 2010

Modal popup de jQuery con EventHandling de Repeater en codebehind

Siguiendo con los posts acerca de jQuery, espero que este os solucione la papeleta más de una vez. Muchos leeréis el título y os preguntaréis para qué necesito manejar los eventos en el codebehind, si utilizo jQuery y ésta es una tecnología diseñada para correr en cliente. De hecho, muchos listillos expertos dan esa respuesta en muchos foros.

Mi situación es la siguiente: tengo un Repeater ASP.NET, y en cada uno de ellos un botón que abre un modal dialog de jQuery como el de mi anterior post. Dentro de ese popup existe un link que debe ser construido irremediablemente en código en servidor, y que evidentemente, será distinto para cada uno de mis popups (recordemos que vienen de botones distintos del Repeater).

La solución que aquí planteo seguramente no sea la mejor, pero era la que me permitía mantener la gestión de eventos que ya tenía en los botones del Repeater utilizando el atributo CommandName de asp:Button. Lo que haré será registrar la llamada a un nuevo método en el evento ItemCommand del Repeater, de la siguiente manera:


private void RptDocumentInstancesListItemCommand(object source, RepeaterCommandEventArgs e)
{
try
{
if (e.CommandName == "Ver")
{
...
Page.ClientScript.RegisterStartupScript(Page.GetType(), "openPopupDialogVer", string.Format("", idDocGuid)).Value));
...
}
}
}


Y modificar el script que abre el modal popup en jQuery, pasándole por parámetro el valor que he tenido que calcular en el codebehind (que en mi caso es un identificador de un documento) y asignándoselo, si quiero, a otro a otro input del formulario.


function openPopupDialogVer(docGuid) {
$(function () {
$('input[id^="idDoc"]').val(docGuid);
$("#panelVer").dialog('open');
return false;
});
}


Así conseguimos que al pasar por el evento ItemCommand, se llame a la función javascript que tiene que llamar jQuery (nuestro .dialog('open')).

Estoy listo para las críticas :-)

Wednesday, November 10, 2010

Modal Popup de jQuery en MOSS 2007 con EventHandling de botones ASP.NET

Desde hace un par de semanas he dejado a un lado SharePoint 2010 y he estado retocando un viejo proyecto de SharePoint 2007. Entre otras muchas cosas, me ha tocado hacer frente a la configuración del AjaxControlToolkit en un portal de publicación, algo que ya había hecho hacía un año sin problemas. Con esto quería conseguir cosas como los ModalPopupExtender que tanto gustan a los UX designers.

Pues bien, será que me he vuelto más viejo, más tonto, o ambas, porque aún siguiendo el manual "straightforward" de MS, no logré hacer que funcionara (claro, que también puede ser la cantidad ingente de modificaciones que hay que hacer al web.config... grrr).

Hablando con Luru del problema, me acabó convenciendo de que jQuery es mucho mejor, y de que además "es el futuro, maaacho". Sinceramente mis recuerdos de hace un año sobre jQuery eran desastrosos, por eso elegí AJAX en su día. El caso es que la desesperación hizo que me bajara los .js de jQueryUI y una CSS que me gustó de su página, con la intención de conseguir algo parecido a esto.

Mmmhhh... no tenía mala pinta, pero ¿funcionaría? Meto los .js y los CSS en el LAYOUTS de la carpeta 14 12 y los añado en la master page, haciendo referencia directa a la ruta "_layouts/jquery-ui-1.8.6.custom.js" y a la de jquery. También incluyo el siguiente código en mi User Control con el panel que quiero mostrar en el popup.



$(document).ready(function () {
$("#panelAdjuntar").dialog(
{
autoOpen: false,
modal: true
});

$("#btAdjuntar").click(function (event) {
$("#panelAdjuntar").dialog('open');
});
});




En donde btAdjuntar es un botón en cliente normal, de los de toda la vida:






Y el panelAdjuntar es el div que quiero mostrar en el modal popup. Este div incluye varios controles ASP.NET como Label, Button, TextBox, FileUploads, y sus respectivos EventHandler.



...



Pruebo todo esto y voilá. Funciona! Juhuuu! Muestra el modal popup y además es bonito :-)

Le doy a uno de los botones ASP.NET de dentro de nuestro div panelAdjuntar y........... me c$#@-kW%a!!! No funciona nada. Depuro el código y tampoco. Vamos, que no hace nada, que no pilla el click del botón :-(

Un par de minutos más tarde encontré la solución aquí. Al parecer hay que modificar el código moviendo el div al form, y que así pille los eventos. El script me queda así entonces.





Y ahora sí que funciona el modal popup. Con sus botones ASP.NET y todo. Y además sigue siendo chulo :-)

Y yo... definitivamente me paso a jQuery. Gracias Luru!


PS: ¿Y vosotros? ¿jQuery o Ajax?.......


Friday, November 5, 2010

Integración Facebook - ASP.NET con Graph API (III)

En esta última parte del post acerca de la integración de Facebook con ASP.NET (parte 1 y parte 2) explicaré por encima el nuevo método de autenticación que utilizaremos para poder postear comentarios en el muro ASP.NET de nuestro grupo de Facebook, OAuth.

Al parecer OAuth está últimamente arrasando en cuando a protocolos de autenticación se refiere, y ya lo están utilizando Google, Twitter, y Facebook, entre otros muchos.

Graph API utiliza OAuth 2.0 como método de autenticación basado en el intercambio de tokens. Como ya comentamos en la segunda parte de este post, lo primero que tenemos que hacer para recuperar cualquier tipo de dato de las entrañas de Facebook (posts, imágenes, información de usuarios) es obtener un access token público. Una vez obtenido ese token, podremos solicitar un access token privado, con el que el usuario podrá interactuar con Facebook. La recuperación de este token privado implica los siguientes pasos:
  • Obtención de un token público con el que poder instanciar un nuevo objeto de nuestro conector FacebookAPI (al que si os acordáis deberemos pasar el AppID y el AppSecret de nuestra aplicación residente en FB).
  • Solicitud de un access token privado, mediante redirección a la página de autenticación de Facebook (en donde el usuario introducirá su login y password) pasándole por parámetro el token público que ya tenemos.
  • Redirección por parte de Facebook, y sólo en caso de éxito en el login, a la página configurada en la Postback Url de la aplicación residente en FB, en donde se nos pasa por parámetro un código para intercambiar por el access token privado.
  • Obtención de un token privado al intercambiarlo por el código devuelto.
  • Una vez tenemos el nuevo access token privado, podemos desechar el público y utilizar éste, que nos permitirá realizar llamadas POST sobre el objeto FacebookAPI para postear datos, o simplemente poder obtener los comentarios de los posts en el muro.

Como véis, éste método tiene 2 claras ventajas:
  • Delega en Facebook la crítica parte de login/password que siempre nos puede traer de cabeza, y...
  • Nos proporciona un token con una vida de 60 minutos que tendremos que incluir en cada llamada a Facebook, y con el que tendremos acceso al mundo Facebook.

Genial, ¿no? Pues vamos con un poco de código.

En el botón estilo "Connect with Facebook" manejamos el evento del click generando una URL de autenticación del estilo https://graph.facebook.com/oauth/client_id=[]& redirect_uri=[]&scope=publish_stream,read_stream.



///
/// Handles the Click event of the btConnect control.
///

/// The source of the event.
/// The instance containing the event data.
protected void BtConnectClick(object sender, EventArgs e)
{
var api = new FacebookAPI(this.Token);
var authParameters = new Dictionary

{
{ "client_id", AppId },
{ "redirect_uri", PostbackUrl },
{ "scope", "publish_stream,read_stream" }
};
var urlConnect = api.GetAuthorizeUrl(authParameters);

this.Response.Redirect(urlConnect.AbsoluteUri, true);
}


Si el usuario autoriza realiza el login con éxito y autoriza la aplicación, Facebook redirige al usuario de vuelta con un código que utilizaremos para intercambiar por el token privado. Este intercambio lo realizaremos mediante llamando a nuestro método sobrecargado GetAccessToken, esta vez con más parámetros que en la parte 2 de este post.


///
/// Gets the access token for authenticated users.
///

/// The app id.
/// The app secret.
/// The redirect URL.
/// The app code from callback.
/// Authenticated access token.
public static string GetAccessToken(string appId, string appSecret, string redirectUrl, string appCodeFromCallback)
{
if (string.IsNullOrEmpty(appId) || string.IsNullOrEmpty(appSecret) || string.IsNullOrEmpty(redirectUrl) ||
string.IsNullOrEmpty(appCodeFromCallback))
{
return null;
}

var url =
string.Format(
"https://graph.facebook.com/oauth/access_token?client_id={0}&redirect_uri={1}&client_secret={2}&code={3}&req_perms=publish_stream",
appId,
redirectUrl,
appSecret,
appCodeFromCallback);

string accessTokenValue = null;
var request = WebRequest.Create(url) as HttpWebRequest;

try
{
if (request != null)
{
using (var response
= request.GetResponse() as HttpWebResponse)
{
if (response != null)
{
var reader
= new StreamReader(response.GetResponseStream());

// access_token is the first of the parameters
accessTokenValue = reader.ReadToEnd();
accessTokenValue = accessTokenValue.Split(new[] { "&" }, StringSplitOptions.RemoveEmptyEntries)[0];
accessTokenValue = accessTokenValue.Replace("access_token=", string.Empty);
}
}
}
}
catch (WebException e)
{
throw new FacebookAPIException("Server Error", e.Message);
}

return accessTokenValue;
}


Con este access token privado podremos hacer llamadas como postear un nuevo mensaje en el muro de nuestro grupo de Facebook, a través de una llamada al método ya visto Call, pero de tipo POST.


///
/// Makes a Facebook Graph API POST request.
///

/// The path for the call,
/// e.g. /username
/// A dictionary of key/value pairs that
/// will get passed as query arguments. These determine
/// what will get set in the graph API.
/// JSON object of the request.
public JSONObject Post(string relativePath, Dictionary args)
{
return this.Call(relativePath, HttpVerb.POST, args);
}


Y podremos gestionar el evento click del botón de postear un nuevo comentario así:


///
/// Handles the Click event of the btMessage control.
///

/// The source of the event.
/// The instance containing the event data.
protected void BtMessageClick(object sender, EventArgs e)
{
var api = new FacebookAPI(this.Token);
var url = string.Format("/{0}/feed", GroupId);
var postParameters = new Dictionary

{
{ "message", this.tbMessage.Text }
};
api.Post(url, postParameters);
}


Colgaré todo el código de esta mini-integración con la GraphAPI en un futuro, pero de momento aquí finaliza esta serie de posts.

Espero que os haya resultado interesante. En la mente tengo hacer algo del estilo para Android, aunque todavía queda mucho para eso, ufff...

Por supuesto cualquier otra idea será muy bien recibida :-)