Вы находитесь на странице: 1из 24

DevMediaVersoparaimpresso

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

01 socialHubClient.atualizarCurtidas = function (comentarioId, pessoasQueCurtiram) {


02 window.muralViewModel.findComentarioAndAct
(comentarioId, muralViewModel, function (comentario) {
03 comentario.curtiram.push({
04 id: pessoasQueCurtiram.Id,
05 name: pessoasQueCurtiram.Name
06 });
07 });
08 };
09
10 socialHubClient.atualizarDescurtidas = function (comentarioId, pessoasQueCurtiram) {
11 window.muralViewModel.findComentarioAndAct
(comentarioId, muralViewModel, function (comentario) {
12 for (var i = comentario.curtiram().length - 1; i >= 0; i--) {
13 if (comentario.curtiram()[i].id == pessoasQueCurtiram.Id) {
14 comentario.curtiram.splice(i, 1);
15 break;
16 }
17 }
18 });
19 };

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

01 socialHubClient.atualizarCurtidas = function (comentarioId, pessoasQueCurtiram) {


02 window.muralViewModel.findComentarioAndAct(comentarioId, muralViewModel,
function (comentario) {
03 comentario.curtiram.push({
04 id: pessoasQueCurtiram.Id,
05 name: pessoasQueCurtiram.Name
06 });
07 });
08 };


[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

Вам также может понравиться