Browsing posts in: Web

Consumiendo APIs desde ASP.NET MVC

Hoy me preguntó alguien que está aprendiendo ASP.NET MVC cuál era la mejor forma de consumir una API usando este framework; y no seré yo quien le responda cuál es la mejor forma, pero al menos era una pregunta que da para post, y no está mal que me critiquéis mi solución.

La API la vamos a consumir desde el servidor, ya que consumirla desde JavaScript parece cumbersome; aunque puede tener sus ventajas si tenemos restricciones por IP, aunque sea jugar sucio, al mismo tiempo podríamos estar exponiendo datos que no nos interesan en una aplicación cliente, o podríamos tener el caso en el que el cliente no tenga JS activado, caso tan raro como cierto.

Al lío: lo primero que vamos a hacer es instalar Unity en el proyecto Web de la solución si usamos MVC 5, o cantar algo si ya usamos ASP.NET vNext, ya que usa inyección de dependencias de por sí, por lo que no tendremos que preocuparnos por el contenedor.

Después de un paso obvio, vamos a definir la interfaz que será la fundación sobre la cual vamos a desarrollar nuestra propia abstracción sobre la API externa, pokeapi.co, en este ejemplo. Lo primero que haremos será definir una abstracción sobre HttpClient.

    public interface IHttpCommunicator
    {
        string BaseAddress { get; set; }

        Task<string> SendGetRequestAsync(string uri);
        Task<string> SendPostRequestAsync<T>(string uri, T data);
    }

Una vez tenemos una abstracción sobre el servicio de comunicación, tendremos que definir una abstracción sobre la API que usaremos, con los métodos que usaremos, donde inyectaremos el servicio HTTP y haremos uso de él:

    public interface IPokeApiClient
    {
        Task<Pokemon> GetPokemon(int id);

        Task<Ability> GetAbility(int id);

        Task<Models.Type> GetType(int id);
    }

Y, finalmente, inyectaremos la abstracción de la API externa en nuestros controladores, u otros servicios donde la vayamos a usar:

        [HttpPost]
        public async Task<ActionResult> Pokemon(int id)
        {
            var pokemon = await _pokeApiClient.GetPokemon(id);
            var vm = new PokemonViewModel
            {
                Pokemon = pokemon
            };
            return View(vm);
        }

Aunque no será la mejor implementación, proporciona una abstracción útil y sencilla sobre APIs de terceros, a pesar de provocar una dependencia temporal sobre definir la BaseAddress desde un punto externo, pero nos permite reutilizar el servicio de HTTP en cualquier parte.

La solución completa se puede encontrar en GitHub.


Rewriting ¿better? WCF RIA Services callbacks while reusing code

There’s a legacy project I’ve been working on that has recently had it’s environment migrated to a different architecture, meaning, problems have arisen, but manageable problems. Until now.

The affected part is a Silverlight app that connects to a WCF RIA Service on a server, and then this server connects to a CRM 4 service and does some CRUD operations on CRM entities. The Silverlight scenario is fairly common, but rather exhausting: ExpedientViewModel is the VM to a child window of InterviewViewModel, which inherits from BaseInterviewViewModel, which inherits from BaseTaskViewModel that, finally, inherits from BaseViewModel. ExpedientViewModel is in charge of creating/editing a set of entities, that is then handed over to InterViewViewModel (remember, parent-child window) through MvvmLight messaging.

Leaving aside the discussion about the architecture, the problem was one of the entities was failing on an insert and we couldn’t debug why, because every call to Context.SubmitChanges() was done with the parameterless overload, meaning you had to do something like this:

var operation = Context.SubmitChanges();
operation.Completed += SubmitChangesCompleted;
//...
private void SubmitChangesCompleted(object sender, EventArgs args)
{
    ///do something else once the data is "inserted". There's no way to get that operation variable that actually holds information about the operation in here. And I'm doing a global variable for that.
}

The problem was sound: the Complete operation does not say anything about it being completed with or without errors, nor there’s any way to actually get the OperationBase.SubmitOperation object on the callback to determine if anything has gone wrong. The solution goes without mention: use the SubmitChanges overload that takes 2 parameters, an Action callback and an object userState. But then again, I didn’t wanted to rewrite the whole application again, including the callbacks within lambdas.

Having in mind I’m no architecture whatsoever, the solution I came up with was having a GeneralSubmitChangesCompleted function in the BaseViewModel taking a SubmitOperation and an Action to be passed as a callback to every SubmitChanges and, inside this function, call whatever function is next. Like so:

protected void GeneralSubmitChangesCompleted(SubmitOperation operation, Action<object, EventArgs> next)
{
    if(!operation.HasError)
    {
        next(new object(), new EventArgs());
    }
    else
    {
        var frame = new StackFrame(1);
        InsertLog(this.GetType().Name, frame.GetMethod().Name, new Exception(operationCompleted.Error.Message, operationCompleted.Error.InnerException));
    }
}

So far it works and I’m a bit more certain that the operation actually completes successfully and at least I’m able to discard that part as the cause of the problem. But I don’t know if it’s actually a good practice to follow.

¿Any expert?


How to avoid content being cached when using a CrmDataContext

Lately I’ve been working on a project that uses CRM and has a Silverlight app connected to it via a RIA Service. This RIA Service itself uses Microsoft.Xrm.Client.Data.Services.CrmDataContext to access the CRM’s data and it’s wrapped in a DomainService in order to make things easier.

Thing is we’re migrating a part of the app into an ASP.NET app, while reusing the RIA Service’s code by cloning the DomainService. So far so good, because besides making the proper changes to the app’s code, which may seem non-trivial some times, the DomainService works.

The problem is we have and use a lot of child windows wrapped into iframes that connect themselves to CRM. So, for example, if an iframed child window updates a contact details, the parent window will not be aware of the changes…unless you make an AJAX request when the child window is closed and refresh the client’s data; or that’s what you may think, but it doesn’t work, because the Domain Services objects are different in each window and the parent’s Context has content being cached. In Silverlight there’s no problem, because both child and parent windows share the same Context, that’s not possible in ASP.NET without being a mess.

The solution

Remove the cache, right? Well, no, one does not simply remove the cache, nor kill the Batman; it’s undocumented, but there’s a way. 2, actually:

Clearing the cache for a single entity type

 public void ClearCache(string entityName)
{
    var format = "adxdependency:crm:entity:{0}";
    var dep = string.Format(format, entityName).ToLower();
    var cache = CacheManager.GetBaseCache();
    cache.Remove(dep);
}

Or:

CacheManager.GetBaseCache().Remove(string.Format("adxdependency:crm:entity:{0}", entityName));

Clearing the cache for every single entity

BaseCache baseCache = CacheManager.GetBaseCache();
foreach (string x in from x in baseCache
        where x.Key.Contains("adxdependency:crm:entity:")
        select x.Key)
    baseCache.Remove(x);

Or, with an extension method:

public static void Clear(this Cache x)
{
    List<string> cacheKeys = new List<string>();
    IDictionaryEnumerator cacheEnum = x.GetEnumerator();
    while (cacheEnum.MoveNext())
    {
        cacheKeys.Add(cacheEnum.Key.ToString());
    }
    foreach (string cacheKey in cacheKeys)
    {
        x.Remove(cacheKey);
    }
}

Generar datos de ejemplo a partir de clases y NBuilder en ASP.NET MVC 4

A estas alturas creo que no es muy necesario introducir lo bueno de los datos de ejemplo en las aplicaciones, sobre todo al momento de probar el diseño de las mismas, o hacer todo tipo de pruebas y perrerías que nos podría meter algún usuario en las vistas, aunque normalmente estas deberían estar controladas aunque sea con un if(), idealmente con anotaciones sobre el modelo. Con NBuilder podemos tener datos de ejemplo para nuestras vistas de ASP.NET MVC 4 de una manera ultra-sencilla, generándolos directamente en el Controller. Voy a suponer que ya habréis creado un nuevo proyecto de MVC 4 e instalado NBuilder desde Nuget. Vaya por delante que esta entrada no pretende ser más que una pequeña introducción a una herramienta que me está resultando útil estos días.

Primero que nada, cabe subrayar cómo NBuilder nos genera los datos de prueba, que dependen del tipo de datos que pretendas generar. Por ejemplo, para las strings será algo como string.Format({0}{1},propertyName, i) dentro de un bucle. Es decir, si tenemos un campo “Name” que es una string, los datos que nos generará serán “Name1, Name2,…,NameN”. Para los números es tan sencillo como un i++ desde 1 a N (1,2,3…N). Para las fechas, parte de la actual y le va sumando un día.

Bien, supongamos que tenemos la siguiente entidad (escribiré el código directamente en WordPress, sabrán perdonarme alguna identación):

public class Event
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Venue { get; set; }
    public string City { get; set; }
    public string Country { get; set; }
}

Entidad modelo sencillísima donde se podrían hacer mil cosas más, así como optimizaciones agrupando en un objeto varias propiedades…pero eso será ejercicio del lector, vamos al grano de lo que queremos con NBuilder. Ahora, en el controlador, tendremos que importar dos namespaces, el de nuestro modelo y Fizzware.NBuilder. Una vez hecho esto podremos escribir un código parecido a este en nuestro controlador:

public ActionResult Index()
{
    var events = Builder.CreateListOfSize(10).Build();
    return View(events);
}

Asumiendo que la vista la habréis creado con clic derecho en la acción -> crear vista tipada, el trabajo está hecho. Pero dejarlo así es un poco soso, teniendo en cuenta las capacidades de creación de contenido casi como queramos que nos provee NBuilder. Por ejemplo, supongamos que queremos hacer que todos los datos sean iguales. No sé bien por qué, pero supongamoslo:

public ActionResult Index()
{
    var events = Builder.CreateListOfSize(10).All().With(x=>x.Id = 1).And(x=> x.City = "Valencia").And(x=> x.Country = "Spain").And(x=> x.Venue = "L'umbracle").Build();
    return View(events);
}

O mejor aún, algo más elaborado, donde tendremos los primeros N elementos de una forma, los siguientes N de otra, y así sucesivamente:

public ActionResult Index()
{
    var events = Builder.CreateListOfSize(10).All().TheFirst(2).With( x=> x.Id = 1).TheNext(3).With( x=> x.City = "Madrid").TheNext(3).With(x=>x.Country = "USA").TheLast(2).With(x=>x.Venue = "Microsoft").Build();
    return View(events);
}

Por supuesto podéis usar NBuilder en otros proyectos, así como con tipos de datos complejos, pero…ya tenéis la idea 🙂


Cómo solucionar “Hacked by Gabby” en WordPress

Ninguna plataforma es 100% fiable ni segura, mucho menos cuando tienes un hosting compartido con cPanel, como es mi caso. Por ello, esta noche tuve una intromisión en este blog; afortunadamente todo estaba con copia de seguridad pertinente.

El problema fue el “Hacked by Gabby”, parecido al “hacked by hacker”, pero algo más enrevesado y complicado de solucionar, ya que Google no arroja ningún resultado de momento, además de no dejar acceder al wp-admin. En principio reinstalé todo WordPress, pero el error continuaba -aunque ya tenía acceso al wp-admin-, aunque por un momento lograba ver mi web anterior, antes de ser reemplazada por la molesta frase. Buscando en todos los archivos de PHP buscaba la frase, incluso cortada; también en los ficheros de JS del tema, pensando que era una redirección o sobrescritura en el onready. Pero era algo más fácil, una línea de código insertada desde un widget de texto en la barra lateral que reemplazaba el innerHtml del documentElement.

document.documentElement.innerHTML = unescape('%48%61%63%6b%65%64%20%42%79%20%47%61%62%62%79');

Nótese la malicia poniendo el texto.

Conclusión

  1. Para tener acceso al wp-admin reinstala WordPress por FTP. (Nota: no sé si habrá una forma más fácil de hacerlo).
  2. Ve a Apariencia->Widgets.
  3. Busca un Widget de texto con el trozo de código arriba mencionado.
  4. Elimina dicho widget.
  5. Ya tienes tu blog sin el “Hacked By Gabby” :).

Cómo enviar comentarios a WordPress desde Windows Phone [C#]

Por si alguna vez necesitáis enviar comentarios a un blog de WordPress desde vuestra aplicación de Windows Phone 7 (en realidad se puede adaptar el código a otras plataformas con dos pequeños tweaks), lo que necesitáis hacer es lo siguiente:

##El problema, identificando requerimientos##

Necesitamos enviar un comentario a un blog de WordPress, se nos puede ocurrir que tenemos que enviar una petición con unos datos al blog. ¿A qué dirección? ¿Qué datos? ¿En qué forma?

WordPress tiene una página para eso, es http://nombreblog.com/wp-comments-post.php. En este caso, por ejemplo, es http://danielrozo.es/wp-comments-post.php. Ya tenemos resuelta la primera duda.

Ahora necesitamos saber qué datos debemos enviar, para ello sólo basta con mirar el formulario que aparece debajo de cada entrada de WordPress, o bien, mirar el código fuente de wp-comments-post.php y ver las peticiones POST que acepta, que son:

  • comment_post_ID.
  • author.
  • email.
  • comment.
  • url.

Con esto hemos respondido las preguntas que nos quedaban: debemos enviar todos estos datos en una petición de tipo POST a /wp-comments-post.php.

El diseño de una página que haga esto es muy sencillo, os lo dejo a vosotros (son textboxes y fuera).

La única duda que queda por contestar es ¿Cómo identifica wp-comments-post.php el post al que quiero enviar el comentario? Pues con el comment_post_ID que le enviamos. Como consecuencia de ello, necesitamos el ID del post, en los WordPress que no tengan vanity URLs es el número que sale después de ?p= en la dirección. Para los que sí la tengan, es necesario cogerlo del RSS. Por ejemplo, si vemos el RSS de esta página vemos que dentro de cada <item> hay un <guid>, este es el elemento que necesitamos tratar para coger el ID del post. Vamos a ver cómo hacerlo usando LINQ, que es una maravilla. Supondré que tenéis una clase Post con los atributos creados, getters, setters y esas cositas que hacen falta. Este código debéis encapsularlo en un método al que le pasáis la string del XML del RSS que descargáis.


StringReader stringReader = new StringReader(feedXML);
 XmlReader xmlReader = XmlReader.Create(stringReader);
 XDocument loadedPosts = XDocument.Load(xmlReader);
 XNamespace dc = "http://purl.org/dc/elements/1.1/";
 XNamespace content = XNamespace.Get("http://purl.org/rss/1.0/modules/content/");
 var data = from query in loadedPosts.Descendants("item")
 select new Post
  {
   NombreBlog=(string)query.Parent.Element("title"),
   Titulo = (string)query.Element("title"),
   Autor = (string)query.Element(dc + "creator"),
   Contenido = (string)query.Element(content + "encoded"),
   Fecha = (string)query.Element("pubDate"),
   Link = (string)query.Element("link"),
   ID=getId((string)query.Element("guid")),
   Imagen = getImage((string)query.Element(content + "encoded"))
  };
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
  feedListBox.ItemsSource = data;
});

Dejando de lado los detalles del asunto, sólo os hace falta el método getId, que es el siguiente:

</pre>
private string getId(string s)
 {
string [] sa=s.Split('=');
return sa[1];
 }

Separa la string que le pasas, que será de tipo http://nombreblog.com/?p=xxxx, y devuelve solo el “xxxx” que es el ID.

Ahora sólo nos queda montar la petición POST que será enviada, que será algo parecido a esto:


WebClient webClient = new WebClient();
 webClient.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded";
 var uri = new Uri("http://" + url + "/wp-comments-post.php?", UriKind.Absolute);
 StringBuilder postData = new StringBuilder();
 postData.AppendFormat("{0}={1}", "comment_post_ID", HttpUtility.UrlEncode(_sItem.ID));
 postData.AppendFormat("&{0}={1}", "author", HttpUtility.UrlEncode(nombreTb.Text));
 postData.AppendFormat("&{0}={1}", "email", HttpUtility.UrlEncode(correoTb.Text));
 postData.AppendFormat("&{0}={1}", "comment", HttpUtility.UrlEncode(comentarioTb.Text));
 postData.AppendFormat("&{0}={1}", "url", HttpUtility.UrlEncode(urlTb.Text));
 MessageBox.Show("" + postData);

webClient.Headers[HttpRequestHeader.ContentLength] = postData.Length.ToString();
 webClient.UploadStringCompleted += new UploadStringCompletedEventHandler(webClient_UploadStringCompleted);
 webClient.UploadProgressChanged += webClient_UploadProgressChanged;
 webClient.UploadStringAsync(uri, "POST", postData.ToString());

Obviamente necesitáis tener los textboxes montados en vuestro XAML e implementar los métodos que se llaman por UploadStringCompleted (que será mostrar un mensaje de “Comentario posteado!” o algo y el UploadProgressChanged, que vendrá a actualizar una barra de progreso que tengáis con el ProgressPercentage del UploadProgressChangedEventArgs que le paséis al método.

¡Esto es todo, saludos!


8 crímenes en jQuery que nunca deberías cometer

Cualquiera puede programar en jQuery o JavaScript, ¿hay alguna duda de ello? Ahora, lo realmente interesante está en programar teniendo en cuenta la optimización del código, teniendo en cuenta todos los entresijos del lenguaje para poder entregar la aplicación con el mejor rendimiento posible. Y como yo nos los conozco todos, pero sí hay gente que lo hace,  sale este artículo.

Crímen #1, no usar la versión de jQuery alojada en Google

De lógica, casi, si sale una versión nueva de jQuery (y casi de cualquier framework), por algo será. En el caso de jQuery las nuevas versiones siempre vienen cargadas de correcciones de bugs y mejoras de rendimiento brutales. Si somos un poco manitas, tendremos muchos proyectos pululando por la web, ¿vas a ir uno por uno resubiendo y retocando todos para cambiar la versión de jQuery? Lo dudo. Por ello, la solución es usar el que está alojado en la CDN de Google, que no suele fallar. Y si falla, no os preocupéis, seguid leyendo.

<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.min.js"></script>

Crímen #2, no tener una chuleta a mano

Y no sólo para los no-iniciados, puede que te acostumbres a trabajar de una forma que no es la más indicada y la memoria no es infinita. Ejemplos de buenas hojas de chuletas:

Crímen #3, no tener un fallback a local cuando falle la CDN

Relacionado al crímen #1. Si Google cae, por alguna extraña razón o el fin del mundo, que no te pille desprevenido. Es un script mega-sencillo que chequea si la ventana tiene jQuery activo, si no, crea el elemento script con tu versión de jQuery en local:

<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.min.js"></script>
<script type="text/javascript">window.jQuery || document.write('<script src="js/jquery-1.8.1.min.js"></script>')</script>

Útil también para cuando trabajes en local y se te pierda la conexión, mucho más probable que lo de Google.

Crímen #4, usar selectores repetitivamente

Creía que esto era algo más que obvio para todos los programadores, pero parece que hay una oleada de código malo en jQuery pululando por la web. Cuando usas un selector, jQuery tiene que encontrar el elemento al que haces referencia, con su consecuente gasto de tiempo. Si tienes que usar el mismo elemento para modifcar varias propiedades del mismo, ¿no es mejor encadenarlas?

La versión cutre:

$("#mySmashingID").css("color","pink"); $("#mySmashingID").css("font","Verdana"); $("#mySmashingID").text("Some error message goes here!");

Versión correcta:

$("#mySmashingID").css({ "color": "pink", "font": "Verdana"}).text("Some error message goes here!!");

Crímen #5, no cachear los elementos apropiadamente

Uno de los más importantes en cuanto a rendimiento, parecido al anterior. Si tienes que usar un elemento varias veces, guárdalo en una variable, no recorras el DOM cada vez para encontrarlo.

Versión cutre:

 $(‘#mySmashingGag’).appendTo(‘#mysidebar’);
 $(‘#mySmashingGag’).addClass(‘widget’);
 $(‘#mySmashingGag’).hide();
 $(‘#mySmashingGag’).fadeIn(‘fast’);

Versión correcta:

 var mySmashingGag = $(‘#mySmashingGag’);
 mySmashingGag.appendTo(‘#mysidebar’);
 mySmashingGag.addClass(‘widget’);
 mySmashingGag.hide();
 mySmashingGag.fadeIn(‘fast’);

Crímen #6, no usar los IDs cuando puedes hacerlo

Entrando en el funcionamiento de jQuery, cuando usas un selector con una clase, jQuery recorre todo el árbol DOM para encontrar los elementos; en cambio, si usas un selector con el ID del elemento, usa la función nativa findElementById() que, como imaginarás, es mucho más rápida. Otra versión de lo mismo es la modificación de la selección por IDs para su optimización:


$("#hola").find("div.barra");

En lugar de


$("#hola div.barra");

Crímen #7, otra forma de escribir el $(document).ready

Todos sabréis para qué sirve el $(document).ready (ejecutar funciones tan pronto esté cargado el documento, en grosso), otra forma de escribirlo es con una función estilo lambda:


$(function(){

//cosas guay-ses

});

Crímen #8, no dar contexto

Simple: tratar de filtrar el contexto donde jQuery tiene que buscar.


$(".miClase","#MiElemento").on("click",hacerCosasMolonas);