MAD.NUG: ¿Qué es Windows Server AppFabric?

AppFabric_evento

Es posible que muchos de vosotros hayais oído hablar de AppFabric como parte de Windows Azure. El 24 de Junio, vamos a ver con la ayuda de Roberto Gonzalez, MVP de Biztalk, qué es Windows Server AppFabric fuera de la nube, qué relación tiene con Biztalk y cuándo usar uno u otro.

El evento tendrá lugar en el edificio de Microsoft Ibérica en Pozuelo de Alarcón, Madrid.

Asignar imagen

Para acceder al registro podéis hacerlo a través del siguiente enlace. Por otro lado, si necesitáis más información acerca de esta tecnología podéis acceder al centro de desarrollo de Windows Server.

¡Os esperamos!

Cambiar el idioma en el grid de Telerik

Hace algún tiempo estuve comentado los controles de Telerik que ofrecen con licencia Open Source para ASP.NET MVC. También recuerdo que existía un comentario al respecto donde uno de los lectores comentaba que no era posible el multi-idioma en el grid donde aparecen los literales por defecto en inglés:

Ha llegado el momento en el cual tuve que pelearme con ello y, al menos a día de hoy, sí que es posible modificar estos literales. Actualmente no existía el idioma español, pero he enviado a Telerik las traducciones y me comentan que las incluirán en la próxima release. Para descargar las mismas podemos hacerlo a través de la siguiente dirección.

¿Cómo usarlo?

En primer lugar, debemos crear la carpeta App_GlobalResources en nuestro proyecto, donde incluiremos el archivo GridLocalization.es-ES.resx.

Una vez añadido, necesitamos especificar el idioma en nuestro grid a través del método Localizable que ofrece Telerik:

 <% Html.Telerik().Grid(Model)
.Name("Tweets")
.Pageable(pager => pager.PageSize(5))
.Filterable()
.Sortable()
.Localizable("es-ES")
.Columns(columns =>
{
columns.Bound(c => c.ID).Title("ID");
columns.Bound(c => c.Text).Title("Tweet");
columns.Bound(c => c.User.Name).Title("Usuario");
})
.Render();%>

Si arrancamos la aplicación, vemos que efectivamente los literales han cambiado a perfecto castellano 🙂

Espero que sea de utilidad.

¡Saludos!

Configurar credenciales del proxy en el web.config

Si tenemos una aplicación que necesita hacer uso de Internet y nos encontramos con un proxy, es necesario especificar de alguna manera la dirección del mismo. Si además es necesario hacer uso de unas credenciales para que se nos autorice el acceso, debemos especificar más valores en la configuración.

Cuando solamente se realiza una llamada desde nuestro código a Internet, podemos pensar que esta podría ser una solución válida:

            var httpWebRequest = (HttpWebRequest)WebRequest.Create(url);
var proxy = new WebProxy(Settings.Default.UrlProxy);

proxy.Credentials = new NetworkCredential(Settings.Default.UserProxy,
Settings.Default.PasswordProxy,
Settings.Default.DomainProxy);
httpWebRequest.Proxy = proxy;

Sin embargo, puede que esta no sea la forma más correcta cuando necesitamos hacer distintas peticiones en distintos puntos de nuestra aplicación. ¿Cuál sería la mejor solución? Definir un módulo dentro de la sección <defaultProxy> del archivo de configuración. En él especificaremos una clase donde implementaremos la interfaz IWebProxy como muestro a continuación:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using Utils.Properties;

namespace Utils
{
public class Proxy : IWebProxy
{
public ICredentials Credentials
{
get
{
return new NetworkCredential(Settings.Default.UserProxy,
Settings.Default.PasswordProxy,
Settings.Default.DomainProxy);
}
set { }
}

public Uri GetProxy(Uri destination)
{
return new Uri(Settings.Default.UrlProxy);
}

public bool IsBypassed(Uri host)
{
return false;
}
}
}

Por último, añadimos las siguientes líneas en el web.config, dentro de <configuration> para que, cada vez que creemos una petición con WebRequest, automáticamente utilice esta configuración.

<system.net>
<defaultProxy enabled="true" useDefaultCredentials="false">
<module type="Utils.Proxy, Utils" />
</defaultProxy>
</system.net>

¡Saludos!

Estadísticas sobre tus links con bit.ly

Hace algún tiempo cree un pequeño post que hablaba de la forma de obtener una short url a través del servicio Tiny url. Sin embargo, este servicio no soporta en la actualidad un reporte de estadísticas como el que tiene bit.ly. Afortunadamente, disponemos una API para poder crear y consultar direcciones acortadas por ellos.

El primer paso sería registrarnos de manera gratuita en el servicio para poder hacer uso de la API, ya que es necesario el envío de las credenciales cada vez que hagamos una petición a sus endpoints. Una vez registrados, deberemos acceder a la siguiente dirección para obtener nuestra API Key: http://bit.ly/a/your_api_key

Si quisiéramos obtener una short url a través de la API, bastaría con indicar los siguientes valores en la petición:

            var longUrl = Uri.EscapeDataString("http://geeks.ms/blogs/gtorres/archive/2010/06/05/estadisticas-sobre-tus-links-con-bit-ly.aspx");
const string login = "YOUR USER NAME";
const string apiKey = "YOUR API KEY";
const string format = "xml"; //json is valid too

const string urlShorten = "http://api.bit.ly/v3/shorten?";
var credentials = string.Format("login={0}&apiKey={1}&", login, apiKey);
var parameters = string.Format("&longUrl={0}&format={1}", longUrl, format);

var bitLy = WebRequest.Create(string.Format("{0}{1}{2}", urlShorten, credentials, parameters));

var shortUrl = bitLy.GetResponse();

using (var reader = new StreamReader(shortUrl.GetResponseStream()))
{
Console.WriteLine(reader.ReadToEnd());
}

Al especificar el formato XML, como respuesta obtenemos lo siguiente:

<?xml version="1.0" encoding="UTF-8"?>
<response>
<status_code>200</status_code>
<status_txt>OK</status_txt>
<data>
<url>http://bit.ly/9L79lW</url>
<hash>9L79lW</hash>
<global_hash>bUHuTf</global_hash>
<long_url>http://geeks.ms/blogs/gtorres/archive/2010/06/05/estadisticas-sobre-tus-links-con-bit-ly.aspx</long_url>
<new_hash>0</new_hash>
</data>
</response>

Para poder ver las estadísticas de esta URL en concreto, saber si otras personas la han compartido y en qué red social, podemos visualizarlo solamente añadiendo el signo + a la short URLdevuelta: http://bit.ly/9L79lW+

Si por el contrario quisiéramos generar nuestras propias estadísticas, recuperando el número de clicks realizados sobre la URL, podríamos realizar la siguiente consulta:

            const string login = "YOUR USER NAME";
const string apiKey = "YOUR API KEY";
const string shortURL = "http://bit.ly/9L79lW";
const string clicksURL = "http://api.bit.ly/v3/clicks?";
const string format = "xml";
const string hash = "j3";

var credentials = string.Format("login={0}&apiKey={1}&", login, apiKey);
var parameters = string.Format("&shortUrl={0}&format={1}&hash={2}", shortURL, format, hash);

var bitLy = WebRequest.Create(string.Format("{0}{1}{2}", clicksURL, credentials, parameters));

var shortUrl = bitLy.GetResponse();

using (var reader = new StreamReader(shortUrl.GetResponseStream()))
{
Console.WriteLine(reader.ReadToEnd());
}

Con la siguiente respuesta:

<?xml version="1.0" encoding="UTF-8" ?>
<response>
<status_code>200</status_code>
<data>
<clicks>
<short_url>http://bit.ly/9L79lW</short_url>
<global_hash>bUHuTf</global_hash>
<user_clicks>6</user_clicks>
<user_hash>9L79lW</user_hash>
<global_clicks>13</global_clicks>
</clicks>
<clicks>
<user_clicks>112</user_clicks>
<global_hash>lLWr</global_hash>
<hash>j3</hash>
<user_hash>j3</user_hash>
<global_clicks>116</global_clicks>
</clicks>
</data>
<status_txt>OK</status_txt>
</response>

Más información sobre el uso de esta API.

Espero que sea de utilidad.

¡Saludos!

MAD.NUG: Bang Bang! Optimización económica de SQL Server

 

Este mes desde Mad.Nug vamos a ponernos las pilas para optimizar todo lo posible SQL Server con la ayuda de Pablo Álvarez Doval.
Veremos algunos casos comunes, cómo diagnosticar el estado de salud del servidor, localización de las consultas más costosas, etcétera.

El evento será en las oficinas de Microsoft Ibérica en Madrid.

Map picture

Más información.

¡Saludos!

Visual Web Developer HTML SourceEditor Package’ has failed to load properly (GUID={xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}}

Es posible que en algún momento podamos encontrarnos con el siguiente error en Visual Studio:

Uno de los casos que puede estar sucediendo es que Visual Studio está tomando el mismo idioma que tiene Windows, y que este no sea el mismo que la instalación del entorno de desarrollo. De hecho, si nos fijamos, podemos ver que algunos menús aparecen en el idioma del SO y otros en el idioma del IDE.

Para solucionarlo vamos a Tools => Options y, en Configuración Internacional / International Settings seleccionamos el idioma que nos aparece en el combo.

Por último, sería recomendable entrar en la consola de Visual Studio Tools y ejecutar el comando devenv /resetSkipPkgs

Espero que sea de utilidad.

¡Saludos!

Los webparts de Sharepoint

Uno de los conceptos más básicos que debemos conocer de los portales de Sharepoint es qué es un webpart. Los elementos web nos permiten crear un contenido personalizable de una manera dinámica, donde el usuario puede interactuar con ellos ajustando sus propiedades e incluso el contenido.

A parte de los ya existentes dentro de Sharepoint, nosotros como desarrolladores podemos crear web parts a medida.

HERRAMIENTAS PARA VISUAL STUDIO

Es recomendable la instalación de las plantillas de Sharepoint para Visual Studio. Podemos descargarlas a través de los siguientes enlaces:

CREACIÓN DEL WEB PART

La forma más cómoda de trabajar con Visual Studio y Sharepoint es tener instalado el primero en el mismo sitio que el segundo. De esta manera, tendremos disponibles las librerías necesarias para trabajar con MOSS además de poder debuggear nuestras aplicaciones fácilmente.
Para este post, vamos a crear un webpart desde Visual Studio 2008 llamado BasicWebPart para MOSS 2007:


Al instalar las herramientas, tenemos una nueva rama dentro de los tipos de proyectos llamada Sharepoint. En esta ocasión vamos a seleccionar Elemento web/Web part.

A partir de este momento, tendremos un proyecto con una serie de archivos:

  • El code behind del elemento web, en el cual incluiremos las propiedades que el usuario puede configurar, cargaremos los controles para la interfaz de usuario, etcétera.
  • Un archivo con extensión .webpart donde está incluida la metadata.
  • El archivo XML donde se especifica el namespace del webpart creado.

Como vemos, no tenemos ningún archivo de tipo web que nos ayude a diseñar la interfaz de usuario. En el code behind aparece el método CreateChildControls listo para sobrescribirse pero, si tenemos una serie de controles, botones, algo de lógica, etcétera esto podría convertirse en algo realmente tedioso. Por ello, voy a crear un nuevo proyecto del tipo Web Application donde, a su vez, añadiré un user control con el siguiente código:

<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="TwitterClient.ascx.cs"
Inherits="BasicUserControl.TwitterClient" %>
<div id="content">
<div class="title">
<h2>"What are you doing?"</h2>
</div>
<div class="status">
<asp:TextBox ID="txtStatus" runat="server" TextMode="MultiLine" Rows="6" Columns="30"></asp:TextBox>
</div>
<div class="footer">
<asp:Button ID="btnTweet" runat="server" Text="Tweet" OnClick="BtnTweetClick" />
</div>
</div>

Y como code behind lo siguiente:

using System;
using Twitterizer.Framework;

namespace BasicUserControl
{
public partial class TwitterClient : System.Web.UI.UserControl
{
public string UserName { get; set; }
public string Password { get; set; }

protected void Page_Load(object sender, EventArgs e) { }

protected void BtnTweetClick(object sender, EventArgs e)
{
var twitterUser = new Twitter(UserName, Password);
twitterUser.Status.Update(txtStatus.Text);
}
}
}

Este web part tiene como única tarea actualizar nuestro estado en Twitter. Soy consciente de que la lógica debería ser algo más elaborada (comprobar que se realizó el envío o bien controlar cualquier tipo de error) pero el objetivo de este post es simplificar los pasos para la creación de web parts lo más posible.

Una vez que tenemos el control de usuario y su lógica correspondiente, volvemos al proyecto del elemento web y asociamos el mismo al user control:

using System;
using System.Runtime.InteropServices;
using System.Web.UI;
using System.Web.UI.WebControls.WebParts;
using BasicUserControl;
using Microsoft.SharePoint.Utilities;

namespace BasicWebPart.BasicWebPart
{
[Guid("8a91e4e4-033f-4e87-b9ea-5c7be1dec2fb")]
public class BasicWebPart : WebPart
{
private TwitterClient _ucTwitterClient;
public Exception Error { get; set; }

[Personalizable(PersonalizationScope.Shared),
WebBrowsable(true),
WebDisplayName("User name"),
WebDescription(@"Twitter user name")]
public string UserName { get; set; }

[Personalizable(PersonalizationScope.Shared),
WebBrowsable(true),
WebDisplayName("Password"),
WebDescription(@"Twitter password")]
public string Password { get; set; }

protected override void CreateChildControls()
{
try
{
base.CreateChildControls();
Controls.Clear();

_ucTwitterClient = (TwitterClient)Page.LoadControl("_controls/Twitter/TwitterClient.ascx");
_ucTwitterClient.UserName = UserName;
_ucTwitterClient.Password = Password;

Controls.Add(_ucTwitterClient);
}
catch (Exception ex)
{
Error = ex;
}
}

protected override void Render(HtmlTextWriter writer)
{
if (Error != null)
SPUtility.TransferToErrorPage(Error.Message + " ---> " + Error.StackTrace);
base.Render(writer);
}
}
}

En primer lugar he creado una variable privada del mismo tipo que el user control que hemos creado, además de una propiedad que recogerá cualquier excepción que pudiera suceder dentro de nuestro elemento.
En el control de usuario teníamos declaradas dos propiedades para almacenar el nombre de usuario y la contraseña para la conexión con Twitter. En este caso queremos que estos datos los facilite el usuario para poder actualizar el estado de su cuenta. Por ello, se han creado dos propiedades, UserName y Password, las cuales están decoradas con una serie de atributos propios de Sharepoint.

Por último, hemos modificado el método CreateChildControls para cargar el control de usuario y poder pasarle los valores de usuario y contraseña y, además, en el método Render comprobamos si ocurrió algún error para mostrarlo o bien renderizamos el contenido.

Si compiláramos la solución, ocurriría lo siguiente:

El error nos indica que es necesario un nombre seguro para el ensamblado. Para solucionarlo, debemos crear una firma accediendo a las propiedades del proyecto:

En mi caso cree una firma sin contraseña.

PUBLICACIÓN DEL WEB PART

En el supuesto más sencillo, donde no tenemos una granja de servidores y únicamente es necesario desplegar nuestro web part en un único sitio, podríamos seguir los siguientes pasos para poder utilizar el web part que acabamos de crear en un portal de MOSS:

  1. Copiar el assembly del web part en la GAC (Global Assembly Cache). En este caso, iríamos a la carpeta bin del proyecto BasicWebPartcopiaríamos en la carpeta assembly de WINDOWS la dll  BasicWebPart.dll ubicada dentro de Debug.
  2. Accedemos a C:InetpubwwwrootwssVirtualDirectories y entramos en la carpeta del portal donde queremos utilizar el web part. Por defecto, estas carpetas tienen como nombre el número del puerto asociado al portal.
  3. Creamos un nuevo directorio llamado _controls y, dentro de él, otro llamado Twitter. Copiamos dentro el archivo ascx que creamos en el proyecto web (TwitterClient.ascx).
  4. Hacemos una copia del contenido de binDebug de nuestro proyecto BasicWebPart en la carpeta bin del directorio virtual.
  5. Modificamos el web.config del sitio y añadimos una nueva línea dentro de la sección SafeControls:
      <SafeControl Assembly="BasicWebPart, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9f4da00116c38ec5" Namespace="BasicWebPart.BasicWebPart" TypeName="*" Safe="True" />
    </SafeControls>

    La clave pública del web part (PublicKeyToken) podemos localizarla en las propiedades de la dll correspondiente dentro de la carpeta assembly de WINDOWS:

  6. Abrimos una consola de MS-DOS y ejecutamos iisreset /noforce para que los cambios sean tomados por el sitio de Sharepoint.
  7. Accedemos a la configuración del sitio:

  8. En el apartado Galerías seleccionamos Elementos web.

  9. Pulsamos sobre el botón Nuevo y seleccionamos el web part dentro de la lista. Una vez localizado, hacemos clic en Llenar galería.

  10. Para facilitar la búsqueda del web part dentro del listado de los elementos disponibles, podemos modificar algunas de sus propiedades pulsando en el botón editar.

  11. Accedemos a la página donde queremos poner el nuevo elemento y pulsamos sobre Editar página. Al pulsar en cualquiera de los sitios disponibles para un nuevo elemento web, nos aparecerá un listado con los web part disponibles. Si hemos modificado las propiedades del mismo, aparecerá en el apartado Twitter.

  12. Una vez que hemos agregado el web part, pulsamos sobre el botón editar y modificamos las propiedades. En este caso, al no categorizar las que añadimos aparecerán en el apartado Varios.

Nota: Para este caso en concreto, donde estamos haciendo una llamada a través de Internet para conectar con Twitter, es necesario modificar la confianza del sitio. Cuando creas un portal, por defecto, está definida a Minimal Trust. Para modificar este parámetro, en el web.config cambiamos esta línea:

<trust level="WSS_Minimal" originUrl="" />

Por esta otra:

<trust level="Full" originUrl="" />

Más adelante hablaremos sobre ello 🙂

Adjunto el proyecto por si fuera de utilidad.

¡Saludos!