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 { get; set; }
public string Nome { get; set; }
public string Telefone { get; set; }
public string Email { get; set; }
public string Senha { get; set; }
}
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<Usuario> UsuarioSet { get; set; }
}
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 através do Package Manager Console, o Migrations permite seja feito o versionamento da estrutura do banco de dados. Também podemos fazer o processo manualmente, mas neste caso vamos usar o automático. 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<Models.Usuario> Get(ODataQueryOptions options)
{
var results = (options.ApplyTo(db.UsuarioSet) as IQueryable<Models.Usuario>);
var count = results.Count();
var limitedResults = results.Take(5).ToArray();
return new ODataResult<Models.Usuario>(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();
});
</script>
}
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.