Atualmente, e cada vez mais, tem se observado a necessidade de diferentes aplicações interagirem, enviando e recebendo dados em diversos formatos. E é exatamente neste ponto que muitos esbarram, por não conhecerem ou utilizarem um formato que possa ser aproveitado por diversos tipos de sistema, independente da linguagem ou plataforma em que tenham sido desenvolvidos.

Para suprir essa necessidade e facilitar essa comunicação, surgiu a XML, linguagem de representação de dados que se apresentou como uma solução multiplataforma, independente de IDE ou linguagem de programação. A XML organiza os dados em tags, definindo elementos e atributos delimitados pelos caracteres < e >.

Hoje, praticamente todas (senão todas) as linguagens de programação oferecem suporte à criação e leitura de arquivos XML e o .NET Framework, como não poderia deixar de ser, possui diversas classes que tornam essa tarefa bastante simples.

Neste artigo, veremos como seriailizar e deserializar objetos para e do formato XML utilizando a linguagem C#, simulando a comunicação entre duas aplicações através da exportação e importação de arquivos nesse formato.

Entendendo a Serialização

Serializar um objeto significa criar uma representação dele em um determinado formato e com um determinado objetivo. Geralmente esse processo é utilizado, como já foi citado aqui, para exportar esses objetos em um certo formato. As formas mais comuns de serialização, pelo menos no .NET Framework, são a serialização em XML e a serialização binária.

No primeiro formato, os objetos são convertidos em representação XML, de fácil leitura e interpretação não só pelas classes do framework, como também por qualquer pessoa que tenha acesso ao arquivo/código XML gerado e tenha algum conhecimento sobre esse tipo representação.

Na serialização binária, por sua vez, os objetos são convertidos para uma representação em bits, que geralmente não é possível de ser lida por humanos. Caso se deseje maior sigilo na exportação dos objetos, a serialização binária pode ser mais adequada.

Neste artigo utilizaremos a serialização XML, de forma que possamos analisar a estrutura do XML gerado ao serializar um objeto.

Serialização XML no .NET Framework

No .NET Framework contamos com a classe XmlSerializer, que encontra-se no namespace System.Xml.Serialization e, para o escopo deste artigo, possui dois métodos de maior relevância:

  • Serialize: este método recebe o objeto a ser serializado e o stream que representa e controla o arquivo onde o objeto serializado será salvo. Apesar de possuir 8 sobrecargas, apenas a primeira delas será utilizada neste artigo.
  • Deserialize: funcionando de forma inversa ao anterior, este método recebe um stream que representa e referencia o arquivo a ser lido, que depois de desserializado, gerará um retorno do tipo object. Geralmente será necessário efetuar o cast desse objeto para o tipo esperado, como veremos mais adiante.

Criando a aplicação de exemplo

Para o exemplo que será desenvolvido aqui, utilizaremos uma aplicação do tipo Console, para que possamos concentrar a atenção no processo de serialização sem se preocupar com interface.

Nossa aplicação simulará um pequeno cadastro de clientes onde o usuário terá duas opções:

  • Cadastrar cliente: nesta opção ele informará os dados do cliente e exportará o objeto criado para um arquivo XML.
  • Importar cadastro: aqui o usuário poderá importar um arquivo XML com o cadastro de um cliente e visualizar seus dados na tela.

Então, após criar uma Console Application, o primeiro passo será criar a classe Cliente, que ficará responsável por serializar e deserializar objetos desse mesmo tipo.

O código dessa classe é apresentado na Listagem 1.

Listagem 1: Classe Cliente

public class Cliente
{
    public string Nome { get; set; }
    public string Email { get; set; }

    public bool Exportar(string caminho)
    {
        try
        {
            FileStream stream = new FileStream(caminho, FileMode.Create);
            XmlSerializer serializador = new XmlSerializer(typeof(Cliente));
            serializador.Serialize(stream, this);
            return true;
        }
        catch
        {
            return false;
        }
    }

    public static Cliente Importar(string caminho)
    {
        try
        {
            FileStream stream = new FileStream(caminho, FileMode.Open);
            XmlSerializer desserializador = new XmlSerializer(typeof(Cliente));
            Cliente cliente = (Cliente)desserializador.Deserialize(stream);
            return cliente;
        }
        catch
        {
            return null;
        }
    }
}

Para manter a simplicidade do exemplo e foco do artigo, esta classe possui apenas duas propriedades e dois métodos, um para serializar e outro para deserializar o objeto.

Em ambos os métodos o caminho do arquivo é recebido como parâmetro, mas no primeiro este caminho será utilizado para criar o arquivo, enquanto no segundo ele será utilizado para ler o arquivo já existente.

Nos dois métodos também foi criado um objeto do tipo XmlSerialializer, responsável por exportar e importar o objeto. No constructor dessa classe informamos o tipo com o qual ele trabalhará, que neste caso é a classe Cliente. Tal informação é necessária para que o XmlSerializer saiba como representar o objeto quando exportá-lo e como efetuar sua leitura no processo de deserialização.

No método Exportar passamos como parâmetro para o método Serialize, além do FileStream criado, o próprio objeto que invoca o método (através da palavra reservada this).

Já no método Importar, passamos apenas o FileStream como para a função Deserialize, porém, foi necessário efetuar o cast do retorno deste método para o tipo com o qual estamos trabalhando.

Agora podemos partir para o método Main da aplicação e escrever o código principal da aplicação, que trata da interação com o usuário, conforme a Listagem 2.

Listagem 2: Código do método Main da aplicação

static void Main(string[] args)
{
    while (true)
    {
        Console.WriteLine("--------------------");
        Console.WriteLine("Escolha uma opção (digite o número correspondente):");
        Console.WriteLine("1 - CADASTRAR CLIENTE 2 - IMPORTAR CADASTRO; 0 - SAIR");
        Console.WriteLine("--------------------");
        string opc = Console.ReadLine();
        switch (opc)
        {
            case "1":
                Cliente novoCliente = new Cliente();
                Console.Write("Nome: ");
                novoCliente.Nome = Console.ReadLine();
                Console.Write("Email: ");
                novoCliente.Email = Console.ReadLine();
                Console.WriteLine("Informe o caminho do arquivo para exportar o
cadastro do cliente:");
                string caminhoExportacao = Console.ReadLine();
                if(novoCliente.Exportar(caminhoExportacao))
                    Console.WriteLine("Cadastro exportado com sucesso.");
                break;
            case "2":
                Console.WriteLine("Informe o caminho do arquivo para importar o
cadastro do cliente:");
                string caminhoImportacao = Console.ReadLine();
                Cliente cliente = Cliente.Importar(caminhoImportacao);
                if (cliente != null)
                {
                    Console.WriteLine("Nome: " + cliente.Nome);
                    Console.WriteLine("Email: " + cliente.Email);
                }                        
                break;
            default:
                return;  
        }
    }
}

Caso o usuário escolha a opção 1, ele será solicitado a preencher as informações do cliente e definir o caminho do arquivo no qual será salvo o objeto serializado no formato XML. Esta operação pode ser vista na Figura 1.

Conteúdo do arquivo XML gerado

Figura 1: Cliente cadastrado e exportado para arquivo

Podemos então abrir o arquivo que foi gerado para analisar seu conteúdo, que para o caso deste exemplo, é apresentado na Listagem 3.

Listagem 3: Conteúdo do arquivo XML gerado

<?xml version="1.0"?>
<Cliente xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <Nome>Joel</Nome>
  <Email>joelrlneto@gmail.com</Email>
</Cliente>

Vemos que são inseridas algumas inscrições padrão de namespace e versão do XML, informações que geralmente estão presentes em arquivos deste tipo. Além disso, e o que é o principal para nosso entendimento, percebemos que o objeto do tipo Cliente foi representado como uma tag Cliente com duas tags internas, Nome e Email. Essa estrutura, como fora dito acima, é bastante simples e clara, podendo ser lida com facilidade.

Agora vamos utilizar a opção de importar cadastro para deserializar este mesmo arquivo e ver se os dados são realmente lidos da forma correta. Para isso, executamos novamente a aplicação e selecionamos a opção 2, conforme ilustra a Figura 2.

Cliente cadastrado e exportado para arquivo

Figura 2: Objeto importado do arquivo XML

Como vemos, o arquivo foi importado corretamente e nosso objeto Cliente foi desserializado da forma esperada, tendo seus campos preenchidos com os valores salvos no arquivo XML.

Aqui não foi feito tratamento de erros, de forma a não estender desnecessariamente o código, mas isso pode ser feito facilmente nos métodos Exportar e Importar.

Conclusão

A serialização de objetos em formato XML é um processo bastante simples de ser executado, tudo graças à facilidade que o .NET Framework nos oferece para efetuar essa e outras tarefas comuns no dia a dia.

O exemplo desenvolvido aqui é de fato simples, mas serve como base para extensão e desenvolvimento de procedimentos de exportação e importação de dados em sistemas reais. Por exemplo, é possível importar não só um objeto, como também uma coleção de objetos (utilizando a classe List, por exemplo). Basta ver a documentação da classe XmlSerializer, entender o formato XML e desenvolver suas rotinas de serialização.

Links