Criando a estrutura do projeto e o banco

Com o Visual Studio 2010 aberto, vamos iniciar criando um projeto do tipo ASP.NET MVC 2 Web Application com o nome de ExportacaoExcel. Podemos também criar um DB no SQL Server com o nome de sua preferência, dentro do DB criamos uma tabela de Usuários com a seguinte estrutura:

CREATE TABLE [dbo].[tbUsuarios]

(

      [codUsuario] [int] IDENTITY(1,1) PRIMARY KEY NOT NULL,

      [nome] [varchar](200) NULL,

      [idade] [int] NULL,

      [codContato] [int] NULL,

      [dataCadastro] [datetime] NULL,

      [login] [varchar](100) NULL,

      [senha] [varchar](100) NULL,

      [ativo] [bit] NULL,

      [observacao] [varchar](max) NULL

)

 

No diretório Model do projeto vamos criar um novo item do tipo LINQ to SQL Classes com o nome de DB.dbml. Com o mesmo aberto, arrastamos a tabela criada anteriormente para dentro do mesmo e a renomeamos para Usuario.

 

Agora sim, mão a obra

Na Master Page vamos adicionar a referencia ao jQuery conforme o código abaixo:

 

<head runat="server">

    <title><asp:ContentPlaceHolder ID="TitleContent" runat="server" />title>

   

    <link href="../../Content/Site.css" rel="stylesheet" type="text/css" />

    <script src="../../Scripts/jquery-1.4.1.min.js" type="text/javascript">script>

 

    <asp:ContentPlaceHolder ID="HeadContent" runat="server" />

head>

  

Agora vamos adicionar um botão na View Index.aspx:

 

 <input type="button" id="btnExportar" value="Exportar Usuários" />

 

 E o evento referente ao click do botão:

  

<asp:Content ID="Content3" ContentPlaceHolderID="HeadContent" runat="server">

   <script type="text/javascript">

        $(document).ready(function () {

            $("#btnExportar").click(function () {

                var campos = "codUsuario,nome";

               window.location = "/Home/GeraExcel/?nomeEntidade=Usuario&campos=" + campos;

           });

       });

     script>

asp:Content>

 

 

Note que, o parâmetro nomeEntidade é o nome da tabela definida no arquivo DB.dbml que queremos obter, e a propriedade campos é justamente os campos que desejamos exportar da tabela.

 

Agora no HomeController vamos criar um método do tipo ActionResult chamado GeraExcel que é justamente o método chamado no evento acima, e um outro chamado SelecionaDados, conforme é exibido abaixo:

 

 public ActionResult GeraExcel(string nomeEntidade, string campos)

        {

            Type tipoEntidade = Type.GetType("ExportacaoExcel.Models." + nomeEntidade);

             return this.Excel(new DBDataContext(),

                              this.SelecionaDados(tipoEntidade),

                              nomeEntidade + ".xls",

                              campos.Split(','));

        }

 

public IQueryable SelecionaDados(Type tb)

        {

            DBDataContext _db = new DBDataContext();

             return _db.GetTable(tb).AsQueryable();

        }

 

 Observe, o método GeraExcel recebe os parâmetro (nomeEntidade e campos) enviados pela nossa View Index.aspx, a propriedade tipoEntidade como o próprio nome diz, recebe o tipo da entidade enviada como parâmetro. Porém, será exibida uma mensagem de que não existe uma definição para Excel e que não existe nenhum ExtesionMethod.

 

Para um melhor entendimento sobre ExtensionMethods veja: http://msdn.microsoft.com/en-us/library/bb383977.aspx

 

Vamos então criar um, na raiz do projeto criaremos um diretório chamado Helpers e dentro do mesmo adicionaremos uma classe chamada ExtensionMethods.cs com o seguinte código:

 

 

using System.Web.Mvc;

using System.Data.Linq;

using System.Linq;

using System.Web.UI.WebControls;

 

namespace ExportacaoExcel.Helper

{

    public static class ExcelControllerExtensions

    {

         public static ActionResult Excel

        (

            this Controller controller,

            DataContext dataContext,

            IQueryable rows,

            string fileName

        )

        {

            return new ExcelResult(dataContext, rows, fileName, null, null, null, null);

        }

 

        public static ActionResult Excel

        (

            this Controller controller,

            DataContext dataContext,

            IQueryable rows,

            string fileName,

            string[] headers

        )

        {

            return new ExcelResult(dataContext, rows, fileName, headers, null, null, null);

        }

 

        public static ActionResult Excel

        (

            this Controller controller,

            DataContext dataContext,

            IQueryable rows,

            string fileName,

            string[] headers,

            TableStyle tableStyle,

            TableItemStyle headerStyle,

            TableItemStyle itemStyle

        )

        {

            return new ExcelResult(dataContext, rows, fileName, headers, tableStyle, headerStyle, itemStyle);

        }

 

    }

}

 

 Note agora que é apresentado um novo erro, explicando que não existe o tipo ou namespace ExcelResult, portanto vamos cria-lo também.

Dentro do diretório Helpers adicionaremos outra classe, agora chamada ExcelResult.cs, da seguinte forma:

  

using System;

using System.Data.Linq;

using System.Drawing;

using System.IO;

using System.Linq;

using System.Web;

using System.Web.Mvc;

using System.Web.UI;

using System.Web.UI.WebControls;

using System.Data;

using TesteExcel.Models;

 

namespace ExportacaoExcel.Helper

{

    public class ExcelResult : ActionResult

    {

        private DBDataContext _db = new DBDataContext();

        private DataContext _dataContext;

        private string _fileName;

        private IQueryable _rows;

        private string[] _headers = null;

 

        private System.Web.UI.WebControls.TableStyle _tableStyle;

        private TableItemStyle _headerStyle;

        private TableItemStyle _itemStyle;

 

        public string FileName

        {

            get { return _fileName; }

        }

 

        public IQueryable Rows

        {

            get { return _rows; }

        }

 

         public ExcelResult(DataContext dataContext, IQueryable rows, string fileName)

            : this(dataContext, rows, fileName, null, null, null, null)

        {

        }

 

        public ExcelResult(DataContext dataContext, IQueryable rows, string fileName, string[] headers)

            : this(dataContext, rows, fileName, headers, null, null, null)

        {

        }

 

        public ExcelResult(DataContext dataContext, IQueryable rows, string fileName, string[] headers, System.Web.UI.WebControls.TableStyle tableStyle, TableItemStyle headerStyle, TableItemStyle itemStyle)

        {

            _dataContext = dataContext;

            _rows = rows;

            _fileName = fileName;

            _headers = headers;

            _tableStyle = tableStyle;

            _headerStyle = headerStyle;

            _itemStyle = itemStyle;

 

            if (_tableStyle == null)

            {

                _tableStyle = new System.Web.UI.WebControls.TableStyle();

            }

            if (_headerStyle == null)

            {

                _headerStyle = new TableItemStyle();

                _headerStyle.BackColor = Color.LightGray;

            }

        }

 

        public override void ExecuteResult(ControllerContext context)

        {

            // Cria um HtmlTextWriter

            StringWriter sw = new StringWriter();

            HtmlTextWriter tw = new HtmlTextWriter(sw);

 

            if (_tableStyle != null)

                _tableStyle.AddAttributesToRender(tw);

            tw.RenderBeginTag(HtmlTextWriterTag.Table);

 

            // Gera os headers

            if (_headers == null)

            {

                _headers = _dataContext.Mapping.GetMetaType(_rows.ElementType).PersistentDataMembers.Select(m => m.Name).ToArray();

            }

 

            // Cria o header para as Rows

            tw.RenderBeginTag(HtmlTextWriterTag.Thead);

            foreach (String header in _headers)

            {

                if (_headerStyle != null)

                    _headerStyle.AddAttributesToRender(tw);

                tw.RenderBeginTag(HtmlTextWriterTag.Th);

                tw.Write(header);

                tw.RenderEndTag();

            }

            tw.RenderEndTag();

 

 

            // Cria Data Rows

            tw.RenderBeginTag(HtmlTextWriterTag.Tbody);

            foreach (Object row in _rows)

            {

                tw.RenderBeginTag(HtmlTextWriterTag.Tr);

                foreach (string header in _headers)

                {

                    string strValue = "";

 

                    if (row.GetType().GetProperty(header).GetValue(row, null) == null)

                        strValue = "";

                    else

                        strValue = row.GetType().GetProperty(header).GetValue(row, null).ToString().Trim();

 

                    strValue = ReplaceSpecialCharacters(strValue);

                    if (_itemStyle != null)

                        _itemStyle.AddAttributesToRender(tw);

                    tw.RenderBeginTag(HtmlTextWriterTag.Td);

                    tw.Write(HttpUtility.HtmlEncode(strValue));

                    tw.RenderEndTag();

                }

                tw.RenderEndTag();

            }

            tw.RenderEndTag();

 

            tw.RenderEndTag();

 

            WriteFile(_fileName, "application/ms-excel", sw.ToString());

        }

 

        private static string ReplaceSpecialCharacters(string value)

        {

            value = value.Replace("’", "'");

            value = value.Replace("“", "\"");

            value = value.Replace("”", "\"");

            value = value.Replace("–", "-");

            value = value.Replace("…", "...");

            return value;

        }

 

        private static void WriteFile(string fileName, string contentType, string content)

        {

            HttpContext context = HttpContext.Current;

            context.Response.Clear();

            context.Response.AddHeader("content-disposition", "attachment;filename=" + fileName);

            context.Response.Charset = "";

            context.Response.Cache.SetCacheability(HttpCacheability.NoCache);

            context.Response.ContentType = contentType;

            context.Response.Write("");

            context.Response.Write("");

            context.Response.Write("");

            context.Response.Write("");

            context.Response.Write("");

            context.Response.Write("");

            context.Response.Write(content);

            context.Response.Write("");

            context.Response.Write("");

            context.Response.End();

        }

    }

}

 

Pronto, agora em HomeController basta adicionarmos a referência ao diretório Helpers:

 

using ExportacaoExcel.Helper;

 

Note que, ao executar a aplicação e clicar no botão de exportação, é disponibilizado o download do arquivo Excel

 

Em próximos artigos mostrarei como realizar a importação de um arquivo Excel.

Até a próxima !!

 

Rafael Zaccanini

rafael.zaccanini@gmail.com