Meu Primeiro Windows Service

Hoje tive a oportunidade de criar o meu primeiro Projeto a sério não Web-based. Trata-se de um processo que deverá correr sem nenhuma intervenção humana (salvo as opções como: “Iniciar”, “Pausar”, “Continuar” e “Parar”), justamente o que um Windows Service tem como finalidade.

Claro que o design ainda esta longe do ideal, mas so o fato de ver o mesmo correndo em background automaticamente achei muito interessante e curioso. Tive até a oportunidade de criar algo a mais, como por exemplo um projeto em WinForms onde vocè pode executar as funcionalidade básicas de um Windows Service, como já descrevi acima, inclusive colocando-o no SysTray e criando um Menu de Contexto para que o administrador tenha um acesso rápido ao serviço quando precisar dar algum tipo de manutenção.

Claro que pra muitos isso é até banal, mas fica aqui registrada a minha experiència nesta área e com certeza a minha satisfação. 😉

Pool de Objetos – COM+

Não sou lá um especialista em COM+, mas leio sobre. Aliás, é algo que me tenta, ou seja, estou obsecado para fazer um projeto que utilize componentes no COM+ para trabalhar com Pool de Objetos, Transações, entre outras coisas que o mesmo nos oferece, mas até então não tive oportunidade para isto. 😥

Estou nas horas vagas lendo um livro de Juval Löwy chamado COM + e .NET onde é mostrado como criar e manter componentes .NET no COM+, e lendo sobre Pooling de Objeto COM+, algo que achei interessante foi dito, e gostaria de aqui expor:

O objeto é retornado para o pool quando o cliente libera a sua referencia a ele. Sendo assim, sabemos que objetos gerenciados utilizam a chamada “coleta de lixo” (Garbage Collector), e com isso, o objeto gerenciado só retorna ao pool quando este lixo é coletado.

Isso pode ser de certa forma prejudicial, pois poderá haver um retardo entre o momento em que este objeto não é mais necessário até o momento em que o mesmo retorna ao pool, pois lembre-se que o “coletor de lixo” tem um período/tempo para passar, pois ele não sai varrendo o nosso objeto assim que nós o descartamos. Agora o que de mais interessante achei: como já sabemos, um objeto é colocado em pool porque a sua criação é custosa e se este objeto gastar um tempo esperando que o “coletor de lixo” o recolha, então o aplicativo quase não se beneficia do pool de objetos.

Vi que existem duas maneiras de resolver este problema. A primeira é utilizando JITA e a segunda já requer a participação do cliente, pois como todo componente .NET que tira proveito dos serviços COM+ precisa derivar da classe base ServicedComponent que tem um método público estático chamado DisposeObject(), definido como:

public static void DisposeObject(ServicedComponent sc);

Assim que continuar os testes e a leitura por aqui, dou o feedback do uso do método DisposeObject() e sobre o JITA. 😉 Mas claro que se alguém quiser contribuir, fico/ficaremos grato 😉

Gerando Stream para PDFs

Há dois dias tive a necessidade de exibir um relatório criado em Crystal Reports em uma Aplicação ASP.NET. Crei o RPT utilizando DataSet tipado como fonte de dados. Tirando a complexidade de fazer o relatório, me deparei em como exibir o tal na Web. Esta fora de cogitação utilizar o CrystalReportViewer, então a solução foi exportar o arquivo *.rpt para PDF.

Inicialmente pensei em utilizar o System.IO para criar o mesmo fisicamente utilizando o Session.SessionID como o nome do arquivo. Funcionou perfeitamente, porém o arquivo estava sendo criado fisicamente, que com isso, ia gerar um grande acúmulo de arquivos no servidor.

Falando com meu Amigo João, ele me sugeriu a criação de um Stream para esta exibição. Bem, não pensei duas vezes e fui logo criar. Com certeza fico bem melhor, pois o arquivo não é mais criado fisicamente, apenas é exibido seu conteúdo no browser. Eis o código em C# para realizar esta tarefa:

using CrystalDecisions.Shared;
using CrystalDecisions.ReportSource;
using CrystalDecisions.CrystalReports.Engine;
using System.IO;

MeuDataSetTipado DS = new MeuDataSetTipado();
MeuRelatorioRPT R1 = new MeuRelatorioRPT();
R1.SetDataSource(DS);

BinaryReader stream = new BinaryReader(R1.ExportToStream(CrystalDecisions.Shared.ExportFormatType.PortableDocFormat));
HttpContext.Current.Response.ClearContent();
HttpContext.Current.Response.ClearHeaders();
HttpContext.Current.Response.ContentType = “application/pdf”;
HttpContext.Current.Response.BinaryWrite(stream.ReadBytes(Convert.ToInt32(stream.BaseStream.Length)));
HttpContext.Current.Response.Flush();
HttpContext.Current.Response.Close();

DataReader para DataSet

Ontem recebi um email de um amigo que me pedia se existia alguma forma de pegar o conteúdo de um DataReader e colocar em um DataSet.

Nunca tinha feito isso, e tinha certeza que é possível. Fiquei com tanta curiosidade que decidi colocar a “mão na massa” e tentar fazer essa funcionalidade.

Inicialmente sei que era possível percorrer os registros retornados. A única dúvida que estava um pouco preocupado, foi em como resgatar as colunas (tanto seus valores, quantos seus nomes). Pois bem, fui o Help e procurei pelos membros do DataReader e encontrei a propriedade FieldCount, qual retorna o número de colunas da linha em questão. Com isso, “matei” um problema, mas ainda faltava saber como resgatar o nome da coluna. Da mesma forma, fui ao Help e encontrei o método GetName, que dado um índice, ele retorna o nome desta coluna.

Depois disso, ficou simples, basta apenas percorrer os registros (linhas) do DataReader, e a cada linha, percorrer as colunas da mesma. O código abaixo, ilustra o processo:

        Dim conn As New SqlConnection(“ConnectionString”)
        Dim cmd As New SqlCommand(“SELECT * FROM Categories”, conn)
        Dim dr As SqlDataReader

        Dim i As Integer = 0
        Dim dRow As DataRow
        Dim num2 As Integer
        Dim ds As DataSet = New DataSet

        Try
            conn.Open()
            dr = cmd.ExecuteReader(CommandBehavior.CloseConnection)
            If dr.HasRows() Then
                ds.Tables.Add(“NomeTabela”)
                While dr.Read
                    dRow = ds.Tables(0).NewRow
                    num2 = 0
                    Do While (num2 < dr.FieldCount)
                        If (i = 0) Then
                            ds.Tables(0).Columns.Add(dr.GetName(num2))
                        End If
                        dRow(num2) = dr.GetValue(num2)
                        num2 = (num2 + 1)
                    Loop
                    i = (i + 1)
                    ds.Tables(0).Rows.Add(dRow)
                End While
                dr.Close()
            End If
        Catch ex As Exception
            MessageBox.Show(ex.ToString)
        Finally
            If Not
(dr Is Nothing) Then
                dr.Close()
            End If
        End Try

Mas uma coisa que fique bem claro: isso não quer dizer que gosto de DataSets 😉

Design Patterns

Para quem gosta de Design Patterns como eu, encontrei um site que com certeza está em meus favoritos. Site qual foi adaptado para o Portugues o conteúdo do famoso doFactory. Para quem se interessar o site chama-se OODesign e sua URL: http://www.oodesign.com.br/patterns/

Não são todas as Patterns que estão publicadas (com exemplos, definições, etc.), mas as quais estão, são disponibilizados exemplos em C#, C++, Java e Delphi. Para as que ainda não foram, lá consta a data prevista para publicação. Vale a visita.

Atributo

Muitas vezes criamos uma função em uma classe, disponibilizando-a para outros desenvolvedores/sistemas fazerem uso dela. Com o tempo, as regras de negócio mudam e é necessário a construção de uma nova função para que tais regras sejam atendidas.

Com isso não podemos sairmos mudando seus parametros ou sua implementação porque já existem sistemas que consomem estas funções. Como isso te obrigará a criar uma nova função (ou até mesmo sobrecarregar). Existe um Atributo dentro do .NET para dizermos ao desenvolvedor que for consumi-lá que existe uma nova versão da mesma, e podemos indicar o uso dela. Esse atributo chama-se <Obsolete()>

<Obsolete(“O Correto é utilizar a função Exibir”)> Public Function Buscar() As Integer
    ‘…
End Function

Com isso o compilador verificará e fará entradas do tipo Warning dentro da TaskList, mas o aplicativo continua rodando normalmente.

Evento InfoMessage

Existe um Evento da SqlConnection que retorna todas as mensagens geradas pelo SQL Server que não são interpretadas como Exception. É possível recuperar tais mensagens através da SqlConnection. Para isso podemos utilizar o Evento InfoMessage que retorna isso. Abaixo um exemplo de como utilizá-lo:

Criando a StoredProcedure:

CREATE PROCEDURE InfoMessage AS
Print ‘Disparado pelo InfoMessage’
GO

No Evento Load do Formulário:

Private WithEvents conn As SqlClient.SqlConnection
Private Sub Form1_Load(…) Handles MyBase.Load
    conn = New SqlConnection(“…”)
    Dim cmd As SqlCommand = New SqlCommand(“InfoMessage”, conn)
    cmd.CommandType = CommandType.StoredProcedure
    Try
        conn.Open()
        cmd.ExecuteScalar()
        conn.Close()
    Catch ex As Exception
        MessageBox.Show(ex.ToString)
    End Try
End Sub

E no Evento InfoMessage da SqlConnection, capturamos a mensagem da StoredProcedure:

Private Sub conn_InfoMessage(ByVal sender As Object, ByVal e _
    As System.Data.SqlClient.SqlInfoMessageEventArgs) Handles conn.InfoMessage

    MessageBox.Show(e.Message)
End Sub



Com isso, a mensagem que é escrita através do Print do SQL Server, será capturado pelo Evento, e poderá fazer tratamentos no Sistema.

Conversão de Boolean para Numeric Type

Quando criamos uma variável do tipo Integer e atribuímos à essa variável o resultado de uma variável Booleana, há algumas diferenças: o False virá 0 e o True vira -1.

Dim boo As Boolean = True
Dim x As Integer = boo

Response.Write(x.ToString)
Response.Write(boo.ToString)
Response.Write(Convert.ToInt32(boo))

A saída será:

-1
True
1

Com essas conversões, talvez nos “embaralhamos” um pouco nas condicionais, que muitas vezes nos retornam um valor que não é o esperado.

Sabendo as DLL’s carregadas

Encontrei um utilitário bastante interessante, qual lista as DLL’s que um programa carrega. Este utilitário chama-se ListDLLs, e pode ser encontrado em: http://www.sysinternals.com/ntw2k/freeware/listdlls.shtml

Por exemplo poderia escrever esta linha no prompt de comando: Listdlls.exe inetinfo.exe e ele mostrará todas as DLL’s carregadas para esse aplicativo.

Download: http://www.sysinternals.com/files/listdlls.exe

Minha primeira Impressão

Ontem meu professor criou uma máquina virtual no seu NoteBook através do Microsoft Virtual PC 2004 para mostrar-nos o novo Sistema Operacional da Microsoft, qual é conhecido pelo “CodeName”: LongHorn.

Apesar de ser um NoteBook potente, com processador Intel P4, com 512 MB de memória RAM, o LongHorn me pareceu um pouco pesado, mas temos que dar os descontos por ainda estar em sua versão Alpha. Há ainda muita coisa à ser melhorada.

Mas a minha primeira impressão sobre ele foi sem dúvida a melhor possível. Apesar de ter as Ferramentas/Acessórios iguais ao do Windows XP, o Layout ficou muito bonito. Com certeza será uma mudança bastante impactante para os que estão acostumandos aos sistemas operacionais atuais. Dizem que o impacto será tão grande quanto a mudança do 3.1/3.11 para Windows 95.

Além disso, ainda temos o Avalon, Indigo e WinFX que teremos que conhecer para o desenvolvimento de nossas aplicações.

Tenho lido sobre um tal de “Windows XP Reloaded”, que diz que virá para preencher o longo intervalo de tempo entre o lançamento do Windows XP e do LongHorn, mas não sei se isso procede mesmo.

Bem, resta-nos esperar. 😉