Mais acessados

Mostrando postagens com marcador Web API. Mostrar todas as postagens
Mostrando postagens com marcador Web API. Mostrar todas as postagens

terça-feira, 13 de agosto de 2013

ASP.NET Web API - Criação de select (DropDownList) em cascata, usando Ajax, JQuery e JSON.

Essa semana estava criando um sistema e me deparei com um problema relacionado a select list (nome da tag HTML, mas conhecido como Drop Down List no mundo Windows) encadeados. O sistema teria vários desses select em cascata.

Como um bom programador, resolvi encapsular a lógica deste em algum lugar, para futuro reuso. Então surgiu a ideia de criar uma extensão do JQuery que já fizesse o trabalho duro. É 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.cs, antes da rota MVC, por causa de sua precedência.

A ideia

O principal objetivo era diminuir a complexidade de criar o cascateamento e também performance, dado que o resultado é em JSON, diminuindo assim, o tráfego de dados. Principalmente porque eu o usaria para mobile.

O cascateamento de componentes é recursivo por natureza. Então resolvi usar os novos padrões HTML5 data-* (chamado de "data dash attribute"), que salva as informações para que o select saiba seu comportamento. A url de origem dos dados, os parâmetros a serem passados, paramName, quem dispararia o evento para ele ser preenchido, o parentSelectId e um texto padrão que este teria vazio ou não selecionado o defatulText.

Chamada do método

A Web API

Criei um objeto SelectOption  que remete ao que é esperado pelo jquery-cascadeselect (esse o nome da extensão que crie :D).  Então nossos métodos devem preencher e retornar esse objeto.

Model/SelectOption.cs


Padrão do JSON gerado

No exemplo eu vou usar Estado, Cidade e Região. Veja que retorno em cada método de API é uma lista de SelectOption. Preste atenção também nos parâmetros. Vamos usá-los mais tarde.

Controller/SearchController.cs


Na configuração do Web API, adicionei a action na rota, porque temos mais de um método GET dentro do mesmo controller, caso contrário  o Routing não irá resolver o endereço requisitado. Além disso, JSON foi colocado como padrão de retorno.

App_Start/WebApiConfig.cs

Uso

O uso é bem simples, basta chamar como se fosse um método do JQuery, dado que é uma extensão. No exemplo abaixo estou usando com ASP.NET Web API, mas não há restrições, o endereço passado só deve garantir que seja retornado JSON no formato correto .

Cascateamento entre Regiões, Estado e Cidades


Lembra-se dos parâmetros da nossa WebAPI? Por exemplo regiaoId, o nome deve ser idêntico para que o GET seja feito corretamente.

HTML exemplo

Resultado

Abaixo está o resultado, o jquery-cascadeselect cuida da parte chata de lógica automaticamente. Ao mudarmos as seleções os select são populados segundo a configuração feita. No exemplo clássico abaixo tenho Região, Estado, e Cidade:

Regiões é o pai de todos, então já vem populado

Mudando a seleção de Região o Estado é populado

Mudando a seleção de Estado vêem as Cidades

Contribua

Eu criei uma entrada no Git Hub para jquery-cascadeselect. Não sou nenhum "expert" em JavaScript, então o código pode estar um pouco "bagunçado" e sem padrão, mas está funcionando que é uma maravilha :D! Se você tem interesse em contribuir acesse. 

Espero que tenham gostado. O exemplo que usei para testar, igual ao das imagens acima, pode ser baixado aqui.


terça-feira, 6 de agosto de 2013

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

No último post sobre ASP.NET Web API, ASP.NET Web API - AutoComplete usando Web API, Jquery UI e JSON mostrei como fazer um simples AutoComplete. Nesse artigo vou mostrar como incrementar o que foi feito anteriormente, possibilitando exibir a imagem do que está sendo pesquisado, ou até mais informações para cada item. É necessário uma revisão post mencionado e o Visual Studio 2010/2012 com o template do ASP.NET MVC 4 Project instalados.


AutoComplete com Imagem


Criando o Modelo AutoComplete

No artigo anterior o nosso AutoComplete exibia apenas um texto para o usuário. Nosso modelo então precisa de um pequeno "upgrade" :). Precisamos de um AutoCompleteImageModel, que terá além informações básicas padrão para o Jquery UI AutoComplete , também caminho da imagem de cada item.


 Model/AutoCompleteImageModel.cs

Modificando a View

A versão original do AutoComplete não possui overflow, logo, quando o resultado traz muitos itens fica uma "bagunça". Para solucionar isso basta alterar o css, conforme uma solução como esta: Jquery UI Scrollable Results.

Content/Site.css

Basicamente alterei o css padrão do AutoComplete para ter um tamanho máximo e exibir a scrollbar.

Para nossa Imagem e descrição do AutoComplete, criei o css abaixo:

Content/Site.css

Modificando a função JavaScript

A api do Jquery UI é bem robusta, logo a personalização é algo que estava em mente quando foi construída. É possível então no AutoComplete modificar o template que é exibido para o usuário. Logo, existe o Jquery UI AutoComplete custom data. O exemplo que vou usar é bem parecido com o do site oficial.

Views/Home/Index.cshtml


O item é nosso objeto JSON espelho do AutoCompleteImageModel, logo item.value, item.label e item.image são exatamente o que criamos no servidor.

Resultado JSON para a API

Em amarelo está mudança que fiz ao log. Ao selecionarmos um item o log exibirá o mesmo que está no AutoComplete.


Em azul está o Html personalizado. O AutoComplete é uma tag ul, que passamos por parametro por essa função do proprio Jquery. Na ul é possível adicionar qualquer Html personalizado como eu fiz. Coloquei a imagem, o código e o modelo que vem do nosso JSON. 

É possível colocar praticamente qualquer coisa, o único cuidado é que o conteúdo tem que estar dentro de uma tag a.


Finalizando

Na parte Web API o que foi mudado é que populo o novo modelo já com o caminho da imagem que será exibida de cada item.

O resultado é esse:




Ao selecionar um item este vai para o log:


Espero que tenham gostado, o exemplo pode ser baixado aqui.


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.cs, antes 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.

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: