martes, 29 de enero de 2013

Blogger: icono para dispositivos Apple

Si desde un dispositivo

Apple

(Iphone o Ipad) accedes a tu blog de

Blogger

(o realizado con cualquier otra plataforma) puedes añadir una página en la pantalla de inicio del dispositivo pero ¿con qué icono saldrá? En este artículo te explicaré cómo personalizarlo.

Si no has hecho nada por personalizar el

icono para dispositivos Apple

lo más normal es que si añades una página en la pantalla de inicio del dispositivo te salga un icono con una especie de miniatura de la página que has añadido y con las esquinas redondeadas. Lo normal es que quieras personalizar este icono:

  1. Crea un icono personalizado de 57x57 píxeles, guárdalo en formato png y súbelo a algún sitio donde esté accesible desde

    Blogger

    (dropbox, Google Drive,...). En el caso de

    areaTIC

    lo que tengo es una página de

    Blogger

    que no publico y donde añado este icono, los de redes sociales,... una vez añadidos el enlace que me genera lo puedo utilizar en las distintas páginas artículos del blog. El icono creado para

    areaTIC

    es el siguiente (no es necesario que redondees las esquinas, ni lo sombrees,... se encarga tu dispositivo

    Apple

    por tí).


    Si queremos más información sobre los

    iconos para dispositivos Apple

    , consejos para su creación,... podemos acceder a la siguiente página de la iOS Developer Library.

  2. Entramos en

    Blogger

    , vamos al apartado Plantilla y pulsamos sobre el botón "Edición de HTML".


  3. Buscamos en el HTML de la plantilla el código:
    </head>
    
  4. Justo encima del código anterior añadimos el código siguiente:
    <link rel='apple-touch-icon' href='http://.../iphoneicon.png' />
    
    Donde:
    • "iphoneicon.png" es el nombre del icono que has creado en el paso 1.
    • "http://.../iphoneicon.png" es la URL correspondiente al icono.
    Tras los cambios guardamos la plantilla.

  5. Ahora llega el momento de probarlo, si disponéis de un dispositivo

    Apple (iPhone o iPad)

    es muy sencillo, ¿pero y si no lo tenemos? Podemos acceder al blog de Duopixel y utilizar su simulador de

    iPhone

    , seleccionas la imagen creada en el paso 1 la subes y podrás ver el resultado. En un

    iPad

    se visualiza de igual forma.


Y hasta aquí el artículo de hoy, espero que os haya sido interesante, dentro de

areaTIC

puedes encontrar otros artículos, no dudes en consultar nuestro archivo; también puedes seguirnos por RSS o las principales redes sociales (twitter, facebook, linkedin...)


sábado, 26 de enero de 2013

WCF ChannelFactory<T>. Cómo simplificar la creación de clientes WCF.

En el artículo anterior vimos como usar

ChannelFactory

para crear un cliente

WCF

, hoy veremos un ejemplo sobre como crear nuestra clase "proxy" que podría servirnos para simplificar la creación de clientes

WCF

y no complicar la vida a los miembros del equipo que trabajen en presentación.

En el mismo proyecto AreaTIC.Client crearemos un clase AreaTicWCFProxy que implemente la interfaz

ICommunicationObject

y que en el constructor simplemente obligue a pasar el nombre del servicio al creador, dentro ya implementaríamos todo el tema de bindings, seguridad y demás aspectos configurables del cliente. Veamos un ejemplo que se podría ir complicando en función de las características de cada arquitectura.
using System.ServiceModel;

namespace AreaTIC.Shared
{
 public class AreaTicWCFProxy:ICommunicationObject
 {
   private ChannelFactory mfactory = null;

   public AreaTicWCFProxy(string Address)
   {
     //definimos binding.
     WSHttpBinding binding = new WSHttpBinding(SecurityMode.None);

     //definimos endpoint 
     EndpointAddress endPoint = new EndpointAddress(string.Format("http://localhost:8080/Services/{0}",Address));

     //definimos factory y creamos canal.
     mfactory = new ChannelFactory(binding, endPoint);

     mfactory.Open();
    }

    public T client 
    {
      get { return mfactory.CreateChannel(); }
    }

    void ICommunicationObject.Abort()
    {
      mfactory.Abort();
    }

    IAsyncResult ICommunicationObject.BeginClose(TimeSpan timeout, AsyncCallback callback, object state)
    {
      throw new NotImplementedException();
    }

    IAsyncResult ICommunicationObject.BeginClose(AsyncCallback callback, object state)
    {
       throw new NotImplementedException();
    }

    IAsyncResult ICommunicationObject.BeginOpen(TimeSpan timeout, AsyncCallback callback, object state)
    {
       throw new NotImplementedException();
    }

    IAsyncResult ICommunicationObject.BeginOpen(AsyncCallback callback, object state)
    {
       throw new NotImplementedException();
    }

    void ICommunicationObject.Close(TimeSpan timeout)
    {
       mfactory.Close(timeout);
    }

    void ICommunicationObject.Close()
    {
       mfactory.Close();
    }

    event EventHandler ICommunicationObject.Closed
    {
       add { throw new NotImplementedException(); }
       remove { throw new NotImplementedException(); }
    }

    event EventHandler ICommunicationObject.Closing
    {
       add { throw new NotImplementedException(); }
       remove { throw new NotImplementedException(); }
    }

    void ICommunicationObject.EndClose(IAsyncResult result)
    {
       throw new NotImplementedException();
    }

    void ICommunicationObject.EndOpen(IAsyncResult result)
    {
       throw new NotImplementedException();
    }

    event EventHandler ICommunicationObject.Faulted
    {
       add { throw new NotImplementedException(); }
       remove { throw new NotImplementedException(); }
    }

    void ICommunicationObject.Open(TimeSpan timeout)
    {
       mfactory.Open(timeout);
    }

    void ICommunicationObject.Open()
    {
       mfactory.Open();
    }

    event EventHandler ICommunicationObject.Opened
    {
       add { throw new NotImplementedException(); }
       remove { throw new NotImplementedException(); }
    }

    event EventHandler ICommunicationObject.Opening
    {
       add { throw new NotImplementedException(); }
       remove { throw new NotImplementedException(); }
    }

    CommunicationState ICommunicationObject.State
    {
       get { return mfactory.State; }
    }
  }
}
Si os fijáis en fragmento de código hemos definido un atributo privado

ChannelFactory

y a partir de los parámetro que recibimos en el constructor de nuestra clase configuraríamos el canal.

El resto son métodos que obliga a implementar la interfaz

ICommunicationObject

, en este caso no he implementado el tema de asíncronos ni los eventos... Implementamos los básicos Open, Close (...) para gestionar el canal.

Para conectar al servicio que levantamos en el artículo anterior el código sería tan simple como esto:
using AreaTIC.Shared.ServiceContracts;
using AreaTIC.Shared.DataContracts;
using AreaTIC.Shared;

namespace AreaTIC.Client
{
 class Program
 {
   static void Main(string[] args)
   {
    string result = new AreaTicWCFProxy("EjemploAreaTIC").client.FuncionEjemplo(new Tipo1());
    Console.Write(result);
    Console.ReadLine();
   }
 }
}
Si queremos conectar con otro servicio y disponemos de la interfaz simplemente tendríamos que sustituir la interfaz en la llamada de modo que la misma clase proxy nos serviría para conectar a todos los servicios que tengamos en nuestro servidor de negocio.

Ya de cara al siguiente artículo veríamos como implementar el tema de asíncronos. Recordaros que podéis seguir

areaTIC

en las redes sociales, esperamos vuestra participación!


martes, 22 de enero de 2013

WCF ChannelFactory<T>. Evitar el uso de svcUtil para generar clientes WCF.

A la hora de crear un cliente para un servicio

WCF

podemos hacer algo tan sencillo y rápido como botón derecho "Agregar referencia de Servicio" y aquí introducir la URL que contiene los meta-datos del servicio.

Visual Studio en este punto usa svcUtil para generar automáticamente las clases proxy y los tipos que se usarán en el servicio.

Hasta aquí todos estaremos de acuerdo que no hay modo más sencillo y rápido de generar un cliente que usando svcUtil. En caso que estemos trabajando en una arquitectura en la que disponemos de los tipos y la interfaz que se ha usado para crear el servicio, crear un "service reference" sería práctico pero poco óptimo dado que estaríamos generando clases y archivos que realmente no sería necesario crear en presentación (cliente).

Hoy veremos como usar la clase

ChannelFactory<T>

que nos permitirá generar un cliente para nuestro servicio. Para el ejemplo será necesario crear 3 proyectos; AreaTIC.Client (Consola), AreaTIC.Server (Consola) y AreaTIC.Shared (librería de clases).

Crearemos una solución que contenga los proyectos AreaTIC.Server y AreaTIC.Shared. En primer lugar crearemos los tipos que usaremos en las operaciones del servicio (

DataContract

). Para implementar el patrón estos tipos necesitaremos que sean accesibles tanto en servidor como cliente así que ubicaremos las clases en el proyecto AreaTIC.Shared en un namespace AreaTIC.Shared.DataContract.
namespace AreaTIC.Shared.DataContracts
{
    [DataContract]
    public class Tipo1
    {
        [DataMember]
        public string Atributo1 { get; set; }
        [DataMember]
        public string Atributo2 { get; set; }
    }
}
En segundo lugar, para crear un servicio

WCF

nos hará falta una interfaz con el atributo

[ServiceContract]

que contenga la firma de los métodos que se incluirán en el servicio. Dicha interfaz será necesaria tanto en servidor como cliente así que la ubicaremos dentro del proyecto AreaTIC.Shared en un namespace que llamaremos AreaTIC.Shared.ServiceContracts.
namespace AreaTIC.Shared.ServiceContracts
{
    [ServiceContract]
    public interface IServiceEjemplo
    {
        [OperationContract]
        string FuncionEjemplo(Tipo1 pValue);
    }
}
Crearemos la clase que implementará la interfaz anterior dentro de AreaTIC.Server.Services.
using AreaTIC.Shared.ServiceContracts;
using AreaTIC.Shared.DataContracts;

namespace AreaTIC.Server.Services
{
    public class ServiceEjemplo:IServiceEjemplo
    {
        string IServiceEjemplo.FuncionEjemplo(Tipo1 pValue)
        {
            Thread.Sleep(5000);

            //Implementación (...)

            return "bla bla";
        }
    }
}
Para acabar con la parte servidor faltaría definir un

Binding

y hospedar el servicio (esta parte podría hacerse vía web.config

<system.servicemodel>

).
using System.ServiceModel;
using AreaTIC.Server.Services;
using AreaTIC.Shared.ServiceContracts;

namespace AreaTIC.Server
{
 class Program
 {
 static void Main(string[] args)
 {
  try
  {
    Uri baseURI = new Uri("http://localhost:8080/Services/");
    string Address = "EjemploAreaTIC";
    ServiceHost hostEjemplo = new ServiceHost(typeof(ServiceEjemplo), baseURI);
    string ContractTypeName="AreaTIC.Shared.ServiceContracts.IServiceEjemplo";

    WSHttpBinding binding = new WSHttpBinding(SecurityMode.None);
    hostEjemplo.AddServiceEndpoint(ContractTypeName, binding, Address);

    Console.WriteLine("Servicio Ejemplo a la escucha");
  }
  catch (Exception)
  {
    Console.WriteLine("Error al hospedar el servicio");
  }
  finally 
  {
    Console.ReadLine();
  }
 }
 }
}
Llegado este punto ya tenemos el servicio a la escucha ahora veamos como generar el cliente usando

ChannelProxy

. En primer lugar crearemos otra solución que contenga un nuevo proyecto AreaTIC.Client al que añadiremos como referencia la librería de clases AreaTIC.Shared. En la misma clase Program.cs definiremos el

binding

,

endPointAddress

y conectaremos al servicio que hemos creado en el paso anterior mostrando la información que devuelve la llamada por pantalla.
using System.ServiceModel;
using AreaTIC.Shared.DataContracts;
using AreaTIC.Shared.ServiceContracts;

namespace AreaTIC.Client
{
 class Program
 {
   static void Main(string[] args)
   {
     //definimos binding.
     WSHttpBinding binding = new WSHttpBinding(SecurityMode.None);

     //definimos endpoint 
     EndpointAddress endPoint = new EndpointAddress("http://localhost:8080/Services/EjemploAreaTIC");

     //definimos factory y creamos canal.
     ChannelFactory<IServiceEjemplo> factory = new ChannelFactory<IServiceEjemplo>(binding,endPoint);
            
     //en este punto podríamos personalizar el comportamiento de nuestro cliente (serializador, inspectors, credenciales, certificados, ...);
     
     factory.Open();
     IServiceEjemplo wcfClient = factory.CreateChannel();
     Console.WriteLine(wcfClient.FuncionEjemplo(new Tipo1()));
     Console.ReadLine();
     factory.Close();
    }
 }
}
Si todo ha ido bien, mostraremos el texto 'bla bla' por pantalla. En arquitecturas donde se accede a datos vía

WCF

es muy interesante usar

ChannelFactory<T>

en cliente para evitar tener una lista interminable de "Service Reference" que serán engorrosos de configurar vía app.config.

Hasta aquí el artículo de hoy. Espero les sea de ayuda y como siempre os animo a participar con vuestros comentarios y/o aportaciones. Recuerda que puedes seguir

areaTIC

en las redes sociales!


viernes, 18 de enero de 2013

Blogger: página de error 404 y SEO eficiente

La

página de error 404

se produce cuando hay conectividad con el servidor pero este no es capaz de encontrar la página que se solicita. Por ejemplo, si introducimos en nuestro navegador la URL www.areatic.net/inicio (página que no existe) nos llevará a la página de error personalizada de

areaTIC.net

.

Desde la perspectiva de

SEO

es importante que nuestro sitio , sea realizado en

Blogger

como comentaré en este artículo o en cualquier otra plataforma (Wordpress, Drupal, Joomla,...) tenga una

página de error 404

personalizada ya que los robots de búsqueda valoran negativamente la no existencia. A tener en cuenta sobre la

página de error 404

:

  1. Un usuario llegará a una

    página de error 404

    de nuestro sitio por diversos motivos, los más frecuentes, porque en el sitio hay un error (por ejemplo en un enlace) que le lleva a una página que no existe o porque introduce una URL que no existe para el sitio. El objetivo debe ser que esta visita que por uno de los dos motivos anteriores (u otros) llega a la

    página de error 404

    no abandone nuestro sitio.

  2. Nuestra

    página de error 404

    debería tener un texto personalizado, que no culpe al usuario del error y enlaces a páginas concretas como podría ser la home, el sitemap del sitio, un buscador... con el objetivo que el usuario los pulse y no abandone nuestro sitio.

  3. Podemos ser más imaginativos, si nuestro sitio tiene una tienda online, tras el mensaje pertinente y algún enlace (por ejemplo al sitemap) podemos presentarle una lista de productos en oferta, es decir, utilizarlo como una landing page a nuestra tienda.

  4. Otra opción imaginativa podría ser intentar utilizar la

    página de error 404

    para conseguir seguidores en las redes sociales mediante los diferentes pluggins que existen de twitter, facebook,... eso sí, deberíamos minimizar en lo posible el uso de ficheros externos (javascript, CSS,...) para no ralentizar la carga de la página.

  5. ¿Más ideas? Seguro que sí, podéis agregarlas en los comentarios del artículo!!! Algunas

    páginas de error 404

    personalizadas:


Llegados a este punto sólo me queda indicaros cómo hacer vuestra

página de error 404

personalizada en

Blogger

, es muy sencillo, es realizar los pasos:
  1. Entramos en

    Blogger

    .

  2. Vamos al menú 'Configuración' y dentro a 'Preferencias de búsqueda'.

  3. En la sección 'Errores y redireccionamientos', junto a 'Mensaje de página no encontrada personalizado', pulsamos el enlace 'Editar'.

  4. En el cuadro que se nos abre podemos introducir el texto/HTML que creamos conveniente.


  5. Guardamos los cambios y ya tenemos

    página de error 404

    personalizada en nuestro sitio de

    Blogger

    .

¿Tenéis más ideas para la

página de error 404

? ¿habéis personalizado ya la vuestra? Ya me diréis... espero que os haya sido interesante, dentro de

areaTIC

puedes encontrar otros artículos, no dudes en consultar nuestro archivo; también puedes seguirnos por RSS o las principales redes sociales (twitter, facebook, linkedin...)


LECTURAS RELACIONADAS RECOMENDADAS POR AREATIC.NET

martes, 15 de enero de 2013

Blogger: script para crear tabla de contenidos a partir de los posts

El otro día buscando una manera de crear una tabla de contenido a partir de los posts de

areaTIC

y agrupados según las etiquetas de cada uno llegué a este interesante artículo en Ciudadblogger. Se acercaba bastante a lo que quería hacer pero lo tuve que adaptar ligeramente (podéis ver el resultado en la pestaña ARCHIVO de este blog):

  • Muestro la fecha del post delante de su título, así dentro de cada grupo (que corresponde a una etiqueta) los tengo ordenados cronológicamente ya que en el caso de

    areaTIC

    tiene más sentido que alfabéticamente.

  • Corrijo un problema que había con la ordenación de los grupos (etiquetas) ya que si había etiquetas en mayúsculas y minúsculas siempre salían primero las mayúsculas y se perdía la ordenación alfabética.

  • Como nuevos marco los 3 últimos posts en lugar de los 10 que tenía el código original... 10 posts se puede ir 1/2/3/... meses atrás, eso según como ya no es nuevo... ¿no? En mi caso no lo era, podéis modificarlo según lo que necesitéis

  • Ajusto el estilo del "Nuevo" y lo coloco al inicio de línea del post, delante de la fecha, se localizan más fácilmente las novedades.

  • Aumento la separación entre los grupos (etiquetas) para que se visualicen mejor las entradas y el grupo al que pertenecen.

A continuación os pego el código resultante y que se está utilizando en

areaTIC

:
<script>
//<![CDATA[
var postTitle=new Array();
var postUrl=new Array();
var postMp3=new Array();
var postDate=new Array();
var postLabels=new Array();
var postBaru=new Array();
var sortBy="titleasc";
var tocLoaded=false;
var numChars=250;
var postFilter=""
var numberfeed=0;

function loadtoc(a){
  function b(){
    if("entry" in a.feed){
      var d=a.feed.entry.length;
      numberfeed=d;
      ii=0;
      for(var h=0;h<d;h++){
        var n=a.feed.entry[h];
        var e=n.title.$t;
        var m=n.published.$t.substring(0,10);
        var j;
        for(var g=0;g<n.link.length;g++){
          if(n.link[g].rel=="alternate"){
            j=n.link[g].href;
            break
          }
        }
        var o="";
        for(var g=0;g<n.link.length;g++){
          if(n.link[g].rel=="enclosure"){
            o=n.link[g].href;break
          }
        }
        var c="";
        if("category" in n){
          for(var g=0;g<n.category.length;g++){
            c=n.category[g].term;
            var f=c.lastIndexOf(";");
            if(f!=-1){
              c=c.substring(0,f)
            }
            postLabels[ii]=c;
            postTitle[ii]='['+m+'] ' + e;
            postDate[ii]=m;
            postUrl[ii]=j;
            postMp3[ii]=o;
            // Marcamos como nuevos los 3 últimos posts
            if(h<3){
              postBaru[ii]=true  
            }else{
              postBaru[ii]=false
            }
            ii=ii+1
          }
        }
      }
    }
  }
  b();
  sortBy="titleasc";
  sortPosts(sortBy);
  sortlabel();
  tocLoaded=true;
  displayToc2();
  document.write('')
}

function filterPosts(a){
  scroll(0,0);
  postFilter=a; 
  displayToc(postFilter)
}

function allPosts(){
  sortlabel();
  postFilter="";
  displayToc(postFilter)
}

function sortPosts(d){
  function c(e,g){ 
    var f=postTitle[e];
    postTitle[e]=postTitle[g];
    postTitle[g]=f;
    var f=postDate[e];
    postDate[e]=postDate[g];
    postDate[g]=f;
    var f=postUrl[e];
    postUrl[e]=postUrl[g];
    postUrl[g]=f;
    var f=postLabels[e];
    postLabels[e]=postLabels[g];
    postLabels[g]=f;
    var f=postMp3[e];
    postMp3[e]=postMp3[g];
    postMp3[g]=f;
    var f=postBaru[e];
    postBaru[e]=postBaru[g];
    postBaru[g]=f
  }
  for(var b=0;b<postTitle.length-1;b++){
    for(var a=b+1;a<postTitle.length;a++){
      if(d=="titleasc"){
        if(postTitle[b].toUpperCase()>postTitle[a].toUpperCase()){
          c(b,a)
        }
      }
      if(d=="titledesc"){
        if(postTitle[b].toUpperCase()<postTitle[a].toUpperCase()){
          c(b,a)
        }
      }
      if(d=="dateoldest"){
        if(postDate[b]>postDate[a]){
          c(b,a)
        }
      }
      if(d=="datenewest"){
        if(postDate[b]<postDate[a]){
          c(b,a)
        }
      }
      if(d=="orderlabel"){
        if(postLabels[b].toUpperCase()>postLabels[a].toUpperCase()){
          c(b,a)
        }
      }
    }
  }
}

function sortlabel(){
  sortBy="orderlabel";
  sortPosts(sortBy);
  var a=0;
  var b=0;
  while(b<postTitle.length){
    temp1=postLabels[b];
    firsti=a;
    do{
      a=a+1;
    }
    while(postLabels[a]==temp1);
    b=a;
    sortPosts2(firsti,a);
    if(b>postTitle.length){
      break
    }
  }
}

function sortPosts2(d,c){
  function e(f,h){
    var g=postTitle[f];
    postTitle[f]=postTitle[h];
    postTitle[h]=g;
    var g=postDate[f];
    postDate[f]=postDate[h];
    postDate[h]=g;
    var g=postUrl[f];
    postUrl[f]=postUrl[h];
    postUrl[h]=g;
    var g=postLabels[f];
    postLabels[f]=postLabels[h];
    postLabels[h]=g;
    var g=postMp3[f];
    postMp3[f]=postMp3[h];
    postMp3[h]=g;
    var g=postBaru[f];
    postBaru[f]=postBaru[h];
    postBaru[h]=g
  }
  for(var b=d;b<c-1;b++){
    for(var a=b+1;a<c;a++){
      if(postTitle[b].toUpperCase()>postTitle[a].toUpperCase()){
        e(b,a)
      }
    }
  }
}

function displayToc(a){
  var l=0;
  var h="";
  var e="Judul Artikel";
  var m="Klik untuk sortir berdasarkan judul";
  var d="Tanggal";
  var k="Klik untuk Sortir bedasarkan tanggal";
  var c="Kategori";
  var j="";
  if(sortBy=="titleasc"){
    m+=" (descending)";
    k+=" (newest first)"
  }
  if(sortBy=="titledesc"){
    m+=" (ascending)";
    k+=" (newest first)"
  }
  if(sortBy=="dateoldest"){
    m+=" (ascending)";
    k+=" (newest first)"
  }
  if(sortBy=="datenewest"){
    m+=" (ascending)";
    k+=" (oldest first)"
  }
  if(postFilter!=""){
    j="Klik untuk menampilkan semua"
  }
  h+="<table>";
  h+="<tr>";
  h+='<td class="toc-header-col1">';
  h+='<a href="javascript:toggleTitleSort();" title="'+m+'">'+e+"</a>";
  h+="</td>";
  h+='<td class="toc-header-col2">';
  h+='<a href="javascript:toggleDateSort();" title="'+k+'">'+d+"</a>";
  h+="</td>";
  h+='<td class="toc-header-col3">';
  h+='<a href="javascript:allPosts();" title="'+j+'">'+c+"</a>";
  h+="</td>";h+='<td class="toc-header-col4">';
  h+="Download MP3";
  h+="</td>";
  h+="</tr>";
  for(var g=0;g<postTitle.length;g++){
    if(a==""){
      h+='<tr><td class="toc-entry-col1"><a href="'+postUrl[g]+'">'+
         postTitle[g]+'</a></td><td class="toc-entry-col2">'+postDate[g]+
         '</td><td class="toc-entry-col3">'+postLabels[g]+
         '</td><td class="toc-entry-col4"><a href="'+postMp3[g]+
         '">Download</a></td></tr>';
      l++
    }else{
      z=postLabels[g].lastIndexOf(a);
      if(z!=-1){
        h+='<tr><td class="toc-entry-col1"><a href="'+postUrl[g]+'">'+postTitle[g]+
           '</a></td><td class="toc-entry-col2">'+postDate[g]+
           '</td><td class="toc-entry-col3">'+postLabels[g]+
           '</td><td class="toc-entry-col4"><a href="'+postMp3[g]+
           '">Download</a></td></tr>';
        l++
      }
    }
  }
  h+="</table>";
  if(l==postTitle.length){
    var f='<span class="toc-note">Menampilkan Semua '+
          postTitle.length+" Artikel<br/></span>"
  }else{
    var f='<span class="toc-note">Menampilkan '+l+
          " artikel dengan kategori '";
    f+=postFilter+"' dari "+postTitle.length+" Total Artikel<br/></span>"
  }
  var b=document.getElementById("toc");
  b.innerHTML=f+h
}

function displayToc2(){
  var a=0;
  var b=0;
  while(b<postTitle.length){
    temp1=postLabels[b];
    document.write("<p/>");
    document.write("<br/>");
    document.write('<p><a href="/search/label/'+temp1+'">'+temp1+"</a></p><ol>");
    firsti=a;
    do{
      document.write("<li>");
      if(postBaru[a]==true){
        document.write('<strong><span style="color:red">[Nuevo] </span></strong>')
      }
      document.write('<a href="'+postUrl[a]+'">'+postTitle[a]+"</a>");
      document.write("</li>");
      a=a+1
    }
    while(postLabels[a]==temp1);
    b=a;
    document.write("</ol>");
    sortPosts2(firsti,a);
    if(b>postTitle.length){
      break
    }
  }
}

function toggleTitleSort(){
  if(sortBy=="titleasc"){
    sortBy="titledesc"
  }else{
    sortBy="titleasc"
  }
  sortPosts(sortBy);
  displayToc(postFilter)
}

function toggleDateSort(){
  if(sortBy=="datenewest"){
    sortBy="dateoldest"
  }else{
    sortBy="datenewest"
  }
  sortPosts(sortBy);
  displayToc(postFilter)
}

function showToc(){
  if(tocLoaded){
    displayToc(postFilter);
    var a=document.getElementById("toclink")
  }else{
    alert("Just wait... TOC is loading")
  }
}

function hideToc(){
  var a=document.getElementById("toc");
  a.innerHTML="";
  var b=document.getElementById("toclink");
  b.innerHTML='<a href="#" onclick="scroll(0,0); showToc();Effect.toggle(\'toc-result\',\'blind\');">?? Menampilkan Daftar Isi</a><img src="http://radiorodja.googlepages.com/new_1.gif"/>'
}

function looptemp2(){
  for(var a=0;a<numberfeed;a++){
    document.write("<br>");
    document.write('Post Link : <a href="'+postUrl[a]+'">'+postTitle[a]+"</a><br>");document.write('Download mp3 : <a href="'+postMp3[a]+'">'+postTitle[a]+"</a><br>");
    document.write("<br>")
  }
};
//]]>
</script>
<script src="http://www.areatic.net/feeds/posts/default?max-results=9999&alt=json-in-script&callback=loadtoc"></script>

Entiendo que con la nueva sección ARCHIVO añadida a

areaTIC

se hace más fácil acceder a los contenidos que realmente interesan al lector y prescindir de los que no son de su interés. Bueno, hasta aquí el artículo de hoy, aprovecho una mejora en

areaTIC

para hacérosla llegar y que la podáis incorporar en vuestros blogs... espero que os haya sido interesante. Dentro de

areaTIC

puedes encontrar otros artículos, no dudes en consultar nuestro archivo; también puedes seguirnos por RSS o las principales redes sociales (twitter, facebook, linkedin...)


jueves, 10 de enero de 2013

WCF: Utilidad para convertir feeds en HTML estático

En el artículo de hoy veremos un ejemplo en el que usaremos

WCF

para leer el contenido de un

RSS feed

y generar código

HTML

estático que podremos incrustar posteriormente en nuestra web o blog.

Ya existen herramientas como feed burner que permiten generar código a partir de un feed para incrustar en una página

HTML

, el caso es que el código resultante es un script (javascript) que se incrusta en la página resultante y genera el contenido HTML del feed en runtime al cargar la página en el navegador.

Vamos con el ejemplo, usaremos Visual Studio 2010 Express en mi caso he usado un proyecto tipo web pero nos valdría también un proyecto Windows Forms o incluso una aplicación de consola.

El proyecto constará de una página con un TextBox que permita introducir la URL del feed, un botón "Generar" y un TextArea donde mostraremos el HTML resultante para poder "copiar y pegar" en nuestra web o blog.



En el botón on_click() del botón "Generar" picaremos el siguiente código que es el encargado de conectar al feed y completar el TextArea con el contenido del feed.
  using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Text;
  using System.Net;
  using System.IO;
  using System.ServiceModel.Syndication;
  using System.Xml;
  using System.Web;

  namespace FeedToHTML
  {
    public partial class FeedToHTML : System.Web.UI.Page
    {
      protected void Page_Load(object sender, EventArgs e)
      {

      }

      protected void btnGenerar_Click(object sender, EventArgs e)
      {
        txtResult.Text = new GetHTMLFeed(txtFeedURL.Text,200);
      }
   
    private string GetHTMLFeed(string pURLFeed, int pMaxContenidoResumen) 
    {
      try
      {
        string res = "";

        #region Obtener XMLFeed
         XmlReaderSettings settings = new XmlReaderSettings();
         settings.DtdProcessing = DtdProcessing.Parse;
         XmlReader xmlReader = XmlReader.Create(pURLFeed, settings);

         SyndicationFeed feed = SyndicationFeed.Load(xmlReader);
         foreach (SyndicationItem item in feed.Items)
         {
           //char[] caracteres = item.Summary.Text.Substring(0, pMaxContenidoResumen).ToCharArray();
           res += string.Format("\r
{2} ...

\r", item.Title.Text, item.Links.LastOrDefault().Uri.ToString(), item.Summary.Text.Substring(0, pMaxContenidoResumen).Replace("\n", "")); } #endregion return res; } catch (Exception ex) { throw ex; } } } }

Hasta aquí el artículo de esta semana, recordaros que podéis consulta el archivo de

areaTIC

en busca de artículos que podrían interesarte y no olvides seguirnos en las redes sociales!


martes, 8 de enero de 2013

SQL Server: Modos de evaluación de directivas

En el artículo "SQL Server: Uso de directivas y condiciones para saber si hay tablas sin índice cluster" del 25 de diciembre os indicaba que existen varios

modos de evaluación de directivas

, hoy toca explicar en qué consiste cada uno de los cuatro existentes:

  1. On demand

    , la

    directiva

    se evalúa cuando lo especifica el usuario (de forma manual).

  2. On schedule

    , mediante un trabajo de

    SQL Server

    se especifica la periodicidad con la que se evalúa la

    directiva

    (automático).

  3. On change: log only

    , utiliza la notificación de eventos para evaluar la

    directiva

    cuando algún cambio relevante sucede (automático).

  4. On change: prevent

    , utiliza DDL triggers para detectar y deshacer las operaciones que provocan la violación de

    directivas

    definidas (de forma automática). Para que este

    modo de evaluación

    funcione es necesario que estén habilitados en el servidor los triggers anidados (nested triggers), podéis encontrar información al respecto en el siguiente enlace del MSDN.

En la siguiente imagen podemos ver cómo especificamos el

modo de evaluación de la directiva

cuando creamos/modificamos una.


También, tal y como comentaba en el artículo citado anteriormente, los

modos de evaluación de directivas

dependen de la

faceta

sobre la que se aplica la

condición

. A destacar:

Para saber los

modos de evaluación de directivas

de cada

faceta

es importante tener en cuenta:
  1. La siguiente consulta nos permite saber qué

    modo de evaluación de directivas

    aplica a cada

    faceta

    .

    -- Modos de evalución por faceta
    SELECT name AS Faceta, 
     CASE execution_mode
     WHEN 7 THEN 'On change: prevent'
     WHEN 6 THEN 'On change: log only'
     WHEN 4 THEN 'On schedule'
     WHEN 0 THEN 'On demand'
     ELSE 'Undefined'
     END AS ModoEvaluacion
    FROM msdb.dbo.syspolicy_management_facets 
    order by execution_mode
    
    Nos devuelve el siguiente conjunto de resultados:


    De este modo, por ejemplo, podemos definir

    directivas

    para prevenir que se creen stored procedures cuyo nombre no comience por 'usp' pero no podemos definir

    directivas

    para prevenir que se creen tablas cuyo nombre no comience por 'tbl'.

  2. Unas pocas

    directivas

    soportan el

    modo de evaluación 'On change: prevent'

    , algunas más el

    On change: log only

    , unas cuantas más el

    On schedule

    y todas el

    On demand

    . El siguiente gráfico muestra mejor el concepto. Sólo soportan los

    modos de evaluación 'On Change'

    aquellas

    directivas

    relacionadas con

    facetas

    que tienen cobertura de eventos DDL.


Y hasta aquí el artículo de hoy, espero que os haya sido interesante, dentro de

areaTIC

puedes encontrar otros artículos, no dudes en consultar nuestro archivo; también puedes seguirnos por RSS o las principales redes sociales (twitter, facebook, linkedin...)


LECTURAS RELACIONADAS RECOMENDADAS POR AREATIC.NET

viernes, 4 de enero de 2013

Importancia DateTime.SpecifyKind trabajando con nullable<DateTime> en escenarios de intercambio XML

Al enviar/recibir información entre varias plataformas en formato

Xml

ya sea vía

soap

o similares tenemos que considerar la importancia de especificar bien la zona horaria al trabajar con campos DateTime en el

Xml

para evitar situaciones comprometidas.

Por defecto al definir un campo de tipo

xs:Datetime

en un modelo

xsd

aceptará un valor de Fecha y Hora con o sin especificar la zona horaria. Para especificar la zona horaria tendríamos que concatenar una "Z" (defecto, UTC) o concatenar al final +/- HH:mm para indicarle que desvío queremos que se aplique en la fecha respecto a GMT.

Resumiendo no hay modo de obligar a través de una definición tipo

xsd

a especificar la zona horaria en los campos de tipo fecha. Tal vez usando el atributo pattern de la especificación para DateTime se podría llegar a hacer algo pero no lo he probado y seguramente herramientas de generación de código como svutil o axis no reconocerían esta restricción con lo tampoco ganaríamos mucho.

A continuación veremos un caso curioso relacionado con la zona horaria que podría darse si estamos trabajando en una plataforma .NET

c#

:
DateTime fechaActual = DateTime.Now;
DateTime? fechaDesde = null;

fechaDesde = fechaActual.AddDays(-1);
Si nos fijamos el campo fechaDesde está definido como

nullable

.
<s:Envelope>
<s:Body>
<request>
<a:fechaDesde>2012-12-28T09:20:12</a:fechaDesde>
<a:fechaHasta>2013-01-03T11:59:55.0938142+01:00</a:fechaHasta>
</request>
</s:Body>
</s:Envelope>
Al enviar esta información vía soap, en el campo fechaDesde no se ha concatenado el +01:00 de la zona horaria mientras en el campo hasta si lo está. Esto podría originar que el receptor del mensaje tome el formato UTC tomando como valor 1 hora menos en este caso. La clase DateTime de .NET tiene una propiedad Kind que permite consultar la zona horaria del tipo, y por otro lado tenemos el método

DateTime.SpecifyKind

que permite especificar el tipo de zona horaria que queremos por defecto. En los tipos DateTime por defecto toma el valor "Local" que se corresponde al sistema operativo que esté ejecutando la aplicación pero en los tipos

nullable

está propiedad no se comporta del mismo modo por defecto al definir la instancia y hemos de asignarle mediante

SpecifyKind

el tipo de zona horaria que necesitamos. Veamos como hacerlo:
DateTime fechaActual = DateTime.Now;
DateTime? fechaDesde = null;

fechaDesde = DateTime.SpecifyKind(fechaActual.AddDays(-1), DateTimeKind.Local);
Con esto ya estaríamos especificando a nivel

soap

la zona horaria en el campo fecha desde como vemos abajo.
<s:Envelope>
<s:Body>
<request>
<a:fechaDesde>2012-12-28T09:20:12+01:00</a:fechaDesde>
<a:fechaHasta>2013-01-03T11:59:55.0938142+01:00</a:fechaHasta>
</request>
</s:Body>
</s:Envelope>
Hasta aquí el artículo de hoy, os recuerdo que podéis seguir

areaTIC

en las redes sociales o vía RSS!


martes, 1 de enero de 2013

Alexa Traffic Rank: qué es, para qué sirve y cómo mejorarlo

Alexa

es una compañía filial de Amazon (desde 1999) conocida principalmente por su web y su barra de herramientas. Precisamente esta barra de herramientas recoge los datos de navegación de los usuarios que la tienen instalada y los utiliza para calcular el

Alexa Traffic Rank

que sirve para medir la popularidad de un sitio web en función del número de visitantes y las páginas que han visto durante los últimos tres meses.


Vendría a ser un ranking en el que la primera posición la ocupa el sitio con mayor número de visitas y páginas visualizadas; dicho ranking está disponible a nivel mundial y para cada país. Es importante destacar que la precisión del

Alexa Traffic Rank

es relativa ya que, tal como comentaba anteriormente, sólo tiene en cuenta los datos de navegación de aquellos usuarios que tienen la barra de herramientas de

Alexa

instalada…

  • ¿Cuántos usuarios la tienen instalada?

    Alexa

    no ofrece información sobre este dato.

  • ¿Qué usuarios la tienen instalada? Normalmente este tipo de barras se la instalan webmasters, managers SEO, managers de marketing online… ¿representa esto a toda la comunidad de internautas? yo diría que no…

  • Sólo tiene en cuenta los últimos tres meses, ¿y todas las visitas y páginas vistas anteriormente?

Si queréis una opinión más sobre lo anterior podéis consultar la de

Peter Norvig

(Director de Investigación de Google) en su siguiente artículo Alexa Toolbar and the Problem of Experiment Design.

A pesar de todo lo anterior el

Alexa Traffic Rank

tiene su reputación en internet y como en todo ranking cuanto mejor esté posicionado nuestro sitio mejor, eso sí, debemos considerarlo un ranking más y no le demos más importancia de la que realmente tiene. Nos puede servir, aunque no sea exacto, como prueba imparcial de las visitas de nuestro sitio frente a otro de la competencia, de cara a posibles anunciantes,… así que para mejorar tu posición en el

Alexa Traffic Rank

es recomendable:

  1. Lo primero es reclamar tu sitio, puedes hacerlo a través del siguiente enlace siguiendo los pasos correspondientes.

  2. Instala la barra de herramientas de

    Alexa

    en tu navegador así cada vez que navegues por tu sitio contarán esas visitas. Puedes instalar la barra mediante este enlace.

  3. Añade alguno de los widgets que ofrece

    Alexa

    a tu sitio, puedes encontrarlos en el siguiente enlace.

  4. Y como siempre lo más importante, el contenido. Crea contenidos de calidad en tu sitio, con frecuencia, utiliza las redes sociales para que lleguen al máximo número de internautas… al final esto se traduce en visitas y seguro que un % de ellas tienen la barra de herramientas

    Alexa

    instalada y hacen mejorar tu posición en el ranking. Os adjunto un par de gráficos sobre la evolución en el

    Alexa Traffic Rank

    de

    areaTIC.net

    durante 3 meses, en el ranking mundial y en España.



Para finalizar el artículo tres temas más que os pueden resultar interesantes:

  • No confundir el

    Alexa Traffic Rank

    con el

    Pagerank

    de Google, no tiene nada que ver ni hay relación entre ellos. Si quieres saber más sobre el

    Pagerank

    consulta el artículo de

    areaTIC.net

    Manual SEO, 5 conceptos básicos.

  • Alexa

    no es la única web que ofrece este servicio, competencia suya son compete.com y quantcast.com.

  • El ranking en

    Alexa

    no influye en el posicionamiento de una web en los distintos buscadores.

Y hasta aquí el artículo de hoy, el primero del 2013!!! Espero os haya parecido interesante, recordad dentro de

areaTIC

puedes encontrar otros artículos, no dudes en consultar nuestro archivo; también puedes seguirnos por RSS o las principales redes sociales (twitter, facebook, linkedin...)