Variáveis com formulas fields no Crystal Reports

Introdução

Formula fields do Crystal reports permitem a você injetar blocos de código em um relatório quando um simples comando  SELECT,não é suficiente.Você pode declarar variáveis,criar blocos if/then,criar arrays,executar loops,ou chamar funções já prontas do Crystal Reports.Esse artigo vai criar um relatório num web site ASP.NET e mostrar como criar um formula field,manipular datas na formula assim como criar uma variavel e lhe atribuir um valor, e tambem usar a lógica if/then pra criar campos de resumo para o trimestre no relatório.

Antes de começar você precisa ter o VS2008 instalado com o crystal reports.Os exemplos foram escritos no VS2008 mas funcionam também no VS2005.Eu criei um banco de dados simples com uma tabela,pra usar como exemplo no relatório:

Passo 1:Criar o banco

  1. Abra o Sql Management Studio 2005/2008 e conecte se ao seu servidor.
  2. Crie um novo banco e lhe de o nome de CrystalFormulas
  3. Esse banco só vai conter uma tabela chamada SalesHeader.Crie a tabela conforme a seguir:
Nome do campo Tipo Permite nulo
SalesHeaderID Int (Identity) Não
SalesDate Datetime Não
Total Money Não

Eu preenchi esta tabela com registros de Janeiro a Junho.Segue o script para a criação deste banco:

create database CrystalFormulas
go
use CrystalFormulas
go
create table [dbo].SalesHeader
(
SalesHeaderID int identity(10,1) not null,
SalesDate datetime not null,
Total money not null,
constraint PK_SALES_HD primary key clustered(SalesHeaderID)
)
go
INSERT [SalesHeader] ( [SalesDate], [Total]) VALUES (CAST(0x00009D2C00000000 AS DateTime), 632.7600)
INSERT [SalesHeader] ( [SalesDate], [Total]) VALUES (CAST(0x00009D1000000000 AS DateTime), 45.6500)
INSERT [SalesHeader] ( [SalesDate], [Total]) VALUES (CAST(0x00009CF100000000 AS DateTime), 65.8700)
INSERT [SalesHeader] ( [SalesDate], [Total]) VALUES (CAST(0x00009D2C00000000 AS DateTime), 231.5600)
INSERT [SalesHeader] ( [SalesDate], [Total]) VALUES (CAST(0x00009D1000000000 AS DateTime), 76.8900)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009CF100000000 AS DateTime), 235.7400)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009D2C00000000 AS DateTime), 874.3600)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES (CAST(0x00009D1000000000 AS DateTime), 98.7600)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009CF100000000 AS DateTime), 234.8400)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009D2C00000000 AS DateTime), 121.7600)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009D1000000000 AS DateTime), 738.8900)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009CF100000000 AS DateTime), 376.1000)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009D2C00000000 AS DateTime), 473.9800)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009D1000000000 AS DateTime), 46.9800)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009CF100000000 AS DateTime), 87.8700)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009D2C00000000 AS DateTime), 234.8700)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009D1000000000 AS DateTime), 334.5600)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009CF100000000 AS DateTime), 908.7000)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009D2C00000000 AS DateTime), 23.6700)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009D1000000000 AS DateTime), 45.8900)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009CF100000000 AS DateTime), 23.5600)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009D2C00000000 AS DateTime), 93.8700)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009D1000000000 AS DateTime), 363.9800)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009CF100000000 AS DateTime), 63.2300)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009D2C00000000 AS DateTime), 574.0000)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009D1000000000 AS DateTime), 34.7600)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009CF100000000 AS DateTime), 897.4600)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009D2C00000000 AS DateTime), 232.4300)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009D1000000000 AS DateTime), 121.5600)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009CF100000000 AS DateTime), 88.5400)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009D2C00000000 AS DateTime), 34.5400)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009D1000000000 AS DateTime), 87.5400)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009CF100000000 AS DateTime), 22.4200)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009D2C00000000 AS DateTime), 234.6600)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009D1000000000 AS DateTime), 44.7600)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009CF100000000 AS DateTime), 99.5600)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009D2C00000000 AS DateTime), 235.6500)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009D1000000000 AS DateTime), 34.5400)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009CF100000000 AS DateTime), 232.6300)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009D2C00000000 AS DateTime), 78.6700)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009D1000000000 AS DateTime), 46.8700)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009CF100000000 AS DateTime), 34.8800)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009D8800000000 AS DateTime), 454.6500)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009D6900000000 AS DateTime), 452.6500)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009D4B00000000 AS DateTime), 651.8700)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009D8800000000 AS DateTime), 23.5600)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009D6900000000 AS DateTime), 767.8900)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009D4B00000000 AS DateTime), 25.7400)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009D8800000000 AS DateTime), 84.3600)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009D6900000000 AS DateTime), 985.7600)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009D4B00000000 AS DateTime), 24.8400)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009D8800000000 AS DateTime), 21.7600)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009D6900000000 AS DateTime), 78.8900)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009D4B00000000 AS DateTime), 36.1000)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009D8800000000 AS DateTime), 73.9800)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009D6900000000 AS DateTime), 465.9800)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009D4B00000000 AS DateTime), 873.8700)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009D8800000000 AS DateTime), 23.8700)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES (CAST(0x00009D6900000000 AS DateTime), 34.5600)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009D4B00000000 AS DateTime), 808.7000)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009D8800000000 AS DateTime), 234.6700)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009D6900000000 AS DateTime), 453.8900)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES (CAST(0x00009D4B00000000 AS DateTime), 232.5600)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009D8800000000 AS DateTime), 937.8700)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009D6900000000 AS DateTime), 36.9800)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009D4B00000000 AS DateTime), 633.2300)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009D8800000000 AS DateTime), 57.0000)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009D6900000000 AS DateTime), 345.7600)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009D4B00000000 AS DateTime), 89.4600)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009D8800000000 AS DateTime), 22.4300)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009D6900000000 AS DateTime), 21.5600)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009D4B00000000 AS DateTime), 885.5400)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009D8800000000 AS DateTime), 343.5400)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009D6900000000 AS DateTime), 879.5400)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009D4B00000000 AS DateTime), 222.4200)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009D8800000000 AS DateTime), 24.6600)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009D6900000000 AS DateTime), 404.7600)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009D4B00000000 AS DateTime), 996.5600)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009D8800000000 AS DateTime), 23.6500)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009D6900000000 AS DateTime), 344.5400)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009D4B00000000 AS DateTime), 23.6300)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009D8800000000 AS DateTime), 783.6700)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009D6900000000 AS DateTime), 462.8700)
INSERT [SalesHeader] (   [SalesDate], [Total]) VALUES ( CAST(0x00009D4B00000000 AS DateTime), 348.8800)

Você pode rodar esse script no SQL Management Studio pra criar a tabela e inserir os registros.

Você pode usar Integrated Security quando for conectar ao banco ou criar um SQL Login.De qualquer forma você precisa se lembrar qual método você escolheu quando estiver pronto pra se conectar ao banco,como definido nos passos abaixo.

Passo 2:Criar o web site,Add o relatório, e conectar ao banco

1. Rode o VS2008 e escolha File>New WebSite
2. Selecione o template de ASP.NET Web Site.Escolha o local que deseja salvar o projeto.Escolha a linguagem C# e clique em OK.
3. Clique com o direito no nome do projeto no Solution Explorer e escolha “Add New Item…”
4. Selecione o template Crystal Reports e mude o nome para QuartelySales.rpt.Clique no botão adicionar.
5. Irá aparecer uma caixa de dialogo do CR.Selecione “As Blank Report” e clique no botão OK.Isso irá add o arquivo do CR ao seu projeto e vai abrir o CR Design.
6. Agora você precisa se conectar ao banco.Clique com o direito em “Database Fields” no Field Explorer e selecione “Database Expert”.
7. A caixa de dialogo “Database Expert” irá aparecer.Clique no sinal de expansão de “Create New Connection”.Clique no sinal de expansão de OLE DB(ADO).A caixa de dialogo do OLE DB(ADO) deve aparecer.
8. Selecione SQL Native Client na lista de provedores e clique em NEXT.
9. Coloque o nome do seu servidor.Você tem então a opção de escolher usar SQL LOGIN ou Integrated Security.Para esse exemplo nós vamos usar Integrated Security,clicando no checkbox “Integrated Security”.
10. Coloque o nome do banco que foi criado no Passo 1,CrystalFormulas.Clique no botão finish.
11. Você deve ver o banco listado abaixo do nó OLE DB(ADO).Clique no sinal de expansão do banco para ver o schemas.Clique no sinal de expansão do dbo para ver as tabelas.
12. Clique na tabela SalesHeader e depois clique no botão > pra mover esta tabela para a lista de tabelas selecionadas para esse relatório.

Clique no botão OK.

Passo 3:Adicionando fields e formulas para o relatorio

Agora que você está conectado ao banco você pode adicionar os campos para o seu relatório.Qualquer campo que você queira mostrar em linha no relatório,deve ser posto na “Details Section”.

  1. No field explorer clique no sinal de expansão  de DatabaseFields.Clique no sinal de expansão de SalesHeader para ver os campos desta tabela.
  2. Arraste os campos SalesDate e Total para a Details Section no relatório.O CR irá automaticamente add o cabeçalho da coluna na seção Page Header quando você arrastar os campos na Details Section.


3. Agora iremos criar um formula field pra mostrar o trimeste de SalesDate.Clique com o direito no nó Formula fields no Field Explorer e escolha “New…”.Coloque quarter para o nome do formula field e clique no botão “Use Editor”.

  1. O CR tem inumeras funções já prontas que você pode usar nas suas próprias formulas.As funções estão listadas na seção de ‘Functions” do formula editor.Clique no sinal de expansão de Functions e depois clique no nó de Date and time.Isso irá mostrar a lista de funções disponiveis para manipular datas.A que estamos procurando se chama DatePart.Se você descer a barra de rolagem do Date and Time você deve encontrar essa função.Observe que as funções não estão em ordem alfabética então você deve ir até o final da lista.
  2. A função DatePart tem 3 diferentes assinaturas.Clique-duplo na primeira assinatura e essa irá aparecer no corpo da fórmula.

  1. O primeiro parâmetro para a função DataPart é o Intervalo.O intervalo pode ser  year(yyyy),quarter(q),month(m),day(d),hour(h),minute(n),second(s),day of week (w) e week (ww).Coloque (q) então o  trimeste é recuperado das datas.
  2. O segundo parâmetro é a expressão de data que deve ser analisada.Esse é o campo SalesData na tabela SalesHeader.O texto da formula deve se parecer com o seguinte:

DatePart (‘q’, {SalesHeader.SalesDate})

  1. Clique no botão “Save and Close”.A formula “Quarter”,irá agora aparecer no nó de Formula fields no Field Explorer.
  2. Arraste o campo para a Details Section.Clique no botão “Main Report Preview” pra mostrar o relatório .Você deve ver ou 1 ou 2 para o trimestre.

Passo 4:Criar formulas com variáveis

O próximo passo será adicionar duas formulas para o relatório.Esse relatório deve mostrar a soma para o 1 trimestre e 2 trimestre.

  1. Clique para voltar em “Main report”.
  2. Clique com o direito  em Formula Fields e escolha “New…”.
  3. Nomeie para “Quarter1” e clique no botão “Use editor”

Essa fórmula vai criar uma variável para armazenar o total  de qualquer venda que ocorreu no 1 trimestre.Variaveis tem 3 opções de escopo:Local,Global,ou Shared.Local significa que a variável é usada na função especifica e seu valor é perdido quando a formula acaba.Global significa que a variavel mantém o valor mesmo depois do final da função e poder ser usada em outras formulas no relatorio.Shared significa que você pode usar essa variável em outras fórmulas ou mesmo em sub-relatórios.Por padrão se você omitir o escopo a variável será Global.Entre com o seguinte código no corpo da formula:

Global NumberVar quarter1;

if DatePart(‘q’, {SalesHeader.SalesDate}) = 1 then
quarter1 := quarter1 + ToNumber({SalesHeader.Total})
else
quarter1 := quarter1

Isso cria uma variavel global chamada  quarter1.O código depois então checa se a data está no primeiro trimestre.Se estiver então é adicionada para a variavel quarter1.

  1. Clique no botão Save and Close
  2. Clique no botão “Main Report Preview” pra mostrar o relatório

  1. Clique para voltar em “Main report”.
  2. Crie um segundo formula field chamado Quarter2  e entre com o seguinte código:

Global NumberVar quarter2;

if DatePart(‘q’, {SalesHeader.SalesDate}) = 2 then
quarter2 := quarter2 + ToNumber({SalesHeader.Total})
else
quarter2 := quarter2

Salve  a formula e arraste para a Details Section proximo do formula Quarter1 e clique no botão preview:

Note que o código não está mostrando o total.Isso é porque a variavel foi declara num escopo local e não global.

  1. Clique para voltar para o design.
  2. Clique com o direito no campo Quarter2 na Details Section e selecion “Edit ”.Retire a palavra local antes da declaração da variavel.Por padrão esta agora será global.Clique em Save and close.De um preview no relatório novamente.Desta vez você verá o total para o 2 trimestre.
  3. Clique para voltar para o design.Arraste os fields Quarter1 e Quarter2 para a seção “Report footer” do relatório nas suas repectivas colunas.
  4. Delete os fields Quarter1 e Quarter2 da Details Section.
  5. Clique com o direito na Details Section e escolha “Suppress (No-Drill-down)”
  6. Agora se você rever o relatório você verá somente os totais.

Conclusão

Formula Fields no crystal reports permitem você manipular seus dados de várias maneiras quando um simples SELECT não é suficiente.A sintaxe é bem simples de usar se você já conhece C# ou VB.CR também tem inumeras funções já prontas que você pode usar nas fórmulas.Você também pode usar loopings,como FOR e WHILE.Você também pode achar o próximo valor ou o valor anterior de um field.O poder das formulas e a linguagem de script é tremendo e permite a você cobrir qualquer requerimento dos usuarios mais exigentes.

Anúncios

Interface ou classe abstrata

Devo usar classe abstrata ou interface?

As funcionalidade de  uma classe abstrata e de uma interface são bastante similares.Entretanto,há alguns prós e contras.

Herança

Uma classe no C# pode herdar somente de uma classe pai.Portanto,quando herdar uma subclasse de uma classe abstrata,a classe derivada,gastou a sua habilidade de participar na hierarquia de classes.

Herança única

C# suporta somente herança única:C# não suporta,herança de multiplas classes assim como o c++;Mas,usando classes abstratas e interfaces,programadores de C# podem obter o mesmo resultado,sem a bagunça e os problemas de  manutenção de multiplas heranças.

Value Types Polimorfismo

Value types no .NET são objetos descendentes de System.Object;eles não podem herdar de outros tipos.Mas podem implementar interfaces.Por exemplo,tipos primitivos – como Int32 – podem implementar a interface Icomparable,tornando se assim,comparaveis.

Versionamento

Uma classe abstrata pode conter implementações de interfaces.Isso simplifica o versionamento.Uma classe abstrata pode ser extendida adicionando novos métodos não abstratos com implementações padrão.

Uma interface não pode ser modificada sem quebra de contrato com as classes que a implementam.Uma vez que a interface esteja em uso,seus membros são fixos permanentemente.Um API baseado em interfaces só pode ser extendido,através de novas interfaces.

Flexibilidade de design

Interfaces oferecem maior flexibilidade em design,precisamente,porque podem ser implementadas por qualquer classe independente de sua hierarquia.

Melhores práticas

Use interfaces e classes abstratas em conjunto para melhorar seu código.
Use classe abstrata:

  • Quando criar uma class library a qual pode ser amplamente destribuida ou reusada – especialmente para clientes.Porque classes abstratas simplificam o versionamento.
  • Pra definir uma classe base em comum entre tipos familiares.
  • Pra oferecer comportamento padrão.

Use Interface:

  • Criar um projeto individual,que possa ser mudado no futuro,use uma interface porque oferece mais flexiblidade.
  • Para introduzir comportamento polifórmico sem subclasses e pra um modelo de multiplas heranças.Permitindo que um tipo especifico possa suportar multiplos comportamentos.
  • Pra desenvolver uma hierarquia poliformica para value types.
  • A intenção for de um contrato imutavel.

Resumo

A tabela a seguir compara interfaces e classes abstratas:

Classe abstrata Interface
Classes abstratas gastam sua opção de herança. Classes podem implementar múltiplas interfaces sem gastar a opção de herança.Mas não há implementações padrão.
Não pode ser instanciada.Exceto como parte de uma subclasse.Somente classes derivadas podem chamar um construtor de uma classe abstrata. Não podem ser instanciadas.
Define assinaturas abstratas de membros que a classe derivada deve implementar.De outra forma,a classe derivada em si também seria abstrata. Define assinaturas abstratas de membros .Todas as classes que implementam a interface devem implementa-los.De outra forma,ocorre um erro de compilação.
Novos membros não abstratos podem ser adicionados,que as classes derivadas não perderão a compatibilidade de versão. Extender uma interface com novos membros,quebra a compatibilidade de versão.
Opcionalmente,oferecer implementação padrão de um membro Virtual. Todos os membros são virtuais e não podem oferecer implementações.
Pode incluir fields. Não pode incluir fields.Mas pode declarar propriedades abstratas.

Confira mais sobre Interface vs Classe abstrata
Até a próxima!

A tabela a seguir compara interfaces e classes abstratas:

C# 3.0 lambda expressions

A melhor maneira que eu tenho pra descrever lambda expressions é – C# Anonymous Methods mais facilitado.

Mas o que é anonymous method no c# 2.0?

Como você deve saber no c#1.x/2.x era possível escrever códigos da seguinte forma:

class AlgumaClasse

{

delegate void AlgumDelegate();

public void InvokeMethod()

{

AlgumDelegate del = new AlgumDelegate(AlgumMetodo);

del();

}

void AlgumMetodo()

{

Console.WriteLine(“Olá mundo”);

}

}

Depois veio anonymous methods que permitem a você escrever o código acima de uma maneira mais simplificada:

class AlgumaClasse

{

delegate void AlgumDelegate();

public void InvokeMethod()

{

AlgumDelegate del = delegate()

{

Console.WriteLine(“Hello”);

};

del();

}

}

O que você vê depois do “Delegate()”, é um método anônimo.Mesmo sendo melhor que a versão do c#1x. ainda assim requer algum código:

Lambda expressions dão a você uma sintaxe mais concisa e funcional,usando a sintaxe “=>”.

O código acima usando lambda expresssions poderia ser escrito da seguinte forma:

class AlgumaClasse

{

delegate void AlgumDelegate();

public void InvokeMethod()

{

AlgumDelegate del = () => Console.WriteLine(“Hello”) ;

del();

}

}

Geralmente a sintaxe é:

Parâmetros => expressão

Agora óbvio,lambda expressions não são apenas uma maneira mais simples de se escrever métodos anônimos.Eles realmente superam em funcionalidade os métodos anônimos.Porque?:

  • Lambda expressions entendem o tipo de parâmetro que você quer passar mesmo que você os omita.Anonymous methods não permitem.
  • Lambda Expressions podem usar bloco de comandos e expressões.Anonymous methods só aceitam blocos de comandos.
  • Lambda Expressions podem ser passadas como argumentos.

Vamos falar de cada um deles:

Lambda expressions entendem o tipo de parâmetro que você quer passar mesmo que você os omita.Anonymous methods não permitem.

Palavras difíceis para algo simples:

(int x) => x + 1 ; // é o mesmo que
x => x + 1 ;

Na segunda linha o tipo está sendo omitido.

Lambda Expressions podem usar bloco de comandos e expressões.Anonymous methods só aceitam blocos de comandos.

Outra vez palavras difíceis para algo simples:

(int x) => x + 1 ; // é o mesmo que
(int x) => { return x + 1; }

Na segunda linha nós temos um bloco de comando,e na primeira nós temos uma expressão.Então a primeira é igual a segunda mas é mais fácil de entender e escrever.

Lambda Expressions podem ser passadas como argumentos.

Você pode passar lambdas expressions como argumentos para métodos genéricos.Vamos considerar o seguinte exemplo.Vamos dizer que você tivesse,um extension method,como mostrado a seguir:

public static class myExtensions
{
public static void SpankIt<T,U>(
this IEnumerable<T> source,
Func<T, U> someParameter)
{
foreach (T element in source)
Console.WriteLine(“SPANK ” + someParameter(element) + “!!”);
}
}

Você poderia usar o extension method acima,assim:

static void Main(string[] args)
{
List<String> whoToSpank = new List<String>() ;
whoToSpank.Add(“Monkey”) ;
whoToSpank.Add(“Bannana”) ;

whoToSpank.SpankIt(c => “Monkey”) ;
}

E “SPANK MONKEY !!” seria escrito duas vezes.

Mas espere um pouco.O significa o “U” no extension method?Se você colocar um breakpoint no seu extension method você vai perceber que o c# 3.0 é esperto o bastante pra saber que “U” é uma string.Você nunca citou que “U” seria uma string,ele se baseia na lambda expression que você passou.

Você não pode fazer isso com métodos anônimos.

É isso!Abraço.

C# Anonymous types (tipos anônimos)

No meu último post,eu falei sobre a palavra–chave var,se você ainda não o leu,recomendo que o faça agora.

Assumindo que você tenha entendido o que é “var” – vamos em frente!

No c# 2.0,vamos dizer que você quisesse representar uma pessoa,você provavelmente criaria uma classe como esta:

public class Person
{
string hairColor ;
string skinColor ;
int teethCount ;
} ….

Aí entra os tipos anônimos.Agora você pode representar esta mesma classe,sem ter que criar sua estrutura primeiro.Assim:

var monster = new {cabelo=”black”, pele=”green”,dentes=64} ;

A linha de código acima irá funcionar mesmo se você não declarar a classe chamada Person.Isso permite você criar estruturas de dados sem ter que declara-las previamente.

O código acima gera uma classe por trás das cenas que você não vê,assim:

class __Anonymous1
{
private string _cabelo = “black”;
private string _pele = “green”;
private int _dentes   = 64;

public string cabelo {get { return _cabelo; } set { _cabelo = value; }}
public string pele {get { return _pele; } set { _pele = value; }}
public int dentes {get { return _dentes; } set { _dentes = value; }}
}

Por essa classe ser um tipo anonimo ela não possui nome quando é gerada pelo compilador c#,é um “System.Type”.

É isso, até a próxima.

C# 3.0 variáveis tipo var

Desmitificando o c# 3.0 keyword var

No c# 2.0 você podia declarar um integer (ou qualquer outro tipo conhecido)como

int i;

Você também podia escrever algo assim:

int i  = 1;

Ou seja:

<tipo><nomevariavel> = <inicializador>;

Ok,bom.A coisa importante pra se notar é que “i” é um inteiro.Em c# 3.0 o código abaixo é válido:

var i = 1;

Mas o que é “var”?”var” é…hum…uma palavra chave,que resulta em “i” sendo do mesmo tipo do inicializador,nesse caso um inteiro.Então var i = 1;irá resultar em uma variável chamada “i” cujo tipo é integer.

Mas qual a diferença entre “var”,object, e variant(VB6)?

Variants eram tranqueiras,que aceitavam praticamente tudo,ocupando bastante espaço na memória.Objects tem problemas de box e unboxing.E variants e objects ambos não são fortemente tipados.

Note que “i”,é um tipo fortemente tipado para integer – não é nem um objeto nem uma variant,nem carrega os problemas de nenhuma das duas.Para garantir a natureza fortemente tipada que é declarada na palavra chave var, c# 3.0 requer que você ponha no inicializador,na mesma linha da declaração.Também,o inicializador deve ser uma expressão,não um objeto ou coleção,e também não pode ser null.

Você também pode criar arrays de var:

var intArr = new[] {3,1,4,1,5} ;

Espero que tenham entendido,até a próxima!

Use autenticação windows em seu website usando forms authentication

Aprenda a autenticar contas usando windows authentication.

Introdução

No último mês eu trabalhei em uma pequena tarefa de autenticar uma conta windows usando forms
Authentication.O propósito dessa tarefa era facilitar o logon de nossos usuários usando qualquer
conta válida do windows.Foi uma tarefa interessante,que eu decidi compartilhar com vocês.

Requerimentos

A aplicação deve autenticar usuários windows,usando forms authentication e o usuario logado
na conta do windows não deve se incomodar tendo que fazer um novo login na aplicação.Ele
deve poder se logar com qualquer conta windows válida.

Solução

Nós devemos seguir os seguintes passos para atingir nosso objetivo:

-Configurar as seções Authorization e Authentication no web.config
-Criar uma página de login e executar a lógica para autenticar usando a conta do windows
-Se as credenciais são válidas no passo anterior,gerar um “token” de autenticação assim o
usario poderá navegar nas diferentes páginas da sua aplicação.

Vamos lá,

Configurar Authorization e Authentication no web.config

Nós precisamos usar Forms authentication.O usuario vai entrar com suas credenciais do windows
no formulario e nós iremos valida-los:

1.<authentication mode=”Forms”>
2.   <forms loginUrl=”login.aspx” name=”.ASPXFORMSAUTH”></forms>
3.</authentication>

Para restringir acesso de usuários não logados,modifique a seção authorization no web.config:

1.<authorization>
2.   <deny users=”?”/>
3.</authorization>

Criar uma página de login para executar a lógica para autenticar as credencias do usuário do windows.

Nós precisamos criar uma página de login,para pegar informações de usuario e senha do usuario
e valida-las.

Nós temos diferentes formas de validar credenciais do Windows.A maneira que eu escolhi foi
o método LogonUser() de uma API Win32 chamada Advapi32.dll

O método LogonUser() tentar logar um usuario na máquina local.Esse método recebe um nome de usuario
uma senha e outras informações como parâmetros e retorna um boolean indicando se o usuario foi
logado ou não.Se retornar true significa que usuarios e senhas estão corretos.

Para usar esse método na sua classe,inclua o seguinte namespace:

1.using System.Runtime.InteropServices;

Depois adicione a seguinte declaração no método com o atributo DLLImport:

1.[DllImport(“ADVAPI32.dll”, EntryPoint = “LogonUserW”, SetLastError = true,
2.   CharSet = CharSet.Auto)]
3.public static extern bool LogonUser(string lpszUsername, string lpszDomain,
4.    string lpszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken);

De acordo com a documentção MSDN:

lpszUsername[in]: string que especifica o nome de usuario.Esse é o nome da conta do logon.
Se você usar o formato “user principal name”(UPN) User@DnsDomainName,o parâmetro lpzszDomain
deve ficar nulo.

lpszDomain [in,opcional]:especifica o nome do dominio ou servidor que contém a conta de usuario
especificada no lpszUsername.

lpszPassword [in]:especifica a senha para a conta de usuario passada no lpszUsername.

dwLogonType[in]:O tipo de operação de logon.

dwLogonProvider[in]:especicifa o provedor de logon.

phToken[out]:Um ponteiro para uma variavel que contém um “token” que representa o usuario especifico.

Gerar um token de autenticação,se as credenciais forem autenticadas

Se as credenciais forem autenticadas no método LogoUser() então nós precisamos gerar um “token”
para que o usuario possa navegar nas paginas autorizadas da aplicação.
FormsAuthentication.RedirectFromLoginPage() ou FormsAuthentication.SetAuthCookie() podem ser usados para isso.

Aqui o código do clique do botão btnLogin pra autenticar e gerar o token de autenticação.
Comentários irão lhe ajudar a enteder o código:

01.protected void btnLogin_Click(object sender, EventArgs e)
02.{
03.   // Extract domain name from provided DomainUsername e.g Domainname\Username
04.   string domainName = GetDomainName(txtUserName.Text);
05.   // Extract user name from provided DomainUsername e.g Domainname\Username
06.   string userName = GetUsername(txtUserName.Text);
07.        IntPtr token = IntPtr.Zero;
08. //userName, domainName and Password parameters are very obvious.
09. /* dwLogonType (3rd parameter): I used LOGON32_LOGON_INTERACTIVE, This logon type is
10. intended for users who will be interactively using the computer, such as a user being
11. logged on by a terminal server, remote shell, or similar process. This logon type has
12. the additional expense of caching logon information for disconnected operations. For
13. more details about this parameter please see http://msdn.microsoft.com/en-
14. us/library/aa378184(VS.85).aspx */

15. /* dwLogonProvider (4th parameter) : I used LOGON32_PROVIDER_DEFAUL, This provider
16. uses the standard logon provider for the system. The default security provider is
17. negotiate, unless you pass NULL for the domain name and the user name is not in UPN
18. format. In this case, the default provider is NTLM. For more details about this
19. parameter please see http://msdn.microsoft.com/en-us/library/aa378184(VS.85).aspx */

20. /* phToken (5th parameter): A pointer to a handle variable that receives a handle to
21. a token that represents the specified user. We can use this handler for impersonation
22. purpose. */

23.    bool result = LogonUser(userName, domainName, txtPassword.Text, 2, 0, ref token);
24.    if (result)
25.    {
26.       //If Sucessfully authenticated
27. /* When an unatuthenticated user try to visit any page of your application that is
28. only allowed to view by authenticated users then ASP.NET automatically redirect that
29. user to login form and add ReturnUrl query string parameter that contain the url of a
30. page that user want to visit, So that we can redirect the user to that page after
31. authenticated. FormsAuthentication.RedirectFromLoginPage() method not only redirect
32. the user to that page but also genrate an authentication token for that user. */

33.       if (string.IsNullOrEmpty(Request.QueryString[“ReturnUrl”]))
34.       {
35.          FormsAuthentication.RedirectFromLoginPage(txtUserName.Text, false);
36.       }
37. /* If ReturnUrl query string parameter is not present , then we need to generate
38. authentication token and redirect the user to any page ( acording to your application
39. need). FormsAuthentication.SetAuthCookie() method will generate Authentication
40. token*/

41.       else
42.       {
43.          FormsAuthentication.SetAuthCookie(txtUserName.Text, false);
44.          Response.Redirect(“default.aspx”);
45.       }
46.   }
47.   else
48.   {
49.      //If not authenticated then display an error message

50.      Response.Write(“Invalid username or password.”);
51.   }
52.}

Lista 1: Login.aspx

<%@ Page Language=”C#” AutoEventWireup=”true” CodeFile=”Login.aspx.cs”
02.     Inherits=”Login” %>
03.<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN”
04. “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”&gt;
05.<html xmlns=”http://www.w3.org/1999/xhtml”&gt;
06.<head runat=”server”>
07.    <title>Windows Authentication Using Form Authentication</title>
08.    <style type=”text/css”>
09.        .style1
10.        {
11.            width: 100%;
12.        }
13.    </style>
14.</head>
15.<body>
16.    <form id=”form1″ runat=”server”>
17.    <div>
18.        <table>
19.            <tr>
20.                <td>
21.                    <asp:Label ID=”lblUserName” runat=”server”
22.                         Text=”User Name:”></asp:Label>
23.                </td>
24.                <td>
25.                    <asp:TextBox ID=”txtUserName” runat=”server”></asp:TextBox>
26.                </td>
27.            </tr>
28.            <tr>
29.                <td>
30.                    <asp:Label ID=”lblPassword” runat=”server”
31.                         Text=”Password:”></asp:Label>
32.                </td>
33.                <td>
34.                    <asp:TextBox ID=”txtPassword” runat=”server”></asp:TextBox>
35.                </td>
36.            </tr>
37.            <tr>
38.                <td>
39.                     </td>
40.                <td>
41.                    <asp:Button ID=”btnLogin” runat=”server” onclick=”btnLogin_Click”
42.                        Text=”Login” />
43.                </td>
44.            </tr>
45.        </table>
46.    </div>
47.    <p>
48.         </p>
49.    </form>
50.</body>
51.</html>

Lista 2: Login.aspx.cs

using System;
002.using System.Collections;
003.using System.Configuration;
004.using System.Data;
005.using System.Linq;
006.using System.Web;
007.using System.Web.Security;
008.using System.Web.UI;
009.using System.Web.UI.HtmlControls;
010.using System.Web.UI.WebControls;
011.using System.Web.UI.WebControls.WebParts;
012.using System.Runtime.InteropServices;
013.public partial class Login : System.Web.UI.Page
014.{
015.    [DllImport(“ADVAPI32.dll”, EntryPoint = “LogonUserW”, SetLastError = true,
016.       CharSet = CharSet.Auto)]
017.    public static extern bool LogonUser(string lpszUsername, string lpszDomain,
018.       string lpszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken);
019.    /// <summary>
020.    /// Parses the string to pull the domain name out.
021.    /// </summary>
022.    /// <param name=”usernameDomain”>The string to parse that must contain the domain
023.    /// in either the domain\username or UPN format username@domain</param>
024.    /// <returns>The domain name or “” if not domain is found.</returns>

025.    public static string GetDomainName(string usernameDomain)
026.    {
027.        if (string.IsNullOrEmpty(usernameDomain))
028.        {
029.            throw (new ArgumentException(“Argument can’t be null.”,
030.               “usernameDomain”));
031.        }
032.        if (usernameDomain.Contains(“\\”))
033.        {
034.            int index = usernameDomain.IndexOf(“\\”);
035.            return usernameDomain.Substring(0, index);
036.        }
037.        else if (usernameDomain.Contains(“@”))
038.        {
039.            int index = usernameDomain.IndexOf(“@”);
040.            return usernameDomain.Substring(index + 1);
041.        }
042.        else
043.        {
044.            return “”;
045.        }
046.    }
047.    /// <summary>
048.    /// Parses the string to pull the user name out.
049.    /// </summary>
050.    /// <param name=”usernameDomain”>The string to parse that must contain the
051.    /// username in either the domain\username or UPN format username@domain</param>
052.    /// <returns>The username or the string if no domain is found.</returns>

053.    public static string GetUsername(string usernameDomain)
054.    {
055.        if (string.IsNullOrEmpty(usernameDomain))
056.        {
057.            throw (new ArgumentException(“Argument can’t be null.”,
058.               “usernameDomain”));
059.        }
060.        if (usernameDomain.Contains(“\\”))
061.        {
062.            int index = usernameDomain.IndexOf(“\\”);
063.            return usernameDomain.Substring(index + 1);
064.        }
065.        else if (usernameDomain.Contains(“@”))
066.        {
067.            int index = usernameDomain.IndexOf(“@”);
068.            return usernameDomain.Substring(0, index);
069.        }
070.        else
071.        {
072.            return usernameDomain;
073.        }
074.    }
075.protected void btnLogin_Click(object sender, EventArgs e)
076.{
077.   // Extract domain name from provided DomainUsername e.g Domainname\Username
078.      string domainName = GetDomainName(txtUserName.Text);
079.   // Extract user name from provided DomainUsername e.g Domainname\Username
080.      string userName = GetUsername(txtUserName.Text);
081.      IntPtr token = IntPtr.Zero;
082. //userName, domainName and Password parameters are very obvious.
083. /* dwLogonType (3rd parameter): I used LOGON32_LOGON_INTERACTIVE, This logon type is
084. intended for users who will be interactively using the computer, such as a user being
085. logged on by a terminal server, remote shell, or similar process. This logon type has
086. the additional expense of caching logon information for disconnected operations. For
087. more details about this parameter please see http://msdn.microsoft.com/en-
088. us/library/aa378184(VS.85).aspx */
089. /* dwLogonProvider (4th parameter) : I used LOGON32_PROVIDER_DEFAUL, This provider
090. uses the standard logon provider for the system. The default security provider is
091. negotiate, unless you pass NULL for the domain name and the user name is not in UPN
092. format. In this case, the default provider is NTLM. For more details about this
093. parameter please see http://msdn.microsoft.com/en-us/library/aa378184(VS.85).aspx */
094. /* phToken (5th parameter): A pointer to a handle variable that receives a handle to
095. a token that represents the specified user. We can use this handler for impersonation
096. purpose. */

097.    bool result = LogonUser(userName, domainName, txtPassword.Text, 2, 0, ref token);
098.    if (result)
099.    {
100.       //If Sucessfully authenticated
101. /* When an unatuthenticated user try to visit any page of your application that is
102. only allowed to view by authenticated users then ASP.NET automatically redirect that
103. user to login form and add ReturnUrl query string parameter that contain the url of a
104. page that user want to visit, So that we can redirect the user to that page after
105. authenticated. FormsAuthentication.RedirectFromLoginPage() method not only redirect
106. the user to that page but also genrate an authentication token for that user. */

107.       if (string.IsNullOrEmpty(Request.QueryString[“ReturnUrl”]))
108.       {
109.          FormsAuthentication.RedirectFromLoginPage(txtUserName.Text, false);
110.       }
111. /* If ReturnUrl query string parameter is not present , then we need to generate
112. authentication token and redirect the user to any page ( acording to your application
113. need). FormsAuthentication.SetAuthCookie() method will generate Authentication
114. token*/

115.       else
116.       {
117.          FormsAuthentication.SetAuthCookie(txtUserName.Text, false);
118.          Response.Redirect(“default.aspx”);
119.       }
120.   }
121.   else
122.   {
123.      //If not authenticated then display an error message
124.      Response.Write(“Invalid username or password.”);
125.   }
126.}

Espero que aproveitem a dica,até a próxima!

Custom Paging ASP.NET com Repeater e Data List

Introdução

Este artigo mostra como fazer um paging para os controles ASP.NET DataList e Repeater que não possuem suporte nativo ao paging.Essa é uma das maneiras mais eficientes que eu conheço de criar custom paging porque não requer uso de ViewState em  nenhum controle utilizado, e além de tudo o SEO é amigável a buscadores como google e bing que podem “rastrear” todos os dados da página facilmente.

customSEO

Como criar o custom paging

Para explicar o funcionamento do paging,eu utilizei o Sql Server 2005 ,o banco Northwind utilizando a tabela “Products”.

ASPX Page – Repeater Control

Vamos ver o código para o controle repeater:

<asp:Repeater ID=”Repeater1″ runat=”server” EnableViewState=”false”>

<ItemTemplate>

<b><%# Eval(“ProductName”) %></b> <%# Eval(“QuantityPerUnit”) %><br />

</ItemTemplate>

</asp:Repeater>

<asp:Literal ID=”Literal1″ runat=”server” EnableViewState=”false”></asp:Literal>

O item template do repeater contém dados das colunas “ProductName” e “QuantityPerUnit” da tabela Products.A última linha é controle Literal que irá listar os links numéricos para as diferentes páginas.Note que os controles possuem a propriedade “enableviewstate=false “ para assegurar que não se usa nenhum viewstate na página para armazenar valores,e isso faz com que nossa página se torne mais veloz.

O código da página.


using System;

using System.Collections.Generic;

using System.Linq;

using System.Web;

using System.Web.UI;

using System.Web.UI.WebControls;

using System.Data.SqlClient;

using System.Data;

using System.Text;

using System.Web.Services;

public partial class Paging_Paging : System.Web.UI.Page

{

string connection = @”Server=xxxx\sqlexpress; Initial Catalog=Northwind; User; Password=xxxxxx”;

int startIndex = 0;

int thisPage = 1;

int pageSize = 10;

int totalRowNumber = 0;

protected void Page_Load(object sender, EventArgs e)

{

if (!Page.IsPostBack)

{

if (Request[“start”] != null && Request[“page”] != null)

{

int.TryParse(Request[“start”].ToString(), out startIndex);

int.TryParse(Request[“page”].ToString(), out thisPage);

}

}

BindGrid();

}

protected void BindGrid()

{

DataTable dt = new DataTable();

using(SqlConnection cn =new SqlConnection(connection))

{

using(SqlCommand cmd=new SqlCommand(“LoadDados”,cn))

{

cmd.CommandType = CommandType.StoredProcedure;

SqlParameter[] parametros = new SqlParameter[3];

parametros[0] = new SqlParameter(“@startRowIndex”, SqlDbType.Int);

parametros[0].Value = startIndex;

parametros[1] = new SqlParameter(“@pageSize”, SqlDbType.Int);

parametros[1].Value = pageSize;

parametros[2] = new SqlParameter(“@totalCount”, SqlDbType.Int);

parametros[2].Direction = ParameterDirection.Output;

cmd.Parameters.AddRange(parametros);

using (SqlDataAdapter da = new SqlDataAdapter(cmd))

{

cn.Open();

da.Fill(dt);

cn.Close();

}

totalRowNumber = int.Parse(parametros[2].Value.ToString());

}

}

Repeater1.DataSource = dt;

Repeater1.DataBind();

Literal1.Text = DoPaging(thisPage, totalRowNumber, pageSize, “Paging.aspx”, “”);

}

protected string DoPaging(int pageNum, int total, int pageTam, string pageName, string extraDado)

{

int pagNo = 0;

int start = 0;

int loop = total / pageTam;

int remainder = total % pageTam;

StringBuilder sb = new StringBuilder(“<br /><b><font color=\”green\”>Page:</font> “,500);

for (int i = 0; i < loop; i++)

{

pagNo = i + 1;

if (pagNo.Equals(pageNum))

sb.Append(pagNo + “&nbsp;|”);

else

sb.Append(“<a href=\”” + pageName + “?start=” + start + “&page=” + pagNo + extraDado + “\” title=\”Go toPage “ + pagNo + “\”>” + pagNo + “</a> | “);

start += pageTam;

}

if (remainder > 0)

{

pagNo++;

if (pagNo.Equals(pageNum))

{

sb.Append(“<b>” + pagNo + “&nbsp;</b>| “);

}

else

{

sb.Append(“<a href=\”” + pageName + “?start=” + start + “&page=” + pagNo + extraDado + “\” title=\”Go to page “ + pagNo + “\”>” + pagNo + “</a> | “);

}

}

return sb.ToString() + “</b></span>” ;

}

}

No código acima eu tenho 4 variaveis relacionadas com o custom paging,são elas:

1-startIndex – serve para armazenar o índice inicial entre as linhas que serão retornadas da consulta,isso nos ajudará a buscar dados para a próxima página.

2-thisPage – é utilizada para armazenar o valor da página atual.

3-pageSize – para armazenar o tamanho da página (nº de registros mostrados por página)

4-totalRowNumber – armazena o nº total de linha no banco,serve para calcular o número total de páginas de nosso paging.

Primeiramente,vamos dar uma olhada no método BindGrid().Esse método contém,um código simples de acesso ao Sql Server  utilizando a Stored Procedure “LoadDados”com dois parâmetros input, (startRowIndex e pageSize) e um parametro de saída (totalCount).O código para a stored procedure “LoadDados”segue abaixo:

set ANSI_NULLS ON

set QUOTED_IDENTIFIER ON

GO

ALTER PROCEDURE [dbo].[LoadDados]

@startRowIndex int,

@pageSize int,

@totalCount int output

AS

BEGIN

SET NOCOUNT ON;

SET @totalCount = 0

SET @startRowIndex = @startRowIndex + 1;

Select * from(Select ProductName, QuantityPerUnit, Row_Number() over(order by ProductName asc)as linhas from Products where CategoryID = 1) as lista where linhas between @startRowIndex and (@startRowIndex + @pageSize) – 1  order by ProductName

Select @totalCount = count(ProductName) from Products where CategoryID = 1

END

O primeiro comando SELECT  está buscando dados paginados do banco e o segundo SELECT está buscando o total de linhas do banco.Note que o 1º SELECT só é suportado no SQL SERVER 2005 .

Depois de exceutar a Stored Procedure no método BindGrid() , eu estou dando um “DataBind()” no repeater com o DataTable que contém os dados retornados do banco.

A última linha desse método é pra escrever o número de páginas e os respectivos links pra cada uma delas.

Esse links estão sendo criados no métodoDoPaging() que pega 5 parâmetoros,são eles:

1-pageNum – esse é o valor da página atual sendo mostrada.

2-total – esse é o total de registros retornado do último SELECT da stored procedure “LoadDados”

3-pageTam – esse é o tamanho da página (total de registros mostrados por vez em cada página)

4-pageName – esse é o nome da página onde o paging está sendo criado (página atual).É uma boa prática manter essa função numa classe comum porque assim você poderá acessar essa função de paging em diferentes páginas no seu projeto,nesse caso esse parâmetro será útil.

5-extraDado – essa é uma string adicional que você queira adicionar com os links de suas páginas (No mundo real você pode querer passar seus parâmetros de filtro ou Ids nos links) Eu não utilizei nesse exemplo por isso deixei vazio.

O código dentro do método DoPaging() não é muito complicado,é matemática:divide-se o total de registros pelo número de registros em cada página,, faz se um loop pelo resultado (dividendo) e escreve os links numéricos.Se tiver um resto, escreve o último paging link também.

Uma vez pronto, teste seu projeto e você deveráver um Custom SEO paging  amigável dos registros como mostrado na figura acima.Como enableViewState dos controles estão false,não é preciso se preocupar com o tamanho do viewstate de cada página.

Esses links são HyperLinks com valores queryString por isso motores de busca irão facilmente encontra-los.

Esse post descreveu como alcançar um Veloz Custom SEO paging com repeater  ou DataList .Esta técnica também pode ser usada com outros controles como GridView etc…