Acessando colunas invisíveis no GridView

Introdução

Quando você mostra dados no GridView você deve sempre tomar cuidado para que a primary key da tabela não seja mostrada.Neste artigo veremos como nós podemos acessar colunas invisíveis do GridView.

Acessando colunas invisíveis:

A primeira coisa que você precisa setar é a propriedade DataKeyNames para a chave primaria de sua tabela,nesse caso”PersonID”.

Código HTML

<asp:GridView runat=”server” AutoGenerateColumns=”False” CellPadding=”4″
DataKeyNames=”PersonID” DataSourceID=”mySource” ForeColor=”#333333″ GridLines=”None”
Width=”266px” OnSelectedIndexChanged=”gvMaster_SelectedIndexChanged”>
<FooterStyle BackColor=”#507CD1″ Font-Bold=”True” ForeColor=”White” />
<RowStyle BackColor=”#EFF3FB” />
<Columns>
<asp:CommandField ShowSelectButton=”True” />
<asp:BoundField DataField=”PersonID” HeaderText=”PersonID” InsertVisible=”False”
ReadOnly=”True” SortExpression=”PersonID” Visible=”False” />
<asp:BoundField DataField=”Name” HeaderText=”Name” SortExpression=”Name” />
<asp:TemplateField HeaderText=”Select”>
<ItemTemplate>
<asp:CheckBox runat=”server” />
</ItemTemplate>
</asp:TemplateField>
</Columns>
<PagerStyle BackColor=”#2461BF” ForeColor=”White” HorizontalAlign=”Center” />
<SelectedRowStyle BackColor=”#D1DDF1″ Font-Bold=”True” ForeColor=”#333333″ />
<HeaderStyle BackColor=”#507CD1″ Font-Bold=”True” ForeColor=”White” />
<EditRowStyle BackColor=”#2461BF” />
<AlternatingRowStyle BackColor=”White” />
</asp:GridView>

Meu gridView possui 3 colunas (esquecendo a coluna do select) chamadas PersonID,Name e uma coluna de checkBox.A coluna PersonID é a chave-primária,e foi marcada como coluna invisível.Nós também temos um botão na página que quando clicado, faz um loop pelos controles do gridView, e mostra as primary keys ,das colunas que tem seu checkbox checado.

Vamos ver o evento do clique do botão:

protected void Button1_Click(object sender, EventArgs e){

string str = String.Empty;

int rowNo = 0;

foreach (GridViewRow row in gvMaster.Rows)

{

bool isChecked = ((CheckBox)row.FindControl(“CheckBox1”)).Checked;

if (isChecked)

{

// Gets the name of the primary key column our primary key is the PersonID

string primaryKey = gvMaster.DataKeyNames[0];

int personID = (int) gvMaster.DataKeys[rowNo].Value;

Response.Write(personID);

}

// increment the row count

rowNo++;

}

Response.Write(str);

}

Até a próxima!

Você sabia?- Como desativar o intellisense para o editor HTML/CSS

Se você quiser desablilitar o intellisense para o editor HTML/CSS,vá até Tools>Options.

Para o editor HTML vá até Tools>Options>HTML>General .No painel direito abaixo de Statement Completion deselecione “Auto List Members“.

HTML

Para o editor CSS, vá até Tools>Options>Text Editor>CSS>General.No painel direito abaixo de Statement Completion deselecione “Auto List Members”.

CSS

Até a próxima!

Você sabia como comentar e descomentar suas páginas rapidamente?

Selecione as linhas que você deseja comentar na página aspx ou html,web.config etc..,e clique no ícone comentar/descomentar na barra de ferramentas.

O ícone comentar:
Comment Icon_thumb_1

O ícone descomentar:
Uncomment_thumb

Você também pode usar os atalhos do teclado  ctrl + c + ctrl + k pra comentar ou ctrl + k + ctrl + u pra descomentar.

Comentários na página ASPX:
Comments in ASPX page_thumb

Comentários no html:
Comments in HTML page_thumb_1

Comentário em blocos de script:
Script block_thumb

Esse atalho está disponível em Edit Menu->Advance –>Comment Selection /Uncomment Selection.
Comment Uncomment Menu Option_thumb

Até a próxima!

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!

Encriptar arquivo web.config

Se você está receoso em manter informações criticas no arquivo web.config,então você deve encripta-lo — ou pelo menos as partes que você mais se importa.

Eu gosto de manter minhas informações na seção appSettings do meu arquivo web.config,isso me permite mudar o comportamento
de um web site inteiro apenas mudando alguns valores no arquivo.Eu especialmente gosto de manter strings de conexão no elemento
ConnectionStrings(isso garante que eu mantenha o número de conexões minimo,o que aumenta as performances de pooling).

Meus clientes nem sempre concordam em manter dados no web.config.Pra ser mais especifico meus clientes,ficam receosos em manter
informações sensiveis(como connectionStrings)num arquivo de texto.Eu digo a meus clientes que se  pessoas podem acessar arquivos
de texto dos seus servidores web,então eles tem problemas,que nem mesmo eu posso resolver.

Meus clientes não consideram esse um argumento válido.

E pra ser honesto,eles tem razão.Uma porcentagem significativa,de brechas de segurança são feitas por pessoas dentro das
empresas .Então eu sugeri aos meu cliente encriptar o arquivo web.config.

Encriptando Seções

Esse é o código que eu utilizei para encriptar,uma sessão especifica do web.config.Eu primeiro selecionei uma seção utilizando,
o objeto de configuração da seção de coleções.Nesse caso eu estou selecionando a seção ConnectionString:


System.Configuration.Configuration configFile;
ConfigurationSection configSection;

configFile = System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration(Request.ApplicationPath);
configSection = configFile.Sections[“connectionStrings”];

Esse código presume que você está executando através de uma página do site por isso usei a propriedade ApplicationPath no objeto
Request para recuperar o caminho fisico para a pasta do web.config.

Agora que tenho a seção,vou encripta-la,especificando o sistema de encriptação que quero usar.O último passo é salvar a versão
encriptada de volta no web.config:

configSection.SectionInformation.ProtectSection(“RsaProtectedConfigurationProvider”);
configFile.Save();

O resultado aparece assim no web.config:

<connectionStrings
configProtectionProvider=”DataProtectionConfigurationProvider”>
<EncryptedData>
<CipherData>
<CipherValue>…encrypted data… </CipherValue>
</CipherData>
</EncryptedData>
</connectionStrings>

A boa noticia é que quando você usa a coleção ConnectionString do ConfigurationManager para recuperar uma conexão encriptada,
essa conexão é automaticamente decriptada para você.Esse código funciona tanto se a conexão estiver encriptada ou não.


string conection = System.Web.Configuration.WebConfigurationManager.ConnectionStrings[“minhaConexao”].ConnectionString;

Uma vez que as strings são encriptadas usando a chave privada para o Web server,mesmo que o arquivo seja roubado do site,
não pode ser decriptado em nenhuma máquina,a não ser no web server.Isso significa também que você não pode encriptar a connection
string até que o arquivo tenha sido movido para o servidor.Se você encriptar a connection string no servidor de teste e depois
mover seu site para o servidor de produção,o ASP.NET não poderá decriptar a connection string usando a chave privada do servidor
de produção.

Dependendo da ocasião,você poderá precisar decriptar a seção do web.config apenas pra checar o que o arquivo na verdade contém.
Esse código faz o serviço:

System.Configuration.Configuration configFile;
ConfigurationSection configSection;

configFile = System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration(Request.ApplicationPath);
configSection = configFile1.Sections[“connectionStrings”];

configSection.SectionInformation.UnprotectSection();

configFile.Save();

Encriptação por linha de comando:

Se você preferir não utilizar código,você pode encriptar ou decriptar seções do seu arquivo web.config,usando o aspnet_regiis utility.
Você deve passar ao utilitario o parametro -pe para especificar a seção que deverá ser encriptada junto com o caminho para,
a pasta do arquivo de configuração.Você também deve passar o parametro -prov para especificar o esquema de encriptação:

aspnet_regiis.exe -pef section physical_directory -prov provider

Esse exemplo encripta a seção configurationStrings para um arquivo de configuração em c:\NorthwindCRM folder:

aspnet_regiis.exe -pef configurationStrings c:\NorthwindCRM
-prov “RsaProtectedConfigurationProvider”

Você também pode usar o aspnet_regiis utility para decriptar uma seção usando parametro -pdf ao invés de -pef.
Ou você também poderia se  certificar que ninguém poderia roubar arquivos de texto do seu web server.

JavaScript para desenvolvedores ASP.NET

Sofri um choque de culturas ao me adptar para trabalhar com JavaScript,iniciando pelo fato de não ser uma linguagem orientada-a-objetos

Eu nunca vi com “bons olhos” a linguagem JavaScript.Sempre me pareceu que apesar de qualquer beneficío que a linguagem
pudesse
trazer,a incapacidade do JavaScript de especificar um tipo de dado para uma variavel mantinha a linguagem afastada de ser
uma “real” linguagem” de programação – pelo menos quando se trata de negócios.

Entretanto,com o passar do tempo eu fui utilizando e me aprofundando mais no estilo de programação AJAX,e me peguei começando
a desenvolver um certo respeito pela linguagem.

Parte do motivo pelo qual eu não gostava de JavaScript era de certa forma falta de conhecimento sobre a linguagem meu.
Desde que comecei a programar,eu trabalhei ou com linguagem orientada-a-objetos.
Eu me aventurei por varias linguagens,mas sempre relacionadas com orientção-a-objetos.

O que mudou um pouco minha visão sobre JavaScript,foi um livro sobre JavaScript de Douglas Crackford chamado JavaScript:The
Good Parts
.Os créditos de Crackford para escrever um livro sobre JavaScript são excelentes,entre outras qualificações,ele
é responsável,pelo formato JSON que é o responsável por transmitir dados estruturados,entre cliente e servidor
em aplicações AJAX.

O livro tem algumas revisões negativas no Amazon.com,que dizem que o livro é curto e definitivamente não ensina vocÊ
a como programar em JavaScript.Ao invés disso,o livro foca em trazer conceitos essenciais da linguagem ao leitor,conceito
esse que eu havia ignorado.

Então essa “clareada” dada por programadores “reais” JavaScript,é a base para este post:para descrever,em termos que fazem
sentido para programadores aSP.NET, os conceitos fundamentais de JavaScript,e como eles são diferentes do conceitos de linguagens
OOP que estamos acostumados.

objetos vs protótipos

Diferentemente de linguagens do lado-servidor que eu escrevia códigos,JavaScript não é orientado a objetos.
Ao invés disso,é organizado em protótipos.Em JavaScript vocÊ pode definir estrutura de dados,e depois ou usa-las ou copia-las.
A habilidade de copiar uma estrutura,para criar uma nova, siginifica que qualquer estrutura pode ser um protótipo para
estruturas subsequentes.Entretanto,diferentemente de uma classe na programação orientada a objetos,onde a definição da estrutura
é inviolável,protótipos e suas cópias podem ser modificados ou extendidos a qualquer momento.

Esse código por exemplo,define uma estrutura de dados que contém duas variaveis:uma chamada id(inicializada com uma string
de tamanho zero)e uma chamada dataOrdered (inicializada com um objeto de Data).Essa estrutura de dados pode ser referenciada
através da variavel salesOrder.

var salesOrder = {
id: “”,
dateOrdered: new Date()
};

Eu posso começar a utilizar esta estrutura imediatamente.Esse código,por exemplo,atribui a propriedade id para um valor string.
(E a boa noticia!A propriedade id irá aparecer no IntelliSense da variavel saleOrder).

salesOrder.id = “A1230”;

Entretanto,eu também posso criar cópias desta estrutura tratando-a como um protótipo.Para copiar a estrutura,eu criei uma
função simples,atribui a propriedade prototype da função para minha estrutura de dados original,depois usei a palavra-chave
new do JavaScript para criar uma nova estrutura a partir daquela estrutura.Esse código cria uma nova cópia da minha estrutura
e referencia ela na variavel através da variavel chamada backOrder.

var SalesOrderGenerator = function(){};
SalesOrderGenerator.prototype = salesOrder;
var backOrder = new SalesOrderGenerator;

Eu posso agora usar essa nova cópia da estrutura de dados:

backOrder.id = “B4567”;

Se esse processo não fosse diferente o bastante,JavaScript permite a você adicionar dinamicamente,um novo elemento para sua
nova cópia simplesmente atribuindo o elemento a um valor.Esse exemplo adiciona um elemento outOfStock para a versão da estrutura
backOrder:

backOrder.outOfStock = true;

Tudo isso,com certeza,é obvio para programadores com experiência em JavaScript.Mas para membros da comunidade ASP.NET que estão
migrando, de código do lado-servidor para código do lado-cliente,existe com certeza um choque de culturas em jogo.

Não ajuda muito saber que uma palavra chave familiar como new aparece em javascript.Uma das melhores regras para seguir,em
design de interfaces de usuário é:”Coisas que fazem a mesma coisa devem parecer iguais,coisas que fazem coisa diferentes,devem
parecer diferentes”.Voltando a palavra chave new,num ambiente diferente essa palavra pode parecer útil,mas na verdade,isso
me encorajou a pensar em javaScript como uma liguagem OOP quando na verdade não é.

Eu ainda estou me ajustando,ah mas se pelo menos eu pudesse declarar uma variável com um simples tipo de dado…

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…