Pesquisar este blog

quinta-feira, 23 de julho de 2015

ASP.NET MVC: EVITE usar HTML Helpers em campos Hidden

Não sou a favor da cópia/plágio de postagens, porém, esbarrei em um problema recentemente que me custou  um bom tempo de pesquisa em busca de uma "resposta" ou justificativa para tal. Em uma aplicação MVC 4.0, uma view de edição possuía dois formulários (duas tags "<form>"). 
O ID da model utilizada pela view era armazenado em hiddens criadas a partir do HTML Helper em ambos os formulários. Notei que após o cadastro da entidade, no retorno do POST da Controller, a model trazia o campo ID preenchido, porém o campo hidden na tela não era preenchido, fazendo com o valor do mesmo ficasse vazio.
Após horas de pesquisa, encontrei em um blog a sugestão de NUNCA utilizar Html Herlpers na criação de campos hidden. Aparentemente não há uma explicação oficial sobre o porque isto ocorre, mas acho interessante disseminar este pequeno inconveniente. Para mais detalhes, acessar o link abaixo:

Fonte: ShivaGaadu

terça-feira, 21 de julho de 2015

Customização de arquivos BAT : Crie arquivos BAT dinâmicamente

Um arquivo BAT é composto por instruções a serem executadas sequencialmente. Sua execução geralmente é agendadas e costuma efetuar tarefas em lote. 
Na maioria dos casos, as tarefas são específicas e dificilmente precisam ser alteradas. Porém, em alguns momentos, é necessário que o arquivo obtenha informações dinâmicas de outras fontes de dados.
E é neste momento que a plataforma .NET se demonstra muito útil! Linguagens de outras plataformas, como Java por exemplo, também são capazes de realizar esta tarefa, porém neste post, utilizaremos a linguagem C# da plataforma .NET. 
Embora o exemplo a seguir seja um tanto quanto simplista, ele permite ter uma ideia do potencial de arquivos bat.
No exemplo a seguir criaremos uma classe dinamicamente e geraremos um arquivo bat responsável pela compilação da mesma, transformando esta em uma dll. Para tal, criaremos um projeto do tipo Console:
A codificação da classe program será a seguinte:
string className = "testeBuild";
string folderPath = @"c:\temp\";
StringBuilder sBuilderClasse = new StringBuilder();
sBuilderClasse.AppendLine("using System;");
sBuilderClasse.AppendLine("namespace CompileViaBatDemo");
sBuilderClasse.AppendLine("{");
sBuilderClasse.AppendLine("     public class " + className);
sBuilderClasse.AppendLine("     {");
sBuilderClasse.AppendLine("         public string Hello { ");
sBuilderClasse.AppendLine("             get {              ");
sBuilderClasse.AppendLine("                 return \"Hi\";");
sBuilderClasse.AppendLine("             } ");
sBuilderClasse.AppendLine("         }");
sBuilderClasse.AppendLine("     }");
sBuilderClasse.AppendLine("}");
File.WriteAllText(string.Format("{0}{1}.cs", folderPath, className), sBuilderClasse.ToString(), Encoding.UTF8);
StringBuilder sBuilderBat = new StringBuilder();
sBuilderBat.AppendLine(@"C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe /target:library " + string.Format("{0}{1}.cs", folderPath, className));
sBuilderBat.AppendLine(@"del " + string.Format("{0}{1}.cs", folderPath, className));
sBuilderBat.AppendLine(@"del " + string.Format("{0}{1}.bat", folderPath, className));
sBuilderBat.AppendLine(@"pause");
File.WriteAllText(string.Format("{0}{1}.bat", folderPath, className), sBuilderBat.ToString(), Encoding.ASCII);
Ao executar este código, será gerado no diretório "c:\temp" nossa classe e o arquivo bat.
Quando o arquivo bat criado é executado, o mesmo gera a dll a partir da compilação da classe, deleta a classe e em seguida a si mesmo.
Ao Importar a dll criada no Visual Studio, é possível consumir sua classe.

quinta-feira, 16 de julho de 2015

JavaScript e OO: Adicionando métodos ao objeto


Na post anterior vimos como criar objetos e manipular suas propriedades através do JavaScript. Porém, "nem só de propriedades viverá um objeto"! Um objeto pode possuir também um ou mais métodos/funções. Por exemplo:

Pensemos num objeto "Carro". Um carro geralmente possui as seguintes características:
  • Ano
  • Cor
  • Fabricante
  • Modelo
Traduzindo estas informações nas propriedades de nosso objeto no JavaScript, teríamos algo mais ou menos assim:
var carro = {
    ano: 0
   ,cor: ""
   ,fabricante: ""
   ,modelo: ""
};
Porém, todo carro que se preze realiza algumas "ações básicas" como:
  • Desligar
  • Ligar
  • Buzinar
No JavaScript, a sintaxe básica para a criação de uma função ou método é: 
function ["nome da função"]([parâmetros]) {
 [Corpo da função]
}
A definição de uma função em um objeto JavaScript não é muito diferente. Abaixo demonstro como seria a implementação das funções necessárias para nosso objeto  (desligar, ligar, buzinar):
var carro = {
    ano: 0
   ,cor: ""
   ,fabricante: ""
   ,modelo: ""
   ,desligar: function(){
       console.log("O carro foi desligado");
   }
   ,ligar: function(){
       console.log("O carro foi ligado");   
   }
   ,buzinar: function(){
       console.log("O carro buzinou");   
   }
}
Após a criação do objeto, para invocar os métodos de nosso objeto, basta utilizar a sintaxe "[objeto].[método]". Ao executar o comando "carro.ligar()", será exibido no console do navegador a mensagem "O carro foi ligado".

terça-feira, 14 de julho de 2015

SQL Server: Auditando alterações no Banco de Dados

Após finalizar os ajustes em um sistema, é chegada a hora de gerar um pacote para publicação. Geralmente o código fonte é armazenado em um controlador de versão, o que facilita na hora de "lembrar" e separar os arquivos que sofreram alterações ao longo do processo de desenvolvimento.
No caso do banco de dados, caso o desenvolvedor não mantenha um controle dos scripts das alterações realizadas no banco de dados, a chance de uma procedure, tabela ou função a ser alterada em produção ser esquecida é muito grande.
Dado este inconveniente, algumas empresas distribuem/comercializam softwares e plugins responsáveis por auditar a base. Ou seja, todas as alterações realizadas nos objetos do banco de dados são registrados e posteriormente é possível obter um script assertivo das mudanças a serem realizadas no ambiente de produção.
Porém, na ausência de um plugin ou software para auditoria das alterações realizadas em base, é possível se guiar pelo objeto sys.all_objects.
Ao realizar a consulta abaixo, o SQL Server traz todos os objetos que foram criados/alterados no banco de dados em relação ao período utilizado no filtro da consulta.
SELECT
    name,
    create_date,
    modify_date
FROM sys.all_objects
WHERE create_date > '[[Data]'
or modify_date > '[Data]'

quinta-feira, 9 de julho de 2015

ASP.NET MVC & Chosen - Parte 1

Conforme prometido, hoje irei mostrar alguns exemplos práticos do uso do plugin Chosen. Neste post irei demonstrar o passo a passo de como utilizar este plugin no Visual Studio utilizando o template ASP.NET MVC. Apenas lembrando que este plugin pode ser utilizado normalmente com HTML e JavaScript/JQuery.

Primeiramente precisamos criar um projeto ASP.NET MVC no Visual Studio:




Feito isso, iremos acrescentar os arquivos CSS e JavaScript que compõe a API nas pastas Content e Scripts:


Criaremos uma Controller responsável por gerenciar as requisições de nossa página de exemplo: 


Nossa controller ficará assim:
using ChosenExample.Web.Models;
using System.Web.Mvc;

namespace ChosenExample.Web.Controllers
{
    public class ChosenExampleController : Controller
    {
        public ActionResult Index()
        {
            return View(new ListHelper());
        }
    }
}
A action Index utilizada na Controller acima, retorna uma View passando nosso objeto Model (ListHelper):
using System.Collections.Generic;

namespace ChosenExample.Web.Models
{
    public class ListHelper
    {
        public int CdAnimal { get; set; }
        public int CdProduto { get; set; }
        public List Animais { get; set; }
        public List Produtos { get; set; }

        public ListHelper()
        {
            FillAnimais();
            FillProdutos();
        }

        private void FillProdutos()
        {
            Produtos = new List();
            Produtos.Add(new Produto() { IdProduto = 1, DsProduto = "Computador" });
            Produtos.Add(new Produto() { IdProduto = 2, DsProduto = "TV" });
            Produtos.Add(new Produto() { IdProduto = 3, DsProduto = "Video Game" });
            Produtos.Add(new Produto() { IdProduto = 4, DsProduto = "DVD Player" });
            Produtos.Add(new Produto() { IdProduto = 5, DsProduto = "Smart Phone" });
            Produtos.Add(new Produto() { IdProduto = 6, DsProduto = "iPhone" });
            Produtos.Add(new Produto() { IdProduto = 7, DsProduto = "Laptop" });
            Produtos.Add(new Produto() { IdProduto = 8, DsProduto = "Janela" });
            Produtos.Add(new Produto() { IdProduto = 9, DsProduto = "Mesa" });
            Produtos.Add(new Produto() { IdProduto = 10, DsProduto = "Lâmpada" });
            Produtos.Add(new Produto() { IdProduto = 11, DsProduto = "Teclado" });
        }

        private void FillAnimais()
        {
            Animais = new List();
            Animais.Add(new Animal() { IdAnimal = 1, DsAnimal = "Cachorro" });
            Animais.Add(new Animal() { IdAnimal = 2, DsAnimal = "Gato" });
            Animais.Add(new Animal() { IdAnimal = 3, DsAnimal = "Pássaro" });
            Animais.Add(new Animal() { IdAnimal = 4, DsAnimal = "Sapo" });
            Animais.Add(new Animal() { IdAnimal = 5, DsAnimal = "Peixe" });
            Animais.Add(new Animal() { IdAnimal = 6, DsAnimal = "Lagarto" });
            Animais.Add(new Animal() { IdAnimal = 7, DsAnimal = "Urso" });
            Animais.Add(new Animal() { IdAnimal = 8, DsAnimal = "Cavalo" });
            Animais.Add(new Animal() { IdAnimal = 9, DsAnimal = "Girafa" });
            Animais.Add(new Animal() { IdAnimal = 10, DsAnimal = "Elefante" });
            Animais.Add(new Animal() { IdAnimal = 11, DsAnimal = "Leão" });
        }
    }
}
As classes abaixo serão utilizadas na tipagem das listas de nossa Model
    public class Produto
    {
        public int IdProduto { get; set; }
        public string DsProduto { get; set; }
    }
    public class Animal
    {
        public int IdAnimal { get; set; }
        public string DsAnimal { get; set; }
    }
Nossa Index (View) conterá dois dropdownlists a serem utilizados em nosso exemplo e um botão a ser utilizado no próximo post.
@model ChosenExample.Web.Models.ListHelper
@{
    ViewBag.Title = "Exemplos";
}


Exemplos Chosen

@Html.DropDownListFor(t => t.CdAnimal, new SelectList(Model.Animais, "IdAnimal", "DsAnimal"), "Selecione", new { multiple = "", @class = "chzn-select search-dropdown chosen-select", data_placeholder = "Selecione", style="width:400px" }) @Html.DropDownListFor(t => t.CdProduto, new SelectList(Model.Produtos, "IdProduto", "DsProduto"), "Selecione", new { @class = "chzn-select search-dropdown chosen-select", data_placeholder = "Selecione", style = "width:400px" }) <input type="submit" name="btnEnviar" value="Enviar" />

Antes de seguir em frente, existem alguns pontos interessantes a serem observados e entendidos:

  1. O atributo multiple = "" indica que o controle será múltipla escolha, tornando possível a seleção de mais de um valor.
  2. A classe search-dropdown habilita a busca no campo


Ao executar a aplicação, o resultado é o seguinte:


Para inicializar o plugin, basta inserir este trecho de código na página dentro da tag script:
$(document).ready(function(){
    $(".chosen-select").chosen()
});
E pronto! Bem diferente da aparência e comportamento padrão não?
Em uma próxima postagem irei abordar o tratamento e manipulação deste campo na Controller.

terça-feira, 7 de julho de 2015

JavaScript e OO: Criando objetos

Embora seja uma linguagem fracamente tipada, com o passar do tempo o JavaScript vem ganhando cada vez mais melhorias e funcionalidades. A tipagem desta linguagem facilita a manipulação de suas variáveis e objetos, visto que estes podem ser criados dinamicamente em tempo de execução.
Na maioria das linguagens orientadas a objeto, como Java/C#/C++, o processo de criação de objetos consiste em definir, criar e instanciar uma classe. 
Com o JavaScript não é muito diferente! A vantagem deve-se ao fato de o JavaScript não precisar ser compilado antes da interpretação do script.
Caso fôssemos criar um objeto "Pessoa", utilizando a linguagem C# por exemplo,  o código fonte seria algo mais ou menos assim:
public class Pessoa
{
  public string Nome { get; set; }
  public int Idade { get; set; }
}
No caso do JavaScript, a implementação desta classe poderia ser feita (de modo simplista), da seguinte maneira:
var pessoa = { 
    Nome: ""
  , Idade: 0
};
Devido ao JavaScript ser fracamente tipado, os campos/propriedades da minha classe "pessoa", são inicializados para que os mesmos "assumam" um tipo. No caso da classe C#, os tipos são pré definidos no momento da criação da classe. Para acessar um atributo de minha classe "Pessoa", é necessário primeiramente instanciar a classe e efetuar a chamada através do objeto "p" criado:
Pessoa p = new Pessoa();
//Acesso e imprimo o atributo nome do meu objeto "p"
Console.WriteLine(p.Nome);
Já para o JavaScript, existem outras maneiras de se acessar as propriedades de objetos, chamadas também de notações. Abaixo demonstro duas delas:

1 - Sintaxe de ponto (dot notation): 
A propriedade é acessada assim como no C#, objeto.propriedade:
pessoa.nome = "Bruno";
2 - Sintaxe de colchetes (bracket notation): 
O acesso a propriedade do objeto lembra o acesso a valores em matrizes, objeto["propriedade"]:
pessoa["nome"] = "Bruno"; 
Outro ponto interessante que faz do JavaScript uma linguagem poderosa, é o fato de se poder criar propriedades para objetos existentes em tempo de execução. Nosso objeto "pessoa" até o momento possuia duas propriedades: "nome" e "idade". Caso seja necessário acrescentar uma nova propriedade a este objeto, como por exemplo "peso", basta "acessar a nova propriedade":
pessoa.peso = 70; 
Feito isso, o objeto "pessoa", passa a ter também a propriedade peso. Incrível, não? Para quem desejar se aprofundar mais, encontrei um link interessante bem aqui

quinta-feira, 2 de julho de 2015

Common Language Run-time Integration: crie e utilize métodos .NET em procedures



No desenvolvimento de uma aplicação que realize acesso a base de dados, geralmente a comunicação é unilateral. Ou seja, a aplicação conhece e realiza acessos ao banco de dados, enquanto que o banco de dados desconhece a aplicação.
Dependendo do nível de complexidade da aplicação, visando evitar a repetição de código, parte da lógica da aplicação (regras de negócio) pode ser encapsulada, geralmente em uma DLL.
Quando se conhece o negócio, é possível a manipulação e consulta dos objetos do banco de dados através de procedures e comandos SQL. Porém, quando o acesso a DLL encontra-se ofuscado ou criptografado, fica a questão: e se fosse possível utilizar um método de uma DLL em uma procedure?

Por mais exótica que aparente ser (e é) esta solução, sim, é possível consumir uma DLL e realizar a chamada de seus métodos a partir de uma procedure ou função no banco de dados. Para realizar este acesso, basta seguir os seguintes passos:

Primeiramente é necessário configurar o banco de dados habilitando o CLR e ativar o TRUSTWORTHY:

sp_configure 'clr enable', 1
GO
RECONFIGURE

ALTER DATABASE TreinamentoNET
SET TRUSTWORTHY ON

1 - Abra o Visual Studio e clique em: File > New > Project ...> Visual C# > Windows > Class Library


2 - No menu "Projeto", selecione a opção "Add New Item" e em seguida "Class". 



3 - Segue abaixo a classe utilizada neste exemplo:

using System;
using Microsoft.SqlServer.Server;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using System.Data;
namespace ProcDotNet.Classes
{
    public class ProcedureDotNET
    {
        [SqlProcedure()]
        public static void InsertProduct(SqlString nome, SqlString observacao)
        {
            using (SqlConnection conn = new SqlConnection(@"Data Source = localhost\SQL; Initial Catalog = TreinamentoNET; User ID = sa ; Password = P@$$w0rd"))
            {
                SqlCommand objCommand = new SqlCommand();
                objCommand.Parameters.AddWithValue("@nome", nome);
                objCommand.Parameters.AddWithValue("@observacao", observacao);
                objCommand.CommandText = "INSERT INTO tbProduto (nome, observacao) VALUES (@nome, @observacao)";
                objCommand.Connection = conn;
                conn.Open();
                objCommand.ExecuteNonQuery();
                conn.Close();
            }
        }
    }
}

Na classe acima, o método InsertProduct recebe dois parâmetros e realiza o insert em tabela. É importante lembrar que o projeto class library deve utilizar o framework .NET correspondente a versão suportada pelo SQL Server utilizado. No caso do SQL Server 2008 por exemplo, a versão do framework suportada é a 2.0


Após a compilação do projeto, é necessário registrar a DLL no banco de dados. Para isso, basta executar os scripts abaixo:

CREATE ASSEMBLY ProcedureDotNET
AUTHORIZATION dbo FROM 'C:\Users\bruno\Desktop\ProcDotNet\ProcDotNet.Classes\bin\Debug\ProcDotNet.Classes.dll'
WITH PERMISSION_SET = UNSAFE
GO

Após a execução do script acima, o SQL Server cria um assembly no banco de dados. A partir deste assembly é possível efetuar as chamadas aos métodos da DLL a partir de procedures e funções.
No exemplo abaixo, uma procedure é criada para receber os dois parâmetros requisitados pelo método e invocá-lo: 

CREATE PROCEDURE sp_insert_product
  @nome nvarchar(50),
  @observacao nvarchar(50)
AS EXTERNAL NAME ProcedureDotNET.[ProcDotNet.Classes.ProcedureDotNET].InsertProduct
GO

Feito isso, é chegada a hora de testar nossa criação. Ao executar a procedure enviando os parâmetros, as informações são persistidas na base de dados:

sp_insert_product 'Carro', '4 portas'

Ao realizar uma consulta na tabela, é possível verificar que tudo funciona perfeitamente e que os dados enviados para a procedure foram persistidos:
select * from tbProduto


terça-feira, 30 de junho de 2015

JavaScript: alert ou console.log?



Lembro me quando comecei a desenvolver sistemas para web. Um novo universo, uma nova realidade. Não precisa compilar? Era tudo novidade! Porém, com o passar do tempo e consequentemente com o aumento da complexidade dos scripts desenvolvidos, surgiu o questionamento: Como eu "debugo" o meu script (JavaScript)?
A primeira opção a mim apresentada foi o método nativo do JavaScript "alert" e em primeira instância, pensei ter descoberto "O Santo Graal" para depuração de scripts. 
No entanto, notei que o método "alert", não era o suficiente para exibir estruturas mais complexas como o exemplo abaixo:
var produto = { Nome: 'Computer',
                  PrecoUnidade: 1110.25,
                  QuantidadeEstoque: 2
              };
Caso eu passe como parâmetro o objeto "produto", o navegador me exibirá o seguinte resultado (pouco útil):
alert(produto);
Ou seja, para objetos, o método alert() não se demonstra tão útil. E neste momento há quem apele para o uso de "alerts" personalizados para inspecionar o objeto criado:
alert("Nome: '"+produto.Nome+"', Preço: $"+produto.PrecoUnidade);

Neste  ponto, podemos chegar a conclusão de que dependendo da complexidade do objeto criado no JavaScript, o uso de alerts para "depuração" é inviável. E é neste momento em que a tecla "F12" do teclado ganha sentido. 
Na maioria dos navegadores modernos como o Chrome ou Firefox e as mais recentes versões do IE (a partir do 9), ao pressionar a tecla F12, o navegador exibe uma janela chamada comumente de "Developer Tools (Ferramentas de Desenvolvimento)".


Note que que entre as ferramentas disponibilizadas, existe o "Console", em minha opinião, a ferramenta mais poderosa dos browsers modernos. 
A princípio esta ferramenta aparentemente simples não demonstra grande importância, porém ela permite a criação e manipulação de todos os objetos existentes em uma página web em tempo de execução.
Dois fatores fazem que o Console supere de longe o método alert:

1 - Ele é discreto: não ocorre, a menos que o método alert seja invocado, a exibição de janelas no navegador.

2 - Ele é eficiente: além de não haver a necessidade de haver um arquivo JavaScript, ele possui intelisense (dependendo do navegador).

Veja como ficaria nosso exemplo anterior utilizando o método console.log([texto]) no Console do navegador:

var produto = { Nome: 'Computer',
                  PrecoUnidade: 1110.25,
                  QuantidadeEstoque: 2
              };

console.log("Nome: '"+produto.Nome+"', Preço: $"+produto.PrecoUnidade);

produto

Resultado:

Ou seja, tudo ocorre dentro do console sem a necessidade de clicar em botões "OK" ou "Cancelar" como no caso do método "alert()"

Para consultar outros métodos de output, clique aqui

quinta-feira, 25 de junho de 2015

JavaScript: 3 maneiras de se utilizar


Em certos momentos do desenvolvimento nos deparamos com certos dilemas como qual abordagem utilizar na codificação de modo a tentar se distanciar o mínimo possível das "Boas práticas de programação".
O bom, o mal e o feioQuando o assunto é "Desenvolvimento Web", nos deparamos com um bombardeio de informações, arquiteturas, frameworks, exemplos, fóruns... Com o JavaScript não é diferente.


Existem "n" modos de se efetuar chamadas a funções JavaScript e neste artigo citarei as três mais utilizadas comentando suas vantagens ou desvantagens:

1 - Inline 

Descrição: no exemplo abaixo, a chamada JavaScript é realizada dentro do evento "onload" da página.
Consideração: pior modo de utilizar.
Motivo: o script vinculado ao evento "onload" só será executado após o carregamento de todos os assets da página. Caso algum elemento da página possua dependência deste script, erros podem ocorrer. Dependendo de como o navegador interpretar o código abaixo, a função alert pode ser executada antes da renderização dos elementos contidos na tag body, impedindo o carregamento da página até que o usuário interaja com a mensagem.


<!DOCTYPE html>
<html>
<head>
    <title>Carregando o javascript</title>
</head>
<body onload="alert('inline');">
    <h1>Formas de carregamento</h1>
</body>
</html>

2 - Embed

Descrição: no exemplo abaixo, a chamada JavaScript é realizada enquanto a página é carregada
Consideração: as vezes é utilizado.
Motivo:   não interrompe o carregamento da página, pois, o script só é carregado/interpretado após o carregamento dos elementos da página e pode ser utilizado quando o conteúdo da página é dinâmico ou condicional. 
Exemplo: exibir ou não informações na página ou aplicar alguma regra de negócio sobre campos/elementos de um formulário.

<!DOCTYPE html>
<html>
<head>
    <title>Carregando o javascript</title>
</head>
<body>
    <h1>Formas de carregamento</h1>
    <script type="text/javascript">
        alert('embed');
    </script>
</body>
</html>


3 - External

Descrição: no exemplo abaixo, a chamada JavaScript é realizada a partir de um arquivo externo.
Consideração: melhor maneira.
Motivo: além da vantagem mencionada no item 2, deixa o HTML da página menos poluído, já que toda a codificação JavaScript fica em um arquivo externo.


<!DOCTYPE html>
<html>
<head>
    <title>Carregando o javascript</title>
</head>
<body>
    <h1>Formas de carregamento</h1>
    <script type="text/javascript" src="externalFile.js"></script>
</body>
</html>

externalFile.js
alert('external');
Vale ressaltar que cada navegador possui sua própria engine e efetua o parse do HTML e JavaScript de modo diferente, resultando consequentemente em comportamentos diferentes.

terça-feira, 23 de junho de 2015

Chosen: dropdownlists multi-seleção

Crie DropDownLists amigáveis, dinâmicos e multi-selecionáveis!

Encontre o que deseja através de busca viva!
No desenvolvimento Web, os controles Dropdown (tag select) acabam sendo vastamente utilizados, seja no preenchimento de um formulário ou no filtro de informações.
Selecione e remova itens de modo intuitivo!

Porém estes controles por padrão permitem a seleção de apenas uma informação, o que em alguns casos não atende aos requisitos do software desenvolvido. Existem na internet diversas empresas e frameworks pagos que possibilitam a customização e/ou adaptação destes controles para que os mesmos permitam a multi-seleção de informações. No entanto, nem sempre os resultados obtidos correspondem ao esperado e a experiência do usuário final é comprometida.
Em meio a minhas pesquisas para o desenvolvimento de uma aplicação ASP.NET MVC, encontrei o Chosen, um plugin jQuery responsável por permitir esta customização do controle @Html.DropDownList. O plugin conta com diversas opções de customização como: busca, agrupamento, multi-seleção, entre outros.
Os resultados do uso deste plugin são surpreendentes, visto que a customização do controle não apresentam alteração significativa na performance do mesmo quando aplicado sobre pequenas quantidades de dados (ex: 100 registros). Em breve publicarei alguns exemplos de uso prático deste plugin.

Para baixar o plugin, basta acessar este link!

quarta-feira, 17 de junho de 2015

Remover senha de planilha Excel

Recentemente recebi a tarefa de dar manutenção em uma página responsável pelo upload de planilhas Excel. A funcionalidade básica (upload de arquivos) funcionava perfeitamente. 
Entretanto, devido a confidencialidade das informações a serem armazenadas, a partir daquele momento, as mesmas seriam enviadas protegidas por senha. A aplicação anteriormente, utilizava o ClosedXML para efetuar a leitura e manipulação da planilha. Mas, esta API não possuía em sua documentação um método capaz de ler uma planilha criptografada (protegida por senha).
Na internet existem inúmeras APIs não gratuitas capazes de decriptar/remover senhas de planilhas, porém preferi recorrer a uma API "quase nativa" em ambientes corporativos. A solução foi apelar para o bom e velho Office.
Ao instalar o Office na máquina, o instalador registra as dlls do mesmo, podendo estas serem importadas e utilizadas no Visual Studio para automatizar operações em documentos.
Então, em busca de uma solução de menor impacto no algoritmo de importação já existente utilizado pela aplicação, codifiquei o seguinte protótipo, responsável por criar uma cópia do documento importado sem a senha, para que assim, o documento criptografado seja armazenado e o sistema efetue a leitura a partir de uma cópia descriptografada.
using Microsoft.Office.Interop.Excel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace Excel.PasswordRemover
{
    class Program
    {
        static void Main(string[] args)
        {
            string password = "12345";

            //Crio as variáveis com os tipos usando pelo Excel
            Application excel = null;
            Workbooks workbooks = null;
            Workbook workbook = null;

            try
            {
                //Inicio uma instância do Excel
                excel = new Application();

                //Inicio os workbooks
                workbooks = excel.Workbooks;

                //Abro o arquivo passando a senha entre os parâmetros
                workbook = workbooks.Open(@"C:\Users\bruno\Desktop\plan1.xlsx"
                , Type.Missing, Type.Missing, Type.Missing, password, password, Type.Missing
                , Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing
                , Type.Missing);
                //Desprotejo o documento
                workbook.Unprotect(password);

                //Limpo as senhas
                workbook.Password = string.Empty;
                workbook.WritePassword = string.Empty;

                //Salvo uma "cópia" do arquivo sem a senha
                workbook.SaveAs(@"C:\Users\bruno\Desktop\plan1_no_password.xlsx"
                , Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing
                , Microsoft.Office.Interop.Excel.XlSaveAsAccessMode.xlShared, Type.Missing
                , Type.Missing, Type.Missing, Type.Missing, Type.Missing);

                workbook.Close();

                excel.Quit();
            }
            catch (Exception)
            {
                //TODO: Tratar Exceptions
            }
            finally
            {
                //Garanto a finalização da instância do Excel
                Marshal.ReleaseComObject(workbook);
                Marshal.ReleaseComObject(workbooks);
                Marshal.ReleaseComObject(excel);
            }
        }
    }
}