segunda-feira, 7 de maio de 2012

Como construir um Widget para o Twitter com ASP.NET

Neste tutorial, você vai aprender a desenvolver um widget Twitter para ASP.NET sob a forma de um controle de servidor reutilizáveis, como transformar automaticamente URLs em links, e cache para acelerar o carregamento da página.

Passo 1 Introdução

Para seguir este tutorial, tudo que você precisa é o Visual Studio (Você pode usar MonoDevelop , projeto Mono, se você não estiver no Windows, embora não haja garantias e nem suporte pela Microsoft, mas você pode tentar.) ou ainda utilizar a versão Web Developer Express Edition.

Você também vai precisar de conhecimento de C# 3.0, como este tutorial faz uso de algumas das novas funcionalidades da linguagem, como a utilização da palavra reservada var.

Passo 2 Criando o Controle

O ASP.NET inclui um recurso útil conhecido como Server Controls. Estas são marcas personalizadas que visam ajudar os desenvolvedores com a estrutura de seu código. Quando uma página usando um controle de servidor é solicitado, o ASP.NET runtime executa o método Render (), e inclui a saída na página final.

Clique na imagem para ampliar

Depois de criar uma nova Web Application no Visual Studio, clique com o botão direito no Solution Explorer e adicione um novo item para a aplicação. Selecione ASP.NET Server Control, e dê um nome. Aqui, eu chamei de Twidget.cs, mas fique à vontade para chamá-lo com quiser. Cole o seguinte código, e não se preocupe se tudo parece um pouco estranho.

using System;
using System.Collections.Generic;
using System.Linq; 
using System.Web; 
using System.Web.UI; 
using System.Web.Script.Serialization; 
using System.Net;

namespace WebApplication1 
{
     public class Twidget : Control 
     { 
            public string Account { get; set; }
            public int Tweets { get; set; } 

            protected override void Render(HtmlTextWriter writer) 
           {
                    writer.Write("<ul>"); 

                    foreach (var t in GetTweets().Take(Tweets)) 
                            writer.Write("<li>{0}</li>", HttpUtility.HtmlEncode(t)); 

                   writer.Write("</ul>");
           }

           public List<string> GetTweets()
           { 
                    var ls = new List<string>();

                    var jss = new JavaScriptSerializer();
                    var d = jss.Deserialize<List<Dictionary<string, object>>>(
                            new WebClient()
                            .DownloadString("http://api.twitter.com/1/statuses/user_timeline.json?screen_name=" + Account)
                            );

                    foreach (var x in d)
                            ls.Add((string)x["text"]);

                    return ls; 
           } 
     } 
}

Passo 3 usando o controle

Agora temos o código para o nosso widget Twitter. Abra a página Default.aspx e coloque o seguinte código após o :

<%@ Register TagPrefix="widgets" Namespace="WebApplication1" Assembly="WebApplication1" %>

Sinta-se livre para mudar o TagPrefix para o que quiser, mas certifique-se que o atributo namespace esta definido corretamente para qualquer espaço que você colocou o código dentro do widget , e veja também se o atributoAssembly está definido para o nome do seu aplicativo web (no nosso caso , WebApplication1).

Uma vez que você registrou o prefixo, você pode começar a usá-lo. Cole o seguinte código em algum lugar na sua página, e mais uma vez, sinta-se livre para alterar os atributos que desejar.

<widgets:Twidget runat="server" Account="Sua-conta-no-Twitter" Tweets="10" />

Se você tiver feito tudo corretamente, você deve ver uma página semelhante a esta quando você executar o aplicativo Web:

Clique na imagem para ampliar

Etapa 4 Melhorando Algumas Coisas …

O controle que nós temos no momento é bastante rudimentar. Para dar uma melhorada vamos tornar os links clicáveis.

Encontre o loop foreach no método Render () e desfazer-se completamente. Substitua-a por isso:
// Você precisa importar o uso de expressões regulares, cole isso junto com os outro using using System.Text.RegularExpressions;

//Substitua esse foreach pelo que já havia no código anterior foreach (var t in GetTweets().Take(Tweets))
        string s = Regex.Replace( 
                HttpUtility.HtmlEncode(t),
               @"[a-z]+://[^\s]+",
               x =&gt; "<a href="&quot; + x.Value.Replace(&quot;">" + x.Value + "</a>",
               RegexOptions.Compiled | RegexOptions.IgnoreCase
                );
        writer.Write("<li>{0}</li>", s); 
}

Vamos entender o Regex.Replace () na linha 6.

O primeiro parâmetro é a entrada do Regex. Neste caso, é apenas o texto do tweet após a passagem através HttpUtility.HtmlEncode (). A entrada é então comparado com o segundo parâmetro que é uma expressão regular concebido para corresponder a uma URL.

Ao final, deve aparece algo parecido com isso:

Clique na imagem para ampliar

Etapa 5 Caching

Há um grande problema com o código acima, e que é que ele não armazena em cache a resposta da API do Twitter. Isto significa que toda vez que alguém carrega sua página, o servidor tem que fazer uma solicitação para a API do Twitter e esperar por uma resposta. Isso pode diminuir seu tempo de carregamento da página e também pode deixar você mais vulnerável a um ataque de negação de serviço. Podemos resolver tudo isso implementando um cache.

Embora a estrutura básica do código do controle permanece após a implementação de cache, há muitas pequenas alterações. Observe:

using System;
using System.Collections.Generic; 
using System.Linq; 
using System.Web; 
using System.Web.UI; 
using System.Web.Script.Serialization; 
using System.Net; 
using System.Threading; 
using System.Text.RegularExpressions; 

namespace WebApplication1 
      public class Twidget : Control 
     { 
            public string Account { get; set; }
            public int Tweets { get; set; } 
            public int CacheTTL { get; set; } 

            static Dictionary<string, CachedData<List<string>>> Cache = new Dictionary<string, CachedData<List<string>>>(); 

            protected override void Render(HtmlTextWriter writer) 
            { 
                   writer.Write("<ul>");
            
                   foreach (var t in GetTweets().Take(Tweets)) 
                  {
                        string s = Regex.Replace(
                               HttpUtility.HtmlEncode(t),
                               @"[a-z]+://[^\s]+",
                                x => "<a href='" + x.Value.Replace("'", "&quot;") + "'>" + x.Value + "</a>",
                                RegexOptions.Compiled | RegexOptions.IgnoreCase 
                                );

                        writer.Write("<li>{0}</li>", s);
                  }

                  writer.Write("</ul>");
            }

            public List<string> GetTweets() 
            { 
                  if (!Cache.Keys.Contains(Account) 
                        || (DateTime.Now - Cache[Account].Time).TotalSeconds > CacheTTL 
                        ) 
                        new Thread(Update).Start(Account);
                     
                  if (!Cache.Keys.Contains(Account)) 
                        return new List<string>();

                  return Cache[Account].Data;
            } 
 
             public static void Update(object acc)
            { 
                  try
                  { 
                        string Account = (string)acc;

                        var ls = new List<string>();

                        var jss = new JavaScriptSerializer();
                        var d = jss.Deserialize<List<Dictionary<string, object>>>(
                                new WebClient()
                                .DownloadString("http://api.twitter.com/1/statuses/user_timeline.json?screen_name=" + Account) 
                                );

                        foreach (var x in d) 
                                ls.Add((string)x["text"]);

                        if (!Cache.Keys.Contains(Account)) 
                                Cache.Add(Account, new CachedData<List<string>>());

                        Cache[Account].Data = ls;
                  } 
                  catch (Exception) { }
            }
     }

     class CachedData<T>
     { 
            public DateTime Time { get; private set; }

            T data;
            public T Data {
                  get { 
                        return data; 
                  } 
                  set          
                  { 
                        Time = DateTime.Now;
                        data = value; 
                  } 
            } 
     } 
}

O método Render () permanece inalterado, mas há algumas mudanças bastante drásticas em algumas partes. Nós mudamos o GetTweets () método, adicionou uma nova propriedade (CacheTTL), acrescentou um campo particular estático (Cache), e há ainda toda uma nova classe – CachedData.

O método GetTweets() não é mais responsável por falar com a API. Em vez disso, ele só retorna os dados no cache. Se detectar que a conta Twitter solicitado não tenha sido ainda colocado em cachê, ele irá gerar um segmento separado de forma assíncrona para atualizar o cache do tweet. Note que todo o corpo do método Update () é encerrado em um bloco try / catch, pois embora uma exceção no segmento página apenas exibe uma mensagem de erro para o usuário, se ocorrer uma exceção em outro segmento, ele irá desenrolar de todos os caminho de volta até a pilha e eventualmente travar o processo de trabalho responsável por atender toda a sua aplicação web.

O cache tweet é implementado como uma string <Dictionary, CachedData <string>>, onde o nome do usuário da conta do Twitter que está sendo armazenado em cache é a chave, e uma instância da classe CachedData <T> é o valor. A classe CachedData <T> é uma classe genérica e pode ser usado com qualquer tipo. Ela tem duas propriedades públicas, Data , que é alimentado pelo valor da resposta do tweet e Time, que é atualizada sempre que o tempo atual da propiedade Data estiver setado.

Você pode usar o seguinte código na sua página para usar esta versão em cache do widget. Note que o atributo CacheTTL é demostrado em segundos.

<widgets:Twidget runat="server" Account="twitter" Tweets="10" CacheTTL="600" />


Então é isso… Espero que tenham gostado! Vejam o artigo original. Até a próxima!


Artigo postado em: ASP.NET

Nenhum comentário:

Postar um comentário