Durante um projeto encontramos com o seguinte problema:
1 – As camadas da aplicação são divididas em projetos separados para facilitar o versionamento e o reuso em outros projetos e devido ao núcleo (Camadas até a classe de serviços) ser utilizado por várias interfaces (desktop, mobile, web).
2 – Como as camadas geravam class libraries (DLL) , o cliente exigia que as mesmas ficassem em um servidor de Componetes.
3 – O uso deste servidor era primordial, uma vez que o servidor da aplicação não tinha acesso ao servidor de Banco de dados
4 – A aplicação já estava desenvolvida, portanto readaptar o sistema para utilizar tudo baseado em Web Services, não era uma opção
Solução: A melhor solução encontrada foi o uso do Remoting, porém encontramos várias barreiras, pois a nossa camada de persistência utilizava muitos generics.
Conseguimos implementar a solução de Remoting ligando a camada de serviços à camada de interface e posto a seguir um exemplo da solução:
Para isto vamos considerar as seguintes classes no lado do Servidor de Componentes:
Classe de Domínio: Usuário – dentro de uma class library
namespace Dominio
{
public class Usuario
{
private Double dblCodigo;
public Double codigo
{
get { return dblCodigo; }
set { dblCodigo = value; }
}
private String strNome;
public String nome
{
get { return strNome; }
set { strNome = value; }
}
private String strLogin;
public String login
{
get { return strLogin; }
set { strLogin = value; }
}
private String strSenha;
public String senha
{
get { return strSenha; }
set { strSenha = value; }
}
}
}
Classe de Serviço – Class Library
namespace Servico
{
public class UsuarioListagem : MarshalByRefObject, InterfaceRemoting.IUsuarioListagem
{
///
/// Retorna um datatable com uma lista de Usuários
///
public DataTable Listar()
{
Manager manager = new Manager();
IList<Usuario> lstUsuario = null;
//Chamada à persistenca para a listagem de usuários, esta retorna uma lista de usuários (Ilist
lstUsuario = manager.Persistencia.usuario.listar();
DataTable dtUsuario = new DataTable("USUARIO");
dtUsuario.Columns.Add("codigo");
dtUsuario.Columns.Add("nome");
dtUsuario.Columns.Add("login");
dtUsuario.Columns.Add("senha");
foreach (Usuario objUsuario in lstUsuario)
{
DataRow linhaUsuario = dtUsuario.NewRow();
linhaUsuario["codigo"] = objUsuario.codigo.ToString();
linhaUsuario["nome"] = objUsuario.nome.ToString();
linhaUsuario["login"] = objUsuario.login.ToString();
linhaUsuario["senha"] = objUsuario.senha.ToString();
dtUsuario.Rows.Add(linhaUsuario);
}
return dtUsuario;
}
}
}
Servidor Remoting – Console Application (podendo ser um Windows service)
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
using System.Runtime.Serialization.Formatters.Binary;
using Servico;
using System.Globalization;
using System.Threading;
namespace Server
{
class Class1
{
//[STAThread]
static void Main(string[] args)
{
try
{
RemotingConfiguration.Configure("Server.config");
RemotingConfiguration.CustomErrorsMode = CustomErrorsModes.Off;
Console.WriteLine("Servidor de Remoting Inciado");
//Esta instrução deve ser repetida para cada classe de Serviço
RemotingConfiguration.RegisterWellKnownServiceType(typeof(UsuarioListagem), typeof(UsuarioListagem).ToString(), WellKnownObjectMode.SingleCall);
foreach (WellKnownServiceTypeEntry teste in RemotingConfiguration.GetRegisteredWellKnownServiceTypes())
{
Console.WriteLine("Servidor inciado: nome - tipo: " + teste.ObjectUri.ToString() + " - " + teste.TypeName.ToString());
}
Console.ReadLine();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
}
xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.runtime.remoting>
<application>
<channels>
<channel ref="tcp" port="80">
<clientProviders>
<formatter ref="binary"/>
clientProviders>
channel> />
channels>
application>
system.runtime.remoting>
<system.web>
<globalization culture="pt-BR" uiCulture="pt-BR"/>
system.web>
configuration>
Agora para o lado da interface, deve ser criada uma interface para o serviço:
using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
namespace InterfaceRemoting
{
public interface IUsuarioListagem
{
DataTable Listar();
}
}
Dentro da interface, para “carregar” a interface com o objeto do domínio utilizamos da seguinte forma:
using InterfaceRemoting;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels.Tcp;
…
IUsuarioListagem objIUsuarioListagem = (IUsuarioListagem)Activator.GetObject(typeof(IUsuarioListagem), ConfigurationManager.AppSettings["ServicoUsuarioListagem"].ToString());
Assim conseguimos consumir o objIUsuarioListagem.Listar()
OBS: Somente conseguimos utilizar o remoting para métodos do serviço, não conseguimos implemtar para propriedades, pois estas não são automaticamente modificadas na interface quando modificadas dentro do serviço
Reiterando, para publicar essa solução criamos um programinha batch que ficava "escutando" no servidor a chamada da aplicação. Porém a forma solicitada pelo Cliente e com certeza mais elegante foi a criação de um Windows Service.
ResponderExcluirRealmente Remoting é uma solução muito interessante.
Olá Danilo,
ResponderExcluirBoa solução. Prática, rápida e exigindo pouquíssima alteração.
No caso de utilizar SOAP, seria o mesmo trabalho, não? Apenas alterar o cliente para referenciar a interface de serviço ao invés da classe.
O problema maior da utilização de SOAP neste caso... seria ter que criar as interfaces, e não o trabalho para consumi-las
ResponderExcluir