terça-feira, 5 de outubro de 2010

Herança no Web.Config - Resolvendo problema de conflito

Fala, galera!!

Segue mais uma dica valiosa que irá poupar tempo de muita gente.

Durante o processo de migração me deparei com um conflito no web.config que ainda não sei se é uma característica do Framework 4.0 ou do IIS 7.

Meu cenário é o seguinte:
Minha solution possui um Web Application referente ao Front-End cujo Framework é o 4.0 e um outro Web Application referente à área de administração cujo Framework é o 3.5. Motivo: Estou utilizando o Asp.Net Dynamic Data para a administração e a nova versão do mesmo não possui o Dynamic Data Filtering implementado. Desta forma, para adicionar novos filtros dinamicamente eu teria que codificar meus próprios templates de filtro. Como outra pessoa já fez isso para a primeira versão do A.D.D, decidi manter esta versão que me atende plenamente.

Prosseguindo...
Meu IIS possui um website principal e um aplicação "filha" que é a área de administração.
Ao fazer o deploy para produção passou a ocorrer um conflito de versões.
Aparentemente, minha aplicação 3.5 estava herdando o web.config da aplicação 4.0.

Perdi um bom tempo tentando entender, mas achei a solução. Bem simples, por sinal.

Basta adicionar a seguinte linha no web.config, logo acima da tag <system.web>:

<location path="." inheritInChildApplications="false">

No meu caso, o web.config ficou mais ou menos assim:


<location path="." inheritInChildApplications="false">
<system.web>
<compilation debug="false" strict="false" explicit="true" targetFramework="4.0">
                        ...
               </system.web>
</location>

Todo código incluído na tag <location> não será herdado pelas aplicações "filhas".
No meu caso, a linha que continha a tag <compilation> estava gerando o conflito.

Um abraço e até a próxima!!

Url Amigável - Migrando do Framework 3.5 para o 4.0

Fala, galera!!

Esta semana migrei minha primeira aplicação do framework 3.5 para o 4.0.
O motivo: Suporte nativo à URL Amigável.

Tudo funcionou perfeitamente em meu ambiente de desenvolvimento.
A surpresa foi quando fiz o deploy da aplicação para o servidor de produção: Todas as URL's amigáveis pararam de funcionar!

Após uma rápida pesquisa, consegui a solução.
Basta adicionar o código abaixo no seu arquivo web.config, logo após a seção <ConfigSections>:

<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>

OBS: Quem criar um novo projeto já no framework 4.0 não deverá passar por esse problema.

Um abraço e até a próxima!!

quinta-feira, 30 de setembro de 2010

Asp.Net Dynamic Data - Ordenando dados do GridView

Fala, galera!!

Hoje irei mostrar como ordenar os dados de um gridview utilizado pelo Asp.Net Dynamic Data.

A primeira coisa a ser feita é definir no seu arquivo de MetaDados qual campo será utilizado como critério de ordenação e qual será o critério: Ascending ou Descending.

O código em negrito é o que deve ser adicionado no arquivo de Metadados.


<MetadataType(GetType(PROJETO_Metadata))> _
       <DisplayColumn("NomeProjeto", "NomeProjeto", False)> _
    Partial Public Class PROJETO

No código acima, minha grid será ordenada pelo nome do projeto em ordem crescente (Ascending).

Agora vamos adicionar o código que fará a ordenação da GridView:

No arquivo List.aspx, basta adicionar o seguinte no código no evento Page_Load:



 If Not Page.IsPostBack Then
            Dim Ordem As String = IIf(table.SortDescending = True, "Descending", "Ascending")
            Dim orderBy As String = String.Format("{0} {1}", table.DisplayColumn.SortExpression, Ordem)
            GridDataSource.OrderBy = orderBy
End If


Um abraço e até a próxima!!

sexta-feira, 24 de setembro de 2010

Update Progress & Update Panel Trigger

Fala, galera!!

Segue a solução para quem, como eu, enfrentou problemas ao colocar o Update Progress para funcionar com um update Panel cuja atualização é disparada através de uma trigger.

<asp:ScriptManager ID="ScriptManager1" runat="server" />

 <script type="text/javascript">
        var prm = Sys.WebForms.PageRequestManager.getInstance();

        prm.add_initializeRequest(InitializeRequest);
        prm.add_endRequest(EndRequest);

        var postBackElement;

        function InitializeRequest(sender, args) {

            if (prm.get_isInAsyncPostBack())

                args.set_cancel(true);

            $get('ctl00_ContentPlaceHolder1_upProgresso').style.display = 'block';

        }

        function EndRequest(sender, args) {
                $get('ctl00_ContentPlaceHolder1_upProgresso').style.display = 'none';
        }
    </script>

O script deve ser adicionado logo após o controle ScriptManager. Caso contrário, ocorrerá um erro no javascript: "Sys is not defined"

Um abraço e até a próxima!!

terça-feira, 21 de setembro de 2010

Exportando dados para o Excel

Fala, galera!!

Fiquei meio ausente. O tempo anda escasso.
Portanto, farei um post relâmpago para quem precisa, como eu precisei, exportar dados de um gridview para uma planilha excel.

Ai vai...


Private Sub ExportarParaExcel()
        Dim util As New util
        Dim tw As New StringWriter()
        Dim hw As New System.Web.UI.HtmlTextWriter(tw)
        Dim frm As HtmlForm = New HtmlForm()
        Response.ContentType = "application/vnd.ms-excel"
        Response.AddHeader("content-disposition", "attachment;filename=Planilha.xls")
        Response.Charset = ""
        EnableViewState = False

        Controls.Add(frm)
        frm.Controls.Add(grdDados) 'Aqui você informa o seu controle GridView
        frm.RenderControl(hw)
        Response.Write(tw.ToString())
        Response.End()

    End Sub

Bem simples e bem útil.

Um abraço e até a próxima!!

domingo, 18 de julho de 2010

LINQ to SQL - Row Not Found or Changed

Fala, galera!!

Essa semana me deparei com o seguinte erro no Linq To SQL: Row Not Found or Changed.
Por isso, resolvi postar aqui a solução.

Ainda não descobri o motivo do erro, pois tudo funcionava normalmente até que o erro passou a ocorrer.

A correção é simples. Basta abrir o arquivo DBML e executar os passos abaixo:

1) Alterar a propriedade "Update Check" para "False" na chave primária da tabela que apresentar o erro.

2) Alterar a propriedade "Timestamp" para "True" na chave primária da tabela que apresentar o erro.

Um abraço e até a próxima!!

sábado, 5 de junho de 2010

FileUpload - Problema com o tamanho dos arquivos

Fala, galera!!

Hoje vou postar um código para solucionar um problema muito comum quando se trabalha com o componente fileupload.
Apesar do problema ser comum, a mensagem de erro não é nada esclarecedora.

Quando se tenta fazer o upload de um arquivo cujo tamanho seja maior do que o permitido(4MB) pelo .Net o site simplesmente "sai do ar". Exatamente. É exibida aquela mensagem de "página não disponível" e o desenvolvedor  não tem nem pista do motivo do problema.

Para solucionar este problema, adicione a seguinte linha dentro da seção <system.web> do seu web.config:

<httpRuntime maxRequestLength="20480" />

Você pode também configurar o tamanho máximo do upload para um diretório específico:

<location path="uploads">
     <system.web>
          <httpRuntime maxRequestLength="20480" />
     </system.web>
</location>

Um abraço e até a próxima!!

sexta-feira, 30 de abril de 2010

Footer Template - Adicionando Colspan

Fala, galera!!

Segue um post relâmpago com o código para adicionar um colspan no footer de sua gridview:

No evento ItemDatabound adicione o seguinte código:


If e.Row.RowType = DataControlRowType.Footer Then
            e.Row.Cells(0).ColumnSpan = 2
            e.Row.Cells(1).Visible = False
End If

Um abraço e até a próxima!!

domingo, 18 de abril de 2010

Removendo Acentuação

Fala, galera!!

Hoje vou postar um código simples, mas bastante útil para retirada de acentuação de uma string.

A essa altura do campeonato, não dá mais para escrever 50 linhas de código com "Replaces" para remover caracteres de acentuação, né?

Então, segue o código "inteligente":


Public Function RemoverAcentos(ByVal Valor As String) As String
        Dim TextoNormalizado As String = Valor.Normalize(NormalizationForm.FormD)
        Dim sbTexto As New StringBuilder

        For i = 0 To TextoNormalizado.Length - 1
            Dim C As Char = TextoNormalizado(i)
            If (CharUnicodeInfo.GetUnicodeCategory(C) <> UnicodeCategory.NonSpacingMark) Then
                sbTexto.Append(C)
            End If
        Next
        Return sbTexto.ToString
End Function


Um abraço e até a próxima!!

sábado, 10 de abril de 2010

Validando um GUID

Fala, galera!!

Dando sequência no assunto GUID.
De acordo com o exemplo citado no post anterior, o usuário recebe por email um link para ativar seu cadastro.
O código de ativação é um GUID.

Ao acessar a página de ativação é preciso verificar se o parâmetro informado na querystring é um GUID válido.
Essa validação é necessária por questões de segurança.

Segue o código de validação do GUID:

Private Function GuidEhValido(ByVal Valor as string) as Boolean
Try
     Dim NovoGuid as System.Guid = New System.Guid(Valor)
     return True
Catch ex as Exception
     return False
End Try

O construtor da classe Guid possui uma sobrecarga que permite que se informe um parâmetro do tipo GUID.
Logo, para validar se o seu GUID é válido, basta instanciar a classe GUID passando esse parâmetro.

Se não ocorrer erro, GUID válido.
Se ocorrer erro, GUID inválido.

Um abraço e até a próxima!!

domingo, 28 de março de 2010

Criando um identificador único - GUID

Fala, galera!!

Continuando a série "Códigos da Vida".
Estive implementando um cadastro de usuários que necessita de uma confirmação por email para ativação do acesso. Coisa simples. Nada fora do trivial.

No entanto, precisava definir como seria feita a ativação do cadastro.
Não que esse seja um grande problema ou até mesmo um problema.
Mas era preciso definir com calma que informação seria enviada para o email do usuário.

Por questões de segurança, não posso enviar o código do usuário sem criptografar esta informação.
Isso porque na maioria (para não dizer em todos) dos sites o identificador do usuário é um código sequencial.
Desta forma, ficaria fácil um usuário malicioso e criativo achar N formas de prejudicar seu site.

Enviar esta informação criptografada também não é a melhor idéia, pois como a informação é enviada via querystring, alguns caracteres da criptografia podem gerar problemas, dependendo da criptografia utilizada.

A solução foi gerar um GUID utilizando a classe system.Guid.
Um Guid é um identificador único. Como o próprio nome já diz: Globally Unique Identifier

Veja como é fácil:

Dim Identificador as string = System.Guid.NewGuid.ToString

A string gerada será algo como: "91752d05-2274-4e56-9251-4bb4b5fccd6c"

Desta forma, não preciso expor nenhuma informação sensível do usuário e nenhum usuário malicioso conseguirá "adivinhar" um GUID válido.

Um abraço e até a próxima!!

domingo, 28 de fevereiro de 2010

Asp.Net Dynamic Data - Ordenando e Definindo os campos para filtros de chave estrangeira

Fala, galera!!

Quando definimos um filtro cuja a origem é uma chave estrangeira o Dynamic Data gera uma combo.
Isto é definido pelo usercontrol ForeignKey.ascx que fica no diretório FilterTemplates.

Por padrão, o campo exibido na propriedade "Text" do dropdown é sempre o primeiro campo logo após a chave primária.

Mas como definir manualmente a propriedade "Text" de cada item da combo e a ordem com que os mesmos aparecerão?

Simples!

Basta adicionar o seguinte código no metadata da tabela origem da chave estrangeira. Ou seja, onde ela é a chave primária.


<DisplayColumn("Descricao", "Descricao", False)> _
    <MetadataType(GetType(Evento_Metadata))> _

O código em negrito é o que deve ser adicionado logo acima da declaração do MetadataType.

Desta forma, seu Dropdownlist ou seu listbox exibirão o campo "Descricao" e serão ordenados pelo mesmo campo por ordem alfabética.

OBS: No exemplo acima utilizei o relacionamento entre uma tabela chamada "Log" e outra chamada "Evento" e inseri um filtro por "Evento" na tabela de Log.


Um abraço e até a próxima!!

sábado, 27 de fevereiro de 2010

ASP.Net Dynamic Data - Inserindo Regras de Negócio

Fala, galera!!

Há alguns meses comecei a estudar o Asp.Net Dynamic Data e escrevi aqui um post sobre como aplicar regras de negócio nos formulários de inclusão/alteração de dados.

Confesso que não era a melhor prática, mas resolvia. :)
Estava no início do estudo da ferramenta e, por ser uma ferramenta nova, ainda não existiam muitos tutoriais na web.

Mas agora, vamos a forma mais correta, rápida e simples de se implementar uma regra de negócio no Asp.Net Dynamic Data.

Como exemplo, vou utilizar uma tabela de parametrização das mensagens de uma ferramenta que desenvolvi.

Ao abrir o arquivo "designer.vb" do meu arquivo dbml, vou até a classe "ParametrosDeSistema" que é o nome da minha tabela e procuro pela Region "Extensibility Method Definitions". Veja a imagem abaixo:



















A imagem acima mostra uma série de métodos parciais que podem ser implementados dentro da classe de metadados.
Para cada propriedade da sua classe existe um método "OnChanging" e "OnChanged".

Vamos agora implementar uma regra onde iremos definir que o atributo TempoDuracaoToken não pode receber valor menor do que 3.

Dentro de nosso arquivo de metadados iremos inserir o código abaixo:

Estou supondo que você já sabe o que é um arquivo de metadados.

Agora veja o que acontece quando tentamos inserir um valor que não atenda nossa regra de negócio:









Simples, não?

Um abraço e até a próxima!!

Utilizando Timer em um Windows Service

Fala, galera!!

Hoje vou postar uma solução para o problema do Timer em um windows service.
O problema é que o Timer simplesmente não funciona. Legal, não? :)

Pois é. Precisei criar um serviço de monitoração e, para isso, utilizei o Timer para que o monitoramento fosse executado no período especificado.

O processo de adição do Timer é o que nós já conhecemos: Arrastar o controle "Timer" da aba "Components" da Toolbox.

O problema é que o serviço ignorava o Timer e a monitoração não era realizada.

Pesquisando na internet, descobri que algumas pessoas passaram pelo mesmo problema.

Das soluções propostas, segue a mais simples e que, de fato, funciona:

Primeiro: Exclua o Timer que você já havia adicionado. :)

Declare o objeto privado oTimer:
Private oTimer As System.Threading.Timer

No envento On_Start do seu serviço adicione o seguinte código:


Dim oCallback As New TimerCallback(AddressOf OnTimedEvent)
oTimer = New System.Threading.Timer(oCallback, Nothing, 60000, 60000)

Em seguida crie o método OnTimedEvent e implemente o código que desejar que seja executada em cada "Tick" do timer.

Private Sub OnTimedEvent(ByVal state As Object)
   'Adicione aqui seu código
End Sub


Um abraço e até a próxima!!

sexta-feira, 26 de fevereiro de 2010

Trabalhando com Threads no Asp.net

Fala, galera!!

Hoje escreverei sobre o uso de Threads no .net.
A grosso modo, uma thread nada mais é do que uma linha de execução de um processo.

Esta semana me deparei com a seguinte situação:
Uma aplicação windows que realiza uma carga grande de dados para uma base SQL Server.
Durante a carga, a janela do aplicativo ficava congelada e no título da janela aparecia o seguinte texto: "Não Respondendo".

A carga continuava sendo feita, mas o usuário tinha a sensação de que o programa tinha travado.
Para acabar com essa sensação era necessário dar um feedback para o usuário sobre o andamento da carga.
Mas nada funcionava, pois a janela ficava congelada.

A solução foi trabalhar com Threads.
Sendo assim, alterei o código para que executasse o método de carga em uma nova Thread.
Enquanto a Thread "principal" apenas monitorava a carga, incrementando um contador e manipulando uma barra de progresso.

Segue o código para a criação da nova Thread:


Dim Thread As New System.Threading.Thread(AddressOf ProcessarCarga)
Thread.Start()

O parâmetro AddressOf recebe o nome do método que será executado na nova Thread.

Desta forma todo o processamento da carga foi executado em "background".
Isto é, em uma thread separada da thread principal que deu origem ao aplicativo.
Isso impediu o congelamento da janela, fazendo com que o feedback para o usuário fosse viável.

Para o feedback, inseri um Timer que monitorava a carga a cada 1 segundo, obtinha o total de registros inseridos para incrementar o contador e ajustava a barra de progresso.

É isso ae!! Um abraço e até a próxima!!

terça-feira, 9 de fevereiro de 2010

Criando Cache de Dados em Asp.net

 Fala, galera!!

Após um longo período de inatividade, hoje estarei postando um código para gerar cache de dados em webservices, serviços criados utilizando o WCF ou aplicações web.

O objetivo é gerar um cache de consultas para evitar acessos constantes ao banco de dados.

Por exemplo:

Imaginemos uma aplicação que possui um método para consultar o CPF de um usuário de acordo com o login do mesmo.

Sabemos que o CPF é uma informação que nunca muda. Portanto, ao invés de acessarmos o banco de dados cada vez que o método for executado, por que não gerarmos um cache dessa informação?

Veja o código:


Public Function ObterCPFUsuario( ByVal Login As String) As String
            'Se houver Cache, a função retorna o valor armazenado no cache.
            If Not IsNothing(HttpContext.Current.Cache("CPF_" & Login)) Then
                Return HttpContext.Current.Cache("CPF_" & Login)
            End If
            'Se não houver Cache, a função realiza a consulta no banco e armazena o resultado no cache
            Dim conn as new Sqlconnection
            Dim cmd as new SqlCommand
            Dim dr as SqlDataReader
            Dim CPF as string
            conn.ConnectionString = "String de conexao"
            conn.open()
            cmd.Connection = conn
            cmd.CommandText = "Select CPF From Usuario Where Login ='" & Login & "'"
            dr = cmd.ExecuteReader()
            if dr.Read() then
               CPF = dr(0)
            end if
            'Armazenando o resultado em um cache que nunca expira
            HttpContext.Current.Cache.Add("CPF_" & Login, CPF, Nothing, DateTime.MaxValue, System.Web.Caching.Cache.NoSlidingExpiration, CacheItemPriority.Normal, Nothing)

            Return CPF
End Function


No exemplo acima, o cache nunca expira pois sabemos que o CPF nunca irá mudar.
Mas você pode estipular um período de validade para o seu cache.

Um abraço e até a próxima!!