Академический Документы
Профессиональный Документы
Культура Документы
MuraldeRedeSocialUsando
ASP.NETMVCParte1
Dequesetrataoartigo
Oartigotratadecomocriarummuralderedesocialutilizandotcnicasdecomposiode
HTMLnobrowserdoclienteutilizandoopadroMVVM.Almdisso,usaabiblioteca
SignalR.NetparaacomunicaoemtemporealmultiusuriocomASP.NETMVC,C#e
JavaScript.
Emquesituaootematil
tilemaplicaeswebcomumaoumaiscaractersticasderedesocial(comonotificaes,
atualizaes,batepapo,muralefrum),quedemandamcomunicaoemtemporeale
atualizaointensivadainterfaceHTML.
ResumoDevman
ComoCriarUmMuraldeRedeSocial:Nesteprimeiroartigoiremosapresentaralgumas
bibliotecas,tcnicas,ferramentaseumaaplicaowebtotalmentefuncionalqueimita
algumasdasfuncionalidadesdoFacebook.
VamosutilizaroframeworkFluentNHibernateparaimplementaromapeamentodomodelo
dedados,deformalimpaesemconfiguraesviaXML.Emseguida,criaremos
cuidadosamenteasviewsaplicandoclientsidecompositioneMVVMbindingcomaajudada
bibliotecaKnockout,eparadeixaraaplicaocomjeitoderedesocialvamosutilizara
bibliotecaSignalR.Netparafazertodootrabalhodeencanamentoparanossas
comunicaesemtemporeal.
Pormuitosanos,ficamospresosaummodeloondeonavegadoreawebapenas
eventualmenteseconectametrocaminformaes:issotemmuitoavercomofatodeo
HTTPserumprotocolostateless,isto,umprotocolosemestado.Emoutraspalavraso
HTTPinterpretaacomunicaodeumaaplicaowebcomoumasequnciadepares
independentesderequisieserespostas.ParaoHTTP,cadanovarequisionotratada
comoumacontinuaodarequisioanterior,massimcomoumanovarequisio.Para
resolveresseproblema,aolongodosanosforamcriadosmecanismosdeautenticaoe
preservaodoestadodanavegao,comooscookies,assesseseosViewStates,que
passaramaserenviadosaoservidoracadarequisio,paraajudaraidentificaroautordos
chamados,asessoeoestadodapgina.Nesseestgiodaweb,todarequisiofeitaao
servidoreraumarequisiodepginacompleta,mesmoqueaalteraofosseapenasum
elemento.Tomandocomoexemploumgerenciadordeemailonline,apginadecaixade
entradateriaquesertotalmenterecarregadaparaquefosseatualizadaumanicalinha
indicandoqueumemailacaboudechegar.
ComapopularizaodesistemasquefuncionaminteiramentenaWebetambmcomo
aumentodavelocidadedasconexesbandalarga,oproblemadaesperapeloenvioeretorno
dapginainteirasetornoumuitomaisevidenteparaousurio.
Depoisforamamadurecendooscomponentesquepermitiramutilizaropotencialda
tecnologiaAJAX,entreelasaAPIchamadaXMLHTTPRequest,escritaemJavaScript.Cada
requisioXMLHTTPRequestpartiadocdigoJavaScripteoresultadoeradevolvidopara
http://www.devmedia.com.br/websys.5/webreader_print.asp?cat=1&artigo=5000&revista=impressao_100#a5000 1/24
requisioXMLHTTPRequestpartiadocdigoJavaScripteoresultadoeradevolvidopara
essemesmocdigo,eentoalgumelementodapginaeraatualizado,comoporexemplo,a
linhacontendooemailnovo.Comrequisiesmaisleves,respostascommenorconsumode
redeeatualizaomaisrpidadocontedodaspginas,empoucotempoosprincipais
websitespassaramautilizarAjaxemlargaescalaelogoelesetornoupadrodaindstria.As
principaisvantagensdasaplicaesAJAXqueosdadosenviadoserecuperadospelarede
soreduzidoseousurionoprecisaesperarapginaserrecarregadaacadarespostado
servidor.Apesardenopossuirnadainovadoremsuaessncia,ousodeAJAXrevolucionou
odesenvolvimentoweb.Haviaclaramenteumanecessidadedesecriarumawebmaisgile
interativa,maiseficientenoconsumodedados,ecommelhorasignificativanacomunicao
entreonavegadoreoservidor.Nessepontoemparticularhaviaoproblemabastantecomum
emqueapginanonavegadornotomavaconhecimentosobreatualizaesimportantes
queocorriamnoservidor.
Paraissosurgiramtcnicascomoopooling,ondeocdigoJavaScriptdonavegadorenvia
requisiesAjaxaoservidoremintervalosdetemporegulares,paraobterpossveis
notificaeseatualizarapginaadequadamente.Emboraopoolingresolvesseoproblema
dasnotificaes,elenoeraumasoluodetemporeal,poisasatualizaesnoeram
instantnease,almdisso,haviaoproblemasriodeconsumoderecursosde
processamentoexcessivostantodonavegadorquantodoservidor.Este,particularmente,
sofriacomonmeroderequisiesquecresciamemprogressogeomtricadevido
entradadenovosusuriosrealizandopoolingaomesmotempo,oqueprejudicavamuitoeat
comprometiaaescalabilidadedaaplicao.
Pararesolverisso,temposdepoissurgiramespecificaesHTML5descrevendoos
WebSockets,comoumatecnologiaquefornececanaisfullduplexdecomunicao
bidirecionalsobreumaconexoTCP,projetadainicialmentepara(masnolimitadaa)
navegadoreseservidoresweb.
OsWebSocketsresolvemdefinitivamenteoproblemadafaltadeummecanismoeficientede
conexopersistenteenotificaoentreclienteeservidor,porm,atarefadeconfigurarum
servidorparafazerusodeWebSocketspodesetornarinvivelparaquemtrabalhacom
tecnologiasMicrosoft,jqueosWebSocketssosuportadossomenteapartirdoWindows8,
WindowsServer2012eInternetExplorer10.
Paraarquitetos,analistasedesenvolvedores,issorestringemuitoaconfiguraomnima
necessriadosservidoresedosusuriosparaqueatecnologiaWebSocketsfuncione.
Poressemotivo,foicriadaabibliotecaSignalR.Net,quefornecetodaainfraestruturaparao
usodeumaconexopersistenteentreonavegadoreoservidorwebdemaneirasimplesde
seconfiguraretransparenteparaodesenvolvedor,permitindotrabalharcomtodosos
servidoresASP.NETenavegadoresexistentesnomercado.Internamente,oSignalR.Net
podetrabalharcomWebSockets,casoelesexistamnainfraestruturadoservidor.Casoos
WebSocketsnoestejampresentes,oSignalR.Netirutilizaraestratgiadelongpooling.
queummecanismoemqueocdigoJavaScriptdecadanavegadorestabeleceuma
conexopersistentecomoservidorweb(isto,aconexonuncaexpira)atqueoservidor
envieumamensagemparaonavegador.Quandoamensagemretornada,aconexo
interrompidaeentooSignalR.Netautomaticamentereestabeleceumanovaconexo
persistenteentreaquelenavegadoreoservidorweb.Issoemulaaconexorealemduasvias
fornecidasnativamentepelosWebSockets.
Tudoissodeformatransparente,semqueodesenvolvedorpreciseconhecerosdetalhes
dessemecanismo.
PodemosdizerqueoSignalR.Netpossibilitaesimplificaodesenvolvimentodeaplicaes
quefazempartedoquepoderamoschamardenovaweb:maisdinmica,gil,interativae
(porquenodizer?)muitomaissocial.Sim,importantefrisarqueoaspectosocialdas
aplicaeswebnopodemaisserdeixadodelado.Ecomsocialnoqueremosdizerqueo
usuriosimplesmentetenhaacessoajoguinhos(apesardacrescenteindstriaquehpor
trsdessenegcio),massimexploraroladodocomportamentohumanoemqueaspessoas
buscamacomunicaocomoutraspessoas.Muitomaisdoqueestabelecerconexes,a
novawebpermitequeaspessoasseexpressem,digamoquepensam,sejamouvidase
tambmsejamouvintesdeoutraspessoas.Sonovoscanaisdecomunicaoqueseabrem
http://www.devmedia.com.br/websys.5/webreader_print.asp?cat=1&artigo=5000&revista=impressao_100#a5000 2/24
tambmsejamouvintesdeoutraspessoas.Sonovoscanaisdecomunicaoqueseabrem
equeagregamvaloraoproduto.Colocarpessoasemprimeiroplanoalgoquemuitas
aplicaeswebmodernasalmejam,poisaparticipaocoletivaumtermmetroimportante,
quemedeograudeinteresseedesatisfaodosusurioscomrelaoaoproduto,eque
quandonecessriotambmpermiteatomadadeaesrpidascomrelaoao
comportamentodessesusurios.
Notoaqueoaspectosocialofatordesucessodemuitasideiasquerapidamentese
tornaramnegciosbilionriosnosltimosanos:BastaolharosexemplosdoGMail,Facebook,
GooglePlus,Outlook.comeTwitter,queconectamusuriosnumaescalagigantescae
gerenciammilhesdeconexessimultneas.Vejatambmoqueocorrecomosjogos
sociaiscomoFarmVille,CityVilleeTheSimsSocial.Todoselessebaseiamnummecanismo
queconectamltiplosjogadoresdediversaspartesdomundoatravsdeserviosdeum
mesmohub,oucentro,noqualosusuriosseautenticamparateracessoaosaplicativos
sociais.Equantomaisusuriosengajados,maioronmeropotencialdenovosconsumidores
edenovastransaesrealizadascomopagamentodeserviosquesooferecidospelas
aplicaessociais.
ComcertezaoFacebookoexemplomaisevidentedessaerasocialdatecnologiaemque
vivemos.Elecomeoucomoumservioexclusivoparaalunosdasuniversidadesamericanas
maisprestigiadasefoiseespalhandorapidamenteatchegarapraticamentetodasas
pessoasdomundocomacessoaumcomputadorouumtelefonecelular.Comoastronmico
nmeroquebeira1bilhodepessoascadastradas,oFacebooknochegouaotopopor
acaso.
Mesmonosendoaprimeiraredesocial,empoucotemposetornoulderdomercadoe
obrigouasconcorrentesabuscarnichosondepudessemsobreviver.
Dopontodevistadeusabilidadeeexperinciadousurio,oFacebooktambmteveuma
vantagemclara:oMuraleoFeeddeNotcias,quesoduascaractersticasmuito
importantesdowebsite,quepodemservistoscomoopontodeencontrodosusurios.
Talvezelessejamaexperinciamaisexemplardaredesocial.Poralicadapessoavideias,
msicaetudoaquiloqueconsideradointeressantepelosseusamigos.Etambm
convidadaaseengajaremdiscusses,curtirecompartilharpostagenseseatualizarcomos
tpicosdomomento.
OMuralumespaonapginadeperfildousurioquepermiteaosamigosenviar
postagensparaqueousurioveja.Elevisvelparaqualquerpessoacompermissopara
veroperfilcompleto,epostsdiferentesnomuralaparecemseparadosno"FeeddeNotcias".
Muitosusuriosusamosmuraisdeseusamigosparadeixarrecadostemporrios.
Mensagensprivadassosalvasem"Mensagens",quesoenviadascaixadeentradado
usurioesovisveisapenasaoremetenteeaodestinatrio.
Obotodecurtirumrecursoondeosusuriospodemgostardecertoscontedos,tais
comoatualizaesdestatus,comentrios,fotos,linkscompartilhadosporamigos,e
propagandas.
tambmumacaractersticadaplataformaFacebook,quepermiteaossitesparticipantesa
exibiremumbotoquepermitemocompartilhamentodecontedodositecomosamigos.
Aplicaodeexemplo
Aaplicaoaseguirumexemplodecomorecriaromuralderedesocialdeformabem
simplificadautilizandoastecnologiasatualmentedisponveisaodesenvolvedor.Net.Seria
interessantetambmqueoleitorimaginasseoutroscenriosondeessetipodecomunicao
emtemporealpudesseseraplicada:umasaladebatepapo,porexemplo,seriaautilizao
maisbvia.Ouentoumpainelmostrandodadosdeclientesemtemporeal(com
geolocalizaobaseadanoendereodeIP,informaessobreonavegador,resoluode
tela,etc.).Outrousoseriaodeaplicaescolaborativasquepermitisseminteraes
http://www.devmedia.com.br/websys.5/webreader_print.asp?cat=1&artigo=5000&revista=impressao_100#a5000 3/24
tela,etc.).Outrousoseriaodeaplicaescolaborativasquepermitisseminteraes
simultneasdemltiplosusuriosnamesmatelaoumesmodocumento.
NaFigura1vocconferecomoficaranossaaplicao.
[abririmagememjanela]
Figura1.Aplicaoexibindoomuralderedesocial
RegrasdeNegcio
Parasimplificar,todososusuriosdosistemasoautomaticamenteamigosunsdosoutros.
Umavezconectado,ousurioserdirecionadoparaomuralondeseroexibidosos
comentriosdousurioedeseusamigos.
Omuralcompostoporumapilhaverticaldecomentrios.Haverdoisnveisde
comentrios:noprimeironvelestooscomentriosenviadosquenoserelacionamcom
comentriosanteriores.Cadacomentriodeprimeironveliniciaumanovaconversa.O
segundonveldecomentriosumarespostaaocomentriodeprimeironvelouaalgum
doscomentriosdesegundonvelpostadoanteriormente.Apilhadecomentriosdesegundo
nvelapareceridentadanoblocodesuarespectivaconversa.
Cadablocodecomentriosercompostopelafotodoautordocomentrio,seguidodeseu
nomeemnegritoedocomentrio.Logoabaixohaverumtextoinformandohquantotempo
aquelecomentriofoienviadoparaosistema.
Oscomentriosdeprimeironveldevemterafotodoautoremtamanhoregular,eos
comentriosdesegundonveldevemterfotosdetamanhopequeno.
Cadacomentriodeveterumlinkcurtir,queirmarcaraquelecomentriocomocurtido
pelousurioconectadoaosistema.Quandoousuriocurteumcomentrio,essainformao
enviadaparaoservidorepersistidanobancodedados.Almdisso,umresumoexibido
abaixodocomentrio,informandoosnomesdaspessoasquecurtiramaquelecomentrio.
Todososusuriosdevemverainformaodequemcurtiuocomentrio.Nosomenteos
usuriosonline,mastambmosusuriosqueseconectaremposteriormenteaocomentrio.
http://www.devmedia.com.br/websys.5/webreader_print.asp?cat=1&artigo=5000&revista=impressao_100#a5000 4/24
usuriosonline,mastambmosusuriosqueseconectaremposteriormenteaocomentrio.
Quandoumusuriocurtirumcomentrio,olinkCurtirdevemudarautomaticamentepara
Curtir(Desfazer),parapermitirqueousuriopossadesfazeraaodecurtirocomentrio.
Seousuriodesfizeraao,essainformaoenviadanovamenteaoservidor,eonomedo
usurioremovidodoresumodequemcurtiuocomentrio.
Todososusuriosdevempoderpostarnovoscomentrios,iniciandoassimumanova
conversa(comentriosdeprimeironvel).
Todososusuriosdevempoderresponderaalgumaconversajexistente(comentriosde
segundonvel).
AModelagemdosDados
NesteprojetoserutilizadaaabordagemCodeFirst(NotadoDevMan1),isto,emvezde
comearaconstruirastabelasdobancodedadosprimeiroesentomodelaraaplicao
todabaseadanelas,primeirovamoscriaromodelocompletoatravsdecdigoC#paraento
criaroesquemadebancodedadosbaseadonasclassesepropriedadesdomodelo.
Umadasvantagensdessaabordagemquepodemosfacilmentecriarerecriarobancode
dadosquantasvezesquisermos.Assim,qualquermudananomodeloirprecisarapenasde
umapequenamudananasnossasclassesepropriedadesC#,seguidodeumcomandopara
recriarobancodedadosapartirdomodelo.
NotaDevman1:CodeFirsttambmsignificaqueoworkflowbaseadoemcdigo,emvezde
serbaseadoemXMLedesigners.Nonecessriodesenharnadaemumaferramentade
designeroumanipularumarquivoXMLconfuso.Oframeworkcodefirstescolhidoter
convenesapartirdasquaisomodelosebeneficiarduranteageraodomodelode
bancodedados.
OutravantagemdaabordagemCodeFirst(emboranoestejamosutilizandonesteprojeto)
ahabilidadedeusarmocksparafacilitaraaplicaodetestesunitrios,ouseja,objetos
fictciosquesimulamcomportamentodeobjetosconcretos,equesubstituemessesobjetos
concretosnoescopodetestesunitrios.
Geralmente,utilizamsemocksnumtesteunitrioapartirdeinterfaces,parasimular
variaesdevaloresdeentradaederetornoemobjetosquesodependnciasdeoutro
objetoqueoalvodotesteemquesto.
FluentNHibernate
AousaraabordagemCodeFirst,possvelescolheroframeworkdemapeamentoobjeto
relacional.UmadasopesoEntityFrameworkdaMicrosoft,quefoilanadocomoopen
sourceemJulhode2012.OutraopobviaoframeworkNHibernate,porm,necessrio
trabalharcomaconfiguraoviaXML.OutrapossvelescolhaoFluentNHibernatequeda
possibilidadedecriarmapeamentosviacdigofluenteefortementetipado.Esteframework
permiteencontrarerrosdemodelagemedemapeamentomaisrapidamentedoqueviaXML.
Almdisso,atravsdomapeamentofluentepossvelcriarclassesbaseapartirdasquais
suasdemaisclassesherdam,escrevendoumcdigomaisconcisoelivrederepeties
desnecessrias.
SQLServerCompact
PorsetratardeumprojetoASP.NET,poderamosescolherpelobancodedadosSQL
Server,porm,porsetratardeumprojetopequeno,podemostrabalharcomembedded,
compactosemaisfacilmenteportveis.
Nessecaso,teramosoSQLServerCompacteoSQLite,eambossobonsparaaplicaes
standalone.PorapresentarterumformatoreconhecidonativamentepeloMicrosoftSQL
ServerManagementStudioutilizaremosoSQLServerCompact.
http://www.devmedia.com.br/websys.5/webreader_print.asp?cat=1&artigo=5000&revista=impressao_100#a5000 5/24
OModelodeDados
AaplicaoSocialChatseamparanomodelodaFigura2.
[abririmagememjanela]
Figura2.Modelodedadosdaaplicao
Pensandonareutilizaodecdigo,podemosanteciparofatodequeasentidadestero
atributoscomuns,taiscomoIdeCriadoEm.Destaforma,podemoscriarumaclasseabstrata,
conformemostradonaListagem1.
AentidadeUsuario(Listagem2)teropapeldousurioquepostaoscomentriose
respostasaoscomentrios,assimcomoodecurtiroscomentrios.
NotequenaListagem2ousuriotemumalistadecomentrios(linha21)etambmum
mtodoAdicionarComentario(linha23)paraadicionarnovasmensagens.Essemtodo
implementadoporquenodeveramosadicionarmensagensdiretamentelistade
mensagens.Emvezdisso,chamamosAdicionarComentario,porqueessafunotemcdigo
adicionalquedeveserprocessadonomomentodaincluso(isto,definiroautordo
comentrioeordenaranovamensagemdentrodalistademensagens).
Listagem1.Classebaseabstrataparaasentidadesdosistema
01publicabstractclassEntidade
02{
03publicEntidade()
04{
05CriadoEm=DateTime.Now;
06}
07
08publicvirtualintId{get;set;}
09publicvirtualDateTimeCriadoEm{get;set;}
10}
Listagem2.EntidadeUsuriodefineosautoresdoscomentrios
01publicclassUsuario:Entidade
02{
03publicUsuario()
04{
05Comentarios=newList<Comentario>();
06}
07
08publicvirtualstringLogin{get;set;}
09[ScriptIgnore]
10publicvirtualstringSenha{get;set;}
11publicvirtualstringNome{get;set;}
12publicvirtualstringSmallPicturePath
13{
14get{return"Content/images/actor"+
this.Id.ToString()+"_small.gif";}
15}
16publicvirtualstringMediumPicturePath
17{
18get{return"Content/images/actor"+
this.Id.ToString()+"_medium.gif";}
http://www.devmedia.com.br/websys.5/webreader_print.asp?cat=1&artigo=5000&revista=impressao_100#a5000 6/24
19}
20publicvirtualstringLargePicturePath
21{
22get{return"Content/images/actor"+
this.Id.ToString()+"_large.gif";}
23}
24publicvirtualstringPicturePath
25{
26get{return"Content/images/actor"+this.Id.ToString()+".gif";}
27}
20[ScriptIgnore]
21publicvirtualIList<Comentario>Comentarios{get;set;}
22
23publicvirtualComentarioAdicionarComentario(Comentariocomentario)
24{
25comentario.Usuario=this;
26comentario.Ordem=Comentarios.Count()+1;
27Comentarios.Add(comentario);
28returncomentario;
29}
30
31
32}
NaListagem3implementamosaclasseComentarioquefazopapeltantoparacomentrios
quantopararespostas.Percebaqueessaclassepossuiduaslistas:umaderespostas(linha
14)eumadeusuriosquederamseuslikes(linha16),isto,osusuriosquecurtiramo
comentrio.
Listagem3.EntidadeComentriodefinecomentrioserespostas
01publicclassComentario:Entidade
02{
03publicComentario()
04{
05Respostas=newList<Comentario>();
06Curtiram=newList<Usuario>();
07}
08
09publicvirtualintOrdem{get;set;}
10publicvirtualUsuarioUsuario{get;set;}
11[ScriptIgnore]
12publicvirtualComentarioComentarioPai{get;set;}
13publicvirtualstringTexto{get;set;}
14publicvirtualIList<Comentario>Respostas{get;set;}
15publicvirtualIList<Usuario>Curtiram{get;set;}
16
17publicvirtualComentarioAdicionarComentario(Comentariocomentario)
18{
19comentario.ComentarioPai=this;
20Respostas.Add(comentario);
21returncomentario;
22}
23
24publicvirtualComentarioAdicionarComentario
(Usuariousuario,Comentariocomentario)
25{
26comentario.Usuario=usuario;
27comentario.ComentarioPai=this;
28comentario.Ordem=Respostas.Count()+1;
29Respostas.Add(comentario);
30
31usuario.Comentarios.Add(comentario);
http://www.devmedia.com.br/websys.5/webreader_print.asp?cat=1&artigo=5000&revista=impressao_100#a5000 7/24
32returncomentario;
33}
34
35publicvirtualUsuarioCurtir(Usuariousuario)
36{
37Curtiram.Add(usuario);
38returnusuario;
39}
40}
Mapeamento
Vamosimplementarumaclasseabstratademapeamento,apartirdaqualtodasasoutras
classesiroherdar,comonaListagem4.
Listagem4.ClasseBaseMapClasseabstrataparaasclassesdemapeamento
01publicabstractclassBaseMap<T>:ClassMap<T>whereT:Entidade
02{
03publicBaseMap()
04{
05Id(x=>x.Id);
06Map(x=>x.CriadoEm);
07}
08}
Ocdigoapresentadoclaroelegvel.Almdisso,umsimplesexemplodemapeamento
imperativofluenteepoderoso.AinstruoId(x=>x.Id)(linha05)dizaoFluentNHibernate
queaentidadetemumidentity(oatributoIdespecificadonaexpressolambda)que
mapeadoparaumcampoidentitynobancodedados.
AinstruoMap(x=>x.CriadoEm)(linha06)dizaoFluentNHibernatequeoatributo
CriadoEmmapeadoparaocampo(nochave)CriadoEm.
AclasseUsuarioMapcontmomapeamentoparaaclasseUsuarioeherdadaclasse
BaseMap.
Dessaforma,podemosreutilizarocdigoeevitarrepetio.AclasseUsuarioMaptambm
contminstruesMap(usandoexpresseslambda)paracadaumadaspropriedadesno
includasnaclasseBaseMap(Nome,Login,Senha),conformeexibidonaListagem5.
Listagem5.ClasseUsuarioMapMapeamentodoautordoscomentrios
01publicclassUsuarioMap:BaseMap<Usuario>
02{
03publicUsuarioMap()
04{
05Map(x=>x.Nome);
06Map(x=>x.Login);
07Map(x=>x.Senha);
08HasMany(x=>x.Comentarios)
09.Cascade.All()
10.Inverse();
11}
12}
AnovainstruoHasMany(linha08)recebecomoargumentoaexpressolambdacontendo
apropriedadeComentarios.Notequequandovoctemumatributodotipolista,como
Comentarios,vocdeveusarHasManyparamapeloe,porisso,nousamosainstruo
Map.
AinstruoCascade.All()dalinha09dizaoFluentNHibernatequetodasasoperaesde
modificaofeitasnaentidadeUsuario(update,save,delete)devemserpropagadasparaa
listademensagens.Isto,quandovocexcluiumautor,todasassuasmensagensdevem
serexcludastambm.
AclasseComentarioMap(Listagem6)similarclasseUsuarioMap(Listagem5),masela
contmalgumasinstruesqueaindanovimos.Soelas:
http://www.devmedia.com.br/websys.5/webreader_print.asp?cat=1&artigo=5000&revista=impressao_100#a5000 8/24
contmalgumasinstruesqueaindanovimos.Soelas:
OmtodoLength(1000)defineotamanhomximoparaoatributoText.
AinstruoespecialReferencesdizaoFluentNHibernateparacriarchavesestrangeiras
comosseguintesnomes:ComentarioPai_ideUsuario_id.
GeraodoEsquema
Agoraquetemosnossomodeloemapeamentos,devemoscriarobancodedadosapartir
deles.AconfiguraonoarquivoWeb.configparaoSQLServerCompactnomuito
diferentedaconfiguraoqueusamosnormalmenteparaoSQLServer.ConfiranaListagem
7.
Almdisso,precisamosdaconfiguraoextraAssemblyWithFluentNHibernateMappings
parainformaraoFluentNHibernatequaloassemblyeondeseencontramasclassesde
mapeamento.VejaestasconfiguraesnaListagem8.
Comtodasaspeasnolugar,podemosiniciaracriaodobancodedados.
Emprimeirolugar,implementamosacriaodosdadosnaclasseDBHelper,comum
mtodoprincipalchamadoGenerate,verListagem9.
Listagem6.ClasseComentarioMapMapeamentodaentidadedecomentriose
respostas
01publicclassComentarioMap:BaseMap<Comentario>
02{
03publicComentarioMap()
04{
06Map(x=>x.Texto).Length(1000);
07Map(x=>x.Ordem);
08References(x=>x.ComentarioPai,"ComentarioPai_id");
09References(x=>x.Usuario,"Usuario_id");
10HasMany(x=>x.Comentarios)
11.Cascade.All()
12.Inverse()
13.OrderBy("Ordem");
14}
15}
Listagem7.StringdeconexodoSQLServerCompactnoarquivoWeb.config
<connectionStrings>
<addname="connectionString"connectionString="DataSource=|DataDirectory|\Chat.sdf"
providerName="Microsoft.SqlServerCe.Client.3.5"/>
</connectionStrings>
Listagem8.Chavedeconfiguraoindicandooassemblycomosmapeamentos
<appSettings>
...
<addkey="AssemblyWithFluentNHibernateMappings"value="Chat.Domain"/>
</appSettings>
Listagem9.Controledesessoetransaodentrodaclassedeacessoadados
01publicclassDBHelper
02{
03publicstaticvoidGenerate()
04{
05//crianossofactorydesessoNHibernate
06varsessionFactory=CreateSessionFactory();
07
08using(varsession=sessionFactory.OpenSession())
09{
10//populaabasededados
11using(vartransaction=session.BeginTransaction())
http://www.devmedia.com.br/websys.5/webreader_print.asp?cat=1&artigo=5000&revista=impressao_100#a5000 9/24
12{
13//AQUIVODIVERSASLINHASQUEINSEREMUSURIOS
14//ECOMENTRIOSNOBANCODEDADOS,MASELASFORAM
//REMOVIDASPARATORNAROARTIGOMAISLEGVEL.
15}
16}
17}
18
19
20
NaListagem9omtodoGenerategeratantoaestruturadobancodedadosquantocriaa
cargainicialdedados(talcomoosusuriosdaaplicaoealgunsdadosdeexemplo.Mas
porenquantovamospularocdigoreferentegeraodosdadosiniciais,evamosnosfocar
nageraodaestruturadastabelas.Percebaqueomtodoobtmumainstnciadafactory
atravsdomtodoCreateSessionFactory,eentoabreumasessonaquelainstnciada
factory.
Nesteponto,aestruturadobancodedadosjfoigerada(iremosfalarsobreissomais
adiante).Eporfim,umatransaoiniciadasobreaquelasessoabertaparapopularo
bancodedadoscomdadosiniciais.
OmtodoCreateSessionFactoryexibidonaListagem10,comojmencionado,criao
esquemadebancodedados.Notequeeleutilizaasconfiguraesquejdefinimos
anteriormente,juntocomasinformaessobrenossasclassesdemapeamento.Eporfim,
elaretornaumainstnciaISessionFactoryapartirdaqualnossastransaesseroiniciadas.
Listagem10.Mtodosparageraroesquemadentrodaclassedeacessoadados
01publicclassDBHelper
02{
03
04
05
06privatestaticISessionFactoryCreateSessionFactory()
07{
08varconnectionString=System.Configuration.ConfigurationManager.ConnectionStrings
["connectionString"].ToString();
09
10returnFluently.Configure()
11.Database(MsSqlCeConfiguration.Standard)
12.Mappings(m=>
13m.FluentMappings.AddFromAssemblyOf<Chat.Domain.Model.Usuario>())
14.ExposeConfiguration(BuildSchema)
15.BuildSessionFactory();
16}
17
18privatestaticvoidBuildSchema(Configurationconfig)
19{
20//omtodoCreatedoSchemaExportdoNHibernaterecebeumaconfigurao(contendo
21//informaesdomapeamento)eexportaoesquemadebancodedadosapartirdela.
22newSchemaExport(config)
23.Create(false,true);
24}
25
26publicstaticFluentNHibernate.Automapping.AutoPersistenceModel
CreateAutomappings{get;set;}
27}
Notequenaslinhas11e12daListagem10temosaconfiguraodobancodeacordocom
oSQLServerCompact.Sequisertrabalharcomdiferentesmotoresdebancodedados,
necessriousardiferentesclassesdeconfigurao(taiscomoMsSqlConfigurationparaSQL
Server,SQLiteConfigurationparaSQLite,OracleClientConfigurationparaOracle,ou
MySQLConfigurationparaMySQL).
http://www.devmedia.com.br/websys.5/webreader_print.asp?cat=1&artigo=5000&revista=impressao_100#a5000 10/24
MySQLConfigurationparaMySQL).
Populandoasentidadescomdadosiniciais
Aindafaltapreencherasentidadesparacriarusurioseconversasfictciasentreelesno
muraldaaplicao.Istointeressanteparaoleitorquedesejaentenderocdigonecessrio
parapreencherasentidadesetambmparaqueaaplicao,quandoiniciadapelaprimeira
vez,exibaumexemplodeumaconversaentremltiplosusurios,conformeaListagem11.
AListagem12exibeocdigoquecriaosusuriosdaaplicao(linhas1214)eos
comentriosfictciosdomural(linhas1544).
Listagem11.Populandoasentidadescomdadosiniciais
01publicstaticvoidGenerate()
02{
03//crianossofactorydesessoNHibernate
04varsessionFactory=CreateSessionFactory();
05
06using(varsession=sessionFactory.OpenSession())
07{
08//populaabasededados
09using(vartransaction=session.BeginTransaction())
10{
11varcommonPassword="123456";
12varhamlet=newUsuario{Login="hamlet",
Senha=commonPassword,Nome="Hamlet"};
13varhoracio=newUsuario{Login="horacio",
Senha=commonPassword,Nome="Horcio"};
14AddAuthors(session,hamlet,horacio);
15varauthor=hamlet;
16vartime=DateTime.Now.Add(newTimeSpan(-40,0,0));
17varmsg=AddMessage(author,"Deixa-mev-lo.
PobreYorick!Conheci-o,Horcio;umsujeito
dechistesinesgotveisedeumafantasiasoberba.
Carregou-memuitasvezesscostas...",time);
18time=time.Add(newTimeSpan(0,149,0));
19session.SaveOrUpdate(msg);
20AddMessage(horacio,msg,"Que,prncipe?",time);
21time=time.Add(newTimeSpan(0,149,0));
22session.SaveOrUpdate(msg);
23AddMessage(hamlet,msg,"AcreditasqueAlexandre,
depoisdeenterrado,tivesseestemesmoaspecto?",time);
24time=time.Add(newTimeSpan(0,149,0));
25session.SaveOrUpdate(msg);
26AddMessage(horacio,msg,"Igual,igual,prncipe.",time);
27time=time.Add(newTimeSpan(0,149,0));
28session.SaveOrUpdate(msg);
29AddMessage(hamlet,msg,"Eestecheiro?Pu!",time);
30time=time.Add(newTimeSpan(0,149,0));
31session.SaveOrUpdate(msg);
32AddMessage(horacio,msg,"Omesmo,prncipe.",time);
33time=time.Add(newTimeSpan(0,149,0));
34session.SaveOrUpdate(msg);
35time=DateTime.Now.Add(newTimeSpan(-1,0,0));
36msg=AddMessage(hamlet,msg,"Aqueusosnfimos
temosdeprestar-nos,Horcio.Porquenoacompanhar
aimaginaoasnobrescinzasdeAlexandre,
atencontr-lasservindoparataparumbarril?",time);
37time=time.Add(newTimeSpan(0,2,0));
38session.SaveOrUpdate(msg);
http://www.devmedia.com.br/websys.5/webreader_print.asp?cat=1&artigo=5000&revista=impressao_100#a5000 11/24
39AddMessage(horacio,msg,"irmuitolonge,
considerarascoisasporessemodo.",time);
40time=time.Add(newTimeSpan(0,3,0));
41session.SaveOrUpdate(msg);
42AddMessage(hamlet,msg,"Deformaalguma.
Acompanhemo-lascombastantemodstia,
deixando-nosguiarapenaspelaverossimilhana.",time);
43time=time.Add(newTimeSpan(0,1,0));
44session.SaveOrUpdate(msg);
45
46transaction.Commit();
47}
48}
49}
Listagem12.MtodosdaclasseDBHelperquecriamnovoscomentrioseautores
01privatestaticComentarioAddMessage(Usuarioauthor,
stringtext,DateTimecriadoEm)
02{
03varmsg=author.AdicionarComentario(newComentario()
{Texto=text,CriadoEm=criadoEm04});
05returnmsg;
06}
07
08privatestaticComentarioAddMessage(Usuarioauthor,
Comentariomsg,stringtext,DateTimecriadoEm)
09{
10returnmsg.AdicionarComentario(author,newComentario()
{Texto=text,CriadoEm=criadoEm});
11}
12
13privatestaticvoidAddAuthors(ISessionsession,
paramsUsuario[]authors)
14{
15foreach(varauthorinauthors)
16{
17session.SaveOrUpdate(author);
18}
19}
ComoexibidonaListagem12,ocdigoiniciacomacriaodocomentriodeprimeironvel
(aquelequeiniciaathread)eemseguidafazoencadeamentodoscomentriosdesegundo
nvel(contidosnamesmathread),atravsdomtodoAddMessage(vistoanteriormentena
Listagem2)quecriaumnovocomentrioeoassociaaumcomentriopreexistente
(propriedadeComentarioPaidaentidadeComentario).NaFigura3,temosumexemplode
comoficaromuralapsaadiodecomentriosdeprimeiroesegundonvel.
MVVMComKnockout.js
OMVVMpermitecriarainterfacecomousurioeconectlacomumViewModel,queo
componentequecontmpropriedadesemtodosquesoexpostoseamarradosinterface
comousurioatravsdoframeworkMVVM,usandoatributosdemarcaoespecialmente
projetadoseposicionadosemelementosdaView.
OKnockoutumabibliotecaJavaScriptquepossuiseuprpriomecanismoMVVM,assim
comooSilverlighteoWPF.AdiferenaqueaKnockoutfoiprojetadaparatrabalharcom
HTML.
Knockouttemummecanismodebindingmuitoricoeflexvele,diferentementedoMVVM
comSilverlight/WPF,noserprecisocriarconversoresdebinding(emborapossacriar,
dependendodequocomplexassoasexpresses).
Tambmpossvelcriarasexpressesdebindingdiretamentenosatributosdebindingdo
HTML,quenadamaisquecdigoJavaScriptqueseravaliadoeexecutadopelo
mecanismoMVVMdoKnockout.
http://www.devmedia.com.br/websys.5/webreader_print.asp?cat=1&artigo=5000&revista=impressao_100#a5000 12/24
mecanismoMVVMdoKnockout.
AlgumasfuncionalidadeschavedoKnockout:
Elerastreiaosdadoseossincronizacomainterfaceecomousurioatravsdebindingde
duasvias,ouseja,oquevistonainterfaceoquetemnoViewModel.
Permitebindinganinhado,isto,possvelamarrarumaseodainterfacecomousurioa
umobjetoPedidoeamarrarumaseosubsequentedainterfaceaumarraydeobjetos
PedidoItem,porexemplo.Dentrodessaseofilha,possvelfacilmenteamarrarelementos
dainterfaceapropriedadescontidasnoobjetopai(objetoPedido).
possvelcriarbehaviorscustomizadoseutilizloscomoquiser.
ComoocdigodobindingJavaScriptpuro,elenodependedenenhumframeworkdo
mesmotipo,ouseja,podeutilizarframeworksjQuery,Mootools,Dojo,etc.
Elepodeseracrescentadoaplicaojexistentesemgrandesmudanasarquiteturais.
umabibliotecabastanteleve.
FuncionaemqualquerumdosprincipaisnavegadoresdoMercado.
[abririmagememjanela]
Figura3.Aplicaoexibindooprimeiroeosegundonveldecomentrios
Knockoutumabibliotecamuitobemdocumentada.Outrarazoatraenteparausar
KnockoutapossibilidadedecriarViewModelsescritosemJavaScriptpuro,ouseja,nada
sabemsobreasinterfacesHTMLqueasiroconsumir.SeformodificadooViewModel,a
interfaceHTMLirsemodificardamesmamaneira.Eseformodificadoosvaloresna
interfacecomousurio,oViewModeltambmsemodificarautomaticamente.Comisso,
possvelreutilizaromesmoViewModelemtiposdiferentesdeViews.Outraconsequncia
interessantedissoquenoserprecisomaismanipularelementosdoDOM(Document
ObjectModel)apartirdocdigoJavaScript.
Paraimplementlonoprojeto,vamosutilizarocdigodaListagem13,queapresentaahome
pageIndex.cshtmlcomrefernciaparaoarquivodeJavaScriptdoKnockout.
http://www.devmedia.com.br/websys.5/webreader_print.asp?cat=1&artigo=5000&revista=impressao_100#a5000 13/24
MasantesdeinvocarqualquermtododoKnockout,precisamosprimeirocriaraView.
QuasetodoartigosobreKnockoutirlhedizerparacriaroViewModelprimeiro,paraento
adaptarviewHTMLparasuasnecessidades.
Listagem13.RefernciaparabibliotecaKnockoutnoarquivoIndex.cshtml
<scriptsrc="@Url.Content("~/Scripts/knockout-2.1.0.js")"type="text/JavaScript">
</script>
Porm,nesteartigovamosfazeroinverso,poisnodiaadiadosdesenvolvedores,amaioria
dosprojetoswebcomeamcomumprottipoHTMLcriadopeloprprioouporalgumweb
designer.Portanto,vamoscriaraViewcomalgunsdadosdeexemplo,semlevaroKnockout
emconsiderao.Comoaviewumpoucoextensa,vamostrabalharcomapenasum
pequenotrechodela,poisocdigocompletovocconferejuntoaodownloaddoartigo:
<div>Oqueh,rapazes?</div>
Obviamente,otextoOqueh,rapazes?referesepropriedadeTextonanossaentidade
Comentario.OmesmobindingdaListagem12comoatributoKnockoutpodeserescritoda
seguinteforma:
<divdatabind="text:texto"></div>
Presteatenonoatributodatabind,poiseleoatributoquetransformaKnockoutem
realidade.
ApalavratextdoladoesquerdoumapalavrareservadadoKnockoutqueserefereao
contedodadiv,enquantoapalavratextodoladodireitoonomedapropriedadeda
ViewModelqueestsendoamarradaView.
AViewModelointermedirioentreainterfacecomousurioeomodelodedados.Elano
ainterfacepropriamentedita,comotambmnoomodelo.Emvezdisso,uma
implementaofeitapuramenteemcdigoJavaScript,queexpeosdadosdomodeloparaa
interfacecomousurioetambmexpeoscomandoseeventosqueseroamarradosaos
elementosdainterface.
MascomocriamosaViewModel?ApropriedadeTextoumdoselementosaserem
amarradosView,eobviamentehoutrosmais.Masvamossuporquetivssemossomente
esseelementoemnossoHTML.Nessecaso,nossoViewModeltambmseriamuitosimples,
conformeexpostonaListagem14.
Listagem14.OcdigoJavaScriptcomaplicaodovalorobservvel
01varviewModel=function(){
02varself=this;
03self.text=ko.observable('Oqueh,rapazes?');
04};
05ko.applyBindings(newviewModel());
NotequetextnoumapropriedadeJavaScriptqualquer.
Emvezdisso,umapropriedadeobservvel(NotadoDevMan2),geradapelomecanismo
doKnockoutepredefinidacomovalorinicialOqueh,rapazes?.
Isto,quandooobservveldefinidocomoOqueh,rapazes?,obindingdata
bind=text:textoquevimosanteriormentenotificadoecomoconsequncia,ocontedodo
elementodivnainterfacedousurioautomaticamentemodificadoparaexibiressenovo
valor.
NotaDevman2:UmobservableumobjetoJavaScriptespecialqueencapsulaumvalore
quetemopoderdenotificarosassinantes(ouobservadores)dapropriedadesobre
quaisquermudanasquepossamocorrernosdadosqueeleencapsula.
http://www.devmedia.com.br/websys.5/webreader_print.asp?cat=1&artigo=5000&revista=impressao_100#a5000 14/24
Eporfim,temosocomandoapplyBindingsqueaplicatodososbindingsqueconstrudos
anteriormente.Paraisso,necessriousarocdigoaseguir:
ko.applyBindings(newviewModel())
Quandoosbindingssoaplicados,finalmentetemosoelementodivrenderizado:
semquererquerendo
EmboratextosejaumapropriedadesimplesnaclasseComentario,existemcasosemque
voctambmpodeacessarpropriedadesinternasdeobjetosquesoatributos,comoo
casodonomedoautor:
<divclass="usuarioname"databind="text:usuario().Nome">
</div>
Parafazeressapartedobindingfuncionar,apropriedadeusuariodeveserumnovo
observveldentrodoobjetoComentario,conformeexibidonaListagem15.
Listagem15.DefinindopropriedadesobservveisdeumobjetoComentario
01varComentario=function(id,text,usuario,criadoEm,replies,likes){
02varself=this;
03
04self.id=ko.observable(id);
05self.text=ko.observable(text);
06self.usuario=ko.observable(usuario);
Queporsuavezirresultarnoseguintecdigo:
<divclass="usuarioname"databind="text:usuario().Nome">Hamlet</div>
OutracaractersticainteressantedoKnockoutahabilidadedeexecutarlaosforeach
utilizandolistasoucoleesdeobjetos,taiscomoasmensagensdomuraldousurioda
aplicao.
Nestecaso,podemoscolocarobindingforeachcomoumblocodecomentrioforadaseo
HTMLqueserrepetidaparacadaitemdalistademensagens.Percebaquepelasintaxedo
Knockoutdevemosprefixarocomentriodeaberturacomkoeocomentriodefechamento
com/ko,comopodeservistonaListagem16.
Listagem16.Usandoforeachparaacessarcadacomentrio,noarquivoIndex.cshtml
01<divclass="wall-messages"style="display:none;">
02<!--koforeach:comentarios-->
03<divclass="comentario-thread">
04<divclass="comentario-thread-usuario"></div>
05.
06.
07.
08<divclass="usuario-name"data-bind="text:usuario().Nome">
09</div>
10.
11.
12.
13</div>
14</div>
15<!--/ko-->
16</div>
EmalgumasvezesserprecisogeraratributosbaseadosnoViewModel.Nestecaso,a
sintaxeligeiramentediferente.Obindingparaatributosdadopelaforma:databind=attr:
http://www.devmedia.com.br/websys.5/webreader_print.asp?cat=1&artigo=5000&revista=impressao_100#a5000 15/24
sintaxeligeiramentediferente.Obindingparaatributosdadopelaforma:databind=attr:
{nomedoatributo:campodoviewmodel}:
<divclass="threadconversation"databind="attr:{conversaId:id}">
OrelacionamentodamensagemcomID=5resultarnoseguintecdigo:
<divclass="threadconversation"databind="attr:{conversaId:id}"conversaId="5">
OutracaractersticabastantetildoKnockoutahabilidadedetrabalharcomcondies.
Suponhaquevocquisesseexibirumelementodivcontendoumgifanimadoparaindicarque
umcarregamentoestemandamentoedaraousurioumfeedbackvisual,todasasvezes
quesuaaplicaotiverqueaguardarporumalongarequisioajax:
<span>
<imgsrc="@Url.Content("Content/images/loading_small.gif")"/>
</span>
Issofuncionariabem,masapartirdomomentoquearequisioajaxretornasseumvalor,
vociriaquererqueessegifanimadodesaparecesse.Emaplicaeswebtradicionais,voc
usariaseuframeworkJavaScriptfavoritoparaacessaroelementoDOMcontendoaimagem
carregando,eentomudariaoestilodoelementoparahiddenparaocultlo,ouento
simplesmenteremoveriaoelementoDOMdapgina.Sim,issofuncionaria,mascom
Knockoutpodemosfazeromesmotrabalhosemprecisarcolocarnossasmosnoselementos
DOM.
Fazemosissosimplesmenteutilizandocondiesquesopartedasintaxedebindingdo
Knockout(oquemuitosemelhanteaumalinguagemdeprogramao)paraexibirouocultar
oselementosDOMbaseadosnumaexpressocondicional:
<spandatabind="ifnot:$root.isSignalREnabled">
<imgsrc="@Url.Content("Content/images/loading_small.gif")"/>
</span>
AgoraparececlaroqueoselementosHTMLcontidosnoblocodacondiosoexibidos
somentequandoapropriedadeisLoadingdoobjetopaitemovalorverdadeiro.Apalavra
reservada$rootdasintaxeKnockoutpermitequevocacesseosancestrais,isto,quando
KnockoutJsestrenderizandoumamensagemdentrodeumalistademensagens,a
expresso$root.isLoadingsereferepropriedadeisLoadingdoobjetoraizquecontmalista
demensagens.
InteraoMultiusurioemTempoRealCom
SignalR.Net
Nossaaplicaoterqueestarpreparadaparaatualizarsesemprequehouvernovidades
nasconversaseprontamenteatualizaraviewdousurioquandohouveralgumanovidade.
Esterequisitoexigealgumtipodecomunicaodeduasvias.Asoluomaiseficienteseria
criarumacomunicaoatravsdewebsocketsHTML5,quefuncionariaenviandoe
recebendomensagens(emvezdebytes)atravsdecanaisfullduplexbidirecionaissobre
umaconexoTCP.Avantagemque,comosetratadeumacomunicaoTCPsobreaporta
80,elanobloqueadaporfirewalls.Masinfelizmente,considerandoosuportedos
navegadoresatuaisaoswebsockets,adotaressecaminhosignificariaexcluiroInternet
Explorerdalista.Nessecaso,existeumaoutraopoqueemulaessacomunicaodeduas
viasemtemporeal,utilizandosinalizaoassncrona,proporcionadaporumabibliotecacomo
oSignalR.Net.Seobrowserdoclientesuportarwebsockets,oSignalR.Netiruslos,caso
contrriooSignalR.Netirutilizarumatcnicaalternativachamadadelongpolling.
Olongpollingabreumaconexodeduraoinfinitaentreclienteeservidorepassa
mensagensatravsdamesma.Quandoaconexointerrompida,oSignalR.Net
automaticamentereageabrindoumanovaconexolongpollingnosbastidores.Essa
reconexototalmentetransparenteparaodesenvolvedor,nonecessitandodequalquer
http://www.devmedia.com.br/websys.5/webreader_print.asp?cat=1&artigo=5000&revista=impressao_100#a5000 16/24
reconexototalmentetransparenteparaodesenvolvedor,nonecessitandodequalquer
codificaoextra.
Damesmaforma,quandooservidorprecisanotificarocliente,aconexolongpolling
estabelecidaentreosdoisretornaparaoclientecomovaloraprprianotificaoinformada
peloservidore,emseguida,ocomponenteSignalR.Netnoclientereestabeleceumanova
conexolongpollingdeduraoinfinitacomoservidor,eassimpermaneceatqueuma
novanotificaosejarecebida.Obviamenteessemecanismomenoseficientequeosweb
sockets,masfuncionamuitobemepermiteodesenvolvimentodeaplicaesquefuncionam
emqualquerumdosbrowsersdomercado.
SignalR.NetHub
OSignalR.NetutilizaumconceitodeHubparacentralizarosmtodosdecomunicao
clienteservidoremumnicopontocentral.QuandovocusaoSignalR.Net,inevitavelmente
precisarcriarumaoumaisclassesdehub,herdandodaclassebaseHub,conformea
Listagem17.
Listagem17.ClasseHub,dentrodonamespaceChat.Hubs
01namespaceChat.Hubs
02{
03publicclassSocialHub:Hub
04{
05.
06.
07.
08}
09}
SignalR.NetClienteChamandooServidor
VocacharinteressanteofatodequetodososmtodosquecolocardentrodoHubsero
automaticamenteexpostosedisponveisnoJavaScriptdoladodocliente.Comoiremosver
maistarde,tudooquevocprecisafazerchamaromtodocomomesmonomenoladodo
objetoJavaScript,conformeexibidonaListagem18.
Listagem18.OsmtodosdecomunicaoclienteservidornaclasseSocialHub
01publicclassSocialHub:Hub
02{
03privatereadonlyChatModel_chat;
04
05publicvoidEnviarCurtirParaServidor(intcomentarioId)
06{
07...
08}
09
11publicvoidEnviarDescurtirParaServidor(intcomentarioId)
12{
13...
14}
15
16publicvoidEnviarComentarioParaServidor(int?comentarioPaiId,stringtexto)
17{
18...
19
20}
21
22publicvoidJoin(stringname)
23{
24...
25}
http://www.devmedia.com.br/websys.5/webreader_print.asp?cat=1&artigo=5000&revista=impressao_100#a5000 17/24
26}
Umfatointeressanteque,umavezcompiladaaaplicao,abibliotecaSignalR.Netgeraum
cdigoJavaScriptquefuncionacomoproxyapartirdaclasseSocialHub(Listagem18)eesse
proxycarregadopelapginaHTMLqueutilizaoSignalR.Net:
<scriptsrc="@Url.Content("~/signalr/hubs")"></script>
dessaformaqueocdigoJavaScriptdesenvolvidoparaoclientesabequaissoos
mtodosquepodemserchamadosnoservidor.
Seabrirmosoendereohttp://enderecodaaplicacao/signalr/hubs,iremosencontraro
cdigoJavaScriptgerado(Figura4)emaisabaixoiremosencontrarosmesmosmtodos
existentesnaclasseSocialHubdoservidor.
Porm,nocdigoJavaScriptdoProxyessesmtodostemcomofunoestabelecer
comunicaocomoservidoreenviar/receberdadosdocliente(Figura5).
[abririmagememjanela]
Figura4.CdigoJavaScriptdoproxygeradopeloSignalR
[abririmagememjanela]
http://www.devmedia.com.br/websys.5/webreader_print.asp?cat=1&artigo=5000&revista=impressao_100#a5000 18/24
Figura5.MtodosdoproxyJavaScriptquecorrespondemaosmtodosdaclasse
SocialHub
SignalR.NetServidorChamandooCliente
claroquevoctambmfarchamadasdoservidorparaosclientes,atravsdaclasse
Clients,queumobjetodinmicoquerepresentatodososclientesconectadosaoHub.A
Listagem19ilustraoqueacontecequandoalgumusuriocurteumcomentrio:primeiro,o
cdigoJavaScriptchamaomtodoEnviarCurtirParaServidordoobjetosocialHubClient,
passandooiddamensagem.Quandoachamadachegaaoservidor,elaroteadaparaa
classeSocialHubeomtodoEnviarCurtirParaServidor.Entoainformaodecurtir
persistidanobancodedados,enquantoomtododinmicoatualizarCurtidaschamadono
objetodinmicoClients,e,dessaforma,ainformaodecurtircomunicadaatodosos
clientesconectados:
Listagem19.OmtodoC#EnviarCurtirParaServidorchamandomtodoatualizarCurtidas
nosclientes
01publicvoidEnviarCurtirParaServidor(intcomentarioId)
02{
03varcomentarioRepository=newComentarioRepository();
05comentarioRepository.Curtir(comentarioId,Context.User.Identity.Name,(usuario)=>
06{
07Clients.atualizarCurtidas(comentarioId,new{Id=usuario.Id,Nome=usuario.Nome});
08});
09}
SignalR.NetConectandoseConversa
Assimqueousurioseconecta,oclienteestsinalizandosobresuadisponibilidade,eassim
eleinscritopeloservidorpararecebernovoscomunicados.Apartedaconexofeitavia
http://www.devmedia.com.br/websys.5/webreader_print.asp?cat=1&artigo=5000&revista=impressao_100#a5000 19/24
eleinscritopeloservidorpararecebernovoscomunicados.Apartedaconexofeitavia
JavaScript.NotenaListagem20queoclientespodeconectarseapsaconexocomo
hubtersidoestabelecida.
Damesmaforma,semprequealgumpostaumnovocomentrio,oservidorprecisa
propagaressenovocomentrioparaosclientesconectados,comovemosnomtodo
adicionarComentariodocdigoJavaScriptdaListagem22.Percebaqueessemtodotrata
tandodapostagemdeprimeironvel(inciodeumaconversa)quantodesegundonvel
(comentriodentrodeumaconversajexistente).
Listagem20.MtodoJavaScriptsetupHubClientestabelecendoaconexocomo
servidor
01functionsetupHubClient(){
02socialHubClient=$.connection.socialHub;
03
04//Iniciaaconexo
05$.connection.hub.start(function(){
06socialHubClient.join(userInfo.Name);
07}).done(function(){
08window.isSignalREnabled=true;
09if(window.muralViewModel){
10window.muralViewModel.isSignalREnabled(true);
11}
12}).fail(function(){
13alert('ConexoSignalRfalhou!');
14});
Comooseventosdecurtiroudesfazercurtirsopropagadosdoservidorparaosclientes
conectados,essesclientesnecessitamdepontosdeentradaparareceberanotificao
desseseventos.
PorissonossocdigoJavaScriptnecessitadedoismtodos:umparaadicionarumnovo
usurionalistadepessoasquecurtiramumapostagem,eoutropararemoverousuriocaso
eledeixedecurtirapostagem.AListagem21mostracomoessesmtodosso
implementados.
Listagem21.MtodosatualizarCurtidaseatualizarDescurtidas,quemodificamoarray
depessoasquecurtiramumcomentrio
Listagem22.MtodoadicionarComentario
01socialHubClient.adicionarComentario=
http://www.devmedia.com.br/websys.5/webreader_print.asp?cat=1&artigo=5000&revista=impressao_100#a5000 20/24
function(parentComentarioId,newComentarioId,
comment,usuario){
02if(parentComentarioId){
03window.muralViewModel.findComentarioAndAct
(parentComentarioId,muralViewModel,
function(parentComentario){
04parentComentario.adicionarNovoComentario(
05newComentarioId,
06comment,
07{Id:usuario.Id,Name:usuario.Name,
SmallPicturePath:usuario.SmallPicturePath,
MediumPicturePath:usuario.MediumPicturePath},
08'/Date('+(newDate()).getTime()+')/'
09);
10});
11}
12else{
13window.muralViewModel.adicionarNovoComentario(
14newComentarioId,
15comment,
16{Id:usuario.Id,Name:usuario.Name,
SmallPicturePath:usuario.SmallPicturePath,
MediumPicturePath:usuario.MediumPicturePath},
17'/Date('+(newDate()).getTime()+')/'
18);
19}
20};
21}
SignalR.NetCurtindoumComentrio
Oprocessodecurtirumcomentriosimples:depoisqueousurioclicanolink,omtodo
curtirdoobjetoComentarioinvocado,conformeexibidonaListagem23.
AListagem24entoexibeocdigoondeoclienteenviaainformaodecurtiraoservidor
(isto,paraohubdoSignalR).
AListagem25exibecomoserpersistidaainformaodecurtirnobancodedadosecomo
tambminformaosdadosdequemcurtiuocomentrioatodososclientesinscritos.
Listagem23.TagHTMLcombindingsparacssdisplayeparaeventoclick
<ahref="JavaScript:void(0);"class="post-info-linklike"
data-bind="style:{display:curtidoPorEsteUsuario()?'none':''},
click:curtir">Curtir</a>
Listagem24.FunoJavaScriptenviandoinformaodeCurtirparaoservidor
01self.addLike=function(){
02socialHubClient.enviarCurtirParaServidor(self.id());
03}.bind(self);
Listagem25.OmtodoC#EnviarCurtirParaServidorchamandomtodoatualizarCurtidas
nosclientes
01publicvoidSendLikeToServer(intcomentarioId)
02{
03varcomentarioRepository=newComentarioRepository();
04comentarioRepository.Curtir(comentarioId,Context.User.Identity.Name,(usuario)=>
05{
06Clients.atualizarCurtidas(comentarioId,new{Id=usuario.Id,Nome=usuario.Nome});
07});
08}
UmavezqueainformaoenviadaparaomtodoatualizarCurtidasdoobjeto
socialHubClient,eesteencontraocomentrioafetado,imediatamenteatualizaalistade
http://www.devmedia.com.br/websys.5/webreader_print.asp?cat=1&artigo=5000&revista=impressao_100#a5000 21/24
socialHubClient,eesteencontraocomentrioafetado,imediatamenteatualizaalistade
pessoasquecurtiramaquelecomentriocomessanovainformaodecurtir,conforme
expostonaListagem26.
Percebaque,graasaosbindingdoKnockout,noprecisolidardiretamentecomos
elementosHTMLparaatualizaraview
AFigura6mostraumexemploderequisiodomtodoEnviarCurtirParaServidor,que
invocadoquandoousuriocurteumcomentrio.
Listagem26.FunoJavaScriptatualizarCurtidasadicionandoonomedapessoalista
dequemcurtiuocomentrio
[abririmagememjanela]
Figura6.UsandoonavegadorChromeparainterceptarachamadadomtodo
EnviarCurtirParaServidor
Nafiguraanterior,estamosutilizandoomododedepuraodonavegadorChrome
(acionadocomateclaF12)paravisualizaroqueocorrequandoumusuriocurteum
comentrio:primeiro,eleclicanolinkcurtir(1)eentooSinalR.Netenviaparaoservidor
umarequisiocomaurl/signalr/send(2),passandocomoargumentosdaurlotipode
conexoeoidentificadordaconexo(3).Onomedomtodoeosargumentosdomtodoso
enviadosnaseoFormDatadocabealhodarequisio(4).Obviamente,odesenvolvedor
noprecisasepreocuparcomessesdetalhestcnicos:aimagemfoicolocadaapenaspara
exemplificaroqueocorreportrsdospanos,poisabibliotecaSignalR.Nettornaesse
processodecomunicaoautomticoetransparente.
Alistadepessoasquecurtiramumcomentrioespecficofornecidapelomtodo
sumarioDeCurtidas.VemosnaListagem27queessemtodoestdefinidoemalgunsdos
bindings.
Listagem27.TrechoHTMLcombindingparaalistadenomesdepessoasquecurtiramo
http://www.devmedia.com.br/websys.5/webreader_print.asp?cat=1&artigo=5000&revista=impressao_100#a5000 22/24
comentrio
01<!--koif:curtiram().length>0-->
02<divclass="likeInfo"
03data-bind="text:sumarioDeCurtidas,
04style:{display:sumarioDeCurtidas().trim().length>0?'':'none'}">
05</div>
06<!--/ko-->
OmtodosumarioDeCurtidas(Listagem28)implementadonaclasseComentariocomoum
tipoespecialdeobjeto,chamadocomputedquetrabalhacomoumobservable,masemvez
dearmazenarumvalor,eleavaliadonovamentesemprequeseuvalorrequisitadopelo
Knockout.Issobastantetilnoexemploporqueassimapresentamosumalistadeusurios
quecurtiramumcomentrioespecfico.Alistaescritaemportugusamigvel,porextenso,
conformeilustradonaFigura7.
[abririmagememjanela]
Figura7.Sumriodepessoasquecurtiramumcomentrioespecfico
Listagem28.AfunoJavaScriptsumarioDeCurtidas,quegeraalistadepessoasque
curtiram
01self.sumarioDeCurtidas=ko.computed(function(){
02varsummary=;
03varsortedCurtiram=self.curtiram.sort(function(a,b){
04varexpA=(a.Id==userInfo.Id?-1:1);
05varexpB=(b.Id==userInfo.Id?-1:1);
06returnexpA<expB?-1:1;
07})
08
09$(sortedCurtiram).each(function(index,usuario){
10if(summary.length>0){
11if(index==curtiram.length-1){
12summary+=e;
13}
14else{
15summary+=,;
16}
17}
18
19if(usuario.name==userInfo.Name){
http://www.devmedia.com.br/websys.5/webreader_print.asp?cat=1&artigo=5000&revista=impressao_100#a5000 23/24
20summary+=Voc;
21}
22else{
23summary+=usuario.name;
24}
25});
26if(self.curtiram().length>1){
27summary+=curtiramisto;
28}
29elseif(self.curtiram().length>0){
30summary+=curtiuisto;
31}
32returnsummary;
33});
Oprocessodepostarumnovocomentriobemsimilaraoprocessodecurtirum
comentrio,pormservistonoprximoarigo.
Concluso
Dadoofatodequeacomposiodeviewsdoladodocliente(viaJavaScript)einteraes
emtemporealestosetornandomaisemaisumrequisitoemaplicaesweb,esperoqueo
leitortenhagostadodoscenriosdeexemplodeusodoKnockouteSignalRapresentados
nesteartigo.
http://www.devmedia.com.br/websys.5/webreader_print.asp?cat=1&artigo=5000&revista=impressao_100#a5000 24/24