Criando um ASP.NET MVC Web Application

Postado por Carlos Fernando Sylverio | Postado em Programação, Tecnologia | Postado em 04-04-2010

0

No post ASP.Net MVC fiz uma introdução as caracteristicas desse novo tipo de projeto web. Neste post vou apresentar um pouco mais sobre esse projeto, sua estrutura, comportamento.
Para isso é necessário instalar o ASP.NET MVC. Após a instalação o Visual Studio 2008 apresentará um novo tipo de projeto Web, chamado ASP.NET MVC Web Application.

New Project ASP.NET MVC Web Application

Ao criar um projeto do tipo ASP.NET MVC Web Application uma aplicação de demonstração (padrão) é apresentada na Solution Explorer.

O ASP.NET MVC a primeira vista parece ser bem complicado, mas apartir do momento que se conhece melhor a sua estrutura e seu funcionamento, ele passa a ser bem simples.

Estrutura do ASP.NET MVC Web Application

Primeiramente vamos nos atentarmos a estrutura, pois ela contem diversas convensões que devem ser utilizadas pelo ASP.NET MVC.
Solution Explorer MVC Web Application
Repare nos diretórios, obrigatóriamente teremos o Controller, Model e View.
Outra convensão é para as classes controladoras (contidas no diretório Controller), devem possuir o sufixo Controller em seus nomes e um sub-diretório no diretorio View. Confuso? Repare na Solution o diretorio Controller, note que possui duas classes controladoras Account e Home ambas com o sufixo Controller. Agora veja o diretório View, ele possui dois sub-diretórios com o mesmo nome da controladora (Account e Home).
No diretório View ficam os templates que correspondem a ações dos controllers e seram renderizados.
O sub-diretório View/Shared contém recorsos compartilhados com a aplicação, como página de erro genérica, master page, entre outros.
O diretório Script é destinado a armazenar biblioteca JavaScript e scripts (.js)
O diretório Content é destinado a armazenar arquivos de estilo (CSS), arquivos de imagens e outros não dinâmicos.
Na raiz do ASP.NET MVC Web Application temos os arquivos Global.asax, default.aspx e web.config estes arquivos são utilizados em conjunto para realizarem a sobreescrita (rewrite) de URL, mas esse assunto ficará para um próximo post.

Como ASP.NET MVC trabalha

Para compreender melhor o funcionamento do ASP.NET MVC, vamos remover alguns arquivos e diretórios da aplicação padrão.

  • App_Data (diretório)
  • AccountController.cs (arquivo)
  • Account (diretório)
  • About.aspx (arquivo)
  • Index.aspx (arquivo)
  • Error.aspx (arquivo)
  • LogOnUserControl.ascx (arquivo)
  • Site.Master (arquivo)

Hello Word

Como é padrão e não pode faltar em qualquer tutorial de introdução, vamos criar a famosa aplicação Hello Word!. Para isso no arquivo HomeController reescreva o código para que fique da seguinte forma:

1
2
3
4
5
6
7
    public class HomeController : Controller
    {
        public string Index()
        {
            return "Hello, word!";
        }
    }

Pronto, ao executar (F5) criamos nosso primeiro ASP.NET MVC Application.

Na arquitetura MVC, os controllers são reponsáveis por manipular as requisições. No .NET, controller são classes derivadas de System.Web.Mvc.Controller. E cada método público no Controller é conhecido como Action Method (método de ação), que são chamdos da web por meio de alguma URL. Em nossa aplicação acima temos nosso controller chamado HomeController com seu action method chamado Index.
Quando executamos a aplicação o Routing System (sistema de rotas) do ASP.NET MVC decidiu qual controller e action method executar. Não por acaso utilizei este controller e action method, esta é a configuração padrão de nosso aplicação, que está configurada no arquivo Global.asax.cs, como pode ser visto:

1
2
3
4
5
6
7
8
9
10
public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
 
    routes.MapRoute(
        "Default",                                            // Route name
        "{controller}/{action}/{id}",                         // URL with parameters
        new { controller = "Home", action = "Index", id = "" }// Parameter defaults
    );
}

Em nosso Routing System, é definido a rota default com o controller Home e o action method Index sem passagem de parâmetro. Dessa forma as seguintes requisição serão manipuladas pela action Index no HomeController:

  • /
  • /Home
  • /Home/Index

Renderizando Web Pages

Como já mensionado, na arquitetura MVC o Controller é responsável por manipular as requisições e as Views são componentes de interface do usuário. Assim não está correto em nossa aplicação o controller enviar a resposta (no nosso caso texto) para o browser. Em uma aplicação real o controller deve passar essa tarefa para uma View. Para isso vamos reescrever o método Index da seguinte forma:

1
2
3
4
5
6
7
public class HomeController : Controller
{
    public ViewResult Index()
    {
        return View();
    }
}

Dessa forma a action retorna um objeto do tipo ViewResult, passando para o Framework a instrução de renderizar uma View. O próximo passo é criar a View, para isso podemos clicar com o botão direito no action method Index e selecione Add View, isto irá criar um novo template para o action method em “~/Views/Home/Index.aspx”.
Altere o código HTML na tag body da seguinte forma:

1
2
3
4
<body>
    <h1>Hello, Word!</h1>
    <p>(renderizada apartir da View)</p>
</body>

Nossa aplicação está finalizada, execute para visualizar a página rendenrizada pela View.

Hello Word ASP.NET MVC Web Application

Repare que não é necessário informar o nome da View que será chamada. O Framework renderiza a View que contém o mesmo nome do action method.

Há outros objetos de retorno que um Action Method pode retornar que instrui o framework diferentes fins. Esses tipos de retorno são chamados Action Results, mas isso será assunto para um próximo post, assim como a compreensão do M de Model de nossa arquitetura MVC.

Enjoy ;-)

Cifrando e Decifrando dados com o Enterprise Library

Postado por Carlos Fernando Sylverio | Postado em Programação | Postado em 16-03-2010

0

No post anterior apresentei O que é Enterprise Library.

Neste post irei mostrar como é facil criptografar e descriptografar dados utilizando o Enterprise Library.

Para o exemplo utilizei o Enterprise Library 4.1-October 2008. Que tem como pré requisitos, Framework.NET 3.5 e Visual Studio 2008. Para uma configuração inferior, utilize outras versões do Enterprise Library.

Devido a flexibilidade do Enterprise Library, as configurações são mantidas em uma arquivo XML (app.config, web.config ou um arquivo .xml a parte) na aplicação.
Ao instalar o Enterprise Library duas ferramentas de configuração são instaladas: uma embutida no Visual Studio (Configuration Editor), e uma aplicação externa (Enterprise Library Configuration Console). As alterações feitas no arquivo de configuração não obrigam a recompilação da aplicação, tornando assim fácil a reconfiguração da aplicação.

Configurando uma aplicação com Criptography Application Block

Para o exemplo, crie um projeto do tipo Console Application, de nome EntLibCriptography (pode ser qualquer nome).
Adicione as refenrencias para os assembly do bloco de aplicação Cryptography Application Block. Para isso, no Visual Studio clique com o botão direito sobre o no de projeto da Solution Explorer, e clique em Add References.
Clique em Browser e localize as dlls:

  • Microsoft.Practices.EnterpriseLibrary.Security.Cryptography.dll
  • Microsoft.Practices.EnterpriseLibrary.Common.dll
  • Microsoft.Practices.ObjectBuilder2.dll

Agora adicione ao projeto um arquivo Application Configuration File (App.config).
Clique com o botão direito sobre o arquivo App.config, e clique em Edit Enterprise Library Configuration.

O próximo passo é configurar o Cryptography Application Block no arquivo de configuração.
Para isso, clique com o botão direito sobre o App.config (no Enterprise Library Configuration e não no Solution Explorer), selecione New e clique em Cryptography Application Block.

Observação: A ferramenta de configuração adiciona o nó Cryptography Application Block e os sub-nó Hash Providers e Symmetric Providers, com uma configuração padrão.

Configurando Symmetric Algorithm Provider

Clique em Symmetric Providers, selecione New, e clique em Symmetric Algorithm Provider.

Configuração do Symmetric Algorithm Provider

No Type Selector, selecione o tipo de symmetric algorithm provider, neste exemplo utilizaremos o RijndaelMananged, que é o tipo padrão.

Agora vamos gerar a chave de criptografia (o Cryptographic Key Wizard permite gerar ou importar uma chave existente).
O Cryptographic Key Wizard, apresentará as seguintes opções:

  • Create a new key
  • Use an existing DPAPI-protected key file
  • Import a password-protected key file

Escolha “create a new key” e clique em Next.
No próximo passo, informamos nossa chave CHAVETESTE e clicamos em Generate para converter o texto em uma chave hexadecimal (pode ser informado uma chave hexadecimal diretamente).
Depois clique em Next.
Escolha um local para salvar o arquivo de chave, e clique em Next.
O próximo passo será configura o modo de acesso a chave, escolha Machine mode e clique em Finish.

Código de criptografia e decriptografia

Abaixo o código de ciframento e deciframento utilizando utilizando o tipo de criptografia Rijndael.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
using System;
using System.Text;
using Microsoft.Practices.EnterpriseLibrary.Security.Cryptography;
 
namespace EntLibCriptography
{
    public class Program
    {
        public static void Main(string[] args)
        {
            // Cifra mensagem
            string mensageEncrypted = Cryptographer.EncryptSymmetric("RijndaelManaged", "senha");
            Console.WriteLine("mensagem cifrada: {0}", mensageEncrypted);
 
            // Decifra mensagem
            string mensageDecrypted = Cryptographer.DecryptSymmetric("RijndaelManaged", mensageEncrypted);
            Console.WriteLine("mensagen decifrada: {0}", mensageDecrypted);
        }
    }
}

Resultado:

Resultado da criptografia e decriptografia

Enjoy ;-)

O que é Enterprise Library

Postado por Carlos Fernando Sylverio | Postado em Tecnologia | Postado em 15-03-2010

0

Enterprise Library é uma biblioteca de aplicação que soluciona necessidades comuns.
A Enterprise Library possui uma coleção de blocos de aplicação (Application Blocks) que são reutilizáveis, extensíveis e permitem a customização do código-fonte.

A Enterprise Library faz parte de um grupo da Microsoft Patterns & Practices conhecido como Patterns & Practices, e não é nativo do Framework.NET, não possui suporte, localização ou garantias de compatibilidade, porem pode ser baixado gratuitamente.

O Enterprise Library prove blocos de código com funcionalidades que seria necessário desenvolver em uma aplicação caso já não estivesse pronto. Com a vantagem de já terem sidas testadas pela Microsoft e outras empresas de diversos tipos de aplicação. Estes blocos de aplicação tem a função de auxiliar equipes de desenvolvimento, permitindo que se concentre nas regras de negócio do cliente evitando que percam tempo criando tarefas comuns a uma aplicações como registro de log, autorização de usuários, acesso a dados, criptografia e outros.

Os blocos de aplicação fornecidos pelo Enterprise Library são:

  • Caching Application Block: possibilita a incorporação de cache local na aplicação.
  • Cryptography Application Block: possilita a fácil implementação de criptografia simétrica ou de hash.
  • Data Access Application Block: possibilita a implementação a funcionalidade de acesso ao banco de dados de forma padronizada e simplificada.
  • Exception Handling Application Block: possilita criar uma estratégia consistente de tratamente de exceções entre as camadas de uma aplicação.
  • Logging Application Block: possilita a criação de um procedimento padrão de registro de log na aplicação.
  • Policy Injection Application Block: possibilita implementar politicas de interceptação de operações para implementar funcionalidades comuns como registro de log, uso de cache, tratamento de exceção, entre outros.
  • Security Application Block: possibilita a incorporação de autenticação e cache de dados relacionados a segurança da aplicação.
  • Validation Application Block: utilizado para criar regras de validação para objetos de negócio, podendo ser reutilizado em diversas camadas da aplicação.

A instalação do Enterprise Library fornece os seguintes itens:

  • Arquivos Binários: inclui pre-compilado, strong-named assemblies para todos os códigos fontes.
  • Código Fonte: inclui o código fonte para todos os blocos de aplicação, ferramenta de configuração, teste unitário, e o QuickStarts.
  • Teste Unitário: inclui os teste unitários que foram criados enquanto os blocos de aplicação eram desenvolvidos.
  • QuickStarts: aplicações de exemplo para o fácil entendimento das caracteristicas dos blocos de aplicação.
  • Documentação: que pode ser visualizada como Visual Studio Help. A documentação inclui um guia sobre com utilizar o Enterprise Library e referência a biblioteca.

Abaixo um mapa de dependência entre os blocos de aplicação:

depêndencia entre os blocos de aplicação do Enterprise Library

Até mais ;-)

Garbage Collector (GC) – Gerenciamento de memória

Postado por Carlos Fernando Sylverio | Postado em Programação | Postado em 21-01-2010

0

O Framework.NET trouxe alguns benefícios referentes a utilização e gerenciamento de memória, permitindo mais liberdade de alocação e remoção de variáveis na memória em ordem aleatória, executado por meio de uma gerência complexa do espaço ocupado e identificação dos espaços livres.
Dessa forma vida de nós programadores se tornou muito mais fácil, pois não precisamos nos preocupar com o gerenciamento de memória (nada de malloc e free utilzados em C/C++), com isso temos menos erros relacionados ao vazamento de memória, bugs de ponteiros, entre outros.
O principal componente que realiza esse gerenciamento e liberação de memória é o Garbage Collector (Coletor de Lixo ou GC) existente na arquitetura do Common Language Runtime (CLR) e tem como princípio atividade de funcionamento:

  1. Determinar quais objetos não mais será utilizado, ou seja, não estão mais acessíveis na aplicação;
  2. Liberar os recursos (memória) utilizados por esses objetos

Entendendo o funcionamento do Garbage Collector

Basicamente o GC divide a memória disponível em 3 áreas distintas:

  1. Maneged Heap
  2. Pilha
  3. Unmanaged Heap

O GC em conjunto com a CLR por meio de diversos algoritmos executa o gerenciamento da área de memória managed heap, que aloca reference types. Enquanto a pilha é utilizada para alocar value types. A unmanaged heap é utilizada para armazenar recursos não gerenciados de forma automática ou recursos nativos.
Mais detalhe da arquitetura do GC ficará para um próximo post, pois irá envolver alguns temas ainda não tratados.

Recursos Não Gerenciados

Um ponto importante é controle de recursos não gerenciados (recursos nativos, que pode ser um arquivo, janela, conexões de banco de dados, sockets, Win32, entre outros).
Implicitamente o Framework.NET mantém um controle das instâncias utilizadas pela aplicação, porem o mesmo não se repete para recursos não gerenciados. Para recursos não gerenciados deve-se fornecer uma maneira de liberar os recursos da memória depois que o aplicativo tiver terminado de usá-los, ou seja, deve ser um processo manual (codificado) executado pelo programador.
Há duas maneiras de se finalizar um recurso não gerenciado:

  • Implicitamente utilizando o método Finalize();
  • Explicitamente utilizando o método Dispose() do IDisposable;

Observação: Por padrão a Microsoft recomenda a implementar as duas formas de finalizar o objeto. Sendo que o método Finalize() serve de garantia de execução de liberação de memória impedindo que o recurso fique permanentemente vazando caso algum programador esqueça de chamar o método Dispose().

A primeira impressão que temos ao ver o finalizador (redefinindo ao método Finalize de System.Object) existente no .NET é que este atua como um destruidor (destructor) presente em linguagens com C/C++ é que são similares. Porem não se iluda pela aparência, pois são bem diferentes em suas características.

Caracteristicas do Finalizador:

  • Execução nem sempre é não garantida;
  • Execução não determinística (instante em que o método é executado não é conhecido);
  • Chamada ao método ocorre desde que não existam ciclos infinitos;
  • Quando chamado shutdown, sua execução só ocorre caso seu tempo de execução não seja superior a 2 segundos e o somatório não exceda 40 segundos (tempos aproximados);

Em resumo o CLR não garante a ordem de chamada dos métodos Finalize().

Exemplo de implementação do finalize:

Código C#.NET:

1
2
3
4
5
6
7
8
9
public class AlgumaClasse
{
   …
   ~AlgumaClasse() // finalizador
   {
      // código de limpeza
   }}

Codigo gerado pelo compilador:

1
2
3
4
5
6
7
8
9
10
public class AlgumaClasse
{protected override void Finalize()
   {
      try { /* código de limpeza */ }
      finally { base.Finalize(); }
   }}

O método Dispose é uma implementação de um padrão conhecido como “padrão de descarte” e impõe uma ordem na vida de um objeto.
O método Dispose() deve liberar os recursos que ele possui assim como os recursos de propriedade de seus tipos base. Esse processo é executado através de uma hierarquia de tipos de base, ou seja, cada objeto irá chamar o método Dispose() da classe estendida ou implementada. Garantindo assim que os recursos são sempre limpos adequadamente.
Um característica particular do método Dispose() é que este pode ser chamado várias vezes sem lançar exceção.
É importante salientar que não há benefícios de desempenho na utilização do método Dispose() a objetos gerenciados pela CLR (tais como Arrays). Este método deve ser utilizado em objetos que utilizam recursos nativos e objetos COM que são expostas ao Framework.NET, como exemplo podemos citar a classe FileStream que implementa a interface IDisposable.

Exemplo de implementação do métiodo Dispose():

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// Design pattern para uma classe base.
public class Base: IDisposable
{
   //Implementação da interface IDisposable.
   public void Dispose() 
   {
     Dispose(true);
      GC.SuppressFinalize(this); 
   }
 
   protected virtual void Dispose(bool disposing) 
   {
      if (disposing) 
      {
         // libera outros estados (managed objects).
      }
      // Libera sus próprios estados(unmanaged objects).
      // Define campos grandes como null.
   }
 
   // Sintaxe para finalização do código.
   ~Base()
   {
      //Chamada simples Dispose(false).
      Dispose (false);
   }
}
// Design pattern para a classe derived.
public class Derived: Base
{   
   protected override void Dispose(bool disposing) 
   {
      if (disposing) 
      {
         // Liberação de recursos gerenciados
      }
      // Liberação de recusos não gerenciados.
      // Define campos grandes como null.
      // Chama Dispose da classe base.
      base.Dispose(disposing);
   }
   // A classe derived não tem o método Finalize
   // ou um método Dispose com parametro pois herda da classe base.
}

Enjoy ;-)

Comunicação via socket com C#

Postado por Carlos Fernando Sylverio | Postado em Programação | Postado em 22-12-2009

0

Introdução

Primeiramente vamos conceiturar o que é socket, ou soquete em portugues. De uma visão geral um soquete pode ser definido como uma tomada que designa uma cavidade ou região usada para ligar algum artifício específico.

No mundo da computação, um socket é o elo de ligação entre os processos do servidor e do cliente. Ele é a “porta” na qual os processos enviam e recebem mensagens. De acordo com JAMES F KUROSE: “socket é a interface entre a camada de aplicação e a de transporte dentro de uma máquina”. Para quem não lembra, ou não sabe, camada de aplicação e transporte fazem parte do modelo OSI.
Através de um socket podemos estabelecer a comunicação entre máquinas possibilitando o envio e recebimento de dados.

A interface padronizada de sockets surgiu originalmente no sistema operacional Unix BSD (Berkeley Software Distribution). Tinha a função de suporte a comunicação em rede. Esta interface é a base para a maioria das interfaces entre protocolos de internet TCP/IP existente.

A identificação de um socket na rede é realizada por um IP e um porta. Comumente utiliza-se portas acima de 1000 pois as inferiores são utilizadas pelo sistema operacional. Sua comunicação é realizada pelos protocolos UDP ou TCP. Assim, é possível termos tanto comunicação orientada a conexão (via TCP), quanta não orientada a conexão (via UDP). O socket abstrai esse conceito, permitindo assim a utilização de qualquer um dos meios.

No C# para se trabalhar com sockets os recursos enconstram-se no namespace System.Net.Sockets.

Implementando uma aplicação com socket

Este é um simples código de uma aplicação Client/Server utilizando socket.
Abaixo o passo a passo de criação da aplicação:

Server App

  1. Criar um projeto do tipo WindowsForm com o nome CommunicationSocket.
  2. Incluir um botão que será utilizado para enviar mensagem do servidor para o cliente.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Windows.Forms;
 
namespace CommunicationSocket
{
    public partial class ServerApp : Form
    {
        private Socket socket;
        private Thread thread;
 
        private NetworkStream networkStream;
        private BinaryWriter binaryWriter;
        private BinaryReader binaryReader;
 
        public ServerApp()
        {
            InitializeComponent();
            thread = new Thread(new ThreadStart(RunServer));
            thread.Start();
        }
 
        public void RunServer()
        {
            TcpListener tcpListener;
            try
            {
                IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 2001);
                tcpListener = new TcpListener(ipEndPoint);
                tcpListener.Start();
 
                MessageBox.Show("Servidor habilitado e escutando porta...", "Server App");
 
                socket = tcpListener.AcceptSocket();
                networkStream = new NetworkStream(socket);
                binaryWriter = new BinaryWriter(networkStream);
                binaryReader = new BinaryReader(networkStream);
 
                MessageBox.Show("conexão recebida!", "Server App");
                binaryWriter.Write("\nconexão efetuada!");
 
                string messageReceived = "";
                do 
                {
                    messageReceived = binaryReader.ReadString();
                    MessageBox.Show("Mensagem: " + messageReceived, "Server App");
 
                } while (socket.Connected);
            } 
            catch (Exception ex) 
            {
                MessageBox.Show(ex.Message);
            } 
            finally 
            {
                binaryReader.Close();
                binaryWriter.Close();
                networkStream.Close();
                socket.Close();
 
                MessageBox.Show("conexão finalizada", "Server App");
            }
        }
 
        private void btnSendMsg_Click(object sender, EventArgs e)
        {
            try
            {
                binaryWriter.Write("Server respondendo: Houston, we have a problem!!!");
            }
            catch (SocketException socketEx)
            {
                MessageBox.Show(socketEx.Message, "Erro");
            }
        }
    }
}

Client App

  1. Criar um projeto do tipo WindowsForm com o nome ClientApp.
  2. Incluir botão que será utilizado para enviar mensagem do cliente para o servidor.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
using System;
using System.IO;
using System.Net.Sockets;
using System.Threading;
using System.Windows.Forms;
 
namespace ClientApplication 
{
    public partial class ClientAppForm : Form 
    {
        private NetworkStream networkStream;
        private BinaryWriter binaryWriter;
        private BinaryReader binaryReader;
        private TcpClient tcpClient;
 
        private Thread thread;
 
        public ClientAppForm() 
        {
            InitializeComponent();
            thread = new Thread(new ThreadStart(RunClient));
            thread.Start();
        }
 
        public void RunClient() 
        {
            try 
            {
                tcpClient = new TcpClient();
                tcpClient.Connect("127.0.0.1", 2001);
 
                networkStream = tcpClient.GetStream();
                binaryWriter = new BinaryWriter(networkStream);
                binaryReader = new BinaryReader(networkStream);
 
                String message = "";
                do 
                {
                    try 
                    {
                        message = binaryReader.ReadString();
                        MessageBox.Show(message, "Mensagem Recebida");
                    } 
                    catch (Exception ex) 
                    {
                        MessageBox.Show(ex.Message, "Erro");
                        message = "FIM";
                    }
                } while (message != "FIM");
 
                binaryWriter.Close();
                binaryReader.Close();
                networkStream.Close();
                tcpClient.Close();
            } 
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Erro");
            }
        }
 
        private void btnSendMsg_Click(object sender, EventArgs e) 
        {
            try 
            {
                binaryWriter.Write("Mensagem do cliente");
            } 
            catch (SocketException socketEx) 
            {
                MessageBox.Show(socketEx.Message, "Erro");
            }
        }
    }
}

Para realizar a comunicação o Servidor utiliza o objeto TcpListener que fica escutando toda requisição no IP “127.0.0.1″ porta 2001.
Na aplicação Cliente o objeto TcpClient é informado sobre o IP (ou DNS) e porta do servidor que irá se conectar. Após esse a realização toda a comunicação é feita por meio de stream através do objeto NetworkStream.

Repare que tanto Servidor quanto o Cliente trabalha com processamento em paralelo (Thread) para evitar que a aplicação fique travada até o término do processamento, ou para manter um processamento dedicado e contínuo que é o caso do servidor.

Nesse exemplo utilizei MessageBox para apresentar as mensagens, pois para inseri-las em um TextBox no Form é necessário utilizar delegates e reflections, senão teremos um erro de cruzamento de Threads (Cross-thread operation not valid).
Mas isso acho que é assunto para o nosso próximo post.

Até mais ;-)

Extension Methods no C# 3.0

Postado por Carlos Fernando Sylverio | Postado em Programação, Tecnologia | Postado em 13-12-2009

2

Extension Methods é uma das muitas características que torna o LINQ possível .
Em resumo podemos dizer que Extension Methods é a possibilidade de inserir métodos em objetos já compilados. O método criado tem a característica de um método estático, porem só está acessível ao objeto associado.
Com esse recurso podemos adicionar aos .NET types novos métodos. Assim classes como StringHelpers, Util, entre outras, com uma variedade de métodos de auxílio, podem ser inseridos diretamente no fonte.
Exemplo de uma classe com validação:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
using System.Text.RegularExpressions; 
namespace ExtensionMethodsExample
{
    public class Util
    {
        /// <summary>Verifica se o argumento do tipo string é um numérico</summary>
        /// <param name="arg">argumento a ser validado</param>
        /// <returns>True - se for numérico</returns>
        public bool IsNumeric(string arg)
        {
            return Regex.IsMatch(arg, @"^\d+$");
        }
    }
}

Com o uso do Extension Methods podemos inserir o método que verifica se a variável é numérica no próprio tipo string.
Abaixo um exemplo de seu uso, e depois vou explicar como o extension methods é declarado.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
using System;
using System.Text.RegularExpressions;
 
namespace ExtensionMethodsExample
{
    public static class Extensions
    {
        public static bool IsNumeric(this string arg)
        {
             return Regex.IsMatch(arg, @"^\d+$");
        }
    }
} 
 
public class Program
{
    public static void Main(string[] args)
    {
        string codigo1 = "1234";
        string codigo2 = "ABCD";
 
        Imprime(codigo1);
        Imprime(codigo2);
    }
 
    private static void Imprime(string codigo)
    {
        if (codigo.IsNumeric())
        {
            Console.WriteLine("Codigo numerico: {0}", codigo);
        }
        else
        {
            Console.WriteLine("Codigo alphanumerico: {0}", codigo);
        }
    }
}

Para criarmos um extension methods precisamos de uma classe e método estático. Todo método extension sempre terá seu primeiro parâmetro a palavra reservada this, seguido do tipo ao qual o método será inserido, no exemplo o tipo string. Esse parâmetro representa a própria instância do objeto. Para os parâmetros subseqüentes serão utilizados na chamada do método. O nome da classe é de livre escolha, ela não interfere na implementação do extension methods, a única ressalva é que seja uma classe estática.

Compare a diferença da verificação de condição utilizando a classe Util e o extension methods

1
2
3
4
5
Util util = new Util();
if (util.IsNumeric(codigo))
{
    // faz algo
}

e

1
2
3
4
if (codigo.IsNumeric())
{
    // faz algo
}

O código torna-se mais legível e mais implícito seus métodos, tornando a linguagem muito mais dinâmica.
Enjoy ;-)

Utilizando Reflection com C#

Postado por Carlos Fernando Sylverio | Postado em Programação, Tecnologia | Postado em 08-11-2009

0

Entre as utilização de reflection podemos citar a instânciação de classes ou a utilização de plugins (como os utilizados no firefox), que são definidos em tempo de execução.

Basicamente reflection é uma maneira de se descobrir dados de uma classe/objeto/interface em tempo de execução. Dessa forma podemos examinar os tipos em um assembly e interagir com eles ou instanciá-los. Também podemos criar tipos no momento de execução.

Neste post criarei um exemplo de instânciar objetos em tempo de execução (runtime) utilizando reflection.
Abaixo segue um diagrama de classe do modelo utilizado para o exemplo:

modelo produto

Utilizando reflection

using System;
using System.Collections.Generic;
using System.Reflection;
 
namespace UtilizandoReflection {
    public class Program {
        public static void Main(string[] args) {
 
            StateFactory factory = new StateFactory();
 
            // Cria 3 produtos em estado diferentes
            Product product1 = new Product();
            Product product2 = new Product();
            Product product3 = new Product();
 
            product1.State = factory.Create(1, "item pendente");
            product2.State = factory.Create(2, "item no estoque");
            product3.State = factory.Create(3, "item vendido");
 
            Console.WriteLine("Produto {0}: {1} -- Type {2}", product1.State.ID, product1.State.Description, product1.State.GetType().ToString());
            Console.WriteLine("Produto {0}: {1} -- Type {2}", product2.State.ID, product2.State.Description, product2.State.GetType().ToString());
            Console.WriteLine("Produto {0}: {1} -- Type {2}", product3.State.ID, product3.State.Description, product3.State.GetType().ToString());
        }
    }
 
    /// <summary>Classe responsável por criar intâncias de estado</summary>
    public class StateFactory {
        private Dictionary<int, string> states;
 
        public StateFactory(){
            states = new Dictionary<int, string>(3);
            states.Add(1, "Pending");
            states.Add(2, "Stock");
            states.Add(3, "Sold");
        }
 
        /// <summary>Cria uma instância de estado</summary>
        /// <param name="ID">Identificador da instância</param>
        /// <param name="description">descrição do estado</param>
        /// <returns>Estado</returns>
        public State Create(int ID, string description) {
 
            string baseName = "UtilizandoReflection";
 
            // cria array com os parâmetro utilizado no construtor do estado
            object[] args = new object[2];
            args.SetValue(ID, 0);
            args.SetValue(description, 1);
 
            //using System.Reflection
            Assembly assembly = Assembly.Load(baseName);
            return (State)assembly.CreateInstance(baseName + "." + states[ID], true, BindingFlags.CreateInstance, null, args, null, null);
        }
    }
 
    #region Domain
    public class Product {
        public State State;
    }
    public abstract class State {
        public int ID;
        public string Description;
        public State(int ID, string description) {
            this.ID = ID;
            this.Description = description;
        }
    }
    public class Pending : State { // estado pendente
        public Pending(int ID, string description) : base(ID, description) { }
    }
    public class Stock : State { // estado estoque
        public Stock(int ID, string description) : base(ID, description) { }
    }
    public class Sold : State { // estado vendido
        public Sold(int ID, string description) : base(ID, description) { }
    }
    #endregion
}

Resultado da execução:

Produto 1: item pendente -- Type UtilizandoReflection.Pending
Produto 2: item no estoque -- Type UtilizandoReflection.Stock
Produto 3: item vendido -- Type UtilizandoReflection.Sold

Observe que as classes a serem instanciadas por reflection estão na mesma solution ou project, assim utilizamos o método Load do Assembly, porem quando a classe a ser utilizada for de uma DLL, utilizamos o método LoadFile e informamos o nome completo da DLL.

Como mencionado no início do post, há outras utilizações de reflection, como manipular atributos e métodos, mas isso é assunto para um próximo post.

Enjoy ;-)

Expressão Regular

Postado por Carlos Fernando Sylverio | Postado em Programação, Tecnologia | Postado em 05-02-2009

0

Expressão Regular é um padrão de combinação de caracteres que é parte de diversas linguagens de programação modernas. Com a expressão regular podemos criar padrões para filtrar ou validar uma string de entrada através de uma expressão válida.

Alguns caracteres na expressão regular que têm funções especiais, e recebem o nome de metacaracteres, a combinação desses símbolos com caracteres literais da-se a criação de expressão.

Com a expressão regular é possível validar padrões de escrita como:

  • Número IP
  • E-mail
  • CPF

Para aprender a sintaxe utilizada na criação da expressão regular, segue uma versão on-line da obra de Expressões Regulares – Guia de Consulta Rápida.

OBSERVAÇÕES:

Em Java suporte a expressões regulares tem sido parte da plataforma Java desde a versão 1.4. e está contidas no pacote java.util.regex .

EM C# para utilizar expressões regulares, precisamos incluir o namespace System.Text.RegularExpressions .

Exemplo de expressão regulares com C#

Para testar a utilização de expressão regular, criei um projeto do tipo Console Application, e inclui o seguinte código.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
public static void Main(string[] args)
        {
            // expressões para filtrar as palavras a serem apresentadas
            // cria padrão para todas as palavras que contenham a expressão ATO
            string padrao1 = ".ato";
            // cria padrão para todas as palavras que contenham caracteres especias
            string padrao2 = ".\\?|.\\+|.\\!";
            // cria padrão para todas as palavras que contenham caracteres numéricos
            string padrao3 = "[0-9]";
 
            // cara lista para armazenar as palavras a serem filtradas
            List<string> paravras = new List<string>(10);
 
            paravras.Add("9pato");
            paravras.Add("rat3o");
            paravras.Add("mato");
            paravras.Add("gato");
            paravras.Add("te5to");
            paravras.Add("ramo");
            paravras.Add("duv6ida?");
            paravras.Add("soma+");
            paravras.Add("opa?");
            paravras.Add("que!");
 
            // Cria objetos que representa uma expressão regular
            Regex regex1 = new Regex(padrao1);
 
            Console.WriteLine("Busca de palavras com o padrão ATO");
            Console.WriteLine("");
 
            foreach (string str in paravras)
            {
                // verifica se palavra esta de acordo com o padrão
                // se for verdadeiro entra dentro do laço
                if (regex1.IsMatch(str))
                {
                    Console.WriteLine(str);
                }
            }
 
            // Cria objetos que representa uma expressão regular
            Regex regex2 = new Regex(padrao2);
 
            Console.WriteLine("");
            Console.WriteLine("Busca de palavras com caracteres especias");
            Console.WriteLine("");
 
            foreach (string str in paravras)
            {
                if (regex2.IsMatch(str))
                {
                    Console.WriteLine(str);
                }
            }
 
            // Cria objetos que representa uma expressão regular
            Regex regex3 = new Regex(padrao3);
 
            Console.WriteLine("");
            Console.WriteLine("Busca de palavras que contenham o caracteres numericos");
            Console.WriteLine("");
 
            foreach (string str in paravras)
            {
                if (regex3.IsMatch(str))
                {
                    Console.WriteLine(str);
                }
            }
        }

Até mais… :-P

Generalização Especialização Herança

Postado por Carlos Fernando Sylverio | Postado em Orientação a Objetos, Programação, UML | Postado em 29-01-2009

0

Olá pessoal, estive de férias e passei um bom tempo sem escrever, mas agora descançado, não há mais desculpas.

Fiz uma breve descrição sobre generalização, especialização e herança, devido a um pedido do último post e montei um pequena aplicação para exemplificar o assunto.

Conceito

Podemos dizer que generalização é o agrupamento de objetos ou elementos com características comuns em um modelo ou sistemas, é uma descrição mais geral sobre o objeto referente.

E a especialização é processo inverso, é a definição das particularidades de cada objeto ou elemento, são elementos mais consistentes que estendem o elemento genérico.

Dando continuidade ao exemplo citado no último post, casa, galpão, prédio, chamarei a generalização de “Habitação“.

(achei que não foi uma boa escolha esses elementos, prédio, galpão, etc… Para falar de generalização, mas vou utilizá-los para não confundir quem está começando a ver O.O., e manter um pouco de compatibilidade com o post anterior)

Ou seja, todos os elementos, são habitações, porém cada elemento guarda sua característica particular.

O que se ganha com isso?

A utilização de generalização tem dois propósitos:

  • Permitir que a classe base ou subclasse ser usada como variável. E regra é que uma instância da subclasse possa ser usada quando a superclasse é declarada. Com isso possibilitamos a realização de operações polimórficas.
  • Permitir a incrementar as características de um elemento pelas características comuns de seu antecessor. Esta é a chamada de herança.

Herança é a definição da implementação da generalização no código

Já li em alguns livros que o conceito de generalização pode ser utilizada para agrupar características comuns de cada objeto, passando os atributos comuns para o objeto mais genérico. Mas eu discordo desta opinião.

Não há nenhuma vantagem criar um modelo utilizando generalização e especialização se não for para se aproveitar de um dos benefícios comentados acima.

Na verdade estaremos adicionando mais complexidade ao modelo e tornando o código menos escalável.

Prática

Criei um exemplo simples em C#.NET para mostrar como aplicar os conceitos acima.

Para isso no Visual Studio vá em File->New->Project.

Em Templates, escolha Console Application.

Altere o Name para Generalizacao e clique em OK

Agora vá ao projeto (Generalizacao), clique com o botão direito vá em Add->New Item.

Em Templates, escolha Class.

Altere o Nome para Habitação.

Altere o código de para que fique da seguinte forma:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
using System;
 
namespace Generalizacao
{
    public abstract class Habitacao
    {
        /// <summary>
        /// Quantidade de tomadas da habitação
        /// </summary>
        private int qtdTomada;
 
        /// <summary>
        /// Obtem a quantidade de tomadas
        /// </summary>
        public int GetQtdTomada()
        {
            return qtdTomada;
        }
 
        /// <summary>
        /// Armazena a quantidade de tomada
        /// </summary>
        public void SetQtdTomada(int value)
        {
            qtdTomada = value;
        }
    }
}

Adiciona ao projeto as classes Casa, Predio e Galpao, e altere o código da seguinte forma:

Casa

1
2
3
4
5
6
7
8
9
10
11
using System;
 
 
 
 
namespace Generalizacao
{
    public class Casa : Habitacao
    {
    }
}

Observação:

Em C#, a sintaxe para herança é a utilização do comando: após o nome da classe seguindo do nome da classe a ser herdada.

Em Java, a sintaxe para herança é o comando extends após nome da classe seguindo do nome da classe a ser herdada.

Predio

1
2
3
4
5
6
7
8
using System;
 
namespace Generalizacao
{
    public class Predio : Habitacao
    {
    }
}

Galpao

1
2
3
4
5
6
7
8
using System;
 
namespace Generalizacao
{
    public class Galpao : Habitacao
    {
    }
}

Pronto. Criamos a estrutura modelada em UML acima.

Agora nossa Solution deve ter a seguinte aparência.

Na classe Program.cs, escreva o seguinte código:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
using System;
 
namespace Generalizacao
{
    public class Program
    {
        public static void Main(string[] args)
        {
            // Instâncias de casa
            Casa casa = new Casa();
            casa.SetQtdTomada(15);
 
            // Instâncias de prédio
            Predio predio = new Predio();
            predio.SetQtdTomada(300);
 
            // Instâncias de galpão
            Galpao galpao = new Galpao();
            galpao.SetQtdTomada(40);
 
            ImprimirValorDeTomada(casa, "Casa");
            ImprimirValorDeTomada(predio, "Predio");
            ImprimirValorDeTomada(galpao, "Galpao");
        }
 
        private static void ImprimirValorDeTomada(Habitacao habitacao,String tipo)
        {
            Console.WriteLine("{0} tem a seguinte quantidade de tomadas: {1}", tipo, habitacao.GetQtdTomada());
        }
    }
}

Como você deve ter observado, quando estava codificando, o seguinte acontecimento. O intellisense apresentar os métodos codificados na classe Habitação, para todas as subclasses.

Isso é possível devido às classes Casa, Predio e Galpao herdarem da classe Habitação, ou seja, toda a classe que herda de Habitação terá sua característica e comportamento.

Outra coisa que podemos observar nesse exemplo é o método ImprimirValorDeTomada que recebe como parâmetro Habitação, porém é passado Casa, Predio e Galpao.
Toda subclasse pode ser convertida no tipo da superclasse. Nesse método não importa qual é o tipo de habitação e sim se é do tipo habitação.

Observação

Toda subclasse pode ser convertida no tipo da superclasse, porém para o processo inverso é necessário a realização de cast.

Exemplo:

1
2
3
4
5
Casa casa1 = new Casa();
// conversão Implicit
Habitacao hab = casa1;
// conversão Explicit (Cast)
Casa casa2 = (Casa)hab;

Mas pra frente falarei mais sobre generalização.

Carlos Fernando

Como programar com “responsabilidade”

Postado por Carlos Fernando Sylverio | Postado em Análise, Orientação a Objetos, Programação | Postado em 18-11-2008

2

Uma das formas de se projetar objetos de software é pensar em suas responsabilidades. Essas responsabilidades podem se tratar de um pequeno objeto a uma divisão macro do sistema.
Essas responsabilidades devem descrever o que um objeto deve fazer e o que o deve saber.

História do dia-a-dia

Suponhamos que você tenha que entregar um relatório para seu chefe sobre uma fórmula química de um produto de limpeza. Mas você não conhece nada de química.
Fácil, não é?
Você delega esta atividade a um químico, para que ele escreva o relatório da fórmula química para você.
Pronto, sem mistério ou complicação.

Atribuindo responsabilidade

O desenvolvimento de software deve ser tão fácil quando a história acima.
As responsabilidades devem ser atribuídas aos objetos que tem a informação necessária para satisfazer as responsabilidade.
Vejamos o modelo seguinte, qual é o melhor objeto para informar a quantidade de tomadas de um quarto?
Modelo domínio
Sabemos que o Quarto tem conhecimento das suas paredes, e que cada Parede tem o conhecimento da quantidade de suas suas tomadas.
Desta forma a melhor solução para aplicamos a responsabilidade de obter a quantidade de tomadas é através do objeto Quarto, que delega a cada Parede que informe sua quantidade de tomada. Assim a quantidade total de tomadas é a soma das tomadas presente em cada parede.
Diagrama de classe

O método TotalTomadas() do objeto Quarto:

1
2
3
4
5
6
7
8
9
public int TotalTomadas()
{
     int ret = 0;
     foreach(Parede parede in paredes)
     {
          ret += parede.GetQtdTomadas();
     }
     return ret;
}

Para melhorar ainda mais esse trabalho, podemos criar um objeto chamado Paredes que estenda o Array (Collection) de paredes presente no objeto quarto, e criarmos um método GetTomadas() que faça o trabalho da soma das tomadas.
Assim, a nossa lista de Paredes presente no objeto Quarto ficaria com a responsabilidade de obter o total de tomadas de cada item interno e somá-los.
Desta forma o método TotalTomadas() fica assim:

1
2
3
4
public int TotalTomadas()
{
     return paredes.GetTomadas();
}

O método GetTomadas() do objeto Paredes:

1
2
3
4
5
6
7
8
9
public int GetTomadas()
{
     int ret = 0;
     foreach(Parede parede in this)
     {
          ret += parede.GetQtdTomadas();
     }
     return ret;
}

Isso nos permite reaproveitar código, pois se no projeto existisse objetos como Galpão, Prédio, etc. Poderíamos utilizar o mesmo objeto Paredes para ambos (dependendo do contexto), pois certamente, Galpão e Prédio têm paredes. Assim estaríamos evitando a duplicação de código e facilitando sua manutenção.