sábado, 16 de outubro de 2010

Desenvolvendo aplicações Web com Spring.net

Introdução



O propósito deste artigo é expor as características e benefícios do framework Spring.net, cujo qual vem conquistando um maior número de adeptos por causa da sua facilidade de uso e a forma como o sistema é desenvolvido, ou seja, uma maior facilidade no que diz respeito ao desacoplamento entre as camadas, requisito hoje indispensável, para sistemas de qualquer porte.
Ao contrário do que muitos pensam, o Spring.net não é um framework exclusivo ao suporte de persistência à dados, esta é apenas uma de suas várias funcionalidades, este framework funciona como um pivô para dar apoio ao pattern de injeção de dependência, utilizando a técnica de Inversão de Controles.
 

Inversão de Controles (IoC) e Injeção de Dependência


O que torna o Spring.net um framework tão poderoso no desenvolvimento de aplicações com baixo acoplamento entre camadas e orientado a aspectos é a utilização destes dois conceitos em conjunto. A inversão de controle (Inversion of Control) ocorre quando o controle de execução dos métodos é gerenciado não mais diretamente pelo programador, e sim, por um container de configuração, este, assume o papel de gerenciar a aplicação, desta forma, as camadas ficam independestes entre si reduzindo o acoplamento e facilitando no reuso e testes do sistema. Havendo a necessidade de alterações nas camadas, isso pode ser feito sem problemas e sem necessidade de se estar percorrendo código e descobrindo onde a classe alterada estava sendo utilizada, pois a injeção de dependência é quem trata de amarrar as camadas através de um contexto obtido a partir do container de configuração. Deve-se destacar que a utilização de interfaces deixa o código mais limpo e mais fácil de configurar o container, sendo necessário apenas criar referências às classes que as implementam no arquivo de configuração (XML). Também é importante frisar que estes dois conceitos apesar de trabalharem em conjunto, como explicados, possuem significados totalmente diferentes.
 

Spring.net


O Spring.net é um framework Open Source implementado para utilização no desenvolvimento de aplicações .NET, tendo como embasamento a biblioteca Spring para Java. Seu principal objetivo é criar previamente um suporte estruturado baseado em containers, originando mais tarde em um contexto, contendo todos os objetos da aplicação necessários. Carregados a partir de um arquivo XML de mapeamento, estes objetos estão prontos para realizar a injeção de dependência à medida que vão sendo necessários, bastando ao desenvolvedor referenciar apenas o container sem necessidade de instanciar objeto por objeto, e desta forma, utilizando normalmente seus métodos, propriedades, etc., eliminando assim a complexidade e o alto acoplamento entre as camadas.
A persistência de dados é realizada utilizando uma classe denominada AdoDaoSupport, visto ainda neste artigo e mostrado como a aplicação se tornará independente não só entre suas camadas, mas também na escolha de um banco de dados, pois as transações com a base ficam genéricas, o desenvolvedor apenas deve configurar o DbProvider no arquivo XML, apontando qual banco de dados está utilizando. É importante lembrar que a utilização do Spring.net é facilmente integrado com frameworks como NHibernate, Entity Framework ou o próprio ADO.NET para realizar transações com a base de dados, não sendo restrito apenas às classes do Spring.net.
Com o auxílio das classes disponíveis no framework Spring.net o desenvolvedor, através de melhores práticas de programação, é capaz de criar módulos totalmente independentes, gerenciando e programando com mais facilidade as funções ORM, DAO, Services e a própria camada de apresentação, Web, figura 1. Além disso, é possível a realização de testes unitários, criação de arquivos de log, bem como programação de triggers, aumentando desta forma o desempenho da aplicação. E todas estas funcionalidades podem contar com o auxílio de um poderoso recurso denominado orientação a aspectos (AOP).
Os principais módulos que implementam o Spring.net são:
Spring.Core: Este modulo é responsável por criar a arquitetura de inversão de controle IoC, onde é realizado o mapeamento (criação do contexto), e posteriormente a injeção de dependência.
Spring.Data: Esta camada é responsável por criar o acesso à base de dados através de transações diretas. Em outras palavras, é possível realizar a persistência no banco de dados por conta do Spring.net, inclusive utilizando conceitos ADO.NET de uma forma bastante simples.
Spring.AOP: Modulo correspondente a Programação Orientada a Aspectos, onde é fundamentada grande parte do framework. É capaz de encapsular aspectos específicos do sistema, separando-os em módulos e através de pointcuts o comportamento dos métodos são alterados.
Spring.Web: Esta camada será responsável por realizar injeções de dependência em páginas Web. Ao desenvolver uma aplicação Asp.NET Webforms é possível elevar ao máximo sua abstração, bastando apenas configurações simples no arquivo Web.config.
É importante lembrar que todos os modulos do framework Spring.net são indepentes, ou seja, uma não depende da outra para fucionar. As várias possibilidade de utilização das funções fica por conta do programador.


image Figura 1 - Arquitetura do Framework Spring.net.

Entenda, caro leitor, que é possível sim, desenvolver um sistema com baixo acoplamento entre camadas, sem a utilização do Spring.net, porém, este framework serve como um facilitador desta tarefa, fazendo-se utilização de conceitos explicados anteriormente. Para exemplificar todo o conteúdo estudado até então, vamos desenvolver uma pequena aplicação Web, e deixar bastante explicito as qualidades do framework, desta forma, o desenvolvedor pode ter uma melhor noção se há vantagens no desenvolvimento de uma aplicação utilizando Spring.net ou ainda uma eventual migração para esta tecnologia.
 

Descrição do Case


Um sistema de informação deve realizar o controle de funcionários por setor, possuindo formas de cadastrar, atualizar e excluir funcionários e setores. O objetivo principal do sistema é agilizar o processo de distribuição de funcionários entre diversos setores dentro de uma empresa qualquer, ao mesmo tempo em que possibilita um melhor controle das informações por parte da gerência e facilite a visualização da composição dos setores, no que diz respeito a pessoas. A partir do momento em que os cadastros foram realizados, uma forma de gerenciamento vai ser desenvolvida, onde são listados os setores e em seguida os funcionários disponíveis.
 

Projeto


O Spring.net pode ser baixado no site oficial: http://www.springframework.net/ na opções downloads. Atualmente a última versão encontrada é a 1.3.0, esta não oferece suporte a aplicações utilizando o framework 4.0. Porém, há uma opção chamada Nightly Snapshot Builds encontrada também na opção de downloads. Estes são oferecidos com correções diárias e irão servir bem para nossa aplicação de exemplo. Para este artigo estou utilizando a versão disponibilizada no dia 18/09/2010. Baixe de preferência a versão mais recente. Descompacte o conteúdo e verifique na pasta Bin/net/3.0/release, este é o caminho onde estarão todos os assemblies que serão utilizados neste artigo. Para persistência de informações utilizaremos o banco de dados SQL Server. Abaixo, segue o diagrama da base de dados.


Diagrama

Inicialmente, iremos criar a solução do projeto em branco (Blank Solution), selecionado Other Project Types/Visual Studio Solutions. Quanto a opção de framework marque .NET Framework 4. Nesta aplicação de exemplo o nome da solução será “SpringNet.Exemplo.Solucao”, fique a vontade para inserir o nome que desejar, tanto neste projeto quanto nos outros adicionados posteriormente.
O nosso sistema será dividido, logicamente, em quatro camadas distintas: uma para os objetos de nossa aplicação, sendo eles funcionário, setor e gerenciamento, este último corresponde à designação de um funcionário a um setor. Adicionaremos uma camada de persistência, responsável pelas transações com a base de dados. Outra camada que realizará o gerenciamento da aplicação, ou seja, qualquer tipo de validação de dados, ou outra restrição que o sistema possa ter, tratamento de exceções devem ser adicionados a esta camada. E por fim, nossa camada de apresentação, contendo as interfaces e interações para com o usuário.
 

Camada de Objetos


Iniciaremos então com a camada de objetos, para isso basta criar um projeto do tipo Class Library. Para este projeto, adicionei o nome “SpringNet.Exemplo.Objetos”.
A partir da biblioteca criada, devemos adicionar 3 classes: FuncionarioVO, SetorVO e GerenciamentoVO, a finalização do nome da classe com as letras VO (Value Objects) fica por conta do desenvolvedor, sendo este um padrão bastante utilizado. O diagrama representado na figura 2 demonstra os campos e propriedades pertencentes às classes.


image Figura 2 – Diagrama de Objetos.


Nossa biblioteca de objetos está criada, até aqui nada de novo, não há a mínima configuração do Spring.net.
 

Camada de Persistência


Iremos criar agora a biblioteca responsável por realizar a persistência dos dados. Conforme projeto adicionado anteriormente será adicionada uma nova Class Library para serem adicionadas nossas classes de gerenciamento de dados. Para esta biblioteca será dado o seguinte nome “SpringNet.Exemplo.Persistencia”.
Adicionado nossa nova biblioteca, vamos inserir uma referência do projeto criado anteriormente o qual possui os objetos da aplicação. Neste momento iremos iniciar a utilização do Spring.net, onde adicionaremos a referência de dois assemblies, o Spring.Core e Spring.Data. Após isso iremos estruturar nosso novo projeto criado em um sistema de interfaces, aonde irá nos facilitar na configuração do contexto do Spring.net, além de ser uma boa prática de programação. Adicionaremos as interfaces em uma pasta denominada Interfaces e as classes que às implementam em outra pasta chamada Implementações. A seguir é demonstrado como deverão ser implementados as assinaturas das interfaces de persistência.
using System;
using System.Collections.Generic;
using SpringNet.Exemplo.Objetos; 
namespace SpringNet.Exemplo.Persistencia.Interfaces
{
    public interface IFuncionarioDAO
    {
        void Salvar(FuncionarioVO funcionario); 
        void Atualizar(FuncionarioVO funcionario); 
        void Deletar(int idFuncionario); 
        FuncionarioVO BuscarPorId(int idFuncionario); 
        List<FuncionarioVO> BuscarFuncionarios();
    }
} 
using System;
using System.Collections.Generic;
using SpringNet.Exemplo.Objetos; 
namespace SpringNet.Exemplo.Persistencia.Interfaces
{
    public interface ISetorDAO
    {
        void Salvar(SetorVO setor); 
        void Atualizar(SetorVO setor); 
        void Deletar(int idSetor); 
        SetorVO BuscaPorId(int id); 
        List<SetorVO> BuscarSetores();
    }
} 
using System;
using System.Collections.Generic;
using SpringNet.Exemplo.Objetos; 
namespace SpringNet.Exemplo.Persistencia.Interfaces
{
    public interface IGerenciamentoDAO
    {
        void Salvar(GerenciamentoVO gerenciamento); 
        void Deletar(GerenciamentoVO gerenciamento); 
        List<GerenciamentoVO> BuscarFuncionarios(int idSetor);
    }
} 
Com as nossas assinaturas de persistência prontas, basta apenas implementá-las, e é aqui que iniciaremos o desenvolvimento efetivo com Spring.net, que por sua vez, contém uma gama de classes DAO abstratas e estendíveis. Como já temos uma referência adicionada ao assemblie Spring.Data, faremos utilização de sua classe chamada AdoDaoSupport. Esta classe possui métodos e configurações que suprem perfeitamente nossa necessidade de transação de dados. Basta fazermos com que nossas classes herdem desta super classe e teremos todas as funcionalidades do ADO.NET disponíveis. Observe no código a seguir como a persistência de nosso objeto funcionário é realizada.
using System;
using System.Collections.Generic;
using Spring.Data.Generic;
using SpringNet.Exemplo.Persistencia.Interfaces;
using Spring.Data.Common;
using SpringNet.Exemplo.Objetos;
using System.Data; 
namespace SpringNet.Exemplo.Persistencia.Implementacoes
{
    public class AdoFuncionarioDAOImpl : AdoDaoSupport, IFuncionarioDAO
    { 
        public void Salvar(FuncionarioVO funcionario)
        {
            string prefixo = DbProvider.DbMetadata.ParameterNamePrefix;
            string queryString = string.Format("INSERT INTO FUNCIONARIO VALUES ({0}NOME, {0}CPF, {0}RG, " +
            "{0}SEXO, {0}DATANASCIMENTO, {0}CARGO)", prefixo); 
            IDbParametersBuilder parametros = CreateDbParametersBuilder();
            parametros.Create().Name("NOME").Value(funcionario.Nome).Type(DbType.String);
            parametros.Create().Name("CPF").Value(funcionario.Cpf).Type(DbType.String);
            parametros.Create().Name("RG").Value(funcionario.Rg).Type(DbType.String);
            parametros.Create().Name("SEXO").Value(funcionario.Sexo).Type(DbType.String);
            parametros.Create().Name("DATANASCIMENTO").Value(funcionario.DataNascimento).Type(DbType.DateTime);
            parametros.Create().Name("CARGO").Value(funcionario.Cargo).Type(DbType.String); 
            AdoTemplate.ExecuteNonQuery(CommandType.Text, queryString, parametros.GetParameters());
        } 


Note a herança realizada em nossa classe AdoFuncionarioDAOImpl, temos a interface IFuncionarioDAO com as assinaturas correspondentes ao objeto Funcionario e AdoDaoSupport, cuja qual, contém os métodos para realizar a persistência. Na primeira linha do método Salvar obtemos o prefixo necessário à query através do DbProvider configurado em nosso arquivo XML de configuração, dizendo qual banco utilizaremos. Para nosso exemplo, essa variável retornará um ‘@’ pois estamos utilizando o banco de dados SQL Server, caso estivéssemos utilizando o banco de dados Oracle, retornaria um ‘:’ e assim por diante.
A interface IDbParametersBuilder possui um método chamado CreateDbParametersBuilder(), responsável por criar nossos parâmetros, onde deve-se juntamente ser informado o tipo de dado (DbType). Note que em nenhum momento foi engessado definição de algum tipo de banco, já que passando estas informações ao Spring.net o DbProvider, através do AdoTemplate, automaticamente se encarregará de setar as informações certas na hora da transação, e com este procedimento, excluímos qualquer dependência a banco de dados.
E por último, utilizamos o método bastante familiar ExecuteNonQuery, passando seus parâmetros necessários. É neste momento que acontece o conceito de orientação à aspectos, pois, a transação deve ocorrer sem qualquer tipo de erro, gerando assim automaticamente um commit. Caso contrário um rollback é executado e nenhuma alteração é sofrida. Apesar de esta técnica ser já bastante difundida, o que a torna especial é que o Spring.net realiza estes comandos automaticamente, e o desenvolvedor não se preocupa em saber se a transação ocorreu pela metade, gerando a partir daí serias conseqüências nos dados da aplicação. A seguir segue a implementação do restante da classe de persistência correspondente a FuncionarioVO.
public void Atualizar(FuncionarioVO funcionario)
        {
            string prefixo = DbProvider.DbMetadata.ParameterNamePrefix;
            string queryString = string.Format("UPDATE FUNCIONARIO SET NOME={0}NOME, CPF={0}CPF, RG={0}RG, " +
            "SEXO={0}SEXO, DATANASCIMENTO={0}DATANASCIMENTO, CARGO={0}CARGO WHERE IDFUNCIONARIO={0}IDFUNCIONARIO", prefixo); 
            IDbParametersBuilder parametros = CreateDbParametersBuilder();
            parametros.Create().Name("IDFUNCIONARIO").Value(funcionario.IdFuncionario).Type(DbType.Int32);
            parametros.Create().Name("NOME").Value(funcionario.Nome).Type(DbType.String);
            parametros.Create().Name("CPF").Value(funcionario.Cpf).Type(DbType.String);
            parametros.Create().Name("RG").Value(funcionario.Rg).Type(DbType.String);
            parametros.Create().Name("SEXO").Value(funcionario.Sexo).Type(DbType.String);
            parametros.Create().Name("DATANASCIMENTO").Value(funcionario.DataNascimento).Type(DbType.DateTime);
            parametros.Create().Name("CARGO").Value(funcionario.Cargo).Type(DbType.String); 
            AdoTemplate.ExecuteNonQuery(CommandType.Text, queryString, parametros.GetParameters());
        } 
        public void Deletar(int idFuncionario)
        {
            string prefixo = DbProvider.DbMetadata.ParameterNamePrefix;
            string queryString = string.Format("DELETE FROM FUNCIONARIO WHERE IDFUNCIONARIO = {0}IDFUNCIONARIO", prefixo); 
            IDbParametersBuilder parametros = CreateDbParametersBuilder();
            parametros.Create().Name("IDFUNCIONARIO").Value(idFuncionario).Type(DbType.Int32); 
            AdoTemplate.ExecuteNonQuery(CommandType.Text, queryString, parametros.GetParameters());
        } 
        public FuncionarioVO BuscarPorId(int idFuncionario)
        {
            string prefixo = DbProvider.DbMetadata.ParameterNamePrefix;
            string queryString = string.Format("SELECT * FROM FUNCIONARIO WHERE IDFUNCIONARIO = {0}IDFUNCIONARIO", prefixo); 
            IDbParametersBuilder parametros = CreateDbParametersBuilder();
            parametros.Create().Name("IDFUNCIONARIO").Value(idFuncionario).Type(DbType.Int32); 
            List<FuncionarioVO> listaFuncionarios = AdoTemplate.QueryWithResultSetExtractor<List<FuncionarioVO>>
                (CommandType.Text, queryString, 
                new FuncionarioResultSetExtractor<List<FuncionarioVO>>(), 
                parametros.GetParameters()); 
            return listaFuncionarios[0];
        } 
        public List<FuncionarioVO> BuscarFuncionarios()
        {
            string queryString = "SELECT * FROM FUNCIONARIO"; 
            IDbParametersBuilder parametros = CreateDbParametersBuilder(); 
            return AdoTemplate.QueryWithResultSetExtractor<List<FuncionarioVO>>(CommandType.Text, queryString,
                new FuncionarioResultSetExtractor<List<FuncionarioVO>>(), 
                parametros.GetParameters());
        }
    } 


Nos métodos responsáveis por retornar funcionários, foi utilizado o método do AdoTemplate QueryWithResultSetExtractor. O que este método faz nada mais é, do que executar nossa consulta e retornar o mapeamento do conjunto de resultados para um objeto que implementa a interface IResultSetExtractor. Para isso é feito a utilização de uma classe interna chamada FuncionarioResultSetExtractor, e implementando a interface citada anteriormente, nos possibilita sobrescrever o método ExtractData possuindo como sobrecarga um objeto do tipo IDataReader, e seu retorno sendo o que foi definido na classe, em nosso caso, List<FuncionarioVO>. Detalhadamente a interface que se está sendo implementada é a responsável por sobrescrever de forma correta o método ExtractData, a única informação própria do método, é a sobrecarga do tipo IDataReader, que contém automaticamente o resultado da consulta e irá montar linha a linha o retorno do mapeamento do objeto desejado.
Ao desenvolvedor basta apenas informar o tipo de retorno desejado.
    internal class FuncionarioResultSetExtractor<T> : IResultSetExtractor<List<FuncionarioVO>> where T : List<FuncionarioVO>, new()
    {
        public List<FuncionarioVO> ExtractData(IDataReader reader)
        {
            List<FuncionarioVO> listaFuncionario = new List<FuncionarioVO>(); 
            while (reader.Read())
            {
                FuncionarioVO funcionario = new FuncionarioVO(); 
                funcionario.IdFuncionario = reader.GetInt32(0);
                funcionario.Nome = reader.GetString(1);
                funcionario.Cpf = reader.GetString(2);
                funcionario.Rg = reader.GetString(3);
                funcionario.Sexo = reader.GetString(4);
                funcionario.DataNascimento = reader.GetDateTime(5);
                funcionario.Cargo = reader.GetString(6); 
                listaFuncionario.Add(funcionario);
            } 
            return listaFuncionario;
        }
    }
} 


A implementação das assinaturas ISetorDAO e IGerencimantoDAO devem ser desenvolvidas conforme listagens a seguir.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Spring.Data.Generic;
using SpringNet.Exemplo.Persistencia.Interfaces;
using SpringNet.Exemplo.Objetos;
using System.Data;
using Spring.Data.Common; 
namespace SpringNet.Exemplo.Persistencia.Implementacoes
{
    public class AdoSetorDAOImpl : AdoDaoSupport, ISetorDAO
    {
        public void Salvar(SetorVO setor)
        {
            string prefixo = DbProvider.DbMetadata.ParameterNamePrefix;
            string queryString = string.Format("INSERT INTO SETOR VALUES ({0}NOME, {0}QUANTTOTAL, {0}DESCRICAO)", prefixo); 
            IDbParametersBuilder parametros = CreateDbParametersBuilder();
            parametros.Create().Name("NOME").Value(setor.Nome).Type(DbType.String);
            parametros.Create().Name("QUANTTOTAL").Value(setor.QuantTotal).Type(DbType.Int32);
            parametros.Create().Name("DESCRICAO").Value(setor.Descricao).Type(DbType.String); 
            AdoTemplate.ExecuteNonQuery(CommandType.Text, queryString, parametros.GetParameters());
        } 
        public void Atualizar(SetorVO setor)
        {
            string prefixo = DbProvider.DbMetadata.ParameterNamePrefix;
            string queryString = string.Format("UPDATE SETOR SET NOME={0}NOME, QUANTTOTAL={0}QUANTTOTAL," +
                "DESCRICAO={0}DESCRICAO WHERE IDSETOR={0}IDSETOR", prefixo); 
            IDbParametersBuilder parametros = CreateDbParametersBuilder();
            parametros.Create().Name("IDSETOR").Value(setor.IdSetor).Type(DbType.Int32);
            parametros.Create().Name("NOME").Value(setor.Nome).Type(DbType.String);
            parametros.Create().Name("QUANTTOTAL").Value(setor.QuantTotal).Type(DbType.Int32);
            parametros.Create().Name("DESCRICAO").Value(setor.Descricao).Type(DbType.String); 
            AdoTemplate.ExecuteNonQuery(CommandType.Text, queryString, parametros.GetParameters());
        } 
        public void Deletar(int idSetor)
        {
            string prefixo = DbProvider.DbMetadata.ParameterNamePrefix;
            string queryString = string.Format("DELETE FROM SETOR WHERE IDSETOR = {0}IDSETOR", prefixo); 
            IDbParametersBuilder parametros = CreateDbParametersBuilder();
            parametros.Create().Name("IDSETOR").Value(idSetor).Type(DbType.Int32); 
            AdoTemplate.ExecuteNonQuery(CommandType.Text, queryString, parametros.GetParameters());
        } 
        public SetorVO BuscaPorId(int idSetor)
        {
            string prefixo = DbProvider.DbMetadata.ParameterNamePrefix;
            string queryString = string.Format("SELECT * FROM SETOR WHERE IDSETOR = {0}IDSETOR", prefixo); 
            IDbParametersBuilder parametros = CreateDbParametersBuilder();
            parametros.Create().Name("IDSETOR").Value(idSetor).Type(DbType.Int32); 
            List<SetorVO> listaSetores = AdoTemplate.QueryWithResultSetExtractor<List<SetorVO>>
                (CommandType.Text, queryString, new SetorResultSetExtractor<List<SetorVO>>(), parametros.GetParameters()); 
            return listaSetores[0];
        } 
        public List<SetorVO> BuscarSetores()
        {
            string queryString = "SELECT * FROM SETOR"; 
            IDbParametersBuilder parametros = CreateDbParametersBuilder(); 
            return AdoTemplate.QueryWithResultSetExtractor<List<SetorVO>>
                (CommandType.Text, queryString, new SetorResultSetExtractor<List<SetorVO>>(), parametros.GetParameters());
        }
    } 
    internal class SetorResultSetExtractor<T> : IResultSetExtractor<List<SetorVO>> where T : List<SetorVO>, new()
    {
        public List<SetorVO> ExtractData(IDataReader reader)
        {
            List<SetorVO> listaSetores = new List<SetorVO>(); 
            while (reader.Read())
            {
                SetorVO setor = new SetorVO(); 
                setor.IdSetor = reader.GetInt32(0);
                setor.Nome = reader.GetString(1);
                setor.QuantTotal = reader.GetInt32(2);
                setor.Descricao = reader.GetString(3); 
                listaSetores.Add(setor);
            } 
            return listaSetores;
        }
    }
} 
using System;
using System.Collections.Generic;
using Spring.Data.Generic;
using SpringNet.Exemplo.Persistencia.Interfaces;
using SpringNet.Exemplo.Objetos;
using System.Data;
using Spring.Data.Common; 
namespace SpringNet.Exemplo.Persistencia.Implementacoes
{
    public class AdoGerenciamentoDAOImpl : AdoDaoSupport, IGerenciamentoDAO
    { 
        public void Salvar(GerenciamentoVO gerenciamento)
        {
            string prefixo = DbProvider.DbMetadata.ParameterNamePrefix;
            string queryString = string.Format("INSERT INTO GERENCIAMENTO VALUES ({0}IDSETOR," +
            "{0}IDFUNCIONARIO, {0}FUNCIONARIO, {0}DATAINICIO)", prefixo); 
            IDbParametersBuilder parametros = CreateDbParametersBuilder();
            parametros.Create().Name("IDSETOR").Value(gerenciamento.IdSetor).Type(DbType.Int32);
            parametros.Create().Name("IDFUNCIONARIO").Value(gerenciamento.IdFuncionario).Type(DbType.Int32);
            parametros.Create().Name("FUNCIONARIO").Value(gerenciamento.Funcionario).Type(DbType.String);
            parametros.Create().Name("DATAINICIO").Value(DateTime.Now).Type(DbType.DateTime); 
            AdoTemplate.ExecuteNonQuery(CommandType.Text, queryString, parametros.GetParameters());
        } 
        public void Deletar(GerenciamentoVO gerenciamento)
        {
            string prefixo = DbProvider.DbMetadata.ParameterNamePrefix;
            string queryString = string.Format("DELETE FROM GERENCIAMENTO WHERE IDSETOR = {0}IDSETOR " +
                "AND IDFUNCIONARIO = {0}IDFUNCIONARIO", prefixo); 
            IDbParametersBuilder parametros = CreateDbParametersBuilder();
            parametros.Create().Name("IDSETOR").Value(gerenciamento.IdSetor).Type(DbType.Int32);
            parametros.Create().Name("IDFUNCIONARIO").Value(gerenciamento.IdFuncionario).Type(DbType.Int32); 
            AdoTemplate.ExecuteNonQuery(CommandType.Text, queryString, parametros.GetParameters());
        } 
        public List<GerenciamentoVO> BuscarFuncionarios(int idSetor)
        {
            string prefixo = DbProvider.DbMetadata.ParameterNamePrefix;
            string queryString = string.Format("SELECT * FROM GERENCIAMENTO WHERE IDSETOR = {0}IDSETOR", prefixo); 
            IDbParametersBuilder parametros = CreateDbParametersBuilder();
            parametros.Create().Name("IDSETOR").Value(idSetor).Type(DbType.Int32); 
            return AdoTemplate.QueryWithResultSetExtractor<List<GerenciamentoVO>>
                (CommandType.Text, queryString, new GerenciamentoResultSetExtractor<List<GerenciamentoVO>>(), parametros.GetParameters());
        }
    } 
    internal class GerenciamentoResultSetExtractor<T> : IResultSetExtractor<List<GerenciamentoVO>> where T : List<GerenciamentoVO>, new()
    {
        public List<GerenciamentoVO> ExtractData(IDataReader reader)
        {
            List<GerenciamentoVO> listaFuncionario = new List<GerenciamentoVO>(); 
            while (reader.Read())
            {
                GerenciamentoVO funcionarios = new GerenciamentoVO(); 
                funcionarios.IdSetor = reader.GetInt32(0);
                funcionarios.IdFuncionario = reader.GetInt32(1);
                funcionarios.Funcionario = reader.GetString(2);
                funcionarios.DataInicio = reader.GetDateTime(3); 
                listaFuncionario.Add(funcionarios);
            } 
            return listaFuncionario;
        }
    }
} 
  


Camada de Serviços


Agora, iremos criar a nossa camada de serviço, para isso, basta adicionar um novo projeto do tipo Class Library com nome “SpringNET.Exemplo.Servicos”.
Antes de tudo, vamos adicionar as referências necessárias a este projeto. Uma referência do projeto de objetos, outra do projeto de persistência, por parte do Spring.net, uma referência do assembly Spring.Core. Bem como desenvolvido no projeto de persistência, vamos trabalhar seguindo o conceito de interfaces e também criar as pastas para distinção de interfaces e implementações. A seguir, demonstrações de como as assinaturas da camada de serviço deverão ser criadas, lembrando que a cada classe criada, deve ser realizada a referência aos projetos anteriores.
using System;
using System.Collections.Generic;
using SpringNet.Exemplo.Persistencia.Interfaces;
using SpringNet.Exemplo.Objetos; 
namespace SpringNET.Exemplo.Servicos.Interfaces
{
    public interface IFuncionarioServico
    {
        IFuncionarioDAO FuncionarioDAO { get; set; } 
        void Salvar(FuncionarioVO funcionario); 
        void Atualizar(FuncionarioVO funcionario); 
        void Deletar(int idFuncionario); 
        FuncionarioVO BuscarPorId(int idFuncionario); 
        List<FuncionarioVO> BuscarFuncionarios();
    }
} 
using System;
using System.Collections.Generic;
using SpringNet.Exemplo.Persistencia.Interfaces;
using SpringNet.Exemplo.Objetos; 
namespace SpringNET.Exemplo.Servicos.Interfaces
{
    public interface ISetorServico
    {
        ISetorDAO SetorDAO { get; set; } 
        void Salvar(SetorVO setor); 
        void Atualizar(SetorVO setor); 
        void Deletar(int idSetor); 
        SetorVO BuscaPorId(int id); 
        List<SetorVO> BuscarSetores();
    }
} 
using System;
using System.Collections.Generic;
using SpringNet.Exemplo.Persistencia.Interfaces;
using SpringNet.Exemplo.Objetos; 
namespace SpringNET.Exemplo.Servicos.Interfaces
{
    public interface IGerenciamentoServico
    {
        IGerenciamentoDAO GerenciamentoDAO { get; set; } 
        void Salvar(GerenciamentoVO gerenciamento); 
        void Deletar(GerenciamentoVO gerenciamento); 
        List<GerenciamentoVO> BuscarFuncionarios(int idSetor);   
    }
} 
Com as assinaturas criadas, iremos agora adicionar as classes que às implementarão. Começaremos com a classe FuncionarioServicoImpl, onde utilizando nossas interfaces da camada DAO, basta criar uma propriedade do tipo IFuncionarioDAO e invocar os métodos em suas respectivas funções. Note que você não instancia um novo objeto na propriedade, isso não se faz mais necessários, pois quem irá instanciar no contexto este objeto será os Spring.net em runtime, utilizando injeção de dependência.
using System;
using System.Collections.Generic;
using SpringNET.Exemplo.Servicos.Interfaces;
using SpringNet.Exemplo.Persistencia.Interfaces;
using SpringNet.Exemplo.Objetos; 
namespace SpringNET.Exemplo.Servicos.Implementacoes
{
    public class FuncionarioServicoImpl : IFuncionarioServico
    {
        private IFuncionarioDAO funcionarioDAO; 
        public IFuncionarioDAO FuncionarioDAO
        {
            get
            {
                return funcionarioDAO;
            }
            set
            {
                funcionarioDAO = value;
            }
        } 
        public void Salvar(FuncionarioVO funcionario)
        {
            funcionarioDAO.Salvar(funcionario);
        } 
        public void Atualizar(FuncionarioVO funcionario)
        {
            funcionarioDAO.Atualizar(funcionario);
        } 
        public void Deletar(int idFuncionario)
        {
            funcionarioDAO.Deletar(idFuncionario);
        } 
        public FuncionarioVO BuscarPorId(int idFuncionario)
        {
            return funcionarioDAO.BuscarPorId(idFuncionario);
        } 
        public List<FuncionarioVO> BuscarFuncionarios()
        {
            return funcionarioDAO.BuscarFuncionarios();
        }
    }
} 
Para as interfaces restantes, ISetorServico e IGerenciamentoServico, criaremos as classes de implementações como mostram as listagens a baixo seguindo o mesmo conceito.
using System;
using System.Collections.Generic;
using SpringNET.Exemplo.Servicos.Interfaces;
using SpringNet.Exemplo.Persistencia.Interfaces;
using SpringNet.Exemplo.Objetos;  
namespace SpringNET.Exemplo.Servicos.Implementacoes
{
    public class SetorServicoImpl : ISetorServico
    { 
        private ISetorDAO setorDAO; 
        public ISetorDAO SetorDAO
        {
            get
            {
                return setorDAO;
            }
            set
            {
                setorDAO = value;
            }
        } 
        public void Salvar(SetorVO setor)
        {
            setorDAO.Salvar(setor);
        } 
        public void Atualizar(SetorVO setor)
        {
            setorDAO.Atualizar(setor);
        } 
        public void Deletar(int idSetor)
        {
            setorDAO.Deletar(idSetor);
        } 
        public SetorVO BuscaPorId(int id)
        {
            return setorDAO.BuscaPorId(id);
        } 
        public List<SetorVO> BuscarSetores()
        {
            return setorDAO.BuscarSetores();
        }
    }
} 
using System;
using System.Collections.Generic;
using SpringNET.Exemplo.Servicos.Interfaces;
using SpringNet.Exemplo.Persistencia.Interfaces;
using SpringNet.Exemplo.Objetos; 
namespace SpringNET.Exemplo.Servicos.Implementacoes
{
    public class GerenciamentoServicoImpl : IGerenciamentoServico
    {
        private IGerenciamentoDAO gerenciamentoDAO; 
        public IGerenciamentoDAO GerenciamentoDAO
        {
            get
            {
                return gerenciamentoDAO;
            }
            set
            {
                gerenciamentoDAO = value;
            }
        } 
        public void Salvar(GerenciamentoVO gerenciamento)
        {
            gerenciamentoDAO.Salvar(gerenciamento);
        } 
        public void Deletar(GerenciamentoVO gerenciamento)
        {
            gerenciamentoDAO.Deletar(gerenciamento);
        } 
        public List<GerenciamentoVO> BuscarFuncionarios(int idSetor)
        {
            return gerenciamentoDAO.BuscarFuncionarios(idSetor);
        }
    }
} 


Nossa camada de serviço está devidamente pronta e consumindo a camada de persistência corretamente, caso haja necessidade de criar regras de negócio, realizar validações em dados, tratamentos de exceções, este é o momento, deixe tudo implementado nesta camada, pois ela é a responsável por gerenciar tais regras de negócio, mantendo assim seu código limpo e organizado. Em caso de posterior manutenção, outro programador, por exemplo, conseguirá realizar sem perca de tempo e sem muitas dificuldades.

 

Camada de Apresentação


Iniciaremos agora o desenvolvimento da parte final do nosso sistema, criando a camada de apresentação de dados, e configurando nosso arquivo XML, cujo qual o Spring.net criará nossos contextos.
Adicionaremos então um projeto do tipo ASP.NET Web Application, esta, já vem com algum layout configurado para nós, vamos aproveitar. Iremos agora adicionar referências aos projetos Objetos e Serviços apenas, já que a camada de apresentação não precisa enxergar a camada de persistência, e por parte do Spring.net, vamos precisar dos assemblies Spring.Web, Spring.Core e Spring.AOP. Feito isso iremos adicionar os formulários para cadastro de funcionário, setor e um formulário para gerenciar o relacionamento entre eles.
Vamos acrescentar ao projeto, um Web Form using Master Page responsável por efetuar cadastros de funcionários.Podemos utilizar a Master Page padrão que já veio criada com o projeto. Deixe o design do form criado como mostra a figura 3.


imageFigura 3 – Layout do formulário de cadastro de funcionários.
 
A seguir crie os formulários para cadastro de setor e gerenciamento como mostram as figuras 4 e 5 respectivamente.


image
Figura 4 – Layout do formulário de cadastro de setores.


image
Figura 5 – Layout do formulário de gerenciamento.


Após a criação dos formulários, vamos acessar a nossa Master Page padrão e acessar as propriedades do controle Menu. Clicando na propriedade Items, acesse a coleção. Abrirá um pop up com dois itens adicionados: Home e About. Clique em “Add a root item” e adicione um item com as propriedades Text = Funcionário e NavigateUrl associe ao formulário CadFuncionario.aspx criado anteriormente, é desta forma que ao clicar no menu do item a página será redirecionada ao formulário de funcionários, como mostra a figura 6.

image
Figura 6 – Adição de uma nova opção para o menu.


Adicione mais dois itens seguindo os passos descritos anteriormente, sendo um para Setor e outro para Gerenciamento, associando aos seus respectivos formulários. Neste momento o escopo de seu projeto deve estar conforme figura 7.Antes de iniciarmos o desenvolvimento das funcionalidades dos formulários, vamos configurar o contexto do Spring.net.

EscopoProjeto1 Figura 7 – Escopo do projeto.

 

Configuração do Container


O nosso Web.config conterá todas as informações que o Spring.web necessita para carregar os contextos e realizar a injeção de dependência, mas antes, precisaremos realizar algumas modificações pertinentes a integração do framework com o runtime do ASP.NET.
O Spring.Web necessita da configuração de um manipulador de páginas e requisições web chamado PageHandlerFactory, responsável por gerenciar qualquer solicitação HTTP da aplicação. Se você chegou até aqui e imaginou que iria carregar o contexto dos objetos da aplicação utilizando a interface IApplicationContext se enganou. Você pode muito bem sair de classe em classe nos seus formulários fazendo isso, porém, em uma aplicação web, utiliza-se o arquivo XML Web.config para configurar o container IoC (Inversão de Controles) e realizar o seu “instanciamento” da seguinte forma: dentro da tag system.web insira o código a seguir.
<httpModules>
  <add name="Spring" type="Spring.Context.Support.WebSupportModule, Spring.Web"/>
</httpModules> 
<httpHandlers>
  <add verb="*" path="*.aspx" type="Spring.Web.Support.PageHandlerFactory, Spring.Web" />
</httpHandlers> 


Na tag httpHandlers estamos dizendo a nossa aplicação que toda requisição vinda de um arquivo com extensão .aspx será gerenciado pelo PageHandleFactory do Spring.net, e desta forma injetando as dependências necessárias. A tag httpModules definide que agora conterá mais um módulo raiz que corresponderá às configurações web exclusivas do Spring.net.
Vamos agora definir alguns manipuladores de seção que conterão os objetos pré-instanciados, onde no momento da subida da aplicação é feita a injeção de dependência desses objetos em nossos formulários. Criaremos então dentro da tag configSections os elementos context e objects, necessários em nossas configurações conforme listagem a seguir.
<configSections>
  <sectionGroup name="spring">
    <section name="context" type="Spring.Context.Support.WebContextHandler, Spring.Web"/>
    <section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core" />
  </sectionGroup>
</configSections> 


A seção context é a responsável por informar a localização dos recursos que contém os objetos configurados. Em nosso exemplo faremos esta configuração no próprio Web.config. Porém, poderíamos neste caso informar uma URL, ou arquivos XML localizados em cada camada do projeto. A seção objects compreende a lista de objetos que serão injetados no momento da inversão de controle. Em nosso exemplo como estamos programando contra interfaces, todas as assinaturas dos projetos de persistência e serviços serão configurados nesta tag.
Segue o código para configuração das novas seções criadas, note que elas estão dentro da nova raiz criada anteriormente: <spring>.
<objects
      xmlns="http://www.springframework.net"
      xmlns:tx="http://www.springframework.net/tx"
      xmlns:db="http://www.springframework.net/database">

      <object id="transactionManager" type="Spring.Data.Core.AdoPlatformTransactionManager, Spring.Data">
        <property name="DbProvider" ref="DbProvider"/>
      </object>

      <tx:attribute-driven transaction-manager="transactionManager" />

      <db:provider id="DbProvider"
                   provider="SqlServer-2.0"
                   connectionString="server=RAMON-PC;user=sa;pwd=321;initial catalog=SpringNet.Exemplo"  />

      <object id="adoTemplate" type="Spring.Data.Generic.AdoTemplate, Spring.Data">
        <property name="DbProvider" ref="DbProvider" />
      </object>

      <object id="IFuncionarioDAO" type="SpringNet.Exemplo.Persistencia.Implementacoes.AdoFuncionarioDAOImpl, SpringNet.Exemplo.Persistencia" >
        <property name="AdoTemplate" ref="adoTemplate" />
      </object>

      <object id="ISetorDAO" type="SpringNet.Exemplo.Persistencia.Implementacoes.AdoSetorDAOImpl, SpringNet.Exemplo.Persistencia" >
        <property name="AdoTemplate" ref="adoTemplate" />
      </object>

      <object id="IGerenciamentoDAO" type="SpringNet.Exemplo.Persistencia.Implementacoes.AdoGerenciamentoDAOImpl, SpringNet.Exemplo.Persistencia" >
        <property name="AdoTemplate" ref="adoTemplate" />
      </object>

      <object id="IFuncionarioServico" type="SpringNET.Exemplo.Servicos.Implementacoes.FuncionarioServicoImpl, SpringNET.Exemplo.Servicos">
        <property name="FuncionarioDAO" ref="IFuncionarioDAO" />
      </object>

      <object id="ISetorServico" type="SpringNET.Exemplo.Servicos.Implementacoes.SetorServicoImpl, SpringNET.Exemplo.Servicos">
        <property name="SetorDAO" ref="ISetorDAO" />
      </object>

      <object id="IGerenciamentoServico" type="SpringNET.Exemplo.Servicos.Implementacoes.GerenciamentoServicoImpl, SpringNET.Exemplo.Servicos">
        <property name="GerenciamentoDAO" ref="IGerenciamentoDAO" />
      </object>

      <object type="~/CadFuncionario.aspx">
        <property name="Servico" ref="IFuncionarioServico"/>
      </object>

      <object type="~/CadSetor.aspx">
        <property name="Servico" ref="ISetorServico"/>
      </object>

      <object type="~/CadGerenciamento.aspx">
        <property name="GerenciamentoServico" ref="IGerenciamentoServico"/>
        <property name="FuncionarioServico" ref="IFuncionarioServico"/>
        <property name="SetorServico" ref="ISetorServico"/>
      </object>

    </objects>

    <context>
      <resource uri="config://spring/objects"/>
    </context>


Aqui nós temos todos os objetos necessários para o funcionamento correto de nossa aplicação, utilizando injeção de dependência e com baixo acoplamento entre as camadas. O nome dos ids de cada objeto foi dado de forma a melhorar o entendimento da declaração dos mesmos, caso o desenvolvedor necessite alterar o nome dos ids, isso não implicará no funcionamento do sistema, desde que suas referências, assemblies e namespaces estejam corretos. Ao abrir a tag objects, observa-se 3 xmlns, que nada mais são do que esquemas xmls de configuração do Spring.net correspondente a objetos, transações e banco de dados respectivamente, sendo que se houver necessidade, o desenvolvedor pode criar seus próprios esquemas personalizados.
Nos primeiros objetos criados, transactionManager, que corresponde ao manipulador de transações com a base de dados, dizemos que este entende uma propriedade chamada DbProvider. Este DbProvider possui as definições necessárias para que nós possamos nos conectar a uma base qualquer e realizar todos os tipos de transações. Este é um ponto forte do Spring.net, é aqui que definimos qual banco iremos utilizar, caso haja uma mudança no banco de dados a ser utilizado, basta apenas alterar o provider e a aplicação continuará rodando sem maiores problemas. Caso o seu Web.config venha configurado uma tag connectionString, pode deletar esta e fazer utilização apenas do DbProvider.
O próximo objeto a ser configurado, é o adoTemplate, este é do tipo Spring.Data.Generic.AdoTemplate do assemblie Spring.Data. Ele nos é familiar já que temos nas classes de persistência suas referências. No momento da injeção de dependência, esta referência irá atuar fazendo a ligação entre o DbProvider e a classe genérica do Spring.Data, e note que a seguir todas os objetos de persistência (IFuncionarioDAO, ISetorDAO e IGerenciamentoDAO) referenciam este objeto, pois ele, como já mencionado, é o responsável por gerenciar as transações com a base. Os objetos IFuncionarioServico, ISetorServico e IGerenciamentoServico possuem cada um uma propriedade, os quais foram definidos em suas assinaturas. O nome e a referência (tipo) devem ser os mesmos definidos na interface, pois será nestas propriedades que ocorrerão as injeções de dependência. E por último, seguindo o mesmo conceito dos serviços, são declarados os nossos formulários, relacionando cada um com sua respectiva propriedade. Estas propriedades também devem estar declaradas.
E por fim, com o container IoC do Spring.net configurado, basta agora apenas realizar a codificação de nossos formulários. A primeira alteração a realizar nos 3 formulários e muito importante, é a herança das páginas, onde não será mais herdada de System.Web.UI, e sim de Spring.Web.UI, este assemblie agora será o responsável por gerenciar as nossas páginas web. Esta alteração é necessária, pois caso contrário o Spring.net não conseguirá reconhecer uma página aspx e não injetará nossas dependências completamente. Começaremos com o formulário de cadastro de funcionário, onde ao carregar a página o controle GridView deve listar todos os funcionários, caso tenhamos algum cadastrado. Não podemos esquecer-nos de criar a propriedade que definimos em nosso Web.config, responsável por receber a injeção de dependência.
        private IFuncionarioServico servico;
        private FuncionarioVO funcionario; 
        public IFuncionarioServico Servico
        {
            set { servico = value; }
        }
Nossa propriedade “Servico” foi criada, apenas com um operador set para ser injetado o objeto correspondente. A partir de agora, é programação básica, todos os nossos métodos de persistência que precisamos podem ser invocados através da variável “servico”, e sem grandes dificuldades, implementar o restante das funcionalidades do sistema, observe:
        protected void Page_Load(object sender, EventArgs e)
        {
            CarregarFuncionarios();
        } 
        private void CarregarFuncionarios()
        {
            List<FuncionarioVO> listaFuncionarios = servico.BuscarFuncionarios(); 
            this.grdFuncionarios.DataSource = listaFuncionarios;
            this.grdFuncionarios.DataKeyNames = new string[] { "IDFUNCIONARIO" };
            this.grdFuncionarios.DataBind();
        } 
        protected void grdFuncionarios_SelectedIndexChanged(object sender, EventArgs e)
        {
            int idFuncionario = Convert.ToInt32(this.grdFuncionarios.SelectedDataKey["IDFUNCIONARIO"]);
            FuncionarioVO funcionario = servico.BuscarPorId(idFuncionario); 
            this.txtNome.Text = funcionario.Nome;
            this.txtCpf.Text = funcionario.Cpf;
            this.txtRg.Text = funcionario.Rg;
            this.txtSexo.Text = funcionario.Sexo;
            this.txtDataNascimento.Text = (funcionario.DataNascimento).ToString();
            this.txtCargo.Text = funcionario.Cargo;
        } 
        protected void btnAtualizar_Click(object sender, EventArgs e)
        {
            funcionario = new FuncionarioVO(); 
            funcionario.IdFuncionario = Convert.ToInt32(this.grdFuncionarios.SelectedDataKey["IDFUNCIONARIO"]);
            funcionario.Nome = (this.txtNome.Text).ToString();
            funcionario.Cpf = (this.txtCpf.Text).ToString();
            funcionario.Rg = (this.txtRg.Text).ToString();
            funcionario.Sexo = (this.txtSexo.Text).ToString();
            funcionario.DataNascimento = Convert.ToDateTime(this.txtDataNascimento.Text);
            funcionario.Cargo = (this.txtCargo.Text).ToString(); 
            servico.Atualizar(funcionario);
            CarregarFuncionarios();
        } 
        protected void btnCadastrar_Click(object sender, EventArgs e)
        {
            funcionario = new FuncionarioVO(); 
            funcionario.Nome = (this.txtNome.Text).ToString();
            funcionario.Cpf = (this.txtCpf.Text).ToString();
            funcionario.Rg = (this.txtRg.Text).ToString();
            funcionario.Sexo = (this.txtSexo.Text).ToString();
            funcionario.DataNascimento = Convert.ToDateTime(this.txtDataNascimento.Text);
            funcionario.Cargo = (this.txtCargo.Text).ToString(); 
            servico.Salvar(funcionario);
            CarregarFuncionarios();
            LimparCampos();
        } 
        protected void btnDeletar_Click(object sender, EventArgs e)
        {
            int idFuncionario = Convert.ToInt32(this.grdFuncionarios.SelectedDataKey["IDFUNCIONARIO"]);
            servico.Deletar(idFuncionario);
            CarregarFuncionarios();
            LimparCampos();
        } 
        private void LimparCampos()
        {
            this.txtNome.Text = "";
            this.txtCpf.Text = "";
            this.txtRg.Text = "";
            this.txtSexo.Text = "";
            this.txtDataNascimento.Text = "";
            this.txtCargo.Text = "";
        } 


Segue implementação das funcionalidades do formulário de cadastro de Setor. Note que a propriedade a qual receberá a injeção de dependência do contexto foi criada igualmente como no arquivo de configuração, é importante atentar para este detalhe, caso contrário a injeção de dependência não ocorrerá e uma exceção será disparada.
        private SetorVO setor;
        private ISetorServico servico; 
        public ISetorServico Servico
        {
            set { servico = value; }
        } 
        protected void Page_Load(object sender, EventArgs e)
        {
            CarregarSetores();
        } 
        private void CarregarSetores()
        {
            List<SetorVO> listaSetores = servico.BuscarSetores(); 
            this.grdSetores.DataSource = listaSetores;
            this.grdSetores.DataKeyNames = new string[] { "IDSETOR" };
            this.grdSetores.DataBind();
        } 
        protected void grdSetores_SelectedIndexChanged(object sender, EventArgs e)
        {
            int idSetor = Convert.ToInt32(this.grdSetores.SelectedDataKey["IDSETOR"]);
            SetorVO setor = servico.BuscaPorId(idSetor); 
            this.txtNome.Text = setor.Nome;
            this.txtQuantTotal.Text = setor.QuantTotal.ToString();
            this.txtDescricao.Text = setor.Descricao;
        } 
        protected void btnAtualizar_Click(object sender, EventArgs e)
        {
            setor = new SetorVO(); 
            setor.IdSetor = Convert.ToInt32(this.grdSetores.SelectedDataKey["IDSETOR"]);
            setor.Nome = this.txtNome.Text;
            setor.QuantTotal = Convert.ToInt32(this.txtQuantTotal.Text);
            setor.Descricao = this.txtDescricao.Text; 
            servico.Atualizar(setor);
            CarregarSetores();
        } 
        protected void btnCadastrar_Click(object sender, EventArgs e)
        {
            setor = new SetorVO();
            setor.Nome = (this.txtNome.Text).ToString();
            setor.QuantTotal = Convert.ToInt32(this.txtQuantTotal.Text);
            setor.Descricao = (this.txtDescricao.Text).ToString(); 
            servico.Salvar(setor);
            CarregarSetores();
            LimparCampos();
        } 
        protected void btnDeletar_Click(object sender, EventArgs e)
        {
            int idSetor = Convert.ToInt32(this.grdSetores.SelectedDataKey["IDSETOR"]);
            servico.Deletar(idSetor);
            CarregarSetores();
            LimparCampos();
        } 
        private void LimparCampos()
        {
            this.txtNome.Text = "";
            this.txtQuantTotal.Text = "";
            this.txtDescricao.Text = "";
        } 


A última parte de nossos formulários será implementada a seguir, as funcionalidades para gerenciamento. Na configuração de nosso arquivo XML, adicionamos 3 propriedades para o objeto CadGerenciamento.aspx. Poderíamos acrescentar quantas mais quiséssemos desde que seja respeitado seu nome e referencia.
        GerenciamentoVO gerenciamento; 
        IGerenciamentoServico gerenciamentoServico; 
        public IGerenciamentoServico GerenciamentoServico
        {
            set { gerenciamentoServico = value; }
        } 
        ISetorServico setorServico; 
        public ISetorServico SetorServico
        {
            set { setorServico = value; }
        } 
        IFuncionarioServico funcionarioServico; 
        public IFuncionarioServico FuncionarioServico
        {
            set { funcionarioServico = value; }
        } 
        protected void Page_Load(object sender, EventArgs e)
        {
            if (!Page.IsPostBack)
            {
                CarregarSetores();
                CarregarGerenciamento();
                CarregarFuncionarios();
            }
        } 
        private void CarregarSetores()
        {
            List<SetorVO> listaSetores = setorServico.BuscarSetores(); 
            this.ddlSetores.DataSource = listaSetores;
            this.ddlSetores.DataTextField = "NOME";
            this.ddlSetores.DataValueField = "IDSETOR";
            this.ddlSetores.DataBind();
            this.ddlSetores.SelectedIndex = 0;
        } 
        private void CarregarGerenciamento()
        {
            if (this.ddlSetores.SelectedValue != string.Empty)
            {
                int idSetor = Convert.ToInt32(this.ddlSetores.SelectedValue);
                List<GerenciamentoVO> listaFuncionarios = gerenciamentoServico.BuscarFuncionarios(idSetor); 
                this.grdFuncionarios.DataSource = listaFuncionarios;
                this.grdFuncionarios.DataKeyNames = new string[] { "IDSETOR", "IDFUNCIONARIO" };
                this.grdFuncionarios.DataBind();
            }
        } 
        private void CarregarFuncionarios()
        {
            List<FuncionarioVO> listaFuncionarios = funcionarioServico.BuscarFuncionarios(); 
            this.ddlFuncionarios.DataSource = listaFuncionarios;
            this.ddlFuncionarios.DataTextField = "NOME";
            this.ddlFuncionarios.DataValueField = "IDFUNCIONARIO";
            this.ddlFuncionarios.DataBind();
            this.ddlFuncionarios.SelectedIndex = 0;
        } 
        protected void grdFuncionarios_SelectedIndexChanged(object sender, EventArgs e)
        {
            gerenciamento = new GerenciamentoVO();
            gerenciamento.IdFuncionario = Convert.ToInt32(this.grdFuncionarios.SelectedDataKey["IDFUNCIONARIO"]);
            gerenciamento.IdSetor = Convert.ToInt32(this.grdFuncionarios.SelectedDataKey["IDSETOR"]); 
            gerenciamentoServico.Deletar(gerenciamento);
            CarregarGerenciamento();
        } 
        protected void ddlSetores_SelectedIndexChanged(object sender, EventArgs e)
        {
            CarregarGerenciamento();
        } 
        protected void btnSalvar_Click(object sender, EventArgs e)
        {
            gerenciamento = new GerenciamentoVO();
            gerenciamento.IdSetor = Convert.ToInt32(this.ddlSetores.SelectedValue);
            gerenciamento.IdFuncionario = Convert.ToInt32(this.ddlFuncionarios.SelectedValue);
            gerenciamento.Funcionario = (this.ddlFuncionarios.SelectedItem).ToString(); 
            gerenciamentoServico.Salvar(gerenciamento);
            CarregarGerenciamento();
        } 


Pronto. Basta agora adicionar alguns Breakpoints nas propriedades das páginas e visualizar como é feita a injeção no momento em que a página é carregada, sem necessidade de instanciamento da camada de serviço. Certifique-se de que o projeto Web seja o projeto principal da solução e a página Default.aspx esteja como página inicial.
 

Conclusão


Chegamos ao fim deste artigo, e gostaria de abordar alguns pontos fortes do framework. Usar Spring.net por usar, não é aconselhável, tenha em mente quais qualidades este framework pode lhe oferecer, muitos citados neste artigo, e analisar cuidadosamente se ao invés de solucionar seus problemas, não resultará em muitas dores de cabeça a sua utilização. O Spring.net é capaz de lhe facilitar muito a vida se seu produto necessita ser desenvolvido com baixo acoplamento, mas além deste, existem muitos outros frameworks capazes de auxiliar nesta tarefa. Pudemos comprovar a facilidade que o Spring.net nos oferece quanto a Inversão de Controles, para conseguirmos realizar a injeção de dependência em nossas páginas Web apenas na utilização de um arquivo XML de configuração. Os sistemas de informação hoje crescem de forma muito rápida, exigindo da equipe de desenvolvimento técnicas para suprir esta rapidez, onde realizar alterações em um arquivo XML é bem mais ágil do que alterar suas classes.
Neste artigo foi realizado apenas uma introdução ao framework Spring.net, recomendo ao leitor aprofundar mais seus conhecimentos e descobrir as muitas outras funcionalidades disponibilizadas por esta tecnologia, como por exemplo, funções de Logging, Unit Tests, auxílio na construção de Web Services, Serviços Windows, WCF, MSMQ, entre muitos outros. Basta conferir na referência do Spring.net que pode ser encontrado no site oficial, ou então pesquisar na web. Acredito que a comunidade está bastante forte e disposta a contribuir com profissionais que desejam aderir ao Spring.net.

8 comentários:

  1. Parabéns tio Zacka!!
    Artigo muito bom!

    Só fiquei com uma dúvida... Por que você não usou o objeto GerenciamentoVO nas classes de gerenciamento?
    Pois pensei no caso de se, por acaso, tiver que incluir um novo campo no objeto GerenciamentoVO, você terá que alterar as interfaces... E se as interfaces usassem o objeto, isso não seria necessário...


    Valeu!
    Parabéns!
    Não sabia que ele lidava com página web tão fácil! :P

    ResponderExcluir
  2. Boa Noite caro Ricardo.

    Obrigado pelos elogios e pela sugestão.
    Sim, pode-se usar unicamente o objeto GerenciamentoVO, veja como ficou o código com a sua sugestão. Não tinha atentado a este detalhe pois dei mais ênfase a utilização do Spring.net.
    Mas concerteza ficaria muito mais fácil para uma posterior alteração.

    Obrigado, e até mais.

    ResponderExcluir
  3. olha aí muito bom cara, parabens tio Zacka!! ta matando no Spring.net heim iuhieuheiuheiuee

    flw Abraço

    Junior Alvarino.

    ResponderExcluir
  4. Este comentário foi removido pelo autor.

    ResponderExcluir
  5. Boa Tarde Ramon.

    Ótimo Post muito bem explicado, só que estou com um problema, poís estou tentando implementar o Spring.Net junto com NHibernate e MVC 3 e não estou conseguindo adaptar o seu exemplo com NHibernate se vc tiver algum exemplo manda pra min ou cira um post ai pra gente creio que tem varias pessoas com o meu mesmo problema.

    Desde já agradeço a atenção.

    meu email é: alex.master.ti@gmail.com

    ResponderExcluir
  6. Boa Tarde Ramon.

    Como já foi dito anteriormente estou tentando implementar o Spring com Asp.Net MVC 3 e NHibernate, mas estou com o seguinte erro no meu Web.config :

    Error creating context 'spring.root': Could not load type 'SpringNet.NHibernate.Fluent.Persistencia.Implementacoes.GenericDAO' from assembly 'SpringNet.NHibernate.Fluent.Persistencia, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.

    Se poder me ajudar agradeço.

    ResponderExcluir