Pesquisar

Usando parametros OData na Web API

Neste artigo vou mostrar um recurso muito poderoso da Web API, que é o suporte a ODATA.

Primeiro você deve baixar o Update para o Visual Studio 2012 no link abaixo.

http://www.asp.net/vnext/overview/fall-2012-update

Este update contém algumas novidades, entre elas a integração entre o Entity Framework (Iqueryable) e o a WebApi (OData).

Segundo passo-> Criar uma classe Usuario que servira como modelo para efetuarmos o CRUD.

using System;
using System.Collections.Generic;
 
public partial class Usuario
{
    public int Id { getset; }
    public string Nome { getset; }
    public string Telefone { getset; }
    public string Email { getset; }
    public string Senha { getset; }
}

Segundo passo -> Criar o DBContext do Entity Framework que servira de acesso a dados.

public partial class Model1Container : DbContext
{
    public Model1Container()
        base("name=Model1Container")
    {
    }   
 
    public DbSet UsuarioSet { getset; }
}

Terceiro Passo -> Adicionar a string de conexão no web.config. O nome da string de conexão deve ser a mesma que está em seu DBContext, no nosso caso Model1Container.

<add name="Model1Container" providerName="System.Data.SqlClient" connectionString="Data Source=DANIMAR-PC\SQLEXPRESS;Initial Catalog=Banco_Dados_Teste;Integrated Security=True"/>


Quarto Passo -> Habilitar o Migrations atraves do Package Manager Console, o Migrations permite que o banco de dados seja criado automaticamente. Também podemos fazer o processo manualmente, mas neste caso vamos usar o automatico. Digite o comando no console.

Enable-Migrations –EnableAutomaticMigrations

Quinto Passo -> Adicionar o controller de Usuario que servirá como API para os métodos de Inserir e Listar usuários. Após isto iremos utilizar através de javascript os métodos deste controller.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using System.Web.Http.OData;
using System.Web.Http.OData.Query;
 
namespace ApiTeste.Controllers
{
    public class UsuarioController : ApiController
    {
        private Models.Model1Container db = new Models.Model1Container();
                 
        [HttpGet]       
        public ODataResult Get(ODataQueryOptions options)
        {
            var results = (options.ApplyTo(db.UsuarioSet) as IQueryable);
            var count = results.Count();
            var limitedResults = results.Take(5).ToArray();
            return new ODataResult(limitedResults, null, count);
        }
 
        // POST api/Teste
        public HttpResponseMessage PostUsuario(ApiTeste.Models.Usuario usuario)
        {
            if (ModelState.IsValid)
            {
                db.UsuarioSet.Add(usuario);
                db.SaveChanges();
 
                HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.Created, usuario);
                response.Headers.Location = new Uri(Url.Link("DefaultApi"new { id = usuario.Id }));
                return response;
            }
            else
            {
                return Request.CreateResponse(HttpStatusCode.BadRequest);
            }
        }
         
    }
}

 Aqui está a página que faz o uso da API.

<div id="body">
    <section class="featured">
        <div class="content-wrapper">
            <hgroup class="title">
                <h1>Lista de usuários do sistema!</h1>
            </hgroup>
            <p>
                <button data-bind="click: abrirCriacaoUsuario">Criar Novo Usuário</button>
            </p>
        </div>
    </section>
    <section class="content-wrapper main-content clear-fix">
        @using (Html.BeginForm("PostUsuario", "Usuario", FormMethod.Post, new { id = "formularioUsuario", style = "display:none;", data_bind = "submit: SalvarUsuario, with: Usuario" }))
        {
            <div>
                <label>Nome:</label>
                <input type="text" data-bind="value:Nome" />
            </div>
            <div>
                <label>Telefone:</label>
                <input type="text" data-bind="value:Telefone" />
            </div>
            <div>
                <label>E-mail:</label>
                <input type="text" data-bind="value:Email" />
            </div>
            <div>
                <label>Senha:</label>
                <input type="text" data-bind="value:Senha" />
            </div>
            <div>
                <button type="submit">Salvar Dados</button>
                <button type="reset" data-bind="click:$parent.cancelarInsercao">Cancelar</button>
            </div>
        }
        <hr />
        <span>Nome</span><input type="text" data-bind="value: filtro" /><button data-bind="click:buscarUsuarios">Pesquisar</button>
        <table>
            <thead>
                <tr>
                    <th data-bind="click: ordenarPorNome">Nome</th>
                    <th data-bind="click: ordenarPorTelefone">Telefone</th>
                    <th data-bind="click: ordenarPorEmail">E-mail</th>
                </tr>
            </thead>
            <tbody data-bind="foreach: ListaUsuarios">
                <tr>
                    <td data-bind="text:Nome"></td>
                    <td data-bind="text:Telefone"></td>
                    <td data-bind="text:Email"></td>
                </tr>
            </tbody>
        </table>
        <a href="#" data-bind="click:anterior">Página anterior</a>
                     
        <a href="#" data-bind="click:proximo">Próxima página</a>
    </section>
</div>
 
<style type="text/css">
    th
    {
        cursor: pointer;
    }
</style>
 
@section scripts {
    <script src="~/Scripts/knockout-2.1.0.js"></script>
    <script type="text/javascript">
        $(document).ready(function () {
 
            function UsuarioEntidade(data) {
                this.Id = ko.observable(data.Id);
                this.Nome = ko.observable(data.Nome);
                this.Telefone = ko.observable(data.Telefone);
                this.Email = ko.observable(data.Email);
                this.Senha = ko.observable(data.Senha);
            }
 
            function Modelo() {
                var self = this;
 
                self.Usuario = ko.observable(new UsuarioEntidade({}));
                self.ListaUsuarios = ko.observableArray([]);
                self.order = ko.observable('Nome');               
                self.pagina = ko.observable(0);
                self.filtro = ko.observable('');
 
                self.buscarUsuarios = function () {
                    var url = '/Api/Usuario/Get?$orderby=' + self.order() + '&$skip=' + self.pagina() * 5;
 
                    if(self.filtro()!='')
                        url += "&$filter=startswith(Nome, '" + self.filtro() + "') eq true";
                    $.getJSON(url, null, function (data) {
                        var mapeado = $.map(data.Items, function (obj) { return new UsuarioEntidade(obj); });
                        self.ListaUsuarios(mapeado);
                    });
                };
 
                self.SalvarUsuario = function () {
                    var elemento = ko.toJSON(self.Usuario());
                    jQuery.ajax({
                        url: '/Api/Usuario/PostUsuario',
                        type: "POST",
                        data: elemento,
                        dataType: "json",
                        contentType: 'application/json; charset=utf-8',
                        success: function (result) {
                            debugger;
                            self.buscarUsuarios();
                        }
                    });
                };
 
                self.ordenarPorNome = function () {
                    self.order("Nome");
                    self.buscarUsuarios();
                }
 
                self.ordenarPorTelefone = function () {
                    self.order("Telefone");
                    self.buscarUsuarios();
                }
 
                self.ordenarPorEmail = function () {
                    self.order("Email");
                    self.buscarUsuarios();
                }
 
                self.proximo = function () {
                    self.pagina(self.pagina() + 1);
                    self.buscarUsuarios();
                }
 
                self.anterior = function () {
                    self.pagina(self.pagina() - 1);
                    if (self.pagina() < 0)
                        self.pagina(0);
                    self.buscarUsuarios();
                }
 
                self.cancelarInsercao function () {
                    $('#formularioUsuario').slideUp();
                };
 
                self.abrirCriacaoUsuario function () {
                    self.Usuario(new UsuarioEntidade({}));
                    $('#formularioUsuario').slideDown();
                };
            }
 
            var model new Modelo();
            ko.applyBindings(model);
            model.buscarUsuarios();
        });
    
 
}


A parte mais importante do código anterior é esta:

self.ListaUsuarios = ko.observableArray([]);
self.order = ko.observable('Nome');               
self.pagina = ko.observable(0);
self.filtro = ko.observable('');
 
self.buscarUsuarios = function () {
    var url = '/Api/Usuario/Get?$orderby=' + self.order() + '&$skip=' + self.pagina() * 5;
 
    if(self.filtro()!='')
        url += "&$filter=startswith(Nome, '" + self.filtro() + "') eq true";
    $.getJSON(url, null, function (data) {
        var mapeado = $.map(data.Items, function (obj) { return new UsuarioEntidade(obj); });
        self.ListaUsuarios(mapeado);
    });
};

Nas primeiras linhas temos nossas variaveis:
ListaUsuarios -> Guarda o resultado da consulta a API. Como ela é uma variavel observable do knockout cada vez que modificarmos, o html  será gerado automaticamente.
order -> Guarda a ordem dos resultados.
pagina -> guarda a página atual.
filtro -> guarda o filtro para a consulta.

Dentro do método buscarUsuarios primeiro criamos a url com os parâmetros. Os parâmetros devem obedecer a definição ODATA.
A WebApi irá automaticamente converter nossos parâmetros para a variável do nosso método no controller (ODataQueryOptions options)

A web api atualmente suporta $orderby, $top, $skip e $filter. Vale a pena olhar a ultima documentação para verificar mas opções suportadas.

Você pode baixar o exemplo completo aqui

Obrigado.