MongoDB – CRUD com C#

Muito se ouve falar em NOSQL e também em sua aplicabilidade para trabalhar com grande velocidade numa massa de dados gigante. Quero mostrar como inserir, ler, atualizar e remover dados de uma base de dados MongoDB, que é super fácil, e, após você fazer isso uma vez com certeza terá mais uma opção para trabalhar em suas aplicações.

Fiz um estudo sobre essas operações básicas para um sistema que estou evoluindo, vejam só o que aprendi.

Instalando o banco de dados

A primeira coisa a ser feita aqui é baixar MongoDB e coloca-lo para rodar, basta seguir esse tutorial que existe no próprio site do MongoDB http://docs.mongodb.org/manual/tutorial/install-mongodb-on-windows/.
Após instalar o MongoDB coloque-o para rodar, dê um “start” no banco de dados, dentro do mesma URL informada agora a pouco há também a explicação de como fazer isso. Olha só que legal, na sua máquina está rodando um banco de dados NOSQL :O !!!

Crie seu projeto

Agora crie um novo projeto do tipo Console Application, nesse caso, com a linguagem C#.

Namespaces

Antes de qualquer coisa, leia essa URL http://docs.mongodb.org/ecosystem/tutorial/getting-started-with-csharp-driver/, e, obtenha o driver do MongoDB para C#.
Inclua os seguintes namespaces em sua classe:

  • MongoDB.Bson –> MongoDB usa o formato BSON para armazenamento e transferência de dados. Utilizaremos esse namespace para fazer a utilização de seus objetos.
  • MongoDB.Driver –> Através desse namespace que acessaremos o MongoDB;
  • MongoDB.Driver.Builders –> Aqui estarão as classes e métodos “helpers” para construir vários objetos.

Criando as variáveis para utilização no nosso programa

Aqui estão as variáveis para fazermos conexão com o nosso banco de dados.

 var connectionString = "mongodb://localhost";
 var client = new MongoClient(connectionString);
 var server = client.GetServer();
 var database = server.GetDatabase("teste"); // "test2" é o nome da sua base de dados, caso vc não tenha criado nenhuma base de dados, o próprio driver se encarregará disso

Além dessas variáveis também iremos criar a classe Entidade, conforme abaixo:

public class Entidade
 {
 public ObjectId Id { get; set; }
 public string Nome { get; set; }
 }

Criando uma coleção e inserindo um novo objeto

Uma coisa muito legal no MongoDB é que não é necessário criar as coleções (podemos chamar de tabelas também), abaixo nós estamos:

  1. Criando a coleção “entidades” e tipando-a com nossa classe “Entidade”
  2. Criamos um novo objeto do tipo “Entidade”
  3. Inserimos o objeto na coleção
  4. Setamos o Id com o Id gerado pelo Mongo DB
</pre>
var collection = database.GetCollection<Entidade>("entidades"); // podemos pensar nessa como uma tabela
 var entity = new Entidade() { Nome = "Fulano de tal" };
 collection.Insert(entity);
 var id = entity.Id; // Insere e seta o ID, sempre devemos colocar um ObjectId em nossos objetos que serão inseridos no
<pre>

MongoDB, podemos setar o ID também, mas o mesmo é gerado automaticamente

Encontrando os objetos gravados no banco

Aqui é possível encontrar um objeto através de sua chave (gerada pelo MongoDB)

  1. Setamos a coleção
  2. Criamos um objeto de busca e seu critério
  3. Setamos o retorno em um objeto ou coleção
var collection = database.GetCollection<Entidade>("entidades");
var query = Query<Entidade>.EQ(e => e.Id, id);
var entity = collection.FindOne(query);

Atualizando objetos

Para atualizar um objeto no banco é tão fácil quanto no SQL

  1. Setamos a coleção
  2. Criamos um objeto de busca, nesse caso pelo id
  3. Criamos um objeto de update bem como a atualização dos dados
  4. Fazemos a atualização da coleção
var collection = database.GetCollection<Entidade>("entidades");
 var query = Query<Entidade>.EQ(e => e.Id, id);
 var update = Update<Entidade>.Set(e => e.Nome, "Fulano atualizado"); // update modifiers
 collection.Update(query, update);

Excluindo objetos

A dinâmica é a mesma

  1. Setamos a coleção
  2. Montamos a busca com o critério do ID
  3. E removemos o objeto da coleção
 var collection = database.GetCollection<Entidade>("entidades");
 query = Query<Entidade>.EQ(e => e.Id, id);
 collection.Remove(query);

Conclusão

A ideia aqui foi mostrar CRUD no MongoDB com C# de uma forma prática e simples. Espero que tenha ficado claro e que todos consigam fazer. Qualquer dúvida é só falar.

Espero que isso ajude no crescimento da comunidade. Um forte abraço e até a próxima!

Referências

http://docs.mongodb.org/ecosystem/tutorial/getting-started-with-csharp-driver/
http://docs.mongodb.org/manual/tutorial/install-mongodb-on-windows/
http://docs.mongodb.org/ecosystem/tutorial/use-csharp-driver/

Anúncios

Baixar arquivos da Web com C#

Este exemplo mostra como baixar arquivos a partir de qualquer website para o disco local. Uma maneira simples para efetuar o download do arquivo é usar a classe WebClient e seu método DownloadFile. Este método tem dois parâmetros, primeiro é a url do arquivo que você deseja fazer o download e o segundo parâmetro é o caminho para o disco local para o qual deseja salvar o arquivo.

De forma síncrona

O código a seguir mostra como fazer o download de arquivos de forma síncrona. Este método bloqueia a thread principal até que o arquivo é baixado ou ocorrer um erro (neste caso, o WebException é lançada).


using System.Net;

WebClient webClient = new WebClient();
webClient.DownloadFile("http://localhost/arquivo.txt", @"c:\temp\arquivo.txt");

De forma assíncrona

Para baixar um arquivo sem bloquear o segmento principal uso DownloadFileAsync método assíncrono. Você também pode definir manipuladores de eventos para mostrar o progresso e para detectar que o arquivo é baixado. Faça o exemplo abaixo com uma aplicação Windows Forms.


private void btnDownload_Click(object sender, EventArgs e)
{
 WebClient webClient = new WebClient();
 webClient.DownloadFileCompleted += new AsyncCompletedEventHandler(Completo);
 webClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(ProgressoFeito);
 webClient.DownloadFileAsync(new Uri("http://localhost/arquivo.txt"), @"c:\temp\arquivo.txt");
}

private void ProgressoFeito(object sender, DownloadProgressChangedEventArgs e)
{
 progressBar.Value = e.ProgressPercentage;
}

private void Completo(object sender, AsyncCompletedEventArgs e)
{
 MessageBox.Show("Download efetuado!");
}

Até a próxima.

Encurtador de URL’s

Essa semana, aproveitei para colocar um pequeno projeto para funcionar, arquitetei e montei um Encurtador de URL’s que faz utilização do Dot Net Framework 4, SQL Server 2008, C#, integração com Web Services.

Da forma como foi feito encurtará apenas um pouco mais de 6 milhões de URL’s, mas está muito fácil para alterar o algorítimo para ter 5 caracteres ao invés de 4 na chave da URL.

A idéia é evoluir esse software e se aumentar muito a quantidade de acessos utilizar um banco de dados como o Apache Cassandra.

O Encurtador de URL’s está disponível no link http://devd.im, e o código fonte está em http://sourceforge.net/projects/devdim.

http://devd.im/

Formatar XML com XSL usando Dot Net

Nesse artigo utilizei Visual C# 2010 Express, Framework 4.0 e para o aplicativo teste fiz um console application.

Com o advento de integração, SOA, Web Services, cada dia mais temos que adaptar o conteúdo de nossos dados com agilidade, no meu caso eu atuo em uma empresa na qual temos vários parceiros comerciais que consomem nosso catálogo de produtos, e a forma de integração que temos é com o uso de XML, bom para acelerar o desenvolvimento do XML para cada parceiro, nós criávamos um XML para cada um, só que isso não era feito de forma automática, a codificação de cada XML era feita individualmente, os objetos eram reutilizados, mas ai tivemos problemas com performance, pois a consulta era feita em tempo real, ou seja, os parceiros concorriam com os clientes que navegavam no site, o XML demorava para ser carregado, quando era necessário efetuar algum filtro por categoria, gênero, marca etc, isso era feito na aplicação, ou seja, o catalogo era carregado inteiro e filtrado através de um delegate, quando eram poucos parceiros, poucos clientes, tudo bem, mas 1 ano depois com muito mais acessos o negócio ficou ruim, e é isso que vou mostrar como fazer aqui, como esse problema foi resolvido, os passos foram:

  1. Não acessar mais o banco diretamente, mas sim um XML base;
  2. Efetuar a formatação dos dados baseado em um XSL e não mais fazer isso na codificação;
  3. Colocar os critérios dentro do XSL ao invés de fazer na aplicação ou em query.

O que é um arquivo XSL e para que serve

Segundo a Wikpedia “XSL Transformations, ou XSLT (eXtensible Stylesheet Language for Transformation – linguagem extensível para folhas de estilo de transformações), é uma linguagem de marcação XML usada para criar documentos XSL que, por sua vez, definem a apresentação dos documentos XML nos browsers e outros aplicativos que a suportem.” ou seja, serve para formatar a saída de dados do XML

Fonte: http://pt.wikipedia.org/wiki/XSLT

Agora que estamos alinhados com o cenário vamos começar.

XML Base

Isso é algo muito tranquilo, foi criado um JOB que gera um XML em uma pasta visível pela aplicação com todo catálogo de produtos, para esse estudo vamos usar o exemplo abaixo:

<?xml version="1.0"
encoding="utf-8" ?>
<catalogo>
  <item>
    <Sku>500135</Sku>
<Descricao><![CDATA[Bola de Tênis Wilson Championship ]]></Descricao>
<CodigoCategoria>102</CodigoCategoria>
    <Categoria>RACKET</Categoria>
<CodigoMarca>15</CodigoMarca>
<Marca>WILSON</Marca>
 </item>
 <item>
    <Sku>500139</Sku>
<Descricao><![CDATA[Haltere Ferro Centauro MeioKg]]></Descricao>
<CodigoCategoria>107</CodigoCategoria>
    <Categoria>BODY               </Categoria>
<CodigoMarca>999</CodigoMarca>
<Marca>FORTE</Marca>
  </item>
  <item>
    <Sku>500140</Sku>
<Descricao><![CDATA[Halteres Ferro Centauro 1 Kg]]></Descricao>
<CodigoCategoria>107</CodigoCategoria>
    <Categoria>BODY               </Categoria>
<CodigoMarca>999</CodigoMarca>
<Marca>FORTE</Marca>
  </item>
  <item>
    <Sku>500141</Sku>
<Descricao><![CDATA[Halteres Ferro Centauro 2Kg]]></Descricao>
<CodigoCategoria>107</CodigoCategoria>
    <Categoria>BODY               </Categoria>
<CodSubGrupo>34</CodSubGrupo>
<Marca>FORTE</Marca>
  </item>
  <item>
    <Sku>500142</Sku>
<Descricao><![CDATA[Halteres Ferro Centauro 3kg]]></Descricao>
<CodigoCategoria>107</CodigoCategoria>
    <Categoria>BODY               </Categoria>
<CodigoMarca>999</CodigoMarca>
<Marca>FORTE</Marca>
  </item>
  <item>
    <Sku>500143</Sku>
<Descricao><![CDATA[Halteres Ferro Centauro 4Kg]]></Descricao>
<CodigoCategoria>107</CodigoCategoria>
    <Categoria>BODY
               </Categoria>
<CodigoMarca>999</CodigoMarca>
<Marca>FORTE</Marca>
  </item>
</catalogo>

XSL’s

Bom, o XSL pode ficar ao gosto de cada um, eu vou colocar dois exemplos aqui, o primeiro nos dará a seguinte saída do XML Base:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method='xml' indent='yes' version='1.0' encoding='UTF-8' standalone='yes' cdata-section-elements='NOME'/>
<xsl:template match="/">
<produtos>
<xsl:for-each select="catalogo/item[CodigoCategoria='102' and CodigoMarca='999']">
<PRODUTO>
<SKU>
<xsl:value-of select="Sku"/>
</SKU>
<NOME>
<xsl:value-of select="Descricao"/>
</NOME>
<CATEGORIA>
<xsl:value-of select="Categoria"/>
</CATEGORIA>
</PRODUTO>
</xsl:for-each>
</produtos>
</xsl:template>
</xsl:stylesheet>

O segundo nos dará a saída abaixo:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method='xml' indent='yes' version='1.0' encoding='UTF-8' standalone='yes' cdata-section-elements='NOME'/>
<xsl:template match="/">
<produtos>
<xsl:for-each select="catalogo/item[CodigoCategoria='102']">
<ITEM>
<CODIGO>
<xsl:value-of select="Sku"/>
</CODIGO>
<DESCRICAO>
<xsl:value-of select="Descricao"/>
</DESCRICAO>
</ITEM>
</xsl:for-each>
</produtos>
</xsl:template>
</xsl:stylesheet>

Esses arquivos devem ser criados em um local que a aplicação posso lê-los.

Agora vamos entender algumas tag’s do XSL:

Aqui é feita a declaração do XSL, a versão e qual namespace (xmlns) é utilizado, a tag deve ser fechada

<xsl:stylesheet version="1.0" xmlns:xsl="<a href="http://www.w3.org/1999/XSL/Transform">http://www.w3.org/1999/XSL/Transform</a>">

A saída do arquivo é definida aqui, o método/formato (method), a versão do formato (version), a codificação (encoding) e as tags que terão a saída com CDATA (cdata-section-elements).

<xsl:output method='xml' version='1.0' encoding='UTF-8' cdata-section-elements='NOME'/>

Nesse momento o nó raiz é escolhido para trabalhar, a tag deve ser fechada.

<xsl:template match="/">

Tudo o que não estiver usando o prefixo xsl será escrito da mesma forma como estiver no XSL. Vamos ver o loop agora

Aqui é o começo do loop

<xsl:for-each select="catalogo/item">

E aqui é o seu final

</xsl:for-each>

Tudo o que estiver entre essas tag’s será repetido até que todos os nós tenha sido lidos.

Para escrever os valores que estão no XML basta usar a tag value-of e no atributo select colocar o campo que deseja conforme o exemplo

<xsl:value-of select="Sku"/>

Adicionando critérios no XSL

Assim como em uma query é possível adicionar critérios em XSL, basta adicioná-los conforme o código abaixo na tag for-each, no primeiro exemplo o XSL trará apenas os produtos com o campo CodigoCategoria igual a 102, no segundo exemplo, todos com CodigoCategoria igual a 102 e o CodigoMarca igual 999.

<xsl:for-each select="catalogo/item[CodigoCategoria='102']">
<xsl:for-each select="catalogo/item[CodigoCategoria='102' and CodigoMarca='999']">

Usando XSL para formatar o XML

O Dot Net Framework nos dá suporte para trabalhar com arquivos XML através do Namespace System.Xml e para trabalhar com XSL com o Namespace System.Xml.Xsl

Vamos utilizar a classe XslCompiledTransform para formatar o XML com nosso XSL, essa classe é um processador de XSL e XSLT, ela é a sucessora da classe XslTransform, e segundo a MSDN oferece ganhos de performance com relação a classe antiga (e obsoleta na versão 4.0 do Dot Net Framework)

Uma das sobrecargas do construtor do XslCompiledTransform recebe um XmlReader, então carreguei o XSL dentro de um XmlReader e criei o objeto do XslCompiledTransform, o método Transform de nosso objeto XslCompiledTransform tem uma sobrecarga que recebe o xml base, uma lista de argumentos de Xslt que será passado como nulo e um objeto que terá o resultado da transformação, nesse caso é passado um StringWriter, pronto, agora o objeto StringWriter tem o XML carregado conforme as definições do XSL, tudo bem simples,

Código

Aqui está todo o código utilizado para a aplicação funcionar corretamente.

using System;
using System.Xml;
using System.Xml.Xsl;
using System.IO;
namespace GeradorXmlParceiro
{
class Program
{
static string caminhoXmlBase = @"C:\XmlBase\XmlBase.xml";
static string caminhoXsl = @"C:\Xsl\Xsl1.xsl";
static string caminhoXmlFormatado = @"C:\XmlTransformado\XmlTransformado.xml";
static void Main(string[] args)
{
CriarXmlComXsl();
}

static void CriarXmlComXsl()
{
XmlDocument xml = new XmlDocument();
xml = FormartarXmlBaseParaFormatoComXsl(caminhoXsl);
xml.Save(caminhoXmlFormatado);
}

static XmlDocument FormartarXmlBaseParaFormatoComXsl(string caminhoXsl)
{
XmlDocument xml = new XmlDocument();
XslCompiledTransform xsl = new XslCompiledTransform();
XmlDocument xmlBase = ObterXmlBase();
try
{
XmlReader reader = XmlReader.Create(caminhoXsl);
xsl.Load(reader);
StringWriter writer = new StringWriter();
xsl.Transform(xmlBase, null, writer);
xml.LoadXml(writer.ToString());
}
catch (Exception ex)
{
throw new Exception("Ocorreu um erro ao efetuar a transformação do XML.", ex.InnerException);
}
return xml;
}

static XmlDocument ObterXmlBase()
{
XmlDocument xml = new XmlDocument();
try
{
xml.Load(caminhoXmlBase);
}
catch (Exception ex)
{
throw new Exception("Ocorreu um erro ao carregar o XML.", ex.InnerException);
}
return xml;
}
}
}

É isso ai! Espero que esse artigo posso contribuir para o crescimento da comunidade! Até a próxima!

Referências

http://www.w3schools.com/xsl/

http://www.w3schools.com/xml/

http://msdn.microsoft.com/en-us/library/system.xml.xsl.xslcompiledtransform.aspx

Redimensionando imagens com Dot Net

Com o uso das bibliotecas System.Drawing e System.Drawing.Imaging podemos redimensionar imagens há um tamanho bem menor sem praticar perder a qualidade.

Primeiro pegue uma imagem grande e de boa resolução, no meu caso vou usar uma imagem de 900×900 e vou redimensioná-la para os tamanhos 400×400, 250×2500, 120×120 e 48×48.

Criei um novo projeto do tipo Console Application no Visual Studio 2010, adicionei referência à biblioteca System.Drawing e no método Main adicionei o seguinte código:

List<string> enderecosDeImagens = new List<string>();

enderecosDeImagens = Imagem.ObterImagensNaoRedimensionadas();

List<Resolucao> resolucoes = new List<Resolucao>();

resolucoes.Add(Resolucao._400x400);
resolucoes.Add(Resolucao._250x250);
resolucoes.Add(Resolucao._120x120);
resolucoes.Add(Resolucao._48x48);

Imagem.RedimensionarArquivos(enderecosDeImagens, resolucoes);

Nesse código foi criada uma lista de string’s que conterá os endereços das imagens não redimensionadas, uma lista do tipo resolução, e depois passamos por paramêtro os endereços das imanges e as resoluções que queremos ter. Apreveite para criar o Enum Resolucao

public enum Resolucao
{
_48x48 = 48,
_120x120 = 120,
_250x250 = 250,
_400x400 = 400
}

Crie uma classe static chamada Imagem, adicione o método ObterImagensNaoRedimensionadas que retornorá uma lista de string, o método RedimensionarArquivos que será void, o método CriarPastas que será void, o método RedimensionarArquivo que será booleano, o método SalvarImagem que será void eo método ObterInformacaoDeCodificacao que retornará um ImageCodecInfo.

ObterImagensNaoRedimensionadas

List<string> imagensNaoRedimensionadas = new List<string>();

imagensNaoRedimensionadas = System.IO.Directory.GetFiles(@”D:\Artigos\Images\img\900×900″).ToList();

return imagensNaoRedimensionadas;

RedimensionarArquivos

CriarPastas(resolucoes);

Dictionary<string, bool> arquivosRedimensionados = new Dictionary<string, bool>();

foreach (string enderecoDoArquivo in enderecosDosArquivos)
{
foreach (Resolucao resolucao in resolucoes)
{
if (RedimensionarArquivo(enderecoDoArquivo, resolucao))
{
arquivosRedimensionados.Add(string.Format(“{0} – {1}”, enderecoDoArquivo, resolucao), true);
}
else
{
arquivosRedimensionados.Add(string.Format(“{0} – {1}”, enderecoDoArquivo, resolucao), true);
}
}
}

CriarPastas

foreach (Resolucao resolucao in resolucoes)
{
string pasta = string.Format(@”D:\Artigos\Images\img\{0}x{0}”, (int)resolucao);

if (System.IO.Directory.Exists(pasta) == false)
{
System.IO.Directory.CreateDirectory(pasta);
}
}

RedimensionarArquivo

bool resultado = true;

try
{
Bitmap imagemAtual = new System.Drawing.Bitmap(enderecoArquivo);

Bitmap ImagemRedimensionada = new System.Drawing.Bitmap((int)resolucao, (int)resolucao);

using (Graphics g = Graphics.FromImage((Image)ImagemRedimensionada))
{
g.DrawImage(imagemAtual, 0, 0, (int)resolucao, (int)resolucao);
}

System.IO.FileInfo fi = new System.IO.FileInfo(enderecoArquivo);

string destino = string.Format(@”D:\Artigos\Images\img\{0}x{0}\{1}”, (int)resolucao, fi.Name);

Imagem.SalvarImagem(destino, ImagemRedimensionada, 85L);
}
catch (Exception ex)
{
throw ex;
}

return resultado;

SalvarImagem

// Encoder parameter for image quality
EncoderParameter qualidade =
new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, quality);

// Jpeg image codec
ImageCodecInfo jpegCodec = ObterInformacaoDeCodificacao(“image/jpeg”);

if (jpegCodec == null)
return;

EncoderParameters parametrosDeCodificacao = new EncoderParameters(1);
parametrosDeCodificacao.Param[0] = qualidade;

img.Save(path, jpegCodec, parametrosDeCodificacao);

ObterInformacaoDeCodificacao

// Get image codecs for all image formats
ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders();

// Find the correct image codec
for (int i = 0; i < codecs.Length; i++)
{
if (codecs[i].MimeType == mimeType)
{
return codecs[i];
}
}

return null;

 

Repeater dentro de Repeater (DataList dentro de DataList ou GridView dentro de GridView)

Imagine a seguinte situação: você tem uma lista de um determinado objeto e cada objeto dessa lista tem uma propriedade. Essa propriedade é uma lista de um determinado objeto e você precisa popular um Repeater.

Vamos dar nomes aos objetos: suponha que você tenha uma lista de professores e cada professor tem seus alunos, bem, alguns irão dizer que é fácil, cada vez que o Repeater fizer um ItemDataBound basta fazer um busca novamente no banco de dados e listar o resultado. Como sempre me deparo com essa situação e vira e mexe algum me pergunta se essa é a melhor maneira de fazer resolvi escrever um artigo.

É muito simples, se a sua coleção já vem populada, basta você passar essa lista de objetos para o outro controle dentro do seu Repater (nesse caso outro Repeater), e isso será feito a cada ItemDataBound.

Classes

Temos as seguintes classes:

/// <summary> /// Classe mãe /// </summary> public abstract class Pessoa { private string _nome = string.Empty; public string Nome { get { return _nome; } set { _nome = value; } } public Pessoa() { } } /// <summary> /// Professor implementa Pessoa /// </summary> public class Professor : Pessoa { private string _materia = string.Empty; public string Materia { get { return _materia; } set { _materia = value; } } /// <summary> /// Um professor tem uma lista de alunos /// </summary> private System.Collections.Generic.List<Aluno> alunos = new System.Collections.Generic.List<Aluno>(); public System.Collections.Generic.List<Aluno> Alunos { get { return alunos; } set { alunos = value; } } public Professor(string nome, string materia, System.Collections.Generic.List<Aluno> alunos) { Nome = nome; Materia = materia; Alunos = alunos; } } /// <summary> /// Aluno implementa Pessoa /// </summary> public class Aluno : Pessoa { private string _turma = string.Empty; public string Turma { get { return _turma; } set { _turma = value; } } public Aluno(string nome, string turma) { Nome = nome; Turma = turma; } }

WebForm

Agora que já conhecemos nossas classes vamos para a implementação disso em uma página. Primeiro vamos criar um Repeater na página e, dentro dele, criaremos um segundo repeater, como no exemplo abaixo:

<asp:Repeater ID="ProfessorRepeater" runat="server" OnItemDataBound="ProfessorRepeater_ItemDataBound"> <ItemTemplate> Professor: <%# Eval("Nome") %> <br /> Matéria: <%# Eval("Materia") %> <br /> Alunos: <asp:Repeater ID="AlunoRepeater" runat="server"> <HeaderTemplate> <table> <tr style="font-weight: bold"> <td> Nome</td> <td> Curso</td> </tr> </HeaderTemplate> <FooterTemplate> </table> </FooterTemplate> <ItemTemplate> <tr style="background-color: Gray"> <td> <%# Eval("Nome") %> </td> <td> <%# Eval("Turma")%> </td> </tr> </ItemTemplate> <AlternatingItemTemplate> <tr style="background-color: Silver"> <td> <%# Eval("Nome") %> </td> <td> <%# Eval("Turma") %> </td> </tr> </AlternatingItemTemplate> </asp:Repeater> </ItemTemplate> <SeparatorTemplate> <hr /> </SeparatorTemplate> </asp:Repeater>

Atente para o detalhe que o repeater AlunoRepater está escrevendo as propriedades Nome (que vem de Pessoa) e turma (que é da classe Aluno).

Bom, mas isso não irá funcionar dessa maneira. Vejamos no code behind da página como é a implementação disso.

Code Behind

No PageLoad os objetos são criados e populados.

protected void Page_Load(object sender, EventArgs e) { Page.Title = "Repeater dentro de Repeater (DataList dentro de DataLista ou GridView dentro de GridView)"; // lista de alunos que será atribuída aos professores List<Aluno> alunosEpaminondas = new List<Aluno>(); alunosEpaminondas.Add(new Aluno("Alan", "Sistemas da Informação")); alunosEpaminondas.Add(new Aluno("Fabio", "Ciência da Computação")); alunosEpaminondas.Add(new Aluno("Marcelo", "Desenvolvimento de Sistemas Web")); // Só para não falar que os professores tem os mesmos alunos List<Aluno> alunosAdolfo = new List<Aluno>(); alunosAdolfo.Clear(); alunosAdolfo.Add(new Aluno("Carol", "Análise de Sistemas")); alunosAdolfo.Add(new Aluno("Bruno", "Banco de Dados")); // lista de professores List<Professor> professores = new List<Professor>(); professores.Add(new Professor("Epaminondas", "Gestão de Projetos", alunosEpaminondas)); professores.Add(new Professor("Adolfo", "Programação Orientação a Objetos", alunosAdolfo)); ProfessorRepeater.DataSource = professores; // define o DataSource do repeater como a lista de objetos professores ProfessorRepeater.DataBind(); }

No controle ProfessorRepeater, no evento ItemDataBound que o controle AlunoRepeater é populado, veja como é simples fazer a conversão do item do repeater que é passado.

protected void ProfessorRepeater_ItemDataBound(object sender, RepeaterItemEventArgs e) { // verifica se o item é do tipo ItemType ou AlternatingItem, se não for retorna e não continua o processamento if (e.Item.ItemType != ListItemType.Item && e.Item.ItemType != ListItemType.AlternatingItem) return; // verifica se o objeto AlunoRepeater existe dentro do item if (e.Item.Controls.Contains((Repeater)e.Item.FindControl("AlunoRepeater"))) { // cria um objeto Repeater e define-o como o objeto AlunoRepeater do item Repeater alunoRepeater = (Repeater)e.Item.FindControl("AlunoRepeater"); // converte o item (linha do repeater) para um professor e define a propriedade Alunos como DataSource do repeater alunoRepeater.DataSource = ((Professor)e.Item.DataItem).Alunos; alunoRepeater.DataBind(); } }

Super simples e tranqüilo, não há segredos nisso. A grande sacada é não ter que conectar ao banco novamente apenas obter os outros objetos. É possível utilizar isso também na criação de menus, para exibir a notas fiscais e seus itens, pedidos e seus itens etc. Aí vai depender da necessidade de cada projeto.

Até a próxima!

Upload de imagem com recorte usando Jquery e asp.net

Quem nunca quis disponibilizar, em sua aplicação, a possibilidade de o usuário subir uma imagem e recortá-la, como vários sites já fazem? Dei uma pesquisada, estudei sobre o System.Drawing,  jquery e resolvi compartilhar aqui o que consegui. Veja só.

Bibliotecas

A primeira coisa a ser feita aqui é baixar alguns arquivos, faça o download do jquery e dojcrop.

Namespaces

Inclua os seguintes namespaces em sua página:

  • System.IO
  • System.Drawing
  • System.Drawing.Imaging
  • System.Drawing.Drawing2D

O namespace System.Drawing sera utilizado com apelido SD

Formulário

Adicione três controles do tipo Panel no formulário, conforme a tabela abaixo:

ID Visible
UploadPanel True
ImagemOriginalPanel False
ImagemRecortadaPanel False

Dentro do UploadPanel adicione os controles dessa forma:

Tipo ID Text Visible
FileUpload ArquivoFileUpload N/A True
Button UploadButton Upload True
Label ErroLabel “” False

Dentro do ImagemOriginalPanel adicione os controles como mostrado:

Tipo ID Text
Image OriginalImage N/A
Button RecortarButton Recortar
HiddenField XHiddenField N/A
HiddenField YHiddenField N/A
HiddenField WHiddenField N/A
HiddenField HHiddenField N/A

Dentro do ImagemRecortadaPanel adicione o seguinte controle:

Tipo ID Text
Image ImagemRecortadaImage N/A

O código da sua página deve estar bem parecido com este:

    <form id="form1" runat="server">         <asp:Panel ID="UploadPanel" runat="server">             <asp:FileUpload ID="ArquivoFileUpload" runat="server"/>             <asp:Button ID="UploadButton" runat="server" Text="Upload" />         </asp:Panel>         <asp:Panel ID="ImagemOriginalPanel" runat="server" Visible="false">             <asp:Image ID="OriginalImage" runat="server" />             <asp:Button ID="RecortarButton" runat="server" Text="Recortar" />             <asp:HiddenField ID="XHiddenField" runat="server" />             <asp:HiddenField ID="YHiddenField" runat="server" />             <asp:HiddenField ID="WHiddenField" runat="server" />             <asp:HiddenField ID="HHiddenField" runat="server" />         </asp:Panel>         <asp:Panel ID="ImagemRecortadaPanel" runat="server" Visible="false">             <asp:Image ID="ImagemRecortadaImage" runat="server" />         </asp:Panel>

Estrutura do site

Adicione uma pasta com o nome imagens ao site.

Arquivos das bibliotecas

Adicione os seguintes arquivos no site:

  • jquery.min.js
  • jquery.Jcrop.js
  • jquery.Jcrop.css

HTML

Inclua as referências para os arquivos na sua página.

<script src="jquery.min.js" /></script> <script src="jquery.Jcrop.js" /></script> <link rel="stylesheet" href="jquery.Jcrop.css" type="text/css" />

Aplicando o Jcrop

Inclua as seguintes funções na sua página:

        jQuery(document).ready(function(){             jQuery('#OriginalImage').Jcrop({                 onSelect: marcaPontos             });         });         function marcaPontos(c) {             jQuery('#XHiddenField').val(c.x);             jQuery('#YHiddenField').val(c.y);             jQuery('#WHiddenField').val(c.w);             jQuery('#HHiddenField').val(c.h);         };               

É realmente muito simples. Jcrop foi aplicado ao controle OriginalImage que está dentro de ImagemOriginalPanel, e um handler foi adicionado ao evento de selecionar a imagem. Isso acontecerá quando o usuário tiver acabado de selecionar a área da imagem que deseja manter. O handler chamada a função marcaPontos, que define os valores dos campos XHiddenField, HiddenField, WHiddenField e HHiddenField passando as coordenadas.

Code Behind

O código abaixo irá pegar o caminho físico da pasta imagens e guardá-lo na variável pasta, declare-o no começo da classe da página.

string pasta = HttpContext.Current.Request.PhysicalApplicationPath + "imagens\\";

No evento click do botão upload adicione o seguinte código:

    protected void UploadButton_Click(object sender, EventArgs e) { bool extensaoPermitida = false; bool arquivoGravado = false; if (ArquivoFileUpload.HasFile) { string extensaoArquivo = Path.GetExtension(ArquivoFileUpload.FileName); string[] extensoesPermitidas = { ".png", ".jpg", ".gif", ".jpeg" }; for (int i = 0; i < extensoesPermitidas.Length; i++) if (extensoesPermitidas[i] == extensaoArquivo) extensaoPermitida = true; if (extensaoPermitida) { try { ArquivoFileUpload.PostedFile.SaveAs(pasta + ArquivoFileUpload.FileName); arquivoGravado = true; } catch (Exception ex) { ErroLabel.Text = "Ocorreu um problema na tentativa de salvar o arquivo." + ex.ToString(); ErroLabel.Visible = true; arquivoGravado = false; } } else { ErroLabel.Text = string.Format("Tipo de arquivo inválido. Tipo aceitos {0}.", extensoesPermitidas.ToString()); ErroLabel.Visible = true; } if (arquivoGravado) { ImagemOriginalPanel.Visible = true; OriginalImage.ImageUrl = "imagens/" + ArquivoFileUpload.FileName; Session["arquivo"] = ArquivoFileUpload.FileName; } } }

No evento click do botão recortar adicione o seguinte código:

   protected void RecortarButton_Click(object sender, EventArgs e) { string nomeArquivo = Session["arquivo"].ToString(); int eixoX = Convert.ToInt32(XHiddenField.Value); int eixoY = Convert.ToInt32(YHiddenField.Value); int largura = Convert.ToInt32(WHiddenField.Value); int altura = Convert.ToInt32(HHiddenField.Value); byte[] recorte = Recortar(pasta + nomeArquivo, largura, altura, eixoX, eixoY); using (MemoryStream ms = new MemoryStream(recorte, 0, recorte.Length)) { ms.Write(recorte, 0, recorte.Length); using (SD.Image imagemRecortada = SD.Image.FromStream(ms, true)) { string salvarEm = pasta + "crop" + nomeArquivo; imagemRecortada.Save(salvarEm, imagemRecortada.RawFormat); ImagemOriginalPanel.Visible = false; ImagemRecortadaPanel.Visible = true; ImagemRecortadaImage.ImageUrl = "imagens/crop" + nomeArquivo; } } }

Crie um método do tipo void conforme abaixo.

  private byte[] Recortar(string nomeAbsolutoArquivo, int largura, int altura, int eixoX, int eixoY) { try { using (SD.Image imagemOriginal = SD.Image.FromFile(nomeAbsolutoArquivo)) { using (SD.Bitmap bitmap = new System.Drawing.Bitmap(largura, altura)) { bitmap.SetResolution(imagemOriginal.HorizontalResolution, imagemOriginal.VerticalResolution); using (SD.Graphics grafico = SD.Graphics.FromImage(bitmap)) { grafico.SmoothingMode = SmoothingMode.AntiAlias; grafico.InterpolationMode = InterpolationMode.HighQualityBicubic; grafico.PixelOffsetMode = PixelOffsetMode.HighQuality; grafico.DrawImage(imagemOriginal, new System.Drawing.Rectangle(0, 0, largura, altura), eixoX, eixoY, largura, altura, SD.GraphicsUnit.Pixel); MemoryStream ms = new MemoryStream(); bitmap.Save(ms, imagemOriginal.RawFormat); return ms.GetBuffer(); } } } } catch (Exception ex) { throw ex; } }

Agora é só colocar tudo para rodar. Não é um bicho de sete cabeças, a questão é juntar tudo.

Referências

 

Espero que esse artigo sirva para agregar conhecimento à comunidade. Até a próxima.