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.

Criação de Projeto Team City

 

Começamos com a criação do projeto. Bem simples.

teamcity-projeto-criacao

Após devemos definir uma Build Configuration.

 

create-build-configuration

Nesta parte devemos dar uma importância especial ao Artifact Paths. Este são os artefatos finais do build que poderemos enviar para um ftp, ou copiar para uma pasta. No meu caso como irei compilar um site, estou utilizando a pasta Package, que é onde é salvo quando utilizamos o Target Publish.

 

segunda-etapa

 

Essa é a parte de configuração do SubVersion onde o Team city irá efetuar o download do código.

configuracoes-svn

 

Nesta tela, eu não precisei modificar nenhuma propriedade.

svn-segunda-etapa

Agora devemos configurar as Build Steps. Podemos criar aqui quantas etapas quisermos.

Untitled

Vamos escolher a mais simples para um projeto do VS. O sln, colocamos o caminho relativo para o arquivo sln, e escolhemos qual Configuration, Platform, e Targets.

sln-build

 

Você também pode usar o MSBuild, caso você tenha mais projetos na sua solução e queira publicar apenas um. Ou no meu caso onde eu tinha projeto windows e web, e precisava passar parametros diferentes para os projetos windows.

msbuild-step

 

Apartir disto o team city já está pronto para efetuar o download e compilar seu código. Você ainda pode configurar na aba Build Triggering, quando o o Team City deverá compilar o seu código, é bem simples e você pode escolher a cada commit no svn, o Team city efetuar o build. Por padrão a cada 5 minutos o Team City faz o polling para verificar no svn se teve modificações novas no código.

Até.

Integração continua com Team City

 

Para quem não conhece o Team City, é um servidor para integração continua, ou seja, ele verifica os commits de seu sistema de versão, baixa a versão, compila, e depois envia para o seu servidor, e pode fazer muito mais, isto tudo de maneira automatizada sem interferência humana.

http://www.jetbrains.com/teamcity/

Você pode baixar ele gratuitamente do site. Ele tem suporte até 20 configurações de build no modo gratuito. Para você ter uma noção, se você tiver apenas alguns projetos em sua solução e não muitos locais para publicar essa versão serve. No meu caso, eu tenho dois projetos Windows para publicar via clickonce, um website, e um servico WCF. Todas as quatro publicações são publicadas para dois servidores diferentes via ftp, e para tudo isso necessitei de apenas 4 configurações de build.

No próximo post vou ensinar como criar um projeto, e fazer o envio FTP para projetos com o Visual Studio.

Gerando documentos do Office com OpenXml

 

Para quem precisa gerar documentos do Office como um documento, uma planilha ou até mesmo uma apresentação do Power Point, a Microsoft disponibiliza o padrão OpenXml, este é o novo padrão dos documentos como docx, xlsx, pptx.

Você pode baixar o sdk, ou um pacote mais completo que possui uma ferramenta que permite decompilar o seu docx, ou seja ele gera código .Net que permite você criar o documento que você abriu.

http://www.microsoft.com/en-us/download/details.aspx?id=5124

Veja na imagem abaixo que eu abri um documento, e na parte da direita ele gera o código em c# que corresponde ao documento.

OpenXml sdk

Podemos também usar também a dll DocumentFormat.OpenXml.dll, que é instalada em C:\Program Files\Open XML SDK\V2.0\lib, para podermos criar qualquer tipo de documento em nosso código .Net sem precisarmos ter o word instalado.

Vamos a um simples exemplo de como criar um docx.

using (WordprocessingDocument documento = WordprocessingDocument.Create(@"C:\Users\Danimar\Desktop\primeiro.docx", WordprocessingDocumentType.Document))
{
MainDocumentPart mainPart = documento.AddMainDocumentPart();
mainPart.Document = new Document();
Body body = new Body();
for (int i = 0; i < 10; i++)
{
Paragraph paragraph = new Paragraph();
Run run_paragraph = new Run();
Text text_paragraph = new Text("Escreve vários paragrafos no documento");
run_paragraph.Append(text_paragraph);
paragraph.Append(run_paragraph);
body.Append(paragraph);
}
mainPart.Document.Append(body);
mainPart.Document.Save();
}

Utilizando Localization em Windows Forms

 

Bem neste post vou explicar para vocês como criar uma aplicação que tenha suporte a várias linguagens. Irei explicar passo a passo:

1º -> Criamos um projeto Windows Forms no Visual Studio.

2º -> No Form1 criado mudamos a propriedade Localizable do formulario para true, isto informa ao Visual Studio que ele deverá gerar os resources para cada linguagem diferente.

3º -> Acrescente um botão ao formulário e coloque no texto do botão: “Português”

4º -> Agora vem a parte principal, modifique a propriedade Language do formulário para Inglês(Estados Unidos).

5º -> Mude o texto do botão para: “Inglês(Estados Unidos)”.

6º -> Adicione o seguinte código no construtor do formulário antes de chamar o método InitializeComponent()

hreading.Thread.CurrentThread.CurrentUICulture = New System.Globalization.CultureInfo("en-US")

7º -> Rode a aplicação, pronto a aplicação estará utilizando o texto em inglês, se não setar cultura nenhuma a aplicação ficará em português que é o default da aplicação.

O visual studio gerá um arquivo chamado “Form1.en-US.resx” para a cultura específica, pode-se criar várias culturas apenas criando cópias desse arquivo e mudando os textos dentro dele e mudando seu nome para por exemplo “Form1.de-DE.resx” com isto criamos um resource para alemão. Estes arquivos ficam dentro do projeto juntamente com os arquivos de código fonte, após criar os arquivos devemos lembrar de adicioná-los ao projeto dentro do visual studio.
É possível criar estes arquivos através do Visual Studio utilizando os passos 4 e 5, cada vez que mudarmos a linguagem do formulario e compilarmos a aplicação o Visual Studio gerá um novo arquivo resx.

Podemos utilizar mensagens de erro personalizadas para cada cultura também.
Criamos no arquivo resx uma propriedade MensagemDeErro conforme visto na figura, esta propriedade deve ser criada em todos os resources da nossa aplicação.

imagem

 

Para utilizarmos a mensagem do resource utiliza-se o seguinte código.


im resource As New Resources.ResourceManager("Application.Form1", GetType(Form1).Assembly)
sgBox(resource.GetString("MensagemDeErro"))

Temos nossa mensagem conforme a cultura escolhida


imagem2

Compactando arquivos



Eis um simples exemplo de como compactar arquivos. Este exemplo utiliza a classe FastZip, que possui um método CreateZip, que recebe como argumento um Stream de destino, e o nome do diretório que queremos compactar.
Você deve baixar o componente SharpZipLib, pode baixar ele via Nuget diretamente no Visual Studio.
 public void Compactar(List arquivos, string arquivoDestino)
{
if (System.IO.File.Exists(arquivoDestino))
System.IO.File.Delete(arquivoDestino);
var temp =System.IO.Path.Combine( System.IO.Path.GetTempPath(), "pregao.danimar");
if(System.IO.Directory.Exists(temp))
System.IO.Directory.Delete(temp, true);
System.IO.Directory.CreateDirectory(temp);
for(int i=0;i {
string destino = System.IO.Path.Combine(temp, System.IO.Path.GetFileName(arquivos[i]));
System.IO.File.Copy(arquivos[i],destino);
}
using(var stream = System.IO.File.OpenWrite(arquivoDestino))
{
FastZip zip = new FastZip();
zip.CreateZip(stream, temp, true, "", "");
}
System.IO.Directory.Delete(temp,true);
}

Até mais.

Iniciando com RavenDB

Olá, hoje vou falar um pouco sobre RavenDB.

O RavenDB é uma banco de dados que se encaixa na nova categoria chamada de NOSql(Not Only SQL), mas afinal o que esse banco faz. O RavenDB é um banco de dados orientado a documentos, o seu formato para salvar os dados é o JSon. Os dados pode estar aninhados como em um xml, como você pode ver neste exemplo:

 

Ele possui muitos recursos, e é extremamente fácil de colocar de se usar e efetuar consultas. Vamos começar pelo básico. Vamos usar ele na versão Embedded, ou seja, vamos usar ele junto com nossa aplicação e não como um serviço, ou hosted no IIS.

Você pode baixa-lo aqui: http://ravendb.net/ Após você descompacta e vai encontrar uma pasta Embedded, são essas dlls que você deve acrescentar ao seu projeto, e referenciar Raven.Client.Embedded, Raven.Client.Debug e Raven.Client.Lightweight.

 

libs

O RavenDB trabalha com o conceito de DocumentStore, ou seja o local onde é salvo os seus dados, ou banco de dados. O proximo passo é criarmos uma DocumentStore, para isso utilizamos o seguinte código:

Dim documentStore As New Raven.Client.Embedded.EmbeddableDocumentStore() With {.DataDirectory = "E:\RavenDataBase"}
documentStore.Initialize()

Estamos instanciando um Embeddable Store, e passamos para ela o local para salvar os dados. Após tudo isso já estamos prontos para salvar nosso objetos no banco de dados.


Dim objeto As New Cliente()
objeto.Nome = TextBox1.Text
objeto.Codigo = 1
objeto.Email = "danimaribeiro@gmail.com"
objeto.Endereco = New Endereco()
objeto.Endereco.Bairro = "Bairro"
objeto.Endereco.Cidade = "Chapeco"
objeto.Endereco.Rua = "Condá"

Dim sessao = documentStore.OpenSession() 'Abrir sessao

sessao.Store(objeto) 'Salvar o cliente e o seu endereço, pois o RavenDB salva todos eles juntos.
sessao.SaveChanges() 'Salva modificacoes

sessao.Dispose()
documentStore.Dispose()

Simplesmente abrimos uma sessão, e mandamos o RavenDB salvar nosso objeto. Session.Store(). Como ele salva em formato de documento, o endereço que está sendo salvo faz parte do cliente, sendo salvo dentro dele em formato Json.


Por hoje é isso.

Novidade Windows 8

Hoje faz duas semanas ou mais que comecei a utilizar o Windows 8. Vou escrever aqui as primeiras impressões e as possibilidades que esse novo Windows irá proporcionar aos desenvolvedores e usuários.
A coisa mais legal e grande novidade que irá vir nessa próxima versão do Windows 8 é a nova interface Metro, semelhante ao Windows Phone.



A nova interface será totalmente voltada as telas touch-screen, a facilidade e usabilidade dessa nova interface apesar da versão ser developer, é incrível. A interface se baseia em tiles, que são quadradinhos que substituiram os icones, eles apresentam informações sobre os programas, sem você precisar entrar nele.
A velocidade de resposta é impressionante.
Com essas modificações no Windows, você deve estar se perguntando o que a Microsoft criou para ajudar os desenvolvedores. Entre as grandes novidades dessa nova plataforma que está vindo são:
  • Programação Assincrona facilitada: eu me apaixonei pela nova forma de você criar métodos assincronos, e executar as coisas em paralelo e a tela continuar respondendo.
  • Html e Javascript: você pode criar sua interface com html, e javascript e criar uma biblioteca que busca os dados assincronos em C#, e após chamar este método assincrono no javascript, como se fosse nativo.
  • Templates de aplicação prontos: A microsoft preparou vários templates para serem reutilizados, com a interface Metro, você apenas cria o código, são vários templates, para listas, telas verticais, horizontais, templates para tiles, para notificações.
  • Loja de aplicativos: como o windows 8 foi projetado para rodar em qualquer plataforma, tablets, computadores, notebooks, isso cria uma oportunidade muito grande para o desenvolvimento de aplicativos.
  • Code Contracts: esse vai fazer nossos aplicativos conversarem entre si, e torna-los mais produtivos. Como funciona? Por padrão vão existir alguns contratos: SearchContract, PicturePickerContract, ShareContract,  estes contratos vão funcionar da seguinte forma, se você quer que sua aplicação compartilhe alguma coisa, você implementa este padrão, ou que o windows pesquise algo dentro da sua aplicação. Ou mesmo você tem fotos você implementa o padrão e o windows colocara as suas fotos disponiveis no novo explorer. Aqui uma foto de como seria o ShareContract.


  • WinRT - Essa eu não sei muito bem o que significa mas parece ser mais um conjunto de apis para o programador, em cima do windows. Ela poderá ser usada junto com aplicações C#, Javascript.

Eu acho que o Windows 8 vai revolucionar, muito mais do que o XP ou o Seven fez.

Vagas de TI sobrando?

Como é engraçado a visão dos empregados sobre o funcionário. Neste post da Info sobre carreira e porque as vagas estão sobrando alguns entrevistados entram em divergencia sobre o real motivo.

http://info.abril.com.br/noticias/carreira/vagas-de-emprego-em-ti-encalham.-saiba-por-que-04042011-0.shl

Segundo a GVT “a dificuldade de contratar profissionais de TI no Brasil pode ser minimizada não só com a oferta de melhores salários, mas também com outros atrativos para o crescimento do profissional”, agora para outras empresas a dificuldade em contratar está no alto salário dos profissionais, pois eles estão se auto valorizando, pedindo 20% a mais do que valem, e ainda não estão preparados. O engraçado que uma das principais formas de contratação da empresa é por meio do processo de Trainee, com certeza é mais fácil contratar estagiários do que profissionais qualificados.

Outro ponto que as empresas estão reclamando bastante é a falta de qualificação. Porém quanto custa ao profissional realizar uma pós-graduação? Estudar para uma certificação? E quanto ele ganha realmente?

Aqui onde eu trabalho acho que o salário médio das empresas para um programador gira em torno de 2000 reais, se ele estiver fazendo ainda faculdade vai gastar em torno de 500 reais, só com a faculdade sem contar transporte. Agora ele também necessita aprender inglês, colocamos nessa conta mais 150 reais mês. Agora ele precisa também de uma certificação, pois o mercado valoriza isso. Então ele vai precisar comprar alguns livros, mais 100 reais por um livro.

Agora vem os gastos com moradia, aqui em torno de 600 reais mês, comida mensal em torno de 300 reais(não pode comer muita porcaria). Vamos fazer as contas para a sobrevivencia: 1650 reais por mês. Sobrando exatamente 350 reais por mês para transporte, roupas, algum lazer. Como essa pessoa vai pensar em comprar algum bem? Como eu vou comprar um carro? Isso faz as pessoas deixarem de investir o dinheiro em cursos, e certificações para poderem ter um pouco de conforto.

Porém grande parte dos profissionais hoje que começam em TI começam no suporte, ou como estagiários e nunca chegam a ganhar isso, e sem receber incentivos das empresas, como esses profissionais recém-formados vão conseguir ter essa experiência? Aqui vai um texto que saiu no twitter.

CFO asks CEO "What happens if we invest in developing our people & then they leave us?" CEO: 'What happens if we don't, and they stay?”

Traduzindo: O que acontece se nós investirmos em desenvolver nossos funcionários e eles forem embora? Então o gerente responde: O que acontece se não fizermos e eles ficarem?

Todos os gerentes deveriam ser assim. Na verdade esses são os gerentes de verdade, os outros que estão lá entraram por causa do dinheiro.

Fluent NNhibernate e Auto Mapping

Com o Fluent Nhibernate é possivel utilizar-se do padrão “Convention over Configuration”, Convençao sobre Configuração, quem é programador Java, ou de outras linguagens de script já usam bastante deste padrão, mas para .Net isto não é tão comum assim. Este padrão permite que não precisamos configurar nosso mapeamento, pois ele está implicito na declaração de nossas classes, possibilitado pela convençao. Por exemplo quando criamos um campo Id em nossa classe não necessitamos mapear essa propriedade, pois a convenção nos diz q ele vai ser uma chave primaria de nossa tabela.
O Fluent Nhibernate permite que seja mapeado as classe através dessa convenção, devemos apenas dizer quais as nossas classes devem ser mapeadas.
var mapeamento = AutoMap.AssemblyOf<Dominio.Entidades.Core.Usuario>(convencoes); //Qual assembly deve ser mapeado

var cfgFluent = FluentNHibernate.Cfg.Fluently.Configure(cfg).Mappings(x =>
x.AutoMappings.Add(mapeamento));

cfg = cfgFluent.BuildConfiguration();
this.FabricaSessao = BuildSessionFactory(cfg);

No caso acima passamos o assembly da classe Usuario, fazendo com que todas as outras classes sejam mapeadas.

public class Usuario : IEntidade
{
public virtual long Id { get; set; }

public virtual string Nome { get; set; }
}

A classe Usuário será mapeada para um tabela, onde o Id será a chave primária, e  o campo Nome será um varchar.

Porém necessitamos fazer alguns refinamentos nesses mapeamentos, por exemplo caso queiramos adicionar um prefixo no nome da tabela, ou por exemplo definir o tamanho do campo Nome no banco? Teremos que adicionar os mapeamentos um a um?  Ai entra a possibilidade de extensão do Fluent, todas as convençoes podem ser implementadas manualmente extendendo as convenções padrões.

public class TableNameConvention : IClassConvention
{
public void Apply(IClassInstance instance)
{
instance.Table("tb_" + instance.EntityType.Name);
}
}


Neste exemplo criamos uma convenção para o nome da tabela que será gerado, implementamos o IClassConvention, e setamos o nome da tabela que queremos. Todas as interfaces que podem ser implementadas estão no namespace using FluentNHibernate.Conventions.

Na hora de configurar o Fluent devemos adicionar nossas convenções antes de criar a SessionFactory.

var mapeamento = AutoMap.AssemblyOf<Dominio.Entidades.Core.Usuario>(convencoes); //Qual assembly deve ser mapeado
mapeamento.Conventions.Add<TableNameConvention>();
mapeamento.Conventions.Add<PrimaryKeyNameConvention>();

var cfgFluent = FluentNHibernate.Cfg.Fluently.Configure(cfg).Mappings(x =>
x.AutoMappings.Add(mapeamento));

Desta forma o Fluent saberá que deverá usar nossas classes de configuração.

Essa apenas uma das maneiras que o Fluent permite fazer, temos outras mais em exemplos por ai na internet. Vale a pena dar uma olhada e verificar qual melhor se aplica ao seu projeto. Isso é muito util no caso de você já ter algumas convenções que usa e não quer mudar e para código legado.