quinta-feira, 18 de dezembro de 2014

Serializando entidades do LINQ

Fala galera,

Após um longo período de inatividade vou compartilhar um código para serialização/deserialização de objetos do LINQ.

No meu caso, era preciso armazenar uma lista de objetos do LINQ em sessão. Porém, o sessionstate mode foi alterado de in-proc para sqlserver.

Com isso, passou a ocorrer erro pois o framework informava que a minha entidade no LINQ não era serializável. A solução foi serializar os objetos utilizando a classe "DataContractJsonSerializer".

Seguem os métodos para serialização e deserialização dos objetos:

public static MemoryStream SerializeObject(object obj)
{
MemoryStream stream1 = new MemoryStream();
DataContractJsonSerializer ser = new DataContractJsonSerializer(obj.GetType());
ser.WriteObject(stream1, obj);
return stream1;
}

public static object DeserializeObject(object obj, MemoryStream stream)
{
DataContractJsonSerializer ser = new DataContractJsonSerializer(obj.GetType());
stream.Position = 0;
return ser.ReadObject(stream);
}

Abraços e até a próxima!!

quinta-feira, 5 de junho de 2014

Copiando um diretório recursivamente

Fala galera,

Quem já precisou criar uma cópia de um diretório já deve ter notado que a função Copy que existe na classe System.IO.File não está presente na classe System.IO.Directory.

Segue então um código para quem precisa fazer cópia de um diretório e toda sua estrutura (arquivos e subdiretórios):

public void copyFolder(string oldFolder, string newFolder)
{
    if (!Directory.Exists(newFolder))
        Directory.CreateDirectory(newFolder);

    string[] files = Directory.GetFiles(oldFolder);
    foreach (string file in files)
   {
       string name = Path.GetFileName(file);
       string dest = Path.Combine(newFolder, name);
       File.Copy(file, dest);
   }
   string[] folders = Directory.GetDirectories(oldFolder);
   foreach (string folder in folders)
  {
     string name = Path.GetFileName(folder);
     string dest = Path.Combine(newFolder, name);
     copyFolder(folder, dest);
  }
}


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

quarta-feira, 12 de fevereiro de 2014

Executando métodos em novas Threads com passagem de parâmetros

Fala galera,

Segue um código rápido para quem precisa executar métodos em threads separadas da thread principal com passagem de parâmetros:


public void meuMetodo(string param1, string param2)
{
}
Thread t = new Thread(()=>meuMetodo("abc", "def"));
t.Start();

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

quinta-feira, 6 de fevereiro de 2014

Timeout ao utilizar HttpWebRequest com protocolo HTTPS

Fala galera,

Segue mais um código pra contornar um problema comum no .net para quem precisa trabalhar com WebRequests acessando uma url através do protocolo HTTPS.

O erro que costuma ocorrer é uma mensagem de "Timeout exceeded" (Tempo limite excedido) e a solução é bastante simples. Basta adicionar as 2 linhas abaixo:

//Esta linha fará com que o certificado não seja validado (Útil em casos onde há problemas com o ceritificado)
System.Net.ServicePointManager.CheckCertificateRevocationList = false;

//Esta linha fará com que o tipo de protocolo de segurança a ser utilizado seja o SSL3 ao invés do TLS (que parece ser o protocolo padrão)
System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Ssl3;


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

quarta-feira, 30 de outubro de 2013

Ajaxtoolkit - cannot read property '_notified' of null

Fala, galera!!

Hoje me deparei com a seguinte mensagem de erro ao utilizar um AutocompleteExtender dentro de um updatepanel associado a um updateprogress: "Cannot read property '_notified' of null".

 O mais estranho é que o erro só acontece no Google Chrome. Após uma breve pesquisa, descobri que o erro trata-se de um problema no código de detecção do browser do arquivo MicrosoftAjax.js que não detecta o webkit.

 O webkit é um mecanismo de renderização de páginas utilizado por browsers como o Google Chrome e Safari.

Para contornar esse problema basta incluir o código abaixo na sua página aspx:
 <script type="text/javascript">

Sys.Browser.WebKit = {};
if (navigator.userAgent.indexOf('WebKit/') > -1) {
    Sys.Browser.agent = Sys.Browser.WebKit;
    Sys.Browser.version = parseFloat(navigator.userAgent.match(/WebKit\/(\d+(\.\d+)?)/)[1]);
    Sys.Browser.name = 'WebKit';
 }

</script>

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

sábado, 10 de agosto de 2013

Desabilitando itens no dropdownlist

Fala galera,

Após muito tempo de inatividade no blog, segue mais um compartilhamento de código.
Durante essa semana me deparei com a necessidade de categorizar os itens dentro de um dropdownlist.

Algo mais ou menos assim:

Categoria 1
--- item 1.1
--- item 1.2
--- item 1.3
Categoria 2
--- item 2.1
--- item 2.2
--- item 2.3

Acontece que os itens "categoria 1" e "categoria 2" são apenas informativos e não podem ser selecionáveis.
Para isso, é preciso desabilitar a opção de seleção desses itens.

Definir o atributo "enabled" no server-side como false não soluciona o problema. É preciso trabalhar com os atributos no lado do cliente.

Segue então o código para desabilitar o item no dropdown:

System.Web.UI.WebControls.ListItem item = ddl.Items.FindByValue("[valor]");
if (item != null)
{
   item.Attributes.Add("style""color:gray;");
   item.Attributes.Add("disabled""true");
}

Onde [valor] corresponde ao valor que identifica o item(propriedade value) que deve ser desabilitado.



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

quarta-feira, 26 de dezembro de 2012

Ordenação de dados em Gridview

Fala, galera!!

Hoje postarei uma solução simples utilizando JQuery para uma tarefa um pouco trabalhosa se feita via C# puro: Ordenação de dados em GridView.

Para isso, utilizaremos o plugin TableSorter para Jquery que pode ser encontrado em http://tablesorter.com/docs/.

Para começar, adicione o seguinte código ao code-behind para que sejam incluídas na sua gridview as seções <thead> e <tbody> que serão utilizadas pelo TableSorter:


protected void GridView1_PreRender(object sender, EventArgs e)
        {
           //As 2 linhas abaixo só devem ser adicionadas se você não estiver utilizando ObjectDataSource,   SqlDataSource ou LinqDataSource
            GridView1.DataSource = "SEU DATASOURCE";
            GridView1.DataBind();
            if (GridView1.Rows.Count > 0)
            {
                //Substitui <td> por <th>
                GridView1.UseAccessibleHeader = true;
                //Adiciona <thead> e <tbody>
                GridView1.HeaderRow.TableSection = TableRowSection.TableHeader;
            }
        }

Adicione as referências e o script abaixo em sua página ASPX e seu gridview estará com a ordenação funcionando:

<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>

<script type="text/javascript" src="/script/tablesorter/jquery.tablesorter.js"></script>

<link rel="stylesheet" href="/script/tablesorter/themes/blue/style.css" type="text/css"  id="" media="print, projection, screen" />


$(document).ready(function() {
       $("#<%=GridView1.ClientID%>").tablesorter();
});

É possível a criação de widgets que fazem com que a ordenação selecionada seja persistida durante a sessão do usuário. Mais informações em: http://ybits.net/2009/10/making-jquery-tablesorter-persistent/

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

quinta-feira, 8 de novembro de 2012

Corrigindo erro de acesso ao Oracle - System.Data.OracleClient requires Oracle cliente software version 8.1.7 or greater

Fala, galera!!

Segue uma dica rápida e útil para quem utiliza banco de dados Oracle.

Ao tentar se conectar no Oracle utilizando o driver Sytem.Data.OracleClient pode ocorrer o seguinte erro:
"System.Data.OracleClient requires Oracle cliente software version 8.1.7 or greater"

A solução não é a atualização do Driver, como sugere a mensagem de erro, mas a troca do mesmo para o ODP.net (Oracle Data Provider for .Net)

A própria Microsoft sugere o uso do ODP.net.

O driver da Oracle pode ser baixado no endereço abaixo:
http://www.oracle.com/technetwork/database/windows/downloads/index-101290.html

Segue link do site da Oracle sobre o ODP.net:
http://www.oracle.com/technetwork/topics/dotnet/index-085703.html

Comparativo entre o ODP.net e Microsoft.OracleClient:
http://www.oracle.com/technetwork/topics/dotnet/index-154765.html

OBS: Reinicie a máquina após a instalação do ODP.net.

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

quinta-feira, 1 de novembro de 2012

Gerando PDF a partir de uma URL

Fala, galera!!

Hoje vou postar um código de grande utilidade para quem precisa trabalhar com a geração de PDF.
Pesquisando na internet encontrei muitos componentes pagos e alguns gratuitos, mas que não funcionavam de forma tão simples. O simples, no meu caso, é criar um arquivo PDF a partir de uma URL.

Testei o iTextSharp que é um dos mais conhecidos, mas não funcionou da forma que eu esperava.

Eis que encontrei o wkhtmltopdf.

O componente pode ser baixado em: http://code.google.com/p/wkhtmltopdf/

Basicamente, é um arquivo exe que recebe como parâmetro a url que será convertida em pdf e o nome do arquivo pdf que será gerado.

O lado negativo é que ao usar um servidor compartilhado você pode ter problemas de permissão para executar o componente. Já fiz alguns testes em servidores compartilhados e não tive esse problema. Mas cada ambiente é um ambiente.
O componente não precisa ser instalado. O instalador apenas desempacota os arquivos para um diretório escolhido. Você pode simplesmente copiar esse diretório para o diretório de sua aplicação no servidor e executá-lo a partir da aplicação.

O código é bastante simples:

ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.WindowStyle = ProcessWindowStyle.Hidden; //Faz com que o processo seja executado em background
startInfo.FileName = "c:\diretorio\wkhtmltopdf.exe";
startInfo.Arguments = "http://www.suaurl.com/pagina.aspx + " " + "c:\diretorio\arquivo.pdf";

Process processo = Process.Start(startInfo);
processo.WaitForExit();
processo.Close();
processo.Dispose();

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

terça-feira, 3 de julho de 2012

Gerando string randômica

Fala, galera!!

Mais um post com uma função simples, mas de grande utilidade: Geração de string randômica.
No meu caso, essa função foi utilizada para a geração de uma senha randômica que será enviada para um usuário quando o mesmo for cadastrado no meu sistema.

Segue o código:


public string GenerateRandomString(int passwordLength)
{
   string allowedChars = "abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ0123456789!@$?_-";
  char[] chars = new char[passwordLength];
   Random rd = new Random();
   for (int i = 0; i < passwordLength; i++)
   {
      chars[i] = allowedChars[rd.Next(0, allowedChars.Length)];
   }

   return new string(chars);
}


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

segunda-feira, 2 de julho de 2012

Verificando a consistência do XML

Fala, galera!!

Estou trabalhando numa tela de manipulação de arquivos XML e uma dos requisitos é garantir que o XML editado seja consistente para evitar erros na leitura do mesmo posteriormente.

Segue o código para a validação da consistência do código XML:

 public bool xmlEhValido(string xmlContent)
{
     try
        {
            XDocument.Parse(xmlContent); return true;
         }
     catch
       {
            return false;
       }
}

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

domingo, 3 de junho de 2012

Operation is not valid due to the current state of the object.

Fala, Galera!!

Essa semana me deparei com o seguinte erro ao tentar exportar dados de um gridview para excel: Operation is not valid due to the current state of the object.

A princípio achei que o problema estivesse na exportação dos dados para o excel. Wrong!

Existem alguns relatos, não confirmados pela Microsoft, de que uma atualização de segurança limita em 1000 o número de campos permitidos durante o postback de uma página.

O que faz todo sentido diante do comportamento do erro. Quando faço testes com uma massa menor de dados, o erro não ocorre. Quando aumento a massa de dados o erro passa a ocorrer. 

A solução é simples. Basta adicionar a seguinte linha no web.config na seção "AppSettings":

<add key="aspnet:MaxHttpCollectionKeys" value="2001" />
A linha acima aumenta para 2001 o número de campos permitidos durante o postback.
Mais informações podem ser encontradas no post abaixo:
http://stackoverflow.com/questions/8684049/asp-net-ms11-100-how-can-i-change-the-limit-on-the-maximum-number-of-posted-for

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

segunda-feira, 21 de maio de 2012

DataTable - Removendo linhas em branco

Fala, galera!!

Depois de mais um longo período de inatividade, segue mais um post relâmpago, mas de grande utilidade.
Me deparei hoje com a necessidade de remover todas as linhas em brano de um DataTable.

Esperava que existisse um método mais sugestivo para isso. Algo como "IgnoreEmptyRows" ou "RemoveEmptyRows". Mas seria fácil demais, né? :)

A solução até que é simples, mas não tão sugestiva.

Vamos ao código:


MeuDataTable = MeuDataTable.Rows.Cast<DataRow>().Where(row => !row.ItemArray.All(field => field is System.DBNull || string.Compare((field as string).Trim(), string.Empty) == 0)).CopyToDataTable();



Simples, não? Mas, certamente, não tão fácil de lembrar quanto um simples "RemoveEmptyRows" :)
Minha sugestão é criar o seu próprio RemoveEmptyRows:


public DataTable RemoveEmptyRows (DataTable MeuDataTable)
{
  MeuDataTable = MeuDataTable.Rows.Cast<DataRow>().Where(row => !row.ItemArray.All(field => field is System.DBNull || string.Compare((field as string).Trim(), string.Empty) == 0)).CopyToDataTable();

    return MeuDataTable ;
 }



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

quarta-feira, 20 de julho de 2011

C# - Replace ignorando maiúsculas e minúsculas (Case Insensitive)

Fala galera,

Segue mais um código para quem precisa fazer o replace de uma string ignorando letras maiúsculas e minúsculas (Case Insensitive).

Essa é mais uma das funções que são, na minha opinião, desnecessariamente muito mais complicadas no C# do que no VB.net.

Complicado não pela sintaxe, mas pela mudança na característica da função.
O que exige a busca por uma solução alternativa.

No VB.Net, a função replace possui uma sobrecarga que permite informar que o método de comparação da string irá ignorar maiúsculas e minúsculas.

No C# isso não existe.
Para fazer isso vamos recorrer a classe RegEx.

Veja como fazer o replace:

string value = "Sua Mensagem";
value = System.Text.RegularExpressions.Regex.Replace(value, "mensagem", "mensagem alterada", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
Response.Write(value);

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

terça-feira, 5 de julho de 2011

C# - Split usando mais de um delimitador

Fala galera,

Segue mais uma dica para quem, como eu, migrou do VB.Net para o C# e se deparou com algumas mudanças em funções bastante rotineiras como o SPLIT.

No VB.Net o uso desta função é bem mais simplificado. Algo como: Split("string","@@")

No C# não é bem assim. Segue o código:
string teste = "String1@@String2";
string[] arrList = teste.Split(new char[] {'@', '@'}, StringSplitOptions.RemoveEmptyEntries);

Atenção para o texto em negrito. Pois ao fazer o split de uma string utilizando mais de um delimitador são gerados inúmeras posições em branco no seu array.
Ao utilizar a opção "RemoveEmptyEntries" todas essas posições em branco serão automaticamente removidas do array.

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

quinta-feira, 6 de janeiro de 2011

LINQ to SQL - Ordenando Dados Randomicamente

Fala, galera!!

Depois de alguns meses sem postar, estou voltando com uma postagem relâmpago, mas bastante útil.
Hoje vou mostrar como ordenar randomicamente uma lista utilizando o LINQ e expressão lambda.

Antes do LINQ, a ordenação era feita via SQL utilizando "Order by NewID".

Segue o código para a ordenação randomica no LINQ:

dim db as DataContext()
dim rnd as random = new random()
db.Tabela.OrderBy(function(obj)  rnd.Next).tolist()

Simples assim.

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

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!!