Mais acessados

quinta-feira, 1 de agosto de 2013

ASP.NET Web API - AutoComplete usando Web API, Jquery UI e JSON

ASP.NET Web API é um framework para construir APIs web em cima do .NET Framework. Neste tutorial, vou mostrar com fazer um simples AutoComplete usando WebApi retornando JSON e Jquery UI. É necessário Visual Studio 2010/2012 com o template do ASP.NET MVC 4 Project instalados.

Criando o projeto Web Api

No Visual Studio, para um novo projeto:
  1. File->New Project-> Templates->Installed Templates->Visual C#->ASP.NET MVC 4 Web Application
  2. Na janela selecione Web API.
Caso já tenha um projeto MVC:
  1. Adicione referência para System.Web.Http.WebHost.
  2. Adicione o arquivo App_Start\WebApiConfig.cs (use como exemplo o código do post).
  3. Adicione using System.Web.Http in Global.asax.cs.
  4. Chame WebApiConfig.Register(GlobalConfiguration.Configuration) na função Start Global.asax.csantes da rota MVC, por causa de sua precedência.

Criando o Modelo AutoComplete

Para criar o nosso resultado JSON vou usar um modelo que pode ser reutilizado toda vez que precisarmos da funcionalidade, chamado AutoCompleteModel. Esse modelo possui os campos padrão que a função do Jquery UI utiliza. Segundo a documentação oficial pode ser de duas maneiras:
  • Lista de Strings: [ "Choice1", "Choice2" ]
  • Array de objetos com as propriedades label evalue:[ { label: "Choice1", value: "value1" }, ... ]

Neste exemplo vou trabalhar com o Array de objetos, que será representado pelo objeto AutoComplete. Na maioria dos casos o desenvolvedor trabalha neste modelo, dado que é necessário usar o Value, que pode representar uma chave primária ou outra informação que será essencial para executar alguma lógica ao submeter o form.

     Model/AutoCompleteModel.cs

Criando nossa API

Nossa API será bem simples, vamos criar uma Action que retorne uma lista de AutoComplete passando como parametro uma string com nome term. Fica como observação que term é o nome padrão que o Jquery UI AutoComplete usa na requisição, logo seu método action deve receber exatamente esse nome nesse caso.


Controller/AutoCompleteController.cs


Especificando AcceptVerbs na Action nos permite que chamemos nosso método como api/AutoComplete/Cars. Mas fazendo isso se faz necessário especificar também o método, no nosso caso é um GET, então HttpGet. Isso é somente perfumaria, para que fique mais legível a url.


Configurando a API

A configuração de rotas que vou usar é a que vem por padrão no projeto. Uma coisa que deve ser mudada está relacionado com o Formatter. Por padrão, o Formatter utilizado no Web Api é o XML, mas no nosso caso queremos JSON. Outra coisa está relacionada ao nome das propriedades, dado que em nosso modelo elas estão em case diferente do que é requerido pela função (está Value, precisa ser value).

App_Start/WebApiConfig.cs

Nossa Api já está funcionando, podemos acessá-la pelo próprio browser.


Criando os campos View

Na View haverão dois campos: um input que será usado para autocomplete e um div de log que receberá o que for selecionado. Eu usei basicamente o mesmo html que está no site de referência do Jquery UI Autocomplete.

  Views/Home/Index.cshtml

Esse HTML nos dá como resultado o seguinte:


Criando a função JavaScript

Para o auto complete foi usado o Jquery UI AutoComplete. O exemplo é simples, vamos consultar remotamente nosso caminho de API, retornar um JSON já no formato esperado e ao selecionarmos um elemento esse será colocado no campo Result. A função foi baseada no exemplo do site oficial do Jquery, fiz algumas alterações apenas para adequar o source a nosso local e os nomes dos campos que mudei.


 Views/Home/Index.cshtml

Finalizando

Já com tudo pronto é possível utilizar nosso autocomplete. Ao digitar dois ou mais caracteres o campo exibe as opções de busca.


Ao selecionar um registro, é adicionado ao Log.


Web API e JSON trazem benéfícios impressionantes em relação a banda. A requisição dessa lista auto complete por exemplo não passou de 502 bytes. Espero que tenham gostado, o exemplo pode ser baixado aqui.

quarta-feira, 20 de fevereiro de 2013

ASP.NET WebForms - Urls simplificadas usando o FriendlyUrls

No dia 18/02/2012 saiu mais um patch de atualização ASP.NET and Web Tools 2012.2 update. Dentre as várias melhorias contidas nesse patch a que mais chamou minha atenção foi o suporte nativo a FriendlyUrls, que torna possível usar o sistema de rotas introduzido no ASP.NET v4.0 de maneira fácil com o WebForms.

Conceito


Para aqueles que já programaram para a plataforma ASP.NET MVC/WebApi notaram a estrutura bem definida das Urls organizadas por diretórios, actions e controllers. Com o lançamento deste novo patch ficou simples disponibilizar em sua aplicação Urls que independem da extensão de seu arquivo WebForm. Isso, graças a uma nova classe helper, FriendlyUrls que disponibiliza uma série de métodos que fazem o "trabalho sujo por trás dos panos".

Implementação


Se você estiver criando um novo projeto ASP.NET WebForms depois de instalar o ASP.NET and Web Tools 2012.2 update as configurações do FriendlyUrls já vem habilitadas por padrão. Caso contrário basta adicionar via NuGet, abrindo o Pack Mananger Console, usando o comando "Install-Package Microsoft.AspNet.FriendlyUrls -Pre".
Com o FriendlyUrls instalado no seu projeto resta somente programação. Criei uma classe chamada RouteConfig para habilitar o FriendlyUrls e no Global.asax usei essa classe para registrar as rotas na tabela.
    public static class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.EnableFriendlyUrls();
        }
    }
 
    public class Global : HttpApplication
    {
        void Application_Start(object sender, EventArgs e)
        {
            BundleConfig.RegisterBundles(BundleTable.Bundles);
            AuthConfig.RegisterOpenAuth();
            RouteConfig.RegisterRoutes(RouteTable.Routes);
        }
    }
O método EnableFriendlyUrls() é um extension method da classe FriendlyUrls que faz todo o trabalho duro. Agora basta digitar o endereço de página sem se preocupar com a extensão .aspx. Uma observação é que se a página estiver continda dentro de um diretório com o mesmo nome desta, ele não consegue resolver a rota.
A classe FriendlyUrls trás alguns métodos interessantes. Na imagem abaixo em amarelo estão a Url que acessei e o caminho virtual obtido com a chamada do método.
 //Recupera o caminho virtual da página
 Request.GetFriendlyUrlFileVirtualPath();
 //Recupera os segmentos da url
 Request.GetFriendlyUrlSegments();
Com esse método é possível recuperar os segmentos da Url. Veja que tudo que vem após o nome da página é considerado como segmento.
 //Ajuda a criar os links para as páginas
 FriendlyUrl.Href("~/Pages/QueryStringPage", "ID", "1001");
Grifado na imagem abaixo está uma Url criada com um método utilitário da classe.
Espero que a dica seja útil! Não deixem de baixar o ASP.NET and Web Tools 2012.2 update. O exemplo que criei pode ser baixado aqui.



segunda-feira, 18 de fevereiro de 2013

ASP.NET Web API / HTML5 - Streaming de áudio e vídeo assincronamente

Muita gente acha que a WebApi é apenas um Framework para desenvolver outros Frameworks. Mas na verdade é uma maneira de usar o máximo de desempenho e controle sobre aplicativos que utilizam HTTP. Neste breve texto irei mostrar como fazer streaming de áudio e vídeo assincronamente usando ASP.NET WebApi.

Conceito básico


Para enviarmos dados assincronamente tiraremos proveito da nova classe PushStreamContent contida no namespace System.Net.Http. Essa classe permite que possamos enviar pacotes por demanda para o cliente. A referência que tive veio do blog Andru's WebLog. Em nosso caso leremos o arquivo do disco do servidor e o enviaremos pouco a pouco para o cliente que visualizará ou escutará a mídia por meio de controles HTML5 de áudio e vídeo.

Implementação


//A classe recebe como construtor uma Action
public PushStreamContent(Action onStreamAvailable);

Criei uma classe de ajuda que lê a mídia do disco do servidor e assincronamente a salva em um buffer e libera para o cliente de acordo com a demanda. Usei as novas técnicas de programação contidas no C# 5.0 async/await para realizar a tarefa.
    public class MediaStream
    {
        private readonly string _filename;

        public MediaStream(string filename)
        {
            this._filename = filename;
        }

        public async void WriteToStream(Stream outputStream, HttpContent content, TransportContext context)
        {
            try
            {
                var buffer = new byte[65536];

                using (var media = File.Open(_filename, FileMode.Open, FileAccess.Read))
                {
                    var length = (int)media.Length;
                    var bytesRead = 1;

                    while (length > 0 && bytesRead > 0)
                    {
                        bytesRead = media.Read(buffer, 0, Math.Min(length, buffer.Length));
                        await outputStream.WriteAsync(buffer, 0, bytesRead);
                        length -= bytesRead;
                    }
                }
            }
            catch (HttpException ex)
            {
                return;
            }
            finally
            {
                outputStream.Close();
            }
        }
    }
Note que a assinatura do método WriteToStream corresponde a assinatura do métodos PushStreamContent. Logo depois criei duas classes, uma para Vídeo e outra para Áudio ambas filhas da classe MediaStream. Fiz dessa maneira para promover uma certa extensibilidade caso seja necessário fazer algo mais complexo mais tarde.
    public class VideoStream : MediaStream
    {
        public VideoStream(string filename) : base(filename)
        {

        }
    }
    public class AudioStream : MediaStream
    {
        public AudioStream(string filename) : base(filename)
        {

        }
    }
Agora vamos para a classe Controller para áudio e vídeo, que ficaram bastante simples após a separação nas classes anteriores.
    public class AudiosController : ApiController
    {
        // GET api/music/5
        public HttpResponseMessage Get(string filename, string ext)
        {
            filename = @"\Content\Audio\" + filename + "." + ext;

            var audio = new AudioStream(filename);

            var response = Request.CreateResponse();
            response.Content = new PushStreamContent(audio.WriteToStream, new MediaTypeHeaderValue("audio/" + ext));

            return response;
        }
    }

    public class VideosController : ApiController
    {
        // GET api/music/5
        public HttpResponseMessage Get(string filename, string ext)
        {
            filename = @"\Content\Audio\" + filename + "." + ext;

            var video = new VideoStream(filename);

            var response = Request.CreateResponse();
            response.Content = new PushStreamContent(video.WriteToStream, new MediaTypeHeaderValue("video/" + ext));

            return response;
        }
    }
O nome do arquivo deve conter o caminho completo do mesmo em seu servidor, logo quando for fazer o seu teste lembre-se disso. Agora para que o cliente possa passar um endereço e consumir os nossos serviços é necessário que este registre uma rota com a padrão correspondendo, neste exemplo estou usando api/extensão/nomeDoArquivo:
config.Routes.MapHttpRoute(
    name: "DefaultVideo",
    routeTemplate: "api/{controller}/{ext}/{filename}"
);

Consumindo os serviços


Basta criar uma página e adicionar nossos controles HTML5:
    

Música

Video

Agora você pode abrir alguma ferramenta como firebug e ver que o conteúdo está sendo transmitido por streaming e não sendo carregado como um todo. Uma observação é que você deve usar o Chrome para fazer seus testes e brincar com este exemplo, eu não consegui fazer funcionar em nenhum outro =). Espero que tenham gostado da dica, o código fonte se encontra abaixo: