• Follow us on Twitter
  • Join our Facebook Group
  • Join me on Google Plus
  • Add me on Linkedin
  • RSS

  • Home
  • Séries
    • Entity Framework
    • Minhas Palestras
    • ASP .NET MVC
  • Meus Repositórios
    • CodePlex
    • GitHub

Blog - Latest News

Arquivos CSV com C# no ASP .Net MVC 4

4 Comments/ in ASP.Net / by Cleyton Ferrari
19 de fevereiro de 2013

Existem várias formas de armazenar seus dados, uma delas é utilizar arquivos CSV, que são arquivos de textos que usam algum separador para seus campos, vamos ver como consumir esses arquivos em nossa aplicação em ASP .Net MVC.

Veja uma demonstração da aplicação utilizado como exemplo em http://cid.apphb.com/

A motivação deste post veio da necessidade de importar os dados do CID (Cadastro internacional de Doenças) do DataSUS, eles fornecem os arquivos em CSV com o cadastro das Doenças catalogadas em Capítulos, Grupos, Categorias e Subcategorias, veja abaixo um pequeno trecho de um dos arquivos:

NUMCAP;CATINIC;CATFIM;DESCRICAO;DESCRABREV;
1;A00;B99;Capítulo I - Algumas doenças infecciosas e parasitárias;I.  Algumas doenças infecciosas e parasitárias;
2;C00;D48;Capítulo II - Neoplasias [tumores];II.  Neoplasias (tumores);
3;D50;D89;Capítulo III  - Doenças do sangue e dos órgãos hematopoéticos e alguns transtornos imunitários;III. Doenças sangue órgãos hemat e transt imunitár;
4;E00;E90;Capítulo IV - Doenças endócrinas, nutricionais e metabólicas;IV.  Doenças endócrinas nutricionais e metabólicas;

Reparem como funciona a estrutura dos arquivos CSV, na primeira linha temos o nome dos campos (colunas) e as demais linhas são os dados, para estes arquivos foi utilizado o “;” como separador.
Todos os demais arquivos seguem esta mesma estrutura, sabendo disto temos como fazer um parse neste arquivos e depois manipula-los em memória.

Lendo o arquivos CSV em C#

Você pode armazenar estes arquivos para a leitura em uma pasta, ou dentro do próprio projeto usando o resources, neste caso utilizei os resources.
Antes de continuar precisamos instalar um pacote do nuget chamado CsvHelper.

PM> Install-Package CsvHelper

Uma vez instalado foi criado uma classe genérica para a leitura destes arquivos

using System.Collections.Generic;
using System.IO;
using CsvHelper;
using CsvHelper.Configuration;

namespace Repositorio
{
    public class LerCsv<T> where T : class
    {
        public IEnumerable<T> Ler(string csv)
        {
            if (csv == null) return null;
            var configuracaoCsv = new CsvConfiguration { Delimiter = ";" };
            var csvReader = new CsvReader(new StringReader(csv), configuracaoCsv);
            return csvReader.GetRecords<T>();
        }
    }
}

Dentro desta classe foi criado um método Ler que recebe como parâmetro o conteúdo do arquivo CSV e retorna uma Lista de objetos que representam as linhas deste arquivo.
Uma vez criado o método genérico que fara a leitura do conteúdo do arquivo CSV qualquer objeto que for passado para este método será utilizado como estrutura que representa o arquivo CSV, para exemplificar reparem o código da classe que representa o arquivo de capítulos.csv, chamada ViewModelCapitulo.cs

public class ViewModelCapitulo
    {
        //NUMCAP: número do capítulo (em numeração arábica); se igual a zero, indica o capítulo que contém os códigos não oficialmente pertinentes à CID-10;
        [CsvField(Name = "NUMCAP")]
        public string NumeroCapitulo { get; set; }

        //CATINIC: código da primeira categoria do capítulo;
        [CsvField(Name = "CATINIC")]
        public string CategoriaInicial { get; set; }

        [CsvField(Ignore = true)]
        public int CategoriaInicialCodigo
        {
            get { return Ferramentas.TrocaLetraPorNumero(CategoriaInicial); }
        }

        //CATFIM: código da última categoria do capítulo;
        [CsvField(Name = "CATFIM")]
        public string CategoriaFinal { get; set; }

        [CsvField(Ignore = true)]
        public int CategoriaFinalCodigo
        {
            get { return Ferramentas.TrocaLetraPorNumero(CategoriaFinal); }
        }

        //DESCRICAO: descrição (nome) do capítulo; e
        [CsvField(Name = "DESCRICAO")]
        public string Descricao { get; set; }

        //DESCRABREV: descrição (nome) abreviado do capítulo, com até 50 caracteres.
        [CsvField(Name = "DESCRABREV")]
        public string DescricaoAbreviada { get; set; }
    }

Reparem que a mesma estrutura (colunas) do arquivo csv foi representada na classe usando data annotations que vem com o CsvHelper (CsvField), no exemplo a propriedade da classe “NumeroCapitulo” representa a coluna “NUNCAP” do arquivo CSV, o que significa que o valor da coluna NUNCAP será carregada para a propriedade NumeroCapitulo.
As demais propriedades seguem o mesmo modelo, exceto é claro a propriedade “CategoriaInicialCodigo” que não representa nenhuma coluna do arquivo CSV de capítulos, uma vez que foi utilizado o data annotation “[CsvField(Ignore = true)]”.

Listando os dados de um arquivo CSV em C#

Uma vez criado as classes que serão utilizadas como base para os nossos arquivos CSV, precisamos utiliza-las através do nosso método “Ler” da classe “LerCsv.cs” como mostra o código da classe abaixo.

using System.Collections.Generic;

namespace Repositorio
{
    public class Repositorio
    {
        public IEnumerable<ViewModelCapitulo> ListarCapitulos()
        {
            var recurso = Properties.Resources.CID_10_CAPITULOS;
            return new LerCsv<ViewModelCapitulo>().Ler(recurso);
        }

        public IEnumerable<ViewModelGrupo> ListarGrupos()
        {
            var recurso = Properties.Resources.CID_10_GRUPOS;
            return new LerCsv<ViewModelGrupo>().Ler(recurso);
        }

        public IEnumerable<ViewModelCategoria> ListarCategorias()
        {
            var recurso = Properties.Resources.CID_10_CATEGORIAS;
            return new LerCsv<ViewModelCategoria>().Ler(recurso);
        }

        public IEnumerable<ViewModelSubCategoria> ListarSubCategorias()
        {
            var recurso = Properties.Resources.CID_10_SUBCATEGORIAS;
            return new LerCsv<ViewModelSubCategoria>().Ler(recurso);
        }

        public IEnumerable<ViewModelGrupoCid0> ListarGruposCid0()
        {
            var recurso = Properties.Resources.CID_O_GRUPOS;
            return new LerCsv<ViewModelGrupoCid0>().Ler(recurso);
        }

        public IEnumerable<ViewModelCategoriaCid0> ListarCateogiasCid0()
        {
            var recurso = Properties.Resources.CID_O_CATEGORIAS;
            return new LerCsv<ViewModelCategoriaCid0>().Ler(recurso);
        }
    }
}

Reparem o método “ListarCapitulos” ele nos retorna uma lista (IEnumerable) de objetos da classe ViewModelCapitulo.cs, para isso foi utilizado um arquivo CSV no resources chamado “CID_10_CAPITULOS”, e o valor deste arquivo (uma string) foi passada para a nossa classe genérica “LerCsv” através do método “Ler(recurso)” o mesmo se segue para os demais arquivos CSV e métodos.

Mostrando os dados do arquivo CSV no ASP .Net MVC

Agora que temos nossa estrutura toda montada, baste chamar os métodos de nossa classe repositório dentro das actions de nossos controller em ASP .Net MVC, como mostra o código do controller Home;

using System.Linq;
using System.Web.Mvc;
using Repositorio;

namespace UI.Web.Controllers
{
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            var repositorio = new Repositorio.Repositorio();
            var capitulos = repositorio.ListarCapitulos().ToList();
            return View(capitulos);
        }

        public ActionResult Capitulo(string id)
        {
            var repositorio = new Repositorio.Repositorio();
            var capitulo = repositorio.ListarCapitulos().FirstOrDefault(x => x.NumeroCapitulo == id);
            ViewBag.capitulo = capitulo;
            var grupos = repositorio.ListarGrupos().Where(x =>
                x.CategoriaInicialCodigo >= capitulo.CategoriaInicialCodigo &&
                x.CategoriaFinalCodigo <= capitulo.CategoriaFinalCodigo
                ).ToList();
            return View(grupos);
        }

        public ActionResult Grupo(string categoriaInicial, string categoriaFinal)
        {
            var repositorio = new Repositorio.Repositorio();
            var grupo = repositorio.ListarGrupos().FirstOrDefault(x => x.CategoriaInicial == categoriaInicial && x.CategoriaFinal == categoriaFinal);
            ViewBag.grupo = grupo;
            var capitulo = repositorio.ListarCapitulos().FirstOrDefault(x =>
                    grupo.CategoriaInicialCodigo >= x.CategoriaInicialCodigo &&
                    grupo.CategoriaFinalCodigo <= x.CategoriaFinalCodigo
                    );

            ViewBag.capitulo = capitulo;

            var categorias = repositorio.ListarCategorias().Where(x =>
                x.CodigoDaCategoriaCodigo >= grupo.CategoriaInicialCodigo &&
                x.CodigoDaCategoriaCodigo <= grupo.CategoriaFinalCodigo
                ).ToList();

            return View(categorias);
        }

        public ActionResult Categoria(string codigoDaCategoria)
        {
            var repositorio = new Repositorio.Repositorio();

            var categoria = repositorio.ListarCategorias().FirstOrDefault(x => x.CodigoDaCategoria == codigoDaCategoria);

            var subCategorias = repositorio.ListarSubCategorias().Where(x =>
               x.CodigoDaCategoria == codigoDaCategoria).ToList();

            categoria.ListaDeSubCategorias = subCategorias;

            var grupo = repositorio.ListarGrupos().FirstOrDefault(x => categoria.CodigoDaCategoriaCodigo >= x.CategoriaInicialCodigo && categoria.CodigoDaCategoriaCodigo <= x.CategoriaFinalCodigo);
            ViewBag.grupo = grupo;

            var capitulo = repositorio.ListarCapitulos().FirstOrDefault(x =>
                    grupo.CategoriaInicialCodigo >= x.CategoriaInicialCodigo &&
                    grupo.CategoriaFinalCodigo <= x.CategoriaFinalCodigo
                    );

            ViewBag.capitulo = capitulo;

            return View(categoria);
        }

        public ActionResult Detalhe(string codigo)
        {
            var repositorio = new Repositorio.Repositorio();
            var subcategoria = repositorio.ListarSubCategorias().FirstOrDefault(x => x.CodigoDaSubCategoria == codigo);
            
            return View(subcategoria);
        }

        public ActionResult Busca (string busca)
        {

            busca = Ferramentas.SubstituiAcentos(busca);
            var repositorio = new Repositorio.Repositorio();
            var subCategorias = repositorio.ListarSubCategorias().Where(x => x.DescricaoSemAcentos.ToLower().Contains(busca.ToLower())).ToList();
            ViewBag.busca = busca;
            return View(subCategorias);
        }
    }
}

Reparem a action Index e veja como foi simples listar todos os dados do capítulos de doenças utilizando a estrutura montada, bastou chamar o método “ListarCapitulos” da classe repositório e passar os valores para a View “Index.cshtml”, veja seu código.

@model List<Repositorio.ViewModelCapitulo>
@{
    ViewBag.Title = "W7SAUDE";
}
<h2>Busca CID</h2>
<div class="span12" style="margin-left: 0">
    @Html.Partial("_formBusca")
    <div class="span9">
        @foreach (var capitulo in Model)
        {
            <div class="span6" style="margin-left: 0; height: 110px; padding: 5px;">
                @{
            var titulo = capitulo.Descricao.Split('-');
            titulo[0] = titulo[0].Trim();
            titulo[1] = titulo[1].Trim();
                }
                <h2><a href="~/Home/Capitulo/@capitulo.NumeroCapitulo">@titulo[0]</a></h2>
                <p>@titulo[1]</p>
            </div>
        }
    </div>
</div>

Veja como manipular arquivos CSV se torna fácil utilizando o CsvHelper e uma classe genérica para fazer o trabalho de mapeamento para objetos.

Aproveite e veja o exemplo deste código rodando em http://cid.apphb.com/, ou baixe este código completo no meu GitHub no repositório CidDataSus.
Até breve pessoal!

Tags: asp.net, CSharp
← Validação de Data e Moeda (ASP.Net MVC + JQuery Validation) em Português
Domínio Fake, Alias de domínio e Binding de domínios no IISExpress →
Related Posts
Vídeo-Aula ASP.Net MVC na prática – Parte 8...
Domínio Fake, Alias de domínio e Binding de domínios no IISExpress
Vídeo-Aula ASP.Net MVC na prática – Parte 6
Vídeo-Aula ASP.Net MVC na prática – Parte 9-2

Google+

376Follower
Popular
  • Vídeo-Aula ASP.Net MVC na prática – Parte 1junho 18, 2012, 9:13 pm
  • Validação de Data e Moeda (ASP.Net MVC + JQuery Validation)...janeiro 31, 2013, 11:27 am
  • Vídeo-Aula ASP.Net MVC na prática – Parte 6janeiro 12, 2013, 3:50 pm
  • Rotativa W7 gerando relatórios em PDF no ASP.Net MVCdezembro 26, 2012, 5:53 pm
  • Vídeo-Aula ASP.Net MVC na prática – Parte 9-1setembro 27, 2013, 6:00 pm
Recent
  • Visual StudioVisual Studio 2015julho 20, 2015, 7:57 pm
  • MySQL com ASP.Net MVCmaio 6, 2015, 4:16 pm
  • Vídeo-Aula ASP.Net MVC na prática – Parte 9-3março 29, 2014, 3:14 pm
  • Vídeo-Aula ASP.Net MVC na prática – Parte 9-2janeiro 26, 2014, 9:56 am
  • Vídeo-Aula ASP.Net MVC na prática – Parte 9-1setembro 27, 2013, 6:00 pm
Comments
  • ótimo, agora concidera vírgula como decimal, porém a...janeiro 31, 11:27 am by gilmar
  • Parabéns pelo artigo Cleyton, para utilizar a sua solução...janeiro 31, 11:27 am by Braytiner Heggendorn
  • Certo Danilo! Muito obrigado pela dica!!janeiro 31, 11:27 am by José Furtado
  • Olá José, tudo bem? Então, trabalhando em um projeto...janeiro 31, 11:27 am by Danilo Miranda
  • Olá Danilo! Hoje enfrento o mesmo problema que você, já...janeiro 31, 11:27 am by José Furtado
Tags
.net alsummit asp.net clean code complexidade comunidade CSharp EF evento hyper-v IISExpress jQuery metro MVC MySQL nuget razor Rotativa W7 SignalR SQL TDD TechEd Testes Unitários TFS11 TFS2012 Visual Studio VS2012 Vídeo-Aula windows8 wp7

Series

  • ASP.Net MVC (16)
  • Entity Framework (4)
  • Minhas Palestras (1)

Interesting links

Besides are some interesting links for you! Enjoy your stay :)

Últimos Comentários

  • gilmar em Validação de Data e Moeda (ASP.Net MVC + JQuery Validation) em Português
  • Braytiner Heggendorn em Validação de Data e Moeda (ASP.Net MVC + JQuery Validation) em Português
© Copyright - Cleyton Ferrari - Wordpress Theme by Kriesi.at