Como construir um Widget para o Twitter com ASP.NET

Postado por Abraão Levi Oliveira Figueredo em 25 de maio de 2010

Logo Visual StudioNeste 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.

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 atributo Assembly 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:

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:

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!



Compartilhe:

Sobre: Abraão Levi Oliveira Figueredo

Desenvolvedor web do Kekanto um guia colaborativo de Restaurantes, Bares, Baladas. Acredita em idéias simples e usabilidade. Sigam @AbraaoLevi

Comentários (1)

Rose Pereira 4 de julho de 2010 às 0:58    

nossa. qual e tua profisao mesmo?

Deixe um Comentário!

Nome: ( necessário )

E-Mail: ( necessário )

Website:

Comentário: