<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://geeks.ms/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Omar del Valle Rodríguez</title><link>http://geeks.ms/blogs/omarvr/default.aspx</link><description /><dc:language /><generator>CommunityServer 2008.5 SP1 (Build: 31106.3070)</generator><item><title>[Web Socket] Un evento en el tintero (introducción)</title><link>http://geeks.ms/blogs/omarvr/archive/2013/03/04/web-socket-un-evento-en-el-tintero-introducci-243-n.aspx</link><pubDate>Mon, 04 Mar 2013 20:24:00 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:208770</guid><dc:creator>Omar del Valle Rodríguez</dc:creator><slash:comments>2</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/omarvr/rsscomments.aspx?PostID=208770</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/omarvr/commentapi.aspx?PostID=208770</wfw:comment><comments>http://geeks.ms/blogs/omarvr/archive/2013/03/04/web-socket-un-evento-en-el-tintero-introducci-243-n.aspx#comments</comments><description>&lt;p&gt;&lt;a href="http://www.odelvalle.com/wp-content/uploads/2013/03/HTML-WebSocket-v21.jpg"&gt;&lt;img height="130" width="244" src="http://www.odelvalle.com/wp-content/uploads/2013/03/HTML-WebSocket-v21_thumb.jpg" align="left" alt="HTML-WebSocket-v2[1]" border="0" style="border-left-width:0px;border-right-width:0px;background-image:none;border-bottom-width:0px;float:left;padding-top:0px;padding-left:0px;margin:0px 10px 0px 0px;display:inline;padding-right:0px;border-top-width:0px;" title="HTML-WebSocket-v2[1]" /&gt;&lt;/a&gt;A finales del a&amp;ntilde;o pasado, ten&amp;iacute;a la idea de dar un evento sobre Web Socket, por motivos que no vienen al caso el evento no se dar&amp;aacute;, as&amp;iacute; que he decidido crear una serie de post con lo que pretend&amp;iacute;a ser &amp;ldquo;&lt;strong&gt;Web socket por dentro&amp;hellip;&lt;/strong&gt;&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Sin Frameworks&amp;hellip;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Hoy en d&amp;iacute;a existe un framework casi para cualquier cosa, frameworks para Javascript, frameworks para IoC, frameworks para MVC, MVVM, bases de datos y as&amp;iacute;, podr&amp;iacute;amos pasarnos buen rato enumerando. Como no podr&amp;iacute;a ser de otra forma, tambi&amp;eacute;n hay frameworks para WebSockets.&lt;/p&gt;
&lt;p&gt;Un framework es un pedazo de c&amp;oacute;digo que nos hace m&amp;aacute;s f&amp;aacute;cil determinado trabajo y que puede ser reutilizado en uno o varios proyectos. Su uso est&amp;aacute; m&amp;aacute;s que justificado, no queremos reinventar la rueda, por lo que todo aquello que nos ahorre trabajo, tendr&amp;aacute; todas las papeletas para ser incluido en nuestro proyecto.&lt;/p&gt;
&lt;p&gt;De igual forma que un framework ayuda, encierra a la vez dos grandes peligros si lo usamos sin conocer c&amp;oacute;mo funciona internamente. &lt;/p&gt;
&lt;p&gt;El primero de ellos es incluirlo directamente en nuestro proyecto por no saber hacer las cosas de otro modo. As&amp;iacute;&amp;nbsp; por ejemplo, pudi&amp;eacute;ramos terminar creando una referencia a jQuery cuando solo necesitamos obtener un elemento del DOM por su Id, o lo que es lo mismo, que estemos intentando matar un mosquito con una sofisticada herramienta de artiller&amp;iacute;a.&lt;/p&gt;
&lt;p&gt;Tenemos que tener en cuenta que un framework est&amp;aacute; hecho para cubrir y resolver el mayor n&amp;uacute;mero de problem&amp;aacute;ticas posibles sobre algo en espec&amp;iacute;fico, por lo que puede ser exagerado incluirlo cuando necesitamos tan solo el 0,1% de su funcionalidad.&lt;/p&gt;
&lt;p&gt;El otro gran peligro y que casi siempre olvidamos es que los frameworks est&amp;aacute;n hechos por programadores, persona o grupo de personas con muuuuuuchos derechos a equivocarse. Si en un momento dado nos encontramos con un error, dif&amp;iacute;cilmente vamos a poder colaborar resolvi&amp;eacute;ndolo e incluso, ni siquiera sabremos explicar qu&amp;eacute; ha pasado o qu&amp;eacute; puede estar produciendo el error. &lt;/p&gt;
&lt;p&gt;Es por eso que antes de entrar en el mundo de los frameworks con web sockets, esta serie de art&amp;iacute;culos intentar&amp;aacute; dar a conocer c&amp;oacute;mo funcionan por dentro. &lt;/p&gt;
&lt;p&gt;Para esto me he propuesto el siguiente &amp;iacute;ndice de art&amp;iacute;culos:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Introducci&amp;oacute;n &amp;iquest;Por qu&amp;eacute; no usaremos un framework? (este art&amp;iacute;culo) &lt;/li&gt;
&lt;li&gt;Web Socket. El server. &lt;/li&gt;
&lt;li&gt;Web Socket. El cliente. &lt;/li&gt;
&lt;li&gt;Primer ejemplo: &lt;a target="_blank" href="http://geeks.ms/blogs/gperez/archive/2013/03/04/tutorial-pizarra-compartida-con-signalr-y-canvas.aspx"&gt;La pizarra de @chalalo&lt;/a&gt; sin SignalR &lt;/li&gt;
&lt;li&gt;Segundo ejemplo: Presentaciones paralelas con &lt;a target="_blank" href="http://www.jqueryscript.net/demo/Beautiful-HTML-Presentation-Plugin-with-jQuery-reveal-js/#/"&gt;Reveal.js&lt;/a&gt;. &lt;/li&gt;
&lt;li&gt;Tercer ejemplo: Presentaciones paralelas con Reveal.js y Kinect &lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Hasta el pr&amp;oacute;ximo.. &lt;img src="http://www.odelvalle.com/wp-content/uploads/2013/03/wlEmoticon-smile.png" alt="Sonrisa" style="border-top-style:none;border-left-style:none;border-bottom-style:none;border-right-style:none;" class="wlEmoticon wlEmoticon-smile" /&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=208770" width="1" height="1"&gt;</description></item><item><title>Mockeando Window.location</title><link>http://geeks.ms/blogs/omarvr/archive/2013/02/27/mockeando-window-location.aspx</link><pubDate>Wed, 27 Feb 2013 22:11:03 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:208701</guid><dc:creator>Omar del Valle Rodríguez</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/omarvr/rsscomments.aspx?PostID=208701</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/omarvr/commentapi.aspx?PostID=208701</wfw:comment><comments>http://geeks.ms/blogs/omarvr/archive/2013/02/27/mockeando-window-location.aspx#comments</comments><description>&lt;p&gt;Estoy en un proyecto donde tengo que interactuar con servicios RestFul desde javascript. El problema que tengo es que estos servicios están aún en desarrollo por lo que cuando me toca trabajar con ellos puede que estén o no disponibles.&lt;/p&gt; &lt;p&gt;Para evitar detener mi trabajo cuando los servicios no están disponibles he decidido que los test trabajen con mocks. Hace unos días me tocó hacer un test para chequear un método que internamente hacía uso de window.location.&lt;/p&gt; &lt;p&gt;Hay muchas soluciones disponibles para testear nuestro método, veamos una de ella:&lt;/p&gt; &lt;p&gt; &lt;div id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:07215f5b-1928-49e8-994b-0fe704e9a283" class="wlWriterEditableSmartContent" style="float:none;padding-bottom:0px;padding-top:0px;padding-left:0px;margin:0px;display:inline;padding-right:0px;"&gt; &lt;div style="border:#000080 1px solid;color:#000;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;font-size:10pt;"&gt; &lt;div style="background:#ddd;max-height:300px;overflow:auto;"&gt; &lt;ol style="background:#ffffff;margin:0 0 0 2.5em;padding:0 0 0 5px;white-space:nowrap;"&gt; &lt;li&gt;&lt;span style="background:#ffffff;color:#0000ff;"&gt;var&lt;/span&gt;&lt;span style="background:#ffffff;color:#000000;"&gt; MyNamespace = &lt;/span&gt;&lt;span style="background:#ffffff;color:#0000ff;"&gt;new&lt;/span&gt;&lt;span style="background:#ffffff;color:#000000;"&gt; &lt;/span&gt;&lt;span style="background:#ffffff;color:#0000ff;"&gt;function&lt;/span&gt;&lt;span style="background:#ffffff;color:#000000;"&gt;()&lt;/span&gt;&lt;/li&gt; &lt;li&gt;&lt;span style="background:#ffffff;color:#000000;"&gt;{&lt;/span&gt;&lt;/li&gt; &lt;li&gt;    &lt;span style="background:#ffffff;color:#000000;"&gt;&lt;/span&gt;&lt;span style="background:#ffffff;color:#0000ff;"&gt;this&lt;/span&gt;&lt;span style="background:#ffffff;color:#000000;"&gt;.MyObject = &lt;/span&gt;&lt;span style="background:#ffffff;color:#0000ff;"&gt;function&lt;/span&gt;&lt;span style="background:#ffffff;color:#000000;"&gt;(win)&lt;/span&gt;&lt;/li&gt; &lt;li&gt;    &lt;span style="background:#ffffff;color:#000000;"&gt;{&lt;/span&gt;&lt;/li&gt; &lt;li&gt;        &lt;span style="background:#ffffff;color:#000000;"&gt;&lt;/span&gt;&lt;span style="background:#ffffff;color:#0000ff;"&gt;var&lt;/span&gt;&lt;span style="background:#ffffff;color:#000000;"&gt; __win = win;&lt;/span&gt;&lt;/li&gt; &lt;li&gt;&amp;nbsp;&lt;/li&gt; &lt;li&gt;        &lt;span style="background:#ffffff;color:#000000;"&gt;&lt;/span&gt;&lt;span style="background:#ffffff;color:#0000ff;"&gt;this&lt;/span&gt;&lt;span style="background:#ffffff;color:#000000;"&gt;.NavigateTo = &lt;/span&gt;&lt;span style="background:#ffffff;color:#0000ff;"&gt;function&lt;/span&gt;&lt;span style="background:#ffffff;color:#000000;"&gt;(p1, p2)&lt;/span&gt;&lt;/li&gt; &lt;li&gt;        &lt;span style="background:#ffffff;color:#000000;"&gt;{&lt;/span&gt;&lt;/li&gt; &lt;li&gt;            &lt;span style="background:#ffffff;color:#000000;"&gt;&lt;/span&gt;&lt;span style="background:#ffffff;color:#0000ff;"&gt;var&lt;/span&gt;&lt;span style="background:#ffffff;color:#000000;"&gt; __url = &lt;/span&gt;&lt;span style="background:#ffffff;color:#a31515;"&gt;&amp;quot;http://www.google.com/?q=&amp;quot;&lt;/span&gt;&lt;span style="background:#ffffff;color:#000000;"&gt; + p1 + &lt;/span&gt;&lt;span style="background:#ffffff;color:#a31515;"&gt;&amp;quot;&amp;amp;s=&amp;quot;&lt;/span&gt;&lt;span style="background:#ffffff;color:#000000;"&gt; + p2;&lt;/span&gt;&lt;/li&gt; &lt;li&gt;            &lt;span style="background:#ffffff;color:#000000;"&gt;__win.location.href = __url;&lt;/span&gt;&lt;/li&gt; &lt;li&gt;        &lt;span style="background:#ffffff;color:#000000;"&gt;};&lt;/span&gt;&lt;/li&gt; &lt;li&gt;    &lt;span style="background:#ffffff;color:#000000;"&gt;};&lt;/span&gt;&lt;/li&gt; &lt;li&gt;&lt;span style="background:#ffffff;color:#000000;"&gt;};&lt;/span&gt;&lt;/li&gt; &lt;/ol&gt; &lt;/div&gt; &lt;/div&gt; &lt;/div&gt;&lt;/p&gt; &lt;p&gt;Este sería nuestro objeto en javascript el cual contiene un método llamado NavigateTo y al que le pasamos dos parámetros para formar una url.&lt;/p&gt; &lt;p&gt;Probar este método es muy fácil: (usaremos &lt;a href="http://api.qunitjs.com/" target="_blank"&gt;qunit&lt;/a&gt; por su cómoda integración con ReSharper)&lt;/p&gt; &lt;p&gt; &lt;div id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:8270535d-0372-48ee-89af-0d6711f0e47e" class="wlWriterEditableSmartContent" style="float:none;padding-bottom:0px;padding-top:0px;padding-left:0px;margin:0px;display:inline;padding-right:0px;"&gt; &lt;div style="border:#000080 1px solid;color:#000;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;font-size:10pt;"&gt; &lt;div style="background:#ddd;max-height:300px;overflow:auto;"&gt; &lt;ol style="background:#ffffff;margin:0 0 0 2.5em;padding:0 0 0 5px;white-space:nowrap;"&gt; &lt;li&gt;&lt;span style="background:#ffffff;color:#000000;"&gt;test(&lt;/span&gt;&lt;span style="background:#ffffff;color:#a31515;"&gt;&amp;quot;Window location&amp;quot;&lt;/span&gt;&lt;span style="background:#ffffff;color:#000000;"&gt;, &lt;/span&gt;&lt;span style="background:#ffffff;color:#0000ff;"&gt;function&lt;/span&gt;&lt;span style="background:#ffffff;color:#000000;"&gt; ()&lt;/span&gt;&lt;/li&gt; &lt;li&gt;&lt;span style="background:#ffffff;color:#000000;"&gt;{&lt;/span&gt;&lt;/li&gt; &lt;li&gt;    &lt;span style="background:#ffffff;color:#000000;"&gt;&lt;/span&gt;&lt;span style="background:#ffffff;color:#0000ff;"&gt;var&lt;/span&gt;&lt;span style="background:#ffffff;color:#000000;"&gt; __winMock = { location: { href: &lt;/span&gt;&lt;span style="background:#ffffff;color:#a31515;"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span style="background:#ffffff;color:#000000;"&gt; }};&lt;/span&gt;&lt;/li&gt; &lt;li&gt;    &lt;span style="background:#ffffff;color:#000000;"&gt;&lt;/span&gt;&lt;span style="background:#ffffff;color:#0000ff;"&gt;var&lt;/span&gt;&lt;span style="background:#ffffff;color:#000000;"&gt; __myObj = &lt;/span&gt;&lt;span style="background:#ffffff;color:#0000ff;"&gt;new&lt;/span&gt;&lt;span style="background:#ffffff;color:#000000;"&gt; MyNamespace.MyObject(__winMock);&lt;/span&gt;&lt;/li&gt; &lt;li&gt;&amp;nbsp;&lt;/li&gt; &lt;li&gt;    &lt;span style="background:#ffffff;color:#000000;"&gt;__myObj.NavigateTo(&lt;/span&gt;&lt;span style="background:#ffffff;color:#a31515;"&gt;&amp;#39;abc&amp;#39;&lt;/span&gt;&lt;span style="background:#ffffff;color:#000000;"&gt;, &lt;/span&gt;&lt;span style="background:#ffffff;color:#a31515;"&gt;&amp;#39;def&amp;#39;&lt;/span&gt;&lt;span style="background:#ffffff;color:#000000;"&gt;);&lt;/span&gt;&lt;/li&gt; &lt;li&gt;&amp;nbsp;&lt;/li&gt; &lt;li&gt;    &lt;span style="background:#ffffff;color:#000000;"&gt;window.equal(&lt;/span&gt;&lt;span style="background:#ffffff;color:#a31515;"&gt;&amp;quot;http://www.google.com/?q=abc&amp;amp;s=def&amp;quot;&lt;/span&gt;&lt;span style="background:#ffffff;color:#000000;"&gt;, __winMock.location.href, &lt;/span&gt;&lt;span style="background:#ffffff;color:#a31515;"&gt;&amp;quot;is ok&amp;quot;&lt;/span&gt;&lt;span style="background:#ffffff;color:#000000;"&gt;);&lt;/span&gt;&lt;/li&gt; &lt;li&gt;&lt;span style="background:#ffffff;color:#000000;"&gt;});&lt;/span&gt;&lt;/li&gt; &lt;/ol&gt; &lt;/div&gt; &lt;/div&gt; &lt;/div&gt;&lt;/p&gt; &lt;p&gt;Nuestro test pasa sin problemas.&lt;/p&gt; &lt;p&gt;&lt;a href="http://www.odelvalle.com/wp-content/uploads/2013/02/moc-1.png"&gt;&lt;img title="moc-1" style="border-top:0px;border-right:0px;background-image:none;border-bottom:0px;padding-top:0px;padding-left:0px;border-left:0px;display:inline;padding-right:0px;" border="0" alt="moc-1" src="http://www.odelvalle.com/wp-content/uploads/2013/02/moc-1_thumb.png" width="649" height="305" /&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;En el momento en que necesitemos que nuestro objeto trabaje con el objeto real, solo tenemos que pasar el window en el constructor.&lt;/p&gt; &lt;p&gt; &lt;div id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:9203ec32-3e26-4104-b126-d14566538ad4" class="wlWriterEditableSmartContent" style="float:none;padding-bottom:0px;padding-top:0px;padding-left:0px;margin:0px;display:inline;padding-right:0px;"&gt; &lt;div style="border:#000080 1px solid;color:#000;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;font-size:10pt;"&gt; &lt;div style="background:#ddd;max-height:300px;overflow:auto;"&gt; &lt;ol style="background:#ffffff;margin:0 0 0 2em;padding:0 0 0 5px;white-space:nowrap;"&gt; &lt;li&gt;&lt;span style="background:#ffffff;color:#000000;"&gt;&lt;/span&gt;&lt;span style="background:#ffffff;color:#0000ff;"&gt;var&lt;/span&gt;&lt;span style="background:#ffffff;color:#000000;"&gt; __myObj = &lt;/span&gt;&lt;span style="background:#ffffff;color:#0000ff;"&gt;new&lt;/span&gt;&lt;span style="background:#ffffff;color:#000000;"&gt; MyNamespace.MyObject(window);&lt;/span&gt;&lt;/li&gt; &lt;/ol&gt; &lt;/div&gt; &lt;/div&gt; &lt;/div&gt;&lt;/p&gt; &lt;p&gt;Otra solución y mi preferida, es encapsular la llamada a window.location.href en una función que podamos usar desde cualquier parte en nuestro proyecto. Luego solo tendríamos que mockear la función y testear que todo esté correcto.&lt;/p&gt;  &lt;p&gt; &lt;div id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:7cce02b2-b548-41e6-a801-78b76a68c7cd" class="wlWriterEditableSmartContent" style="float:none;padding-bottom:0px;padding-top:0px;padding-left:0px;margin:0px;display:inline;padding-right:0px;"&gt; &lt;div style="border:#000080 1px solid;color:#000;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;font-size:10pt;"&gt; &lt;div style="background:#ddd;max-height:300px;overflow:auto;"&gt; &lt;ol style="background:#ffffff;margin:0 0 0 2.5em;padding:0 0 0 5px;white-space:nowrap;"&gt; &lt;li&gt;&lt;span style="background:#ffffff;color:#0000ff;"&gt;var&lt;/span&gt;&lt;span style="background:#ffffff;color:#000000;"&gt; MyNamespace = &lt;/span&gt;&lt;span style="background:#ffffff;color:#0000ff;"&gt;new&lt;/span&gt;&lt;span style="background:#ffffff;color:#000000;"&gt; &lt;/span&gt;&lt;span style="background:#ffffff;color:#0000ff;"&gt;function&lt;/span&gt;&lt;span style="background:#ffffff;color:#000000;"&gt; ()&lt;/span&gt;&lt;/li&gt; &lt;li&gt;&lt;span style="background:#ffffff;color:#000000;"&gt;{&lt;/span&gt;&lt;/li&gt; &lt;li&gt;    &lt;span style="background:#ffffff;color:#000000;"&gt;&lt;/span&gt;&lt;span style="background:#ffffff;color:#0000ff;"&gt;this&lt;/span&gt;&lt;span style="background:#ffffff;color:#000000;"&gt;.MyObject = &lt;/span&gt;&lt;span style="background:#ffffff;color:#0000ff;"&gt;function&lt;/span&gt;&lt;span style="background:#ffffff;color:#000000;"&gt; ()&lt;/span&gt;&lt;/li&gt; &lt;li&gt;    &lt;span style="background:#ffffff;color:#000000;"&gt;{&lt;/span&gt;&lt;/li&gt; &lt;li&gt;        &lt;span style="background:#ffffff;color:#000000;"&gt;&lt;/span&gt;&lt;span style="background:#ffffff;color:#0000ff;"&gt;this&lt;/span&gt;&lt;span style="background:#ffffff;color:#000000;"&gt;.NavigateTo = &lt;/span&gt;&lt;span style="background:#ffffff;color:#0000ff;"&gt;function&lt;/span&gt;&lt;span style="background:#ffffff;color:#000000;"&gt; (p1, p2)&lt;/span&gt;&lt;/li&gt; &lt;li&gt;        &lt;span style="background:#ffffff;color:#000000;"&gt;{&lt;/span&gt;&lt;/li&gt; &lt;li&gt;            &lt;span style="background:#ffffff;color:#000000;"&gt;&lt;/span&gt;&lt;span style="background:#ffffff;color:#0000ff;"&gt;var&lt;/span&gt;&lt;span style="background:#ffffff;color:#000000;"&gt; __url = &lt;/span&gt;&lt;span style="background:#ffffff;color:#a31515;"&gt;&amp;quot;http://www.google.com/?q=&amp;quot;&lt;/span&gt;&lt;span style="background:#ffffff;color:#000000;"&gt; + p1 + &lt;/span&gt;&lt;span style="background:#ffffff;color:#a31515;"&gt;&amp;quot;&amp;amp;s=&amp;quot;&lt;/span&gt;&lt;span style="background:#ffffff;color:#000000;"&gt; + p2;&lt;/span&gt;&lt;/li&gt; &lt;li&gt;            &lt;span style="background:#ffffff;color:#000000;"&gt;Utils.Browser.Navigate(__url);&lt;/span&gt;&lt;/li&gt; &lt;li&gt;        &lt;span style="background:#ffffff;color:#000000;"&gt;};&lt;/span&gt;&lt;/li&gt; &lt;li&gt;    &lt;span style="background:#ffffff;color:#000000;"&gt;};&lt;/span&gt;&lt;/li&gt; &lt;li&gt;&lt;span style="background:#ffffff;color:#000000;"&gt;};&lt;/span&gt;&lt;/li&gt; &lt;li&gt;&amp;nbsp;&lt;/li&gt; &lt;li&gt;&lt;span style="background:#ffffff;color:#0000ff;"&gt;var&lt;/span&gt;&lt;span style="background:#ffffff;color:#000000;"&gt; Utils =&lt;/span&gt;&lt;/li&gt; &lt;li&gt;&lt;span style="background:#ffffff;color:#000000;"&gt;{&lt;/span&gt;&lt;/li&gt; &lt;li&gt;    &lt;span style="background:#ffffff;color:#000000;"&gt;Browser: &lt;/span&gt;&lt;span style="background:#ffffff;color:#0000ff;"&gt;new&lt;/span&gt;&lt;span style="background:#ffffff;color:#000000;"&gt; &lt;/span&gt;&lt;span style="background:#ffffff;color:#0000ff;"&gt;function&lt;/span&gt;&lt;span style="background:#ffffff;color:#000000;"&gt;()&lt;/span&gt;&lt;/li&gt; &lt;li&gt;    &lt;span style="background:#ffffff;color:#000000;"&gt;{&lt;/span&gt;&lt;/li&gt; &lt;li&gt;        &lt;span style="background:#ffffff;color:#000000;"&gt;&lt;/span&gt;&lt;span style="background:#ffffff;color:#0000ff;"&gt;this&lt;/span&gt;&lt;span style="background:#ffffff;color:#000000;"&gt;.Navigate = &lt;/span&gt;&lt;span style="background:#ffffff;color:#0000ff;"&gt;function&lt;/span&gt;&lt;span style="background:#ffffff;color:#000000;"&gt; (url)&lt;/span&gt;&lt;/li&gt; &lt;li&gt;        &lt;span style="background:#ffffff;color:#000000;"&gt;{&lt;/span&gt;&lt;/li&gt; &lt;li&gt;            &lt;span style="background:#ffffff;color:#000000;"&gt;window.location.href = url;&lt;/span&gt;&lt;/li&gt; &lt;li&gt;        &lt;span style="background:#ffffff;color:#000000;"&gt;};&lt;/span&gt;&lt;/li&gt; &lt;li&gt;    &lt;span style="background:#ffffff;color:#000000;"&gt;}&lt;/span&gt;&lt;/li&gt; &lt;li&gt;&lt;span style="background:#ffffff;color:#000000;"&gt;};&lt;/span&gt;&lt;/li&gt; &lt;/ol&gt; &lt;/div&gt; &lt;/div&gt; &lt;/div&gt;&lt;/p&gt; &lt;p&gt;Aquí ya no estamos falseando el objeto window sino que encapsulamos su utilización dentro de un objeto Browser que contiene un método llamado&amp;nbsp; Navigate.&lt;/p&gt; &lt;p&gt;Para testear el ejemplo anterior, vamos a usar &lt;a href="http://sinonjs.org/" target="_blank"&gt;Sinon&lt;/a&gt; y su &lt;a href="http://sinonjs.org/qunit/" target="_blank"&gt;pluging para qunit&lt;/a&gt;. Como estamos trabajando con ReSharper para las pruebas, debemos indicar la referencia a estos frameworks en nuestro js de pruebas.&lt;/p&gt; &lt;p&gt; &lt;div id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:aee1247e-c56b-490f-ba0e-a227262d9452" class="wlWriterEditableSmartContent" style="float:none;padding-bottom:0px;padding-top:0px;padding-left:0px;margin:0px;display:inline;padding-right:0px;"&gt; &lt;div style="border:#000080 1px solid;color:#000;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;font-size:10pt;"&gt; &lt;div style="background:#ddd;max-height:300px;overflow:auto;"&gt; &lt;ol style="background:#ffffff;margin:0 0 0 2em;padding:0 0 0 5px;white-space:nowrap;"&gt; &lt;li&gt;&lt;span style="background:#ffffff;color:#808080;"&gt;///&lt;/span&gt;&lt;span style="background:#ffffff;color:#008000;"&gt; &lt;/span&gt;&lt;span style="background:#ffffff;color:#808080;"&gt;&amp;lt;reference path=&amp;quot;/resources/sinon-1.5.2.js&amp;quot;/&amp;gt;&lt;/span&gt;&lt;/li&gt; &lt;li&gt;&lt;span style="background:#ffffff;color:#808080;"&gt;///&lt;/span&gt;&lt;span style="background:#ffffff;color:#008000;"&gt; &lt;/span&gt;&lt;span style="background:#ffffff;color:#808080;"&gt;&amp;lt;reference path=&amp;quot;/resources/sinon-qunit-1.0.0.js&amp;quot;/&amp;gt;&lt;/span&gt;&lt;/li&gt; &lt;/ol&gt; &lt;/div&gt; &lt;/div&gt; &lt;/div&gt;&lt;/p&gt; &lt;p&gt;Ya con esto podemos crearnos nuestro test:&lt;/p&gt; &lt;div id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:808e0591-5ea0-45b9-b466-966f8f8b1102" class="wlWriterEditableSmartContent" style="float:none;padding-bottom:0px;padding-top:0px;padding-left:0px;margin:0px;display:inline;padding-right:0px;"&gt; &lt;div style="border:#000080 1px solid;color:#000;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;font-size:10pt;"&gt; &lt;div style="background:#ddd;max-height:300px;overflow:auto;"&gt; &lt;ol style="background:#ffffff;margin:0 0 0 2.5em;padding:0 0 0 5px;white-space:nowrap;"&gt; &lt;li&gt;&lt;span style="background:#ffffff;color:#000000;"&gt;test(&lt;/span&gt;&lt;span style="background:#ffffff;color:#a31515;"&gt;&amp;quot;Window location&amp;quot;&lt;/span&gt;&lt;span style="background:#ffffff;color:#000000;"&gt;, &lt;/span&gt;&lt;span style="background:#ffffff;color:#0000ff;"&gt;function&lt;/span&gt;&lt;span style="background:#ffffff;color:#000000;"&gt; ()&lt;/span&gt;&lt;/li&gt; &lt;li&gt;&lt;span style="background:#ffffff;color:#000000;"&gt;{&lt;/span&gt;&lt;/li&gt; &lt;li&gt;    &lt;span style="background:#ffffff;color:#000000;"&gt;&lt;/span&gt;&lt;span style="background:#ffffff;color:#0000ff;"&gt;var&lt;/span&gt;&lt;span style="background:#ffffff;color:#000000;"&gt; __myObj = &lt;/span&gt;&lt;span style="background:#ffffff;color:#0000ff;"&gt;new&lt;/span&gt;&lt;span style="background:#ffffff;color:#000000;"&gt; MyNamespace.MyObject();&lt;/span&gt;&lt;/li&gt; &lt;li&gt;&amp;nbsp;&lt;/li&gt; &lt;li&gt;    &lt;span style="background:#ffffff;color:#000000;"&gt;&lt;/span&gt;&lt;span style="background:#ffffff;color:#0000ff;"&gt;var&lt;/span&gt;&lt;span style="background:#ffffff;color:#000000;"&gt; __mock = sinon.mock(Utils.Browser);&lt;/span&gt;&lt;/li&gt; &lt;li&gt;    &lt;span style="background:#ffffff;color:#000000;"&gt;__mock.expects(&lt;/span&gt;&lt;span style="background:#ffffff;color:#a31515;"&gt;&amp;quot;Navigate&amp;quot;&lt;/span&gt;&lt;span style="background:#ffffff;color:#000000;"&gt;).once().withArgs(&lt;/span&gt;&lt;span style="background:#ffffff;color:#a31515;"&gt;&amp;quot;http://www.google.com/?q=abc&amp;amp;s=def&amp;quot;&lt;/span&gt;&lt;span style="background:#ffffff;color:#000000;"&gt;);&lt;/span&gt;&lt;/li&gt; &lt;li&gt;&amp;nbsp;&lt;/li&gt; &lt;li&gt;    &lt;span style="background:#ffffff;color:#000000;"&gt;__myObj.NavigateTo(&lt;/span&gt;&lt;span style="background:#ffffff;color:#a31515;"&gt;&amp;#39;abc&amp;#39;&lt;/span&gt;&lt;span style="background:#ffffff;color:#000000;"&gt;, &lt;/span&gt;&lt;span style="background:#ffffff;color:#a31515;"&gt;&amp;#39;def&amp;#39;&lt;/span&gt;&lt;span style="background:#ffffff;color:#000000;"&gt;);&lt;/span&gt;&lt;/li&gt; &lt;li&gt;&amp;nbsp;&lt;/li&gt; &lt;li&gt;    &lt;span style="background:#ffffff;color:#000000;"&gt;__mock.verify();&lt;/span&gt;&lt;/li&gt; &lt;li&gt;&lt;span style="background:#ffffff;color:#000000;"&gt;});&lt;/span&gt;&lt;/li&gt; &lt;/ol&gt; &lt;/div&gt; &lt;/div&gt; &lt;/div&gt;  &lt;p&gt;y el resultado…&lt;/p&gt; &lt;p&gt;&lt;a href="http://www.odelvalle.com/wp-content/uploads/2013/02/moc-11.png"&gt;&lt;img title="moc-1" style="border-top:0px;border-right:0px;background-image:none;border-bottom:0px;padding-top:0px;padding-left:0px;border-left:0px;display:inline;padding-right:0px;" border="0" alt="moc-1" src="http://www.odelvalle.com/wp-content/uploads/2013/02/moc-1_thumb1.png" width="643" height="324" /&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;Lo que me gusta de este método respecto al anterior es que no tenemos necesidad de falsear un objeto nativo del DOM. Por el contrario, lo que hacemos es mokear un objeto nuestro y testear su funcionalidad.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=208701" width="1" height="1"&gt;</description></item><item><title>Microsoft Hosted Network Virtual Adapter</title><link>http://geeks.ms/blogs/omarvr/archive/2012/11/30/microsoft-hosted-network-virtual-adapter.aspx</link><pubDate>Fri, 30 Nov 2012 10:43:29 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:207625</guid><dc:creator>Omar del Valle Rodríguez</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/omarvr/rsscomments.aspx?PostID=207625</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/omarvr/commentapi.aspx?PostID=207625</wfw:comment><comments>http://geeks.ms/blogs/omarvr/archive/2012/11/30/microsoft-hosted-network-virtual-adapter.aspx#comments</comments><description>&lt;p&gt;…o lo que es lo mismo, un router virtual WIFI en mi ordenador. :) …y aquí es donde quizás los de IT digan: ¿Y ahora es que te enteras…? &lt;/p&gt; &lt;p&gt;Resulta que el próximo martes toca realizar una presentación de una aplicación Web y para la cual necesitamos que estén conectados a una misma red: dos ordenadores, un iPad y un Tablet con Windows 8. &lt;/p&gt; &lt;p&gt;Posibles soluciones y problemas:&lt;/p&gt; &lt;p&gt;1- WIFI&lt;br /&gt;Solución: Espero a que el lugar de la presentación tenga WIFI, y además el salón tenga cobertura.&lt;/p&gt; &lt;p&gt;Problema: Pierdes tiempo configurando conexiones en los dispositivos, problemas de coberturas, la primera impresión que se deja es un poco de “estamos perdiendo tiempo”&lt;/p&gt; &lt;p&gt;2- Router WIFI&lt;br /&gt;Solución: Me llevo un Router WIFI previamente configurado y conecto a todo el mundo: Imaginen llegar, sacar un iPad, un tablet de W8, dos ordenadores, una kinect y un router con antenita al estilo “Star Wars light sabers” :) &lt;/p&gt; &lt;p&gt;Problemas: Necesito un router físico y más conectores de alimentación&lt;/p&gt; &lt;p&gt;3- Tengo un Nokia Lumia 800&lt;br /&gt;Solución: Puedo activar “Compartir conexión” lo cual activa en mi teléfono un host WIFI al cual puedo conectar a todo el mundo.&lt;/p&gt; &lt;p&gt;Problemas: Pobre Nokia Lumia… ¿Cuanto dudará la batería? :)&lt;/p&gt; &lt;p&gt;4- Si el teléfono crea un Host WIFI virtual, ¿no podré hacer lo mismo en mi ordenador? Googleando…&lt;/p&gt; &lt;p&gt;Solución: Mi querido amigo &lt;strong&gt;netsh&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;Pues bien, como este trabajo no es de desarrollo sino de IT, en vez de cargar Visual Studio 2012, cargamos la consola de comandos “cmd” y, recuerden que tienen que hacerlo con permisos de administración… &lt;/p&gt; &lt;p&gt;&lt;a href="http://www.odelvalle.com/wp-content/uploads/2012/11/wifi1.png"&gt;&lt;img title="wifi-1" style="border-top:0px;border-right:0px;border-bottom:0px;border-left:0px;display:inline;" border="0" alt="wifi-1" src="http://www.odelvalle.com/wp-content/uploads/2012/11/wifi1_thumb.png" width="460" height="659" /&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;Ejecutamos un primer comando: &lt;br /&gt;&lt;strong&gt;netsh wlan﻿ set hostednetwork mode=allow ssid=odelvalle key=MyPassword&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;wlan: Wireless Lan (vamos a trabajar sobre la conexión WIFI)&lt;br /&gt;set hostednetwork: (vamos a trabajar con las propiedades del hostednetwork). &lt;/p&gt; &lt;p&gt;El hostedNetwork es una funcionalidad soportada en W7, W8 y los 2008R2 en adelante…&amp;nbsp; Su principal objetivo es (para IT) virtualizar un adaptador wireless (para desarrolladores) un router WIFI de toda la vida.&lt;/p&gt; &lt;p&gt;El resto de los comandos indican si vamos a permitir conexión (mode), el nombre que le pondremos a nuestra WIFI (ssid) y la contraseña (key).&lt;/p&gt; &lt;p&gt;Todo lo anterior configura y deja listo nuestro hostednetwork, pero necesitamos echarle a funcionar y, para eso ejecutamos un segundo comando:&lt;/p&gt; &lt;p&gt;&lt;strong&gt;netsh wlan start hostednetwork&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;Este segundo comando inicia el&amp;nbsp; hostednetwork y deja nuestra vista de adaptadores de red de la siguiente forma:&lt;/p&gt; &lt;p&gt;&lt;a href="http://www.odelvalle.com/wp-content/uploads/2012/11/wifi2.png"&gt;&lt;img title="wifi-2" style="border-top:0px;border-right:0px;border-bottom:0px;border-left:0px;display:inline;" border="0" alt="wifi-2" src="http://www.odelvalle.com/wp-content/uploads/2012/11/wifi2_thumb.png" width="653" height="491" /&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;y mi Nokia Lumia…. &lt;br /&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;a href="http://www.odelvalle.com/wp-content/uploads/2012/11/ScreenCapture.jpg"&gt;&lt;img title="Screen Capture" style="border-top:0px;border-right:0px;border-bottom:0px;border-left:0px;display:inline;" border="0" alt="Screen Capture" src="http://www.odelvalle.com/wp-content/uploads/2012/11/ScreenCapture_thumb.jpg" width="395" height="656" /&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;Espero q a alguien le sirva…. Salu2&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=207625" width="1" height="1"&gt;</description></item><item><title>RESTFul en Windows 8</title><link>http://geeks.ms/blogs/omarvr/archive/2012/10/11/restful-en-windows-8.aspx</link><pubDate>Wed, 10 Oct 2012 22:57:00 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:207094</guid><dc:creator>Omar del Valle Rodríguez</dc:creator><slash:comments>1</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/omarvr/rsscomments.aspx?PostID=207094</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/omarvr/commentapi.aspx?PostID=207094</wfw:comment><comments>http://geeks.ms/blogs/omarvr/archive/2012/10/11/restful-en-windows-8.aspx#comments</comments><description>&lt;p&gt;Para las aplicaciones que he realizado para WP7 tenía un helper que me ayudaba a consultar servicios RESTful, pero la verdad, con todo el tema de async, await y Task, es motivo suficiente como para plantearse rescribir cualquier código asíncrono escrito con anterioridad.&lt;/p&gt; &lt;p&gt;Para nuestro helper vamos a necesitar fundamentalmente 2 clases, aunque implementaremos una tercera clase para el tema de serialización.&lt;/p&gt; &lt;p&gt;A todas las clases les vamos a definir una interfaz, las ventajas ya las conocemos: no atamos las clases que usen nuestro helper a nuestra implementación y además, podremos inyectar el helper usando IoC si trabajamos con MVVM.&lt;/p&gt; &lt;p&gt;Empecemos justo por la clase que se encargará de serializar y de-serializar:&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="background:white;color:blue;"&gt;public interface &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;IJsonResolver
&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;{
    &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;Task&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;byte&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;[]&amp;gt; Serialize(&lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;object &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;graph);
    &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;Task&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;&amp;lt;T&amp;gt; Deserialize&amp;lt;T&amp;gt;(&lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;Stream &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;respnseResult) &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;where &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;T : &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;class&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;;
}&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;Nuestra interfaz tiene dos métodos que nos permitan serializar y de-serializar nuestros objetos. Estos métodos retornan un Task, por lo que podremos usar su condición asíncrona durante la implementación.&lt;/p&gt;
&lt;p&gt;En mi caso, voy a usar Json.net para implementar esta interfaz, pero ustedes pueden elegir su propia implementación.&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="background:white;color:blue;"&gt;public class &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;JsonResolver &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;: &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;IJsonResolver
&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;{
    &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;private async &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;Task&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;string&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;&amp;gt; SerializeToString(&lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;object &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;graph)
    {
        &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;return await &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;JsonConvert&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;.SerializeObjectAsync(graph, &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;Formatting&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;.Indented, &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;new &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;JsonSerializerSettings &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;{ NullValueHandling = &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;NullValueHandling&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;.Ignore });
    }

    &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;public async &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;Task&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;byte&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;[]&amp;gt; Serialize(&lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;object &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;graph)
    {
        &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;if &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;(graph &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;is string&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;) &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;return &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;Encoding&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;.UTF8.GetBytes(graph &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;as string&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;);

        &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;var &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;json = &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;await &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;SerializeToString(graph);
        &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;return &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;Encoding&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;.UTF8.GetBytes(json);
    }

    &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;public async &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;Task&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;&amp;lt;T&amp;gt; Deserialize&amp;lt;T&amp;gt;(&lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;Stream &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;respnseResult) &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;where &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;T : &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;class
    &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;{
        T result;

        &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;using &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;(&lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;var &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;sr = &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;new &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;StreamReader&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;(respnseResult))
        {
            &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;var &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;r = &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;await &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;sr.ReadToEndAsync();
            result = &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;await &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;JsonConvert&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;.DeserializeObjectAsync&amp;lt;T&amp;gt;(r, &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;new &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;JsonSerializerSettings &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;{ NullValueHandling = &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;NullValueHandling&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;.Ignore });
        }

        &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;return &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;result;
    }
}&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;Ya tenemos nuestra implementación, vamos a lo que de verdad nos interesa.&lt;/p&gt;
&lt;p&gt;La utilización de un servicio web, ya sea Rest, Xml o cualquier otro formato, está compuesto principalmente por dos elementos:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;El Request: Este elemento podría contener la URL a la cual vamos a realizar la petición, qué tipo de petición vamos a realizar (si es GET, POST, u otra), el ContentType, los parámetros, etc… 
&lt;li&gt;Un cliente que realiza la petición usando todas las opciones definidas en el Request. &lt;/li&gt;&lt;/ol&gt;
&lt;p&gt;Siguiendo esta lógica, mi Helper tendrá dos clases más: un RestRequest y un RestClient.&lt;/p&gt;
&lt;p&gt;Vamos a definir la interfaz para el RestRequest.&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="background:white;color:blue;"&gt;public interface &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;IRestRequest
&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;{
    &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;Uri &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;Url { &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;get&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;; }
    &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;string &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;PostParameter { &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;get&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;; }
    &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;Method &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;Method { &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;get&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;; }
    &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;string &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;Accept { &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;get&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;; }
    &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;string &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;ContentType { &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;get&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;; }

    &lt;/span&gt;&lt;span style="background:white;color:gray;"&gt;/// &amp;lt;summary&amp;gt;
    /// &lt;/span&gt;&lt;span style="background:white;color:green;"&gt;Add Parameter to URL. Value is not encode. If Method is POST, parameter is pass in body, if Method is Get, parameter is pass in URL.
    &lt;/span&gt;&lt;span style="background:white;color:gray;"&gt;/// &amp;lt;/summary&amp;gt;
    /// &amp;lt;param name=&amp;quot;name&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="background:white;color:green;"&gt;Parameter name&lt;/span&gt;&lt;span style="background:white;color:gray;"&gt;&amp;lt;/param&amp;gt;
    /// &amp;lt;param name=&amp;quot;value&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="background:white;color:green;"&gt;Parameter value&lt;/span&gt;&lt;span style="background:white;color:gray;"&gt;&amp;lt;/param&amp;gt;
    &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;void &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;AddParameter(&lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;string &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;name, &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;string &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;value);

    &lt;/span&gt;&lt;span style="background:white;color:gray;"&gt;/// &amp;lt;summary&amp;gt;
    /// &lt;/span&gt;&lt;span style="background:white;color:green;"&gt;Add Parameter to URL. This method encode parameter value by default
    &lt;/span&gt;&lt;span style="background:white;color:gray;"&gt;/// &amp;lt;/summary&amp;gt;
    /// &amp;lt;param name=&amp;quot;name&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="background:white;color:green;"&gt;Parameter name&lt;/span&gt;&lt;span style="background:white;color:gray;"&gt;&amp;lt;/param&amp;gt;
    /// &amp;lt;param name=&amp;quot;value&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="background:white;color:green;"&gt;Parameter value&lt;/span&gt;&lt;span style="background:white;color:gray;"&gt;&amp;lt;/param&amp;gt;
    /// &amp;lt;param name=&amp;quot;pType&amp;quot;&amp;gt; &amp;lt;/param&amp;gt;
    &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;void &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;AddParameter(&lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;string &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;name, &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;string &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;value, &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;ParameterType &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;pType);

    &lt;/span&gt;&lt;span style="background:white;color:gray;"&gt;/// &amp;lt;summary&amp;gt;
    /// &lt;/span&gt;&lt;span style="background:white;color:green;"&gt;Add Parameter to URL. This method encode parameter value by default
    &lt;/span&gt;&lt;span style="background:white;color:gray;"&gt;/// &amp;lt;/summary&amp;gt;
    /// &amp;lt;param name=&amp;quot;name&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="background:white;color:green;"&gt;Parameter name&lt;/span&gt;&lt;span style="background:white;color:gray;"&gt;&amp;lt;/param&amp;gt;
    /// &amp;lt;param name=&amp;quot;value&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="background:white;color:green;"&gt;Parameter value&lt;/span&gt;&lt;span style="background:white;color:gray;"&gt;&amp;lt;/param&amp;gt;
    /// &amp;lt;param name=&amp;quot;encode&amp;quot;&amp;gt; &amp;lt;/param&amp;gt;
    &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;void &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;AddParameter(&lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;string &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;name, &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;string &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;value, &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;bool &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;encode);

    &lt;/span&gt;&lt;span style="background:white;color:gray;"&gt;/// &amp;lt;summary&amp;gt;
    /// &lt;/span&gt;&lt;span style="background:white;color:green;"&gt;Add Parameter to URL. 
    &lt;/span&gt;&lt;span style="background:white;color:gray;"&gt;/// &amp;lt;/summary&amp;gt;
    /// &amp;lt;param name=&amp;quot;name&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="background:white;color:green;"&gt;Parameter name&lt;/span&gt;&lt;span style="background:white;color:gray;"&gt;&amp;lt;/param&amp;gt;
    /// &amp;lt;param name=&amp;quot;value&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="background:white;color:green;"&gt;Parameter value&lt;/span&gt;&lt;span style="background:white;color:gray;"&gt;&amp;lt;/param&amp;gt;
    /// &amp;lt;param name=&amp;quot;encode&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="background:white;color:green;"&gt;if true, encode parameter value&lt;/span&gt;&lt;span style="background:white;color:gray;"&gt;&amp;lt;/param&amp;gt;
    /// &amp;lt;param name=&amp;quot;pType&amp;quot;&amp;gt;&amp;lt;/param&amp;gt;
    &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;void &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;AddParameter(&lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;string &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;name, &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;string &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;value, &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;bool &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;encode, &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;ParameterType &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;pType);
}&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;En esta interfaz tenemos varios elementos que nos ayudan a configurar nuestro Request antes de realizar la petición.&lt;/p&gt;
&lt;p&gt;El método AddPArameter cuenta con varias sobrecargas ya que vamos a tener varias posibilidades de pasar parámetros. Vamos a verlo uno por uno empezando por el más complejo (el último):&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Este método recibe un nombre, un valor, permite indicar si el valor del parámetro debe ser “encodeado” o no y el tipo de parámetro que estamos utilizando. 
&lt;ol&gt;
&lt;li&gt;El “encodear” el valor de un parámetro es usado fundamentalmente cuando pasamos el valor por GET, ya que hay caracteres que no son válidos como parte de la URL 
&lt;li&gt;ParamType es un enumerado que me indica el tipo de parámetro que vamos a pasar a nuestro objeto: QueryString (GET?nombre=valor), Post (se pasa en el body) y UrlSegment que es utilizado cuando el parámetro es parte de la URL. Ej. &lt;a href="http://odelvalle.com/{parametro}/Rest"&gt;http://odelvalle.com/{parametro}/Rest&lt;/a&gt; &lt;/li&gt;&lt;/ol&gt;
&lt;li&gt;Un segundo método en que no es necesario pasar el tipo de parámetro. En este caso el tipo es determinado según el método usado para el Request, si es GET se pasa por QueryString, si es Post, se pasa en el body. 
&lt;li&gt;Otro método que nos permite indicar solo el nombre, el valor y el tipo de parámetro. Todos los parámetros pasados mediante este método, el value es “encodeado”. 
&lt;li&gt;Finalmente, tenemos un método que nos vale para pasar solo el nombre y el valor. Los parámetros que se pasen usando esta sobrecarga no se van a “encodear” y el tipo de parámetro es determinado por el tipo de Request (GET o POST) &lt;/li&gt;&lt;/ol&gt;
&lt;p&gt;Las propiedades definidas en la interfaz nos brindan el resto de la información necesaria para formar nuestro Request. Vamos a ver la implementación&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="background:white;color:blue;"&gt;public enum &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;ParameterType
&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;{
    QueryString,
    Post,
    UrlSegment
}

&lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;public enum &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;Method
&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;{
    GET,
    POST,
    PUT,
    DELETE,
    HEAD,
    OPTIONS,
    PATCH
}

&lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;public enum &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;ContentType &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;{ Json, UrlEncoded }

&lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;public class &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;RestRequest &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;: &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;IRestRequest
&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;{
    &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;struct &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;Parameter
    &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;{
        &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;public string &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;Name { &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;get&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;; &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;set&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;; }
        &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;public string &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;Value { &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;get&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;; &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;set&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;; }

        &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;public &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;ParameterType &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;ParameterType { &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;get&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;; &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;set&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;; }
    }

    &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;private readonly &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;IList&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;Parameter&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;&amp;gt; _parameters;

    &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;private readonly string &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;_url;
        
    &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;public &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;RestRequest(&lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;string &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;url, &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;Method &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;method)
    {
        _parameters = &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;new &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;List&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;Parameter&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;&amp;gt;();
        _url = url;

        Method = method;
    }

    &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;public &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;Uri &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;Url
    {
        &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;get
        &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;{
            &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;var &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;buildUri = &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;new &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;UriBuilder&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;(_url) { Query = BuildQueryString(&lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;ParameterType&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;.QueryString) };
            &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;return &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;buildUri.Uri;
        }
    }

    &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;public string &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;PostParameter { &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;get &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;{ &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;return &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;BuildQueryString(&lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;ParameterType&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;.Post); }}
    &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;public &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;Method &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;Method { &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;get&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;; &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;private set&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;; }

    &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;public string &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;Accept { &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;get &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;{ &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;return &lt;/span&gt;&lt;span style="background:white;color:#a31515;"&gt;&amp;quot;application/json&amp;quot;&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;; }}
    &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;public string &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;ContentType { &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;get &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;{ &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;return &lt;/span&gt;&lt;span style="background:white;color:#a31515;"&gt;&amp;quot;application/x-www-form-urlencoded&amp;quot;&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;; } }

    &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;public void &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;AddParameter(&lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;string &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;name, &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;string &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;value)
    {
        AddParameter(name, value, &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;false&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;);
    }

    &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;public void &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;AddParameter(&lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;string &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;name, &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;string &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;value, &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;ParameterType &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;pType)
    {
        AddParameter(name, value, &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;true&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;, pType);
    }

    &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;public void &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;AddParameter(&lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;string &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;name, &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;string &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;value, &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;bool &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;encode)
    {
        AddParameter(name, value, encode, (Method == &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;Method&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;.GET) ? &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;ParameterType&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;.QueryString : &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;ParameterType&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;.Post );
    }

    &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;public void &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;AddParameter(&lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;string &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;name, &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;string &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;value, &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;bool &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;encode, &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;ParameterType &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;pType)
    {
        &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;var &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;val = encode ? &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;Uri&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;.EscapeDataString(value) : value;

        &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;if &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;(pType == &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;ParameterType&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;.UrlSegment) _url.Replace(&lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;string&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;.Format(&lt;/span&gt;&lt;span style="background:white;color:#a31515;"&gt;&amp;quot;{{0}}&amp;quot;&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;, name), val);
        &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;else &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;_parameters.Add(&lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;new &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;Parameter &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;{ Name = name, Value = val, ParameterType = pType});
    }

    &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;private string &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;BuildQueryString(&lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;ParameterType &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;pType)
    {
        &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;var &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;plist = _parameters.Where(p=&amp;gt; p.ParameterType == pType).Select(p =&amp;gt; &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;string&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;.Concat(p.Name, &lt;/span&gt;&lt;span style="background:white;color:#a31515;"&gt;&amp;quot;=&amp;quot;&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;, p.Value));
        &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;return &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;String&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;.Join(&lt;/span&gt;&lt;span style="background:white;color:#a31515;"&gt;&amp;quot;&amp;amp;&amp;quot;&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;, plist.ToArray());
    }
}&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;Al constructor de la clase RestRequest le vamos a pasar la URL a la cual queremos realizar la petición y el método a utilizar.&lt;/p&gt;
&lt;p&gt;Ya con esto tenemos nuestro RestRequest, vamos a ver el cliente que realizará la petición. Empezamos viendo la interfaz:&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="background:white;color:blue;"&gt;public interface &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;IRestClient
&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;{
    &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;Task&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;&amp;lt;T&amp;gt; Execute&amp;lt;T&amp;gt;(&lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;IRestRequest &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;request) &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;where &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;T : &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;class&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;;
}&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;.. y eso es todo. No necesitamos nada más ya que estamos definiendo un cliente que recibirá un objeto RestRequest y hará una petición. Veamos la implementación.&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="background:white;color:blue;"&gt;public class &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;RestClient &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;: &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;IRestClient
&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;{
    &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;private readonly &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;IJsonResolver &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;_resolver;

    &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;public &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;RestClient(&lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;IJsonResolver &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;resolver)
    {
        _resolver = resolver;
    }

    &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;public async &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;Task&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;&amp;lt;T&amp;gt; Execute&amp;lt;T&amp;gt;(&lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;IRestRequest &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;request) &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;where &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;T : &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;class 
    &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;{
        &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;var &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;wr = &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;WebRequest&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;.CreateHttp(request.Url);

        wr.Method = request.Method.ToString();
        wr.Accept = request.Accept;
        wr.ContentType = request.ContentType;

        &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;if &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;(!&lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;string&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;.IsNullOrEmpty(request.PostParameter))
        {
            &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;return await &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;ExecuteWithData&amp;lt;T&amp;gt;(wr, request);
        }

        &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;var &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;response = &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;await &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;wr.GetResponseAsync();
        &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;return await &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;_resolver.Deserialize&amp;lt;T&amp;gt;(response.GetResponseStream());
    }

    &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;private async &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;Task&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;&amp;lt;T&amp;gt; ExecuteWithData&amp;lt;T&amp;gt;(&lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;WebRequest &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;wr, &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;IRestRequest &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;request) &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;where &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;T : &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;class
    &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;{
        &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;var &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;body = &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;await &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;_resolver.Serialize(request.PostParameter);

        &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;using &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;(&lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;var &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;stream = &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;await &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;wr.GetRequestStreamAsync())
        {
            &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;await &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;stream.WriteAsync(body, 0, body.Length);
        }

        &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;var &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;response = &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;await &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;wr.GetResponseAsync();
        &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;return await &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;_resolver.Deserialize&amp;lt;T&amp;gt;(response.GetResponseStream());
    }
}&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;Nuestro cliente recibe en el constructor el RestRequest que se desea realizar. Mediante el método Execute, el cliente se encarga de realizar la petición y si hay respuesta del servicio Rest, entonces nos retornará el objeto listo para usarse.&lt;/p&gt;
&lt;p&gt;Para probar todo esto y ver lo simple que es de usar, me busqué alguna ejemplo Rest que ya existiera para Windows 8.&amp;nbsp; Aquí tenéis una: &lt;a href="http://code.msdn.microsoft.com/windowsapps/Metro-client-for-Web-API-664848c5"&gt;Metro client for Web API CRUD&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;En esta aplicación al final de la clase MainViewModel.cs tenemos el GET usando HttpClient y DataContractJsonSerializer.&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="background:white;color:blue;"&gt;using &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;(&lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;var &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;http = &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;new &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;HttpClient&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;())
{
    &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;var &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;resp = &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;await &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;http.GetAsync(&lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;new &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;Uri&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;(ApiRoot));
    &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;using &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;(&lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;var &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;stream = &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;await &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;resp.Content.ReadAsStreamAsync())
    {
        &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;var &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;djs = &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;new &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;DataContractJsonSerializer&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;(&lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;typeof&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;(&lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;List&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;Person&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;&amp;gt;));
        People = &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;new &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;ObservableCollection&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;Person&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;&amp;gt;((&lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;IEnumerable&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;Person&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;&amp;gt;)djs.ReadObject(stream));
    }
}&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;Vamos a quitar ese código y vamos a usar el nuestro:&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="background:white;color:blue;"&gt;var &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;request = &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;new &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;RestRequest&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;(ApiRoot, &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;Method&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;.GET);
&lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;var &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;restFul = &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;new &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;RestClient&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;(&lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;new &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;JsonResolver&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;());

People = &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;new &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;ObservableCollection&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;Person&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;&amp;gt;(&lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;await &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;restFul.Execute&amp;lt;&lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;IEnumerable&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;Person&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;&amp;gt;&amp;gt;(request));&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;… ¿probamos?&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.odelvalle.com/wp-content/uploads/2012/10/screenshot_10112012_004023.png"&gt;&lt;img title="screenshot_10112012_004023" style="border-left-width:0px;border-right-width:0px;background-image:none;border-bottom-width:0px;padding-top:0px;padding-left:0px;display:inline;padding-right:0px;border-top-width:0px;" border="0" alt="screenshot_10112012_004023" src="http://www.odelvalle.com/wp-content/uploads/2012/10/screenshot_10112012_004023_thumb.png" width="639" height="362" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Aquí dejo la &lt;a href="http://www.odelvalle.com/downloads/sources/Metro_client_for_Web_API_CRUD.rar"&gt;aplicación de ejemplo modificada&lt;/a&gt; y usando nuestro Helper.&lt;/p&gt;
&lt;p&gt;PD: Aún no he probado todo el Helper, así que es posible que en un escenario específico pueda aparecer algún BUM &lt;img class="wlEmoticon wlEmoticon-smile" style="border-top-style:none;border-left-style:none;border-bottom-style:none;border-right-style:none;" alt="Sonrisa" src="http://www.odelvalle.com/wp-content/uploads/2012/10/wlEmoticon-smile.png" /&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=207094" width="1" height="1"&gt;</description></item><item><title>Carga de páginas en Chrome, rápido sí, pero ¿seguro?</title><link>http://geeks.ms/blogs/omarvr/archive/2012/10/09/carga-de-p-225-ginas-en-chrome-r-225-pido-s-237-pero-191-seguro.aspx</link><pubDate>Tue, 09 Oct 2012 10:54:35 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:207061</guid><dc:creator>Omar del Valle Rodríguez</dc:creator><slash:comments>5</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/omarvr/rsscomments.aspx?PostID=207061</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/omarvr/commentapi.aspx?PostID=207061</wfw:comment><comments>http://geeks.ms/blogs/omarvr/archive/2012/10/09/carga-de-p-225-ginas-en-chrome-r-225-pido-s-237-pero-191-seguro.aspx#comments</comments><description>&lt;p&gt;Estoy haciendo una aplicación que usa Web Socket. Como navegador, por políticas del cliente, se está usando Chrome. &lt;/p&gt; &lt;p&gt;Resulta que en unas de mis pruebas, descubro algo que al menos a mi, me deja un “tin” preocupado respecto a Chrome.&lt;/p&gt; &lt;p&gt;Observen:&lt;/p&gt; &lt;p&gt;&lt;a href="http://www.odelvalle.com/wp-content/uploads/2012/10/chrome.png"&gt;&lt;img title="chrome" style="border-top:0px;border-right:0px;background-image:none;border-bottom:0px;padding-top:0px;padding-left:0px;border-left:0px;display:inline;padding-right:0px;" border="0" alt="chrome" src="http://www.odelvalle.com/wp-content/uploads/2012/10/chrome_thumb.png" width="609" height="655" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Lo que está pasando aquí es que yo abro Chrome, comienzo a escribir la URL y el navegador me propone la URL a usar. El problema es que yo aún no he confirmado que es esa, ni siquiera le he dicho a Chrome que navegue a esa URL, pero ya mi servidor de Web Socket ha detectado una conexión entrante.&lt;/p&gt; &lt;p&gt;¿Entonces?… Pues muy probablemente el listillo de Chrome navegue por detrás para dar la impresión posteriormente de que las páginas cargan más rápido… pero ¿Esto da un poco de miedo no? y más si yo sé que mi web socket en el cliente se inicializa y se ejecuta en el momento en que la página ha sido totalmente cargada, o sea, en el ready.&lt;/p&gt; &lt;p&gt;Probé con IE10 y no pasa. No he probado con más browsers.&lt;/p&gt; &lt;p&gt;Salu2&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=207061" width="1" height="1"&gt;</description></item><item><title>Repository Pattern para ApplicationData en Windows 8</title><link>http://geeks.ms/blogs/omarvr/archive/2012/10/07/repository-pattern-para-applicationdata-en-windows-8.aspx</link><pubDate>Sun, 07 Oct 2012 12:11:29 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:207041</guid><dc:creator>Omar del Valle Rodríguez</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/omarvr/rsscomments.aspx?PostID=207041</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/omarvr/commentapi.aspx?PostID=207041</wfw:comment><comments>http://geeks.ms/blogs/omarvr/archive/2012/10/07/repository-pattern-para-applicationdata-en-windows-8.aspx#comments</comments><description>&lt;p&gt;Con la llegada de Windows 8 y sus aplicaciones para el Store, muchas veces nos toca lidiar con datos almacenados en local. &lt;/p&gt; &lt;p&gt;La idea de este post es implementar el patrón repositorio para independizar nuestras aplicaciones del trabajo con los distintos tipos de almacenamientos en local que existen en Windows 8.&lt;/p&gt; &lt;p&gt;Para profundizar en este patrón puedes echar un ojo a este enlace de Martin Fowler: &lt;a title="http://martinfowler.com/eaaCatalog/repository.html" href="http://martinfowler.com/eaaCatalog/repository.html"&gt;http://martinfowler.com/eaaCatalog/repository.html&lt;/a&gt;&lt;/p&gt; &lt;h3&gt;&lt;font style="font-weight:bold;"&gt;El objetivo&lt;/font&gt;&lt;/h3&gt; &lt;p&gt;- Evitar código duplicado&lt;br /&gt;- Mejor gestión de errores (código centralizado)&lt;br /&gt;- Menos dependencia de nuestras reglas de negocio a la persistencia&lt;br /&gt;- Posibilidad de centralizar políticas relacionadas con datos como el almacenamiento en caché o Lazy load.&lt;br /&gt;- Posibilidad de “testear” la lógica de negocio de forma aislada a la persistencia&lt;/p&gt; &lt;p&gt;Empezamos creándonos una clase abstracta que nos permita de forma genérica trabajar con cualquier tipo de datos. La clase incluirá los métodos más generales para interactuar con el almacenamiento.&lt;/p&gt; &lt;h3&gt;&lt;font style="font-weight:bold;"&gt;Constructores&lt;/font&gt;&lt;/h3&gt; &lt;p&gt;Nuestra clase genérica incluye dos constructores, uno que por defecto usará el LocalFolder y otro que nos permitirá especificar el lugar de almacenamiento.&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="background:white;color:blue;"&gt;protected &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;Repository(&lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;string &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;fileName) : &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;this&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;(fileName, &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;StorageType&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;.Local)
{
}

&lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;protected &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;Repository(&lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;string &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;fileName, &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;StorageType &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;storageType)
{
   _fileName = fileName.EndsWith(&lt;/span&gt;&lt;span style="background:white;color:#a31515;"&gt;&amp;quot;.json&amp;quot;&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;) ? fileName : &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;string&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;.Format(&lt;/span&gt;&lt;span style="background:white;color:#a31515;"&gt;&amp;quot;{0}.json&amp;quot;&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;, fileName);

   &lt;/span&gt;&lt;span style="background:white;color:green;"&gt;// set the storage folder
   &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;switch &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;(storageType)
   {
      &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;case &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;StorageType&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;.Local:
         _storageFolder = _appData.LocalFolder;

         &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;break&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;;
      &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;case &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;StorageType&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;.Temporary:
         _storageFolder = _appData.TemporaryFolder;

         &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;break&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;;
      &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;case &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;StorageType&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;.Roaming:
         _storageFolder = _appData.RoamingFolder;

         &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;break&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;;
      &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;default&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;: &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;throw new &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;Exception&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;(&lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;String&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;.Format(&lt;/span&gt;&lt;span style="background:white;color:#a31515;"&gt;&amp;quot;Unknown StorageType: {0}&amp;quot;&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;, storageType));
   }
}&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;El parámetro fileName nos sirve para especificar un nombre de archivo para nuestros datos. El archivo será identificado siempre por la extensión json y podemos decidir pasar el parámetro con o sin ella, en cualquier caso el constructor se encargará de realizar el chequeo necesario.&lt;/p&gt;
&lt;p&gt;El parámetro storageType es un enumerado que incluye los distintos tipos de almacenamiento. &lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="background:white;color:blue;"&gt;public enum &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;StorageType
&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;{
   Local,
   Temporary,
   Roaming
}&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;Dependiendo de este parámetro, el constructor inicializa&amp;nbsp; el StorageFolder a usar por nuestro repositorio.&lt;/p&gt;
&lt;h3&gt;&lt;font style="font-weight:bold;"&gt;Los métodos&lt;/font&gt;&lt;/h3&gt;&lt;pre class="code"&gt;&lt;span style="background:white;color:gray;"&gt;/// &amp;lt;summary&amp;gt;
/// &lt;/span&gt;&lt;span style="background:white;color:green;"&gt;Delete a file asynchronously
&lt;/span&gt;&lt;span style="background:white;color:gray;"&gt;/// &amp;lt;/summary&amp;gt;
&lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;public async void &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;DeleteAllAsync()
{
   &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;var &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;file = &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;await &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;GetFileIfExistsAsync(_fileName);
   &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;if &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;(file != &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;null&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;) &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;await &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;file.DeleteAsync();
}&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;Este método nos permite eliminar todos los datos almacenados. La operación se realiza de forma asíncrona y se resume a eliminar el archivo donde se encuentran almacenados nuestros datos.&lt;/p&gt;
&lt;p&gt;El método GetFileIfExists nos retorna de forma asíncrona un StorageFile si el archivo existe, de lo contrario retorna nulo. &lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="background:white;color:gray;"&gt;/// &amp;lt;summary&amp;gt;
/// &lt;/span&gt;&lt;span style="background:white;color:green;"&gt;At the moment the only way to check if a file exists to catch an exception... 
&lt;/span&gt;&lt;span style="background:white;color:gray;"&gt;/// &amp;lt;/summary&amp;gt;
/// &amp;lt;param name=&amp;quot;fileName&amp;quot;&amp;gt;&amp;lt;/param&amp;gt;
/// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;
&lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;private async &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;Task&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;StorageFile&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;&amp;gt; GetFileIfExistsAsync(&lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;string &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;fileName)
{
   &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;try
   &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;{
      &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;return await &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;_storageFolder.GetFileAsync(fileName);
   }
   &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;catch
   &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;{
      &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;return null&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;;
   }
}&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;La única forma que tenemos de saber si un archivo existe es capturando el error. La razón que Microsoft nos da para no contar con un File.Exists en el API es que el estado del archivo puede cambiar entre que nosotros preguntamos si existe y realizamos alguna operación. Según Microsoft, si contáramos con un File.Exists, igualmente tendríamos que capturar posibles errores cuando trabajamos con el archivo.&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="background:white;color:gray;"&gt;/// &amp;lt;summary&amp;gt;
/// &lt;/span&gt;&lt;span style="background:white;color:green;"&gt;Persist data to StorageFolder
&lt;/span&gt;&lt;span style="background:white;color:gray;"&gt;/// &amp;lt;/summary&amp;gt;
&lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;public virtual void &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;Flush()
{
   SaveAsync(Data.Value);
}&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;El método Flush usa Data.Value para indicar los datos a persistir. Esto no es más que el lugar en memoria donde está almacenado nuestro objeto.&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="background:white;color:blue;"&gt;protected &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;Lazy&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;&amp;lt;T&amp;gt; Data;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;El uso de Lazy&amp;lt;T&amp;gt; nos permite acceder a StorageFolder en el momento en que se necesiten los datos&amp;nbsp; por primera vez. &lt;/p&gt;
&lt;p&gt;Los datos de memoria se envían al StorageFolder que seleccionemos llamando a un método interno de nuestro repositorio que realiza la persistencia de forma asíncrona.&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="background:white;color:gray;"&gt;/// &amp;lt;summary&amp;gt;
/// &lt;/span&gt;&lt;span style="background:white;color:green;"&gt;Saves a serialized object to storage asynchronously
&lt;/span&gt;&lt;span style="background:white;color:gray;"&gt;/// &amp;lt;/summary&amp;gt;
/// &amp;lt;param name=&amp;quot;data&amp;quot;&amp;gt;&amp;lt;/param&amp;gt;
&lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;protected async void &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;SaveAsync(T data)
{
   &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;if &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;(data == &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;null&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;) &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;return&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;;

   &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;var &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;file = &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;await &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;_storageFolder.CreateFileAsync(_fileName, CollisionOption);
   &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;await &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;FileIO&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;.WriteTextAsync(file, Serialize(data).Result);
}&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;El método interno SaveAsync crea nuestro archivo si este no existe, de lo contrario lo re-escribe.&amp;nbsp; Estamos usando ReplaceExisting como política de Colisión, de cualquier forma, esta&amp;nbsp; variable es protegida en nuestra clase base, así que puede ser cambiada por las clases que heredan.&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="background:white;color:blue;"&gt;protected &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;CreationCollisionOption &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;CollisionOption = &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;CreationCollisionOption&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;.ReplaceExisting;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;De la misma manera que guardamos en el StorageFolder, también necesitamos leer. El siguiente método nos permite recuperar un objeto de forma asíncrona.&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="background:white;color:gray;"&gt;/// &amp;lt;summary&amp;gt;
/// &lt;/span&gt;&lt;span style="background:white;color:green;"&gt;Load a object from storage asynchronously
&lt;/span&gt;&lt;span style="background:white;color:gray;"&gt;/// &amp;lt;/summary&amp;gt;
/// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;
&lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;protected async &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;Task&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;&amp;lt;T&amp;gt; LoadAsync()
{
   &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;try
   &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;{
      &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;var &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;file = &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;await &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;_storageFolder.GetFileAsync(_fileName);
      &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;var &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;data = &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;await &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;FileIO&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;.ReadTextAsync(file);

      &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;return await &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;Deserialize(data);
   }
   &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;catch &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;(&lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;FileNotFoundException&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;)
   {
      &lt;/span&gt;&lt;span style="background:white;color:green;"&gt;//file not existing is perfectly valid so simply return the default 
      &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;return default&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;(T);
   }
}&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;Tanto para leer, como para escribir datos en nuestro repositorio, se usan métodos que se encargan del trabajo de serialización del objeto. &lt;/p&gt;
&lt;p&gt;Como cada cual tiene su propio mecanismo para serializar, estos métodos son declarados como abstractos dentro de nuestra clase base, de esta forma, podemos indicar en cada clase que herede, cual será la manera en que se serializarán los objetos, incluso, pudiéramos tener dentro de la misma aplicación, objetos que se persistan usando mecanismos de serialización totalmente distintos.&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="background:white;color:blue;"&gt;protected abstract &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;Task&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;string&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;&amp;gt; Serialize(T data);
&lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;protected abstract &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;Task&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;&amp;lt;T&amp;gt; Deserialize(&lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;string &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;data);&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;He dejado para el final una propiedad que nos retorna nuestro objeto desde el StorageFolder o de memoria según sea el caso. &lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="background:white;color:gray;"&gt;/// &amp;lt;summary&amp;gt;
/// &lt;/span&gt;&lt;span style="background:white;color:green;"&gt;Return T
&lt;/span&gt;&lt;span style="background:white;color:gray;"&gt;/// &amp;lt;/summary&amp;gt;
&lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;public virtual &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;T All
{
   &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;get &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;{ &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;return &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;Data.Value; }
}&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;Teniendo en cuenta que nuestro Repositorio puede valer para almacenar un simple objeto o una lista de objetos, tener una propiedad pública que nos retorne “todo” no es una muy buena práctica. De cualquier forma esto no viene a sustituir grandes almacenes de datos, ya que para eso tenemos bases de datos locales como SQLLite, sino que está pensado para pequeños datos. Es por esto que me tomo la libertad de incluir una “mala” práctica en mi código.&lt;/p&gt;
&lt;h3&gt;&lt;font style="font-weight:bold;"&gt;Nuestra clase base está lista, vamos a ver cómo usarla. &lt;/font&gt;&lt;/h3&gt;
&lt;p&gt;Para la implementación, voy a usar Newtonsoft.Json para la serialización de los objetos. Las clases a utilizar con los repositorios serán una simple y otra una lista, para poder ver las dos formas de utilizar nuestro repositorio.&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="background:white;color:blue;"&gt;public class &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;Account
&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;{
   [&lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;JsonProperty&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;]
   &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;public string &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;Name { &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;get&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;; &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;set&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;; }
}&lt;/span&gt;&lt;/pre&gt;&lt;pre class="code"&gt;&lt;span style="background:white;color:blue;"&gt;public class &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;Family &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;: &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;List&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;Person&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;&amp;gt;
{
   [&lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;JsonProperty&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;]
   &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;public &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;IList&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;Account&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;&amp;gt; Itenms { &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;get&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;; &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;set&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;; }
}

&lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;public class &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;Person
&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;{
   [&lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;JsonProperty&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;]
   &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;public &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;Guid &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;Id { &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;get&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;; &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;set&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;; }

   [&lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;JsonProperty&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;]
   &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;public string &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;Name { &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;get&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;; &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;set&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;; }

   &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;public bool &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;IsTransient
   {
      &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;get &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;{ &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;return &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;Id == &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;Guid&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;.Empty; }
   }
}&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;Nuestro repositorio siempre trabaja con un objeto, por lo que la única diferencia entre guardar un objeto simple o una lista, no es otra que usar uno o lo otro.&lt;/p&gt;
&lt;p&gt;En el ejemplo crearemos un repositorio para Account y otro para Family que es una lista de Person.&lt;/p&gt;
&lt;p&gt;Vamos a ver el repositorio de Family:&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="background:white;color:black;"&gt;    &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;public class &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;RepositoryFamily &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;: &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;Repository&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;Family&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;&amp;gt;, &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;IRepositoryFamily
    &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;{
        &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;public &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;RepositoryFamily(): &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;base&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;(&lt;/span&gt;&lt;span style="background:white;color:#a31515;"&gt;&amp;quot;Family&amp;quot;&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;)
        {
            CollisionOption = &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;CreationCollisionOption&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;.OpenIfExists;
            Data = &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;new &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;Lazy&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;Family&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;&amp;gt;(() =&amp;gt; LoadAsync().Result ?? &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;new &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;Family&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;(), &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;true&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;);
        }

        &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;public async &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;Task&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;Person&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;&amp;gt; Get(&lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;Guid &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;id)
        {
            &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;return await &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;Task&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;.Factory.StartNew(() =&amp;gt; All.Single(p =&amp;gt; p.Id == id));
        }

        &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;public void &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;Save(&lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;Person &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;person)
        {
            &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;if &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;(person.IsTransient)
            {
                person.Id = &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;IdentityGenerator&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;.NewSequentialGuid();
                Data.Value.Add(person);

                &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;return&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;;
            }

            &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;var &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;idx = Data.Value.FindIndex(a =&amp;gt; a.Id == person.Id);
            Data.Value[idx] = person;
        }

        &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;protected override &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;Task&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;string&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;&amp;gt; Serialize(&lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;Family &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;data)
        {
            &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;return &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;JsonConvert&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;.SerializeObjectAsync(data);
        }

        &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;protected override &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;Task&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;Family&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;&amp;gt; Deserialize(&lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;string &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;data)
        {
            &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;return &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;JsonConvert&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;.DeserializeObjectAsync&amp;lt;&lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;Family&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;&amp;gt;(data);
        }
    }&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;Como se ve, implementamos los métodos abstractos del repositorio para serializar y ya solo nos queda ir implementando los métodos que necesitemos según el tipo de datos que estemos trabajando.&lt;/p&gt;
&lt;p&gt;Para el ejemplo, tengo el método Save que adiciona una persona en la lista si no existe, o de lo contrario, lo actualiza.&lt;/p&gt;
&lt;p&gt;Cuando deseemos guardar una nueva persona en nuestro repositorio, el código a utilizar sería así:&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="background:white;color:blue;"&gt;private void &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;SaveFamilyNameCommand(&lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;string &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;name)
{
   _familySrv.Save(&lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;new &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;Person &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;{ Name = name});
   _familySrv.Flush();

   Family = &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;new &lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;ObservableCollection&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="background:white;color:#2b91af;"&gt;Person&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;&amp;gt;(_familySrv.All);
   RaisePropertyChanged(()=&amp;gt; Family);
}&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;La aplicación que les dejo de ejemplo, en la vista principal tiene dos TextBox, uno para que escriba su nombre y otro para que adicione los nombres de su familia.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.odelvalle.com/wp-content/uploads/2012/10/screenshot_10072012_135829.png"&gt;&lt;img title="screenshot_10072012_135829" style="border-top:0px;border-right:0px;background-image:none;border-bottom:0px;padding-top:0px;padding-left:0px;border-left:0px;display:inline;padding-right:0px;" border="0" alt="screenshot_10072012_135829" src="http://www.odelvalle.com/wp-content/uploads/2012/10/screenshot_10072012_135829_thumb.png" width="629" height="356" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Después de escribir su nombre y guardar y después de entrar nombres de sus familiares, puede cerrar la aplicación y volverla a abrir para ver cómo los datos se persisten.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.odelvalle.com/wp-content/uploads/2012/10/screenshot_10072012_135936.png"&gt;&lt;img title="screenshot_10072012_135936" style="border-top:0px;border-right:0px;background-image:none;border-bottom:0px;padding-top:0px;padding-left:0px;border-left:0px;display:inline;padding-right:0px;" border="0" alt="screenshot_10072012_135936" src="http://www.odelvalle.com/wp-content/uploads/2012/10/screenshot_10072012_135936_thumb.png" width="632" height="357" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;El ejemplo requiere MVVM Light y Newtonsoft.json. &lt;a href="http://odelvalle.com/downloads/sources/RepositorySample.rar"&gt;Source&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Salu2&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=207041" width="1" height="1"&gt;</description></item><item><title>[IT] Outlook.com con dominio propio</title><link>http://geeks.ms/blogs/omarvr/archive/2012/08/16/it-outlook-com-con-dominio-propio.aspx</link><pubDate>Thu, 16 Aug 2012 07:54:48 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:206482</guid><dc:creator>Omar del Valle Rodríguez</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/omarvr/rsscomments.aspx?PostID=206482</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/omarvr/commentapi.aspx?PostID=206482</wfw:comment><comments>http://geeks.ms/blogs/omarvr/archive/2012/08/16/it-outlook-com-con-dominio-propio.aspx#comments</comments><description>&lt;p&gt;Hola,&lt;/p&gt; &lt;p&gt;Hace unos días q llevo intentando migrar a Outlook.com para probar que tal va. &lt;/p&gt; &lt;p&gt;He leído algunos POST sobre cómo conectar GMAIL a Outlook y así estar al día sobre lo que por allí recibimos desde una única interfaz. Si aún no sabes cómo hacerlo, puedes&amp;nbsp; &lt;a href="http://palelmvp.wordpress.com/2012/08/13/vdeo-y-artculo-conectar-gmail-con-outlook-com/" target="_blank"&gt;ver este post de Pilar con video incluido&lt;/a&gt;. &lt;/p&gt; &lt;p&gt;El problema que algunos nos encontramos es que en todos los casos se usa nuestra dirección de Outlook como dirección de re-envío. Para los que usamos cuentas personales (dominios propios: odelvalle.com) para acceder a live, hacer esto&amp;nbsp; implica re-enviar todo el tráfico de nuestra cuenta GMail a nuestro servidor de correo. &lt;/p&gt; &lt;p&gt;Para evitar esto, intenté cambiar mi cuenta outlook pero me avisó que perdería la conexión de todos los dispositivos asociados a esa cuenta live (malo malo). Busqué si se podía crear una nueva cuenta pero eso implicaría tener 2 accesos a live, una con mi correo personal y la otra con la nueva cuenta outlook (esto tampoco me convence)&lt;/p&gt; &lt;p&gt;Dedicando un ratico cada mañana a buscar posibles soluciones, hoy encuentro una: :&lt;/p&gt; &lt;p&gt;&lt;a href="http://www.odelvalle.com/wp-content/uploads/2012/08/Untitled.png"&gt;&lt;img style="background-image:none;border-bottom:0px;border-left:0px;padding-left:0px;padding-right:0px;display:inline;border-top:0px;border-right:0px;padding-top:0px;" title="Untitled" border="0" alt="Untitled" src="http://www.odelvalle.com/wp-content/uploads/2012/08/Untitled_thumb.png" width="297" height="331" /&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;Crear un alias en outlook.com es la manera que tenemos de unir/asociar varias direcciones de correo electrónico a una sola.&amp;nbsp; &lt;/p&gt; &lt;p&gt;&lt;a href="http://www.odelvalle.com/wp-content/uploads/2012/08/Untitled1.png"&gt;&lt;img style="background-image:none;border-bottom:0px;border-left:0px;padding-left:0px;padding-right:0px;display:inline;border-top:0px;border-right:0px;padding-top:0px;" title="Untitled1" border="0" alt="Untitled1" src="http://www.odelvalle.com/wp-content/uploads/2012/08/Untitled1_thumb.png" width="609" height="296" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Al crear el Alias, Outlook.com te enviará un correo de verificación a tu cuenta personal (live) para asegurarse que el Alias está correctamente asociado.&lt;/p&gt; &lt;p&gt;&lt;a href="http://www.odelvalle.com/wp-content/uploads/2012/08/Untitled2.png"&gt;&lt;img style="background-image:none;border-bottom:0px;border-left:0px;padding-left:0px;padding-right:0px;display:inline;border-top:0px;border-right:0px;padding-top:0px;" title="Untitled2" border="0" alt="Untitled2" src="http://www.odelvalle.com/wp-content/uploads/2012/08/Untitled2_thumb.png" width="610" height="236" /&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;y ya estamos listos. Podemos seguir los pasos que nos cuenta Pilar en su post y utilizar el alias de outlook como dirección de re-envío, de esta forma los correos de GMAIL no pasarán por nuestro pequeño e indefenso servidor e irán directamente al grande de Outlook.com. &lt;img style="border-bottom-style:none;border-left-style:none;border-top-style:none;border-right-style:none;" class="wlEmoticon wlEmoticon-smile" alt="Sonrisa" src="http://www.odelvalle.com/wp-content/uploads/2012/08/wlEmoticon-smile3.png" /&gt;&lt;/p&gt; &lt;p&gt;Salu2&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=206482" width="1" height="1"&gt;</description></item><item><title>POO–Responsabilidades</title><link>http://geeks.ms/blogs/omarvr/archive/2012/08/08/poo-responsabilidades.aspx</link><pubDate>Wed, 08 Aug 2012 12:31:00 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:206411</guid><dc:creator>Omar del Valle Rodríguez</dc:creator><slash:comments>4</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/omarvr/rsscomments.aspx?PostID=206411</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/omarvr/commentapi.aspx?PostID=206411</wfw:comment><comments>http://geeks.ms/blogs/omarvr/archive/2012/08/08/poo-responsabilidades.aspx#comments</comments><description>&lt;p&gt;“Hay una diferencia entre programar orientado a objetos y pensar orientado a objetos”&lt;/p&gt; &lt;p&gt;&lt;a href="http://www.odelvalle.com/wp-content/uploads/2012/08/CNX-B4W.jpg"&gt;&lt;img style="background-image:none;border-bottom:0px;border-left:0px;margin:0px 10px 0px 0px;padding-left:0px;padding-right:0px;display:inline;float:left;border-top:0px;border-right:0px;padding-top:0px;" title="CNX-B4W" border="0" alt="CNX-B4W" align="left" src="http://www.odelvalle.com/wp-content/uploads/2012/08/CNX-B4W_thumb.jpg" width="151" height="244" /&gt;&lt;/a&gt;Debatiendo hoy en el trabajo sobre la funcionalidad que debería tener una toolsbox, salió uno de esos temas que me encantan. ¿Dónde debe estar el código asociado a un clic de un botón? &lt;/p&gt; &lt;p&gt;&lt;strong&gt;&lt;font size="4"&gt;Responsabilidades&lt;/font&gt;&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;Mucho más allá de si la pregunta se responde aplicando un Chain of Responsibility Pattern, dentro se esconde uno de los pilares de la POO, la Especialización. Los objetos mientras mayor sea su especialización, mejor podremos definir su comportamiento.&lt;/p&gt; &lt;p&gt;¿Qué quiere decir esto? Pues que la responsabilidad de cada objeto debe ser solo, la que permita cumplir los objetivos por el cual fue creado. &lt;/p&gt; &lt;p&gt;Un avión vuela (por suerte). Nosotros desde fuera vemos un conjunto, pero dentro del avión hay miles de objetos que tienen una responsabilidad específica y que entre todos, hace que el avión vuele. Creo que excepto en las teles de la antigua URSS (le quitabas piezas y seguían funcionando), todo objeto tiene una responsabilidad que permite lograr una funcionalidad superior.&lt;/p&gt; &lt;p&gt;¿Que es una toolsbox? pues un panel de botones y nada más. Cuando compramos un panel de botones este no incluye para qué se usa cada botón o qué hace cada botón. Si compramos un interruptor eléctrico, este por si solo no apaga ni enciende la luz, incluso, puede llegar a realizar funciones explosivas si conectas incorrectamente los cables (que me pregunten a mi con 11 años la que lié).&lt;/p&gt; &lt;p&gt;Nuestra toolsbox, tiene botones (como casi todas) y el objetivo que cumplirá cada botón debería ser independiente a la misma. Un botón “dentro de la toolsbox” tiene estados cuyos cambios son notificados al exterior para quien quiera hacer algo que lo haga. &lt;/p&gt; &lt;p&gt;Lo mismo pasa con nuestro avión, mueves los mandos de vuelo y giras, esto no ocurre porque las aletas y el mando sean un único e inseparable objeto, sino porque el mando cambia de estado y notifica a todo aquel que pueda estar interesado para que haga algo. Las aletas y seguramente muchos objetos más dentro de un avión, están escuchando continuamente para saber si los mandos de vuelo han cambiado de posición(estado).&lt;/p&gt; &lt;p&gt;Vean que para definir cual debe ser la responsabilidad de mi&amp;nbsp; toolsbox, me he basado en todo momento en ejemplos de la vida real.&lt;/p&gt; &lt;p&gt;En el evento que di sobre POO en &lt;a href="http://www.secondnug.com/" target="_blank"&gt;SecondNug&lt;/a&gt; (&lt;a href="http://geeks.ms/blogs/omarvr/archive/2010/10/06/apuntes-de-un-evento-poo-parte-1.aspx" target="_blank"&gt;aquí tenéis los apuntes&lt;/a&gt;) cuando se analizaba la crisis del software, se definió como objetivo de la programación orienta a objetos el acercamiento del ordenador al problema y no del problema al ordenador, lo cual significa que debemos intentar en todo momento modelar los problemas existentes en la vida real analizándolo como lo que son, cosas que ocurren en la realidad. Esto era y seguramente aún es, el paradigma de la POO.&lt;/p&gt; &lt;p&gt;El otro día leía un artículo de &lt;a href="http://geeks.ms/blogs/etomas/archive/2012/08/01/y-el-combate-se-decidi-243-por-ko-ii.aspx" target="_blank"&gt;Eduard sobre knockout&lt;/a&gt; y había una línea de texto que decía: &amp;quot;&lt;em&gt;el código javascript es totalmente ignorante del DOM y trabaja tan solo con el viewmodel. Separación de responsabilidades&lt;/em&gt;.” ¡Atentos! que en este artículo se habla de separar la responsabilidad entre el HTML y el Javascript… (si digo yo esto en una entrevista de trabajo hace unos años, ya me dirán ustedes que hubieran pensado de mi)&lt;/p&gt; &lt;p&gt;Seguramente hoy por hoy aún queda mucho por hacer, pero da gusto como cada vez más intentamos llevar a la más mínima expresión la separación de responsabilidades. Mi opinión es que mientras menor sea la responsabilidad de un objeto, siempre que cumpla su objetivo, mejor y más fácil será de mantener.&lt;/p&gt; &lt;p&gt;Por cierto, para no dejarles sin saber, la toolsbox terminó con N botones que no saben lo que hacen pero que notifican a quien pueda interesar los estados de onBeforeClick y onClick. (espero no ser yo quien tenga que conectarla) &lt;img style="border-bottom-style:none;border-left-style:none;border-top-style:none;border-right-style:none;" class="wlEmoticon wlEmoticon-smile" alt="Sonrisa" src="http://www.odelvalle.com/wp-content/uploads/2012/08/wlEmoticon-smile2.png" /&gt;&lt;/p&gt; &lt;p&gt;Salu2&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=206411" width="1" height="1"&gt;</description></item><item><title>Mensajes de browser a browser (Web Socket)</title><link>http://geeks.ms/blogs/omarvr/archive/2012/08/07/mensajes-de-browser-a-browser-web-socket.aspx</link><pubDate>Tue, 07 Aug 2012 10:31:51 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:206392</guid><dc:creator>Omar del Valle Rodríguez</dc:creator><slash:comments>2</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/omarvr/rsscomments.aspx?PostID=206392</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/omarvr/commentapi.aspx?PostID=206392</wfw:comment><comments>http://geeks.ms/blogs/omarvr/archive/2012/08/07/mensajes-de-browser-a-browser-web-socket.aspx#comments</comments><description>&lt;p&gt;&lt;a href="http://www.odelvalle.com/wp-content/uploads/2012/08/ws_tornado.png"&gt;&lt;img style="background-image:none;border-bottom:0px;border-left:0px;margin:0px 10px 0px 0px;padding-left:0px;padding-right:0px;display:inline;float:left;border-top:0px;border-right:0px;padding-top:0px;" title="ws_tornado" border="0" alt="ws_tornado" align="left" src="http://www.odelvalle.com/wp-content/uploads/2012/08/ws_tornado_thumb.png" width="163" height="244" /&gt;&lt;/a&gt;He estado trabajando últimamente en un proyecto en el que necesitaba comunicación entre instancias distintas de browsers en tiempos lo más real posible.&lt;/p&gt; &lt;p&gt;La solución se desprende, Web Socket con HTML5 &lt;img style="border-bottom-style:none;border-left-style:none;border-top-style:none;border-right-style:none;" class="wlEmoticon wlEmoticon-smile" alt="Sonrisa" src="http://www.odelvalle.com/wp-content/uploads/2012/08/wlEmoticon-smile1.png" /&gt;&lt;/p&gt; &lt;p&gt;La lógica que necesitamos en el servidor es simple, transmitir un mensaje que viene de un cliente, al resto de los clientes conectados. &lt;/p&gt; &lt;p&gt;En la parte del servidor quiero la menor lógica posible, así podré reutilizarlo en distintos proyectos. Los mensajes van de clientes a clientes, por lo que la responsabilidad del servidor en este caso debe ser solamente la de comunicación.&lt;/p&gt; &lt;p&gt;Para implementar el servidor he usado &lt;a href="https://github.com/statianzo/Fleck" target="_blank"&gt;Fleck&lt;/a&gt;, un Web Socket que ya existe para NET y el cual recomiendo muchísimo, un código claro y fácil de entender si te pica la curiosidad y quieres conocer internamente cómo funciona.&lt;/p&gt; &lt;h3&gt;Server&lt;/h3&gt; &lt;p&gt;De momento vamos a crear una aplicación de consola para hospedar a nuestro Socket Server.&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;class &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;Program
&lt;/span&gt;{
    &lt;span style="color:blue;"&gt;static void &lt;/span&gt;Main()
    {
        &lt;span style="color:#2b91af;"&gt;FleckLog&lt;/span&gt;.Level = &lt;span style="color:#2b91af;"&gt;LogLevel&lt;/span&gt;.Debug;

        &lt;span style="color:blue;"&gt;var &lt;/span&gt;socketManager = &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;MessagesWebSocket&lt;/span&gt;();
        socketManager.Start();

        &lt;span style="color:#2b91af;"&gt;Console&lt;/span&gt;.ReadLine();

        socketManager.Close();
    }
}
&lt;/pre&gt;
&lt;p&gt;La clase MessagesWebSocket tendría:&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;class &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;MessagesWebSocket
&lt;/span&gt;{
    &lt;span style="color:blue;"&gt;private readonly &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color:#2b91af;"&gt;IWebSocketConnection&lt;/span&gt;&amp;gt; _allSockets;
    &lt;span style="color:blue;"&gt;private readonly &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;WebSocketServer &lt;/span&gt;_server;


    &lt;span style="color:blue;"&gt;public &lt;/span&gt;MessagesWebSocket()
    {
        _allSockets = &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color:#2b91af;"&gt;IWebSocketConnection&lt;/span&gt;&amp;gt;();
        _server = &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;WebSocketServer&lt;/span&gt;(&lt;span style="color:#2b91af;"&gt;ConfigurationManager&lt;/span&gt;.AppSettings[&lt;span style="color:#a31515;"&gt;&amp;quot;socketServer&amp;quot;&lt;/span&gt;]);
    }

    &lt;span style="color:blue;"&gt;public void &lt;/span&gt;Start()
    {
        _server.Start(socket =&amp;gt;
        {
            socket.OnOpen = () =&amp;gt;
            {
                &lt;span style="color:#2b91af;"&gt;Console&lt;/span&gt;.WriteLine(&lt;span style="color:#a31515;"&gt;&amp;quot;Open client connection!&amp;quot;&lt;/span&gt;);
                _allSockets.Add(socket);
            };

            socket.OnClose = () =&amp;gt; _allSockets.Remove(socket);
            socket.OnMessage = message =&amp;gt; _allSockets.Where(s=&amp;gt; s != socket).ToList().ForEach(s =&amp;gt; s.Send(message));
        });
    }

    &lt;span style="color:blue;"&gt;public void &lt;/span&gt;Close()
    {
        _allSockets.ForEach(s =&amp;gt; s.Close());
        _server.ListenerSocket.Close();
    }
}
&lt;/pre&gt;
&lt;p&gt;Si has trabajado con Socket verás que no hay mucha diferencia a lo que se hacía hasta ahora, incluso, la clase WebSocketServer de Fleck usa internamente System.Net.Sockets.&lt;/p&gt;
&lt;p&gt;Nuestra clase MessagesWebSocket tiene dos métodos, Start &amp;amp; Stop. &lt;/p&gt;
&lt;p&gt;Start nos permite abrir la conexión y quedarnos a la escucha de cualquier petición de conexión de algún cliente. Cuando un cliente previamente conectado envía un mensaje al servidor, este simplemente toma el mensaje tal cual y lo envía al resto de clientes conectados.&lt;/p&gt;
&lt;p&gt;El servidor no interviene en absoluto en la estructura del mensaje que se envía, justamente lo que necesitamos. Entender los mensajes que se envían los clientes será siempre responsabilidad de ellos.&lt;/p&gt;
&lt;h3&gt;Client&lt;/h3&gt;
&lt;p&gt;Si hablamos de clientes WEB, la moda en comunicación se llama JSON! &lt;img style="border-bottom-style:none;border-left-style:none;border-top-style:none;border-right-style:none;" class="wlEmoticon wlEmoticon-smile" alt="Sonrisa" src="http://www.odelvalle.com/wp-content/uploads/2012/08/wlEmoticon-smile1.png" /&gt; Así que vamos a hacer que este sea el formato que usen los mensajes enviados entre clientes.&lt;/p&gt;
&lt;p&gt;Para que todo el tema de web socket y json nos quede fuera de la lógica de cualquier página o proyecto, vamos a encapsular toda la funcionalidad dentro de un objeto en Javascript que nos permita enviar y recibir mensajes sin importarnos cómo.&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;var &lt;/span&gt;WebSocketHelper = &lt;span style="color:blue;"&gt;function &lt;/span&gt;(server, onMessage, onError)
{
    &lt;span style="color:blue;"&gt;var &lt;/span&gt;w = window;
    &lt;span style="color:blue;"&gt;var &lt;/span&gt;connection;

    &lt;span style="color:blue;"&gt;var &lt;/span&gt;reciveData = onMessage || &lt;span style="color:blue;"&gt;false&lt;/span&gt;;
    &lt;span style="color:blue;"&gt;var &lt;/span&gt;error = onError || &lt;span style="color:blue;"&gt;false&lt;/span&gt;;

    &lt;span style="color:#006400;"&gt;// if user is running mozilla then use it&amp;#39;s built-in WebSocket
    &lt;/span&gt;w.WebSocket = w.WebSocket || w.MozWebSocket;

    &lt;span style="color:#006400;"&gt;// open connection
    &lt;/span&gt;&lt;span style="color:blue;"&gt;try
    &lt;/span&gt;{
        connection = &lt;span style="color:blue;"&gt;new &lt;/span&gt;w.WebSocket(server);
    }
    &lt;span style="color:blue;"&gt;catch &lt;/span&gt;(connErr)
    {
        &lt;span style="color:blue;"&gt;if &lt;/span&gt;(error) error(&lt;span style="color:maroon;"&gt;&amp;quot;Open connection error: &amp;quot; &lt;/span&gt;+ connErr);
        &lt;span style="color:blue;"&gt;return&lt;/span&gt;;
    }

    &lt;span style="color:#006400;"&gt;// only for debug propose
    &lt;/span&gt;connection.onopen = &lt;span style="color:blue;"&gt;function &lt;/span&gt;()
    {
        &lt;span style="color:#006400;"&gt;//alert(&amp;#39;Connected.&amp;#39;);
    &lt;/span&gt;};

    connection.onmessage = &lt;span style="color:blue;"&gt;function &lt;/span&gt;(d)
    {
        &lt;span style="color:blue;"&gt;var &lt;/span&gt;result = jQuery.parseJSON(d.data);
        &lt;span style="color:blue;"&gt;if &lt;/span&gt;(reciveData) reciveData(result);

        &lt;span style="color:blue;"&gt;return false&lt;/span&gt;;
    };

    connection.onerror = &lt;span style="color:blue;"&gt;function &lt;/span&gt;(wsErr)
    {
        &lt;span style="color:blue;"&gt;if &lt;/span&gt;(error) error(&lt;span style="color:maroon;"&gt;&amp;quot;Connection error: &amp;quot; &lt;/span&gt;+ wsErr);
        connection = &lt;span style="color:blue;"&gt;null&lt;/span&gt;;
    };

    &lt;span style="color:blue;"&gt;this&lt;/span&gt;.SendCommand = &lt;span style="color:blue;"&gt;function &lt;/span&gt;(obj)
    {
        &lt;span style="color:blue;"&gt;try
        &lt;/span&gt;{
            &lt;span style="color:blue;"&gt;var &lt;/span&gt;jsonString = JSON.stringify(obj);
            connection.send(jsonString);
        }
        &lt;span style="color:blue;"&gt;catch &lt;/span&gt;(sendErr)
        {
            &lt;span style="color:blue;"&gt;if &lt;/span&gt;(error) error(&lt;span style="color:maroon;"&gt;&amp;quot;Send message error: &amp;quot; &lt;/span&gt;+ sendErr);
        }
    };
};
&lt;/pre&gt;
&lt;p&gt;Vamos por parte. &lt;/p&gt;
&lt;p&gt;1- Al objeto WebSocketHelper le pasamos tres parámetros: la dirección del servidor, una función (opcional) que se ejecutará cuando nos llegue un nuevo mensaje y otra función (también opcional) que se ejecutará si encontramos algún error.&lt;/p&gt;
&lt;p&gt;2- Instanciamos un nuevo objeto WebSocket, y aquí entramos en las diferencias entre browsers de toda la vida. Firefox tiene un objeto MozWebSocket mientras Chrome e Internet Explorer (v10) usan WebSocket. &lt;/p&gt;
&lt;p&gt;3- Luego de instanciado el socket, intentamos abrir la conexión con el servidor, si todo sale bien, estamos listos para enviar y recibir datos mediante el socket.&lt;/p&gt;
&lt;p&gt;4- El evento onmessage es quien me permite capturar los mensajes que llegan desde el servidor. La función asociada a este evento toma el mensaje recibido y lo transforma a un objeto javascript usando jQuery.parseJSON. Al tener la información recibida como objeto javscript, se ejecuta la función que hemos pasado al WebSocketHelper pasando como parámetro el objeto recibido.&lt;/p&gt;
&lt;p&gt;5- Para enviar un objeto al servidor el proceso es parecido. Se usa la función pública SendCommand y se pasa como parámetros el objeto a enviar. Esta función internamente convierte el objeto en string y lo envía mediante el socket al servidor.&lt;/p&gt;
&lt;h3&gt;¿Cómo funciona esto desde una página?&lt;/h3&gt;
&lt;p&gt;Primero que todo hay que llegar a un acuerdo entre clientes, podemos enviar cualquier objeto javascript mediante el servidor pero es necesario que los clientes sepan de que va el asunto, porque de lo contrario sería como pedir una cerveza y que de pronto te lleguen melones, quesos, tomates, gambas y sandias ( y lo peor es que intentes algo porque creas que son cervezas). &lt;/p&gt;
&lt;p&gt;En mi caso he usado una estructura de objetos muy simple. Internamente cada objeto que envío tiene una propiedad llamada command que define el tipo de mensaje que es.&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;var &lt;/span&gt;commands = { stop: &lt;span style="color:maroon;"&gt;&amp;quot;stop&amp;quot;&lt;/span&gt;, start: &lt;span style="color:maroon;"&gt;&amp;quot;start&amp;quot;&lt;/span&gt;, game: &lt;span style="color:maroon;"&gt;&amp;quot;game&amp;quot;&lt;/span&gt;, reset: &lt;span style="color:maroon;"&gt;&amp;quot;reset&amp;quot;&lt;/span&gt;, gameover: &lt;span style="color:maroon;"&gt;&amp;quot;gameover&amp;quot; &lt;/span&gt;};
&lt;/pre&gt;
&lt;p&gt;Inicializando el socket server y recibiendo datos desde el servidor:&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;var &lt;/span&gt;socket = &lt;span style="color:blue;"&gt;new &lt;/span&gt;WebSocketHelper(&lt;span style="color:maroon;"&gt;&amp;quot;ws://192.168.100.64:8181&amp;quot;&lt;/span&gt;, &lt;span style="color:blue;"&gt;function &lt;/span&gt;(cmd)
{
    &lt;span style="color:blue;"&gt;switch &lt;/span&gt;(cmd.command)
    {
        &lt;span style="color:blue;"&gt;case &lt;/span&gt;commands.gameover:

            &lt;span style="color:#006400;"&gt;// GAME Over
            &lt;/span&gt;&lt;span style="color:blue;"&gt;break&lt;/span&gt;;

        &lt;span style="color:blue;"&gt;case &lt;/span&gt;commands.start:
            
            alert(&lt;span style="color:maroon;"&gt;&amp;quot;Welcome {0}. Are you ready?&amp;quot;&lt;/span&gt;.format(cmd.player));
            &lt;span style="color:blue;"&gt;break&lt;/span&gt;;

        &lt;span style="color:blue;"&gt;default&lt;/span&gt;: &lt;span style="color:blue;"&gt;throw new &lt;/span&gt;Error(&lt;span style="color:maroon;"&gt;&amp;quot;Invalid Command on socket server.&amp;quot;&lt;/span&gt;);

    }
});
&lt;/pre&gt;
&lt;p&gt;Enviando mensajes:&lt;/p&gt;&lt;pre class="code"&gt;socket.SendCommand(
{
    command: commands.start,
    player: &lt;span style="color:maroon;"&gt;&amp;#39;Pepe el loco&amp;#39;&lt;/span&gt;,
    device: 1,
    language: &lt;span style="color:maroon;"&gt;&amp;#39;es&amp;#39;
&lt;/span&gt;});
&lt;/pre&gt;
&lt;p&gt;y con esto ya tenemos una comunicación simple de browser a browser. &lt;/p&gt;
&lt;p&gt;Más adelante veremos otro ejemplo en el que vamos a darle más responsabilidad al SocketServer enviando comandos recibidos desde una Kinect a clientes Web y ya de paso, convertiremos nuestro WebSocket en un servicio Windows.&lt;/p&gt;
&lt;p&gt;Salu2&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=206392" width="1" height="1"&gt;</description></item><item><title>Navigator para WP7 en MVVM</title><link>http://geeks.ms/blogs/omarvr/archive/2012/08/05/navigator-para-wp7-en-mvvm.aspx</link><pubDate>Sun, 05 Aug 2012 09:23:59 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:206375</guid><dc:creator>Omar del Valle Rodríguez</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/omarvr/rsscomments.aspx?PostID=206375</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/omarvr/commentapi.aspx?PostID=206375</wfw:comment><comments>http://geeks.ms/blogs/omarvr/archive/2012/08/05/navigator-para-wp7-en-mvvm.aspx#comments</comments><description>&lt;p&gt;Otro tema que estaba pendiente...&lt;/p&gt; &lt;p&gt;Cuando empecé a estudiar y testear cosas de WP7 con MVVM, una de los detalles que más me molestaban era tener que navegar entre páginas usando el code behind.&lt;/p&gt; &lt;p&gt;Es verdad que desde el ViewModel puedes tener acceso al NavigationService, pero esto sería una muy mala práctica de cara a los test unitarios. Por otra parte, desde dónde puedo capturar los parámetros pasados a una vista es siempre el método OnNavigatedTo que tenemos en el Code Behind.&lt;/p&gt; &lt;p&gt;Una tarde escuchando una charla de Josue sobre WP7, comentó que se encontraba desarrollando una aplicación llamada WPControla. Soy de los que piensa que una de las mejores maneras de tomar buenas prácticas en los desarrollos es mirar mucho código, cualquiera, no importa de quien sea porque siempre te ayudan a comparar y sacar conclusiones sobre lo que se debe o no hacer.&amp;nbsp; &lt;/p&gt; &lt;p&gt;En la propia charla le pregunté a Josue si podríamos descargarnos el código de la aplicación y como siempre, nos dio acceso &lt;a href="https://wpcontrola.codeplex.com/" target="_blank"&gt;al repositorio&lt;/a&gt;. &lt;img style="border-bottom-style:none;border-left-style:none;border-top-style:none;border-right-style:none;" class="wlEmoticon wlEmoticon-winkingsmile" alt="Winking smile" src="http://www.odelvalle.com/wp-content/uploads/2012/08/wlEmoticon-winkingsmile.png" /&gt;&lt;/p&gt; &lt;p&gt;Mirando el código de esta aplicación descubrí algo que me llamó mucho la atención, dentro del namespace WPControla.Client.Services había una clase llamada NavigationService. Me imaginé que esta clase, al implementar una interfaz sería una solución a lo que tanto me había molestado hasta el momento, poder navegar entre Views desde el ViewModel sin afectar los test.&lt;/p&gt; &lt;p&gt;Me costó entender cómo funcionaba porque en el repo no está toda la funcionalidad aún implementada, así que le pregunté directamente a Josue si esto era lo que me imaginaba y cómo había pensado en resolver esto, su respuesta no se hizo esperar. Gracias Josue! &lt;img style="border-bottom-style:none;border-left-style:none;border-top-style:none;border-right-style:none;" class="wlEmoticon wlEmoticon-smile" alt="Smile" src="http://www.odelvalle.com/wp-content/uploads/2012/08/wlEmoticon-smile.png" /&gt;&lt;/p&gt; &lt;p&gt;Con permiso del Master, vamos a intentar explicar la solución que implementa&amp;nbsp; WPControla.&lt;/p&gt; &lt;p&gt;Todo parte de una clase llamada NavController en la cual se empieza definiendo un singleton para el acceso a una única instancia. También contamos con un Dictionary que nos permite registrar y referenciar las vistas mediante “alias”. &lt;/p&gt;&lt;pre class="code"&gt;registeredViews.Add(&lt;span style="color:#a31515;"&gt;&amp;quot;Start&amp;quot;&lt;/span&gt;, &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;Uri&lt;/span&gt;(&lt;span style="color:#a31515;"&gt;@&amp;quot;/MainPage.xaml&amp;quot;&lt;/span&gt;, &lt;span style="color:#2b91af;"&gt;UriKind&lt;/span&gt;.Relative));
&lt;/pre&gt;
&lt;p&gt;En mi caso, cambié el Dictionary utilizado:&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;static &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;Dictionary&lt;/span&gt;&amp;lt;&lt;span style="color:#2b91af;"&gt;String&lt;/span&gt;, &lt;span style="color:#2b91af;"&gt;Uri&lt;/span&gt;&amp;gt; registeredViews = &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;Dictionary&lt;/span&gt;&amp;lt;&lt;span style="color:#2b91af;"&gt;String&lt;/span&gt;, &lt;span style="color:#2b91af;"&gt;Uri&lt;/span&gt;&amp;gt;();
&lt;/pre&gt;
&lt;p&gt;por:&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;private static readonly &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;Dictionary&lt;/span&gt;&amp;lt;&lt;span style="color:#2b91af;"&gt;Pages&lt;/span&gt;, &lt;span style="color:#2b91af;"&gt;Uri&lt;/span&gt;&amp;gt; _registeredViews = &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;Dictionary&lt;/span&gt;&amp;lt;&lt;span style="color:#2b91af;"&gt;Pages&lt;/span&gt;, &lt;span style="color:#2b91af;"&gt;Uri&lt;/span&gt;&amp;gt;();
&lt;/pre&gt;
&lt;p&gt;Pages es un enumerado, esto no implica ninguna mejora a la solución planteada por Josue, más bien es un gusto personal, no me gusta trabajar con string porque soy muy despistado &lt;img style="border-bottom-style:none;border-left-style:none;border-top-style:none;border-right-style:none;" class="wlEmoticon wlEmoticon-sadsmile" alt="Sad smile" src="http://www.odelvalle.com/wp-content/uploads/2012/08/wlEmoticon-sadsmile.png" /&gt; y siempre los escribo mal, así que me ahorro errores de ejecución usando enumerados.&lt;/p&gt;
&lt;p&gt;La clase define&amp;nbsp; tres sobrecargas sobre el método NavigateTo. Una sobrecarga nos permite navegar a una vista sin pasar parámetros, en la segunda, podemos incorporar parámetros pasados por QueryString y en la tercera nos vamos a detener:&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;public void &lt;/span&gt;NavigateTo(&lt;span style="color:#2b91af;"&gt;String &lt;/span&gt;navigationTarget, &lt;span style="color:#2b91af;"&gt;Action&lt;/span&gt;&amp;lt;&lt;span style="color:#2b91af;"&gt;NavigationEventArgs&lt;/span&gt;&amp;gt; onNavigated)
&lt;/pre&gt;
&lt;p&gt;Esta sobrecarga incluye un Action&amp;lt;NavigationEventArgs&amp;gt; como parámetro, el objetivo es poder tomar una acción en el momento en que se navegue de una vista a otra. Internamente la clase navController captura el evento Navigated de PhoneApplicationFrame y cuando este ocurre, ejecuta nuestra acción.&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color:gray;"&gt;/// &amp;lt;summary&amp;gt;
/// &lt;/span&gt;&lt;span style="color:green;"&gt;Este evento se lanza cuando hemos navegado a una página.
&lt;/span&gt;&lt;span style="color:gray;"&gt;/// &amp;lt;/summary&amp;gt;
/// &amp;lt;param name=&amp;quot;sender&amp;quot;&amp;gt;&amp;lt;/param&amp;gt;
/// &amp;lt;param name=&amp;quot;e&amp;quot;&amp;gt;&amp;lt;/param&amp;gt;
&lt;/span&gt;&lt;span style="color:blue;"&gt;void &lt;/span&gt;root_Navigated(&lt;span style="color:blue;"&gt;object &lt;/span&gt;sender, &lt;span style="color:#2b91af;"&gt;NavigationEventArgs &lt;/span&gt;e)
{
    &lt;span style="color:blue;"&gt;if &lt;/span&gt;(NavigationMethod != &lt;span style="color:blue;"&gt;null&lt;/span&gt;)
    {
        NavigationMethod(e);
        NavigationMethod = &lt;span style="color:blue;"&gt;null&lt;/span&gt;;
    }
}
&lt;/pre&gt;
&lt;p&gt;Este método de la forma que está escrito, no nos permite capturar el Navigated cuando el NavigationMode es Back, o sea, cuando vamos de regreso. Para solucionarlo solo necesitamos eliminar la línea de código que asigna null al NavigationMethod y no olvidar desasignar el evento cuando regresemos, porque de lo contrario navegando hacia atrás y hacia adelante multiplicará la cantidad de veces que se ejecuta nuestra acción.&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;void &lt;/span&gt;RootNavigated(&lt;span style="color:blue;"&gt;object &lt;/span&gt;sender, &lt;span style="color:#2b91af;"&gt;NavigationEventArgs &lt;/span&gt;e)
{
    &lt;span style="color:blue;"&gt;if &lt;/span&gt;(_navigationMethod == &lt;span style="color:blue;"&gt;null&lt;/span&gt;) &lt;span style="color:blue;"&gt;return&lt;/span&gt;;

    _navigationMethod(e);

    &lt;span style="color:blue;"&gt;if &lt;/span&gt;(e.NavigationMode != &lt;span style="color:#2b91af;"&gt;NavigationMode&lt;/span&gt;.Back) &lt;span style="color:blue;"&gt;return&lt;/span&gt;;
    &lt;span style="color:blue;"&gt;var &lt;/span&gt;rootFrame = (&lt;span style="color:#2b91af;"&gt;PhoneApplicationFrame&lt;/span&gt;)&lt;span style="color:#2b91af;"&gt;Application&lt;/span&gt;.Current.RootVisual;
        
    rootFrame.Navigated -= RootNavigated;
}

&lt;/pre&gt;
&lt;p&gt;Otra particularidad de esta sobrecarga es que mediante el parámetro NavigationEventArgs tenemos acceso a la View que estamos navegando mediante la propiedad Content, a su vez, mediante la View tenemos acceso al DataContext que en una arquitectura MVVM sería el ViewModel. Esta estructura pudiera ser utilizada para inicializar objetos complejos cuando navegamos de una vista a otra (luego veremos un ejemplo).&lt;/p&gt;
&lt;p&gt;Ya que estamos creando métodos de navegación, adicioné a esta clase un método que nos permita hacer Back por código. &lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;public void &lt;/span&gt;NavigateToBack()
{
    &lt;span style="color:blue;"&gt;var &lt;/span&gt;rootFrame = &lt;span style="color:#2b91af;"&gt;Application&lt;/span&gt;.Current.RootVisual &lt;span style="color:blue;"&gt;as &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;PhoneApplicationFrame&lt;/span&gt;;
    &lt;span style="color:blue;"&gt;if &lt;/span&gt;(rootFrame == &lt;span style="color:blue;"&gt;null &lt;/span&gt;|| !rootFrame.CanGoBack) &lt;span style="color:blue;"&gt;return&lt;/span&gt;;

    rootFrame.GoBack();
}
&lt;/pre&gt;
&lt;p&gt;La magia para que todo esto se integre con nuestros ViewModels llega ahora:&lt;/p&gt;
&lt;p&gt;Definimos una interfaz con los distintos métodos para la navegación que necesitamos en nuestra aplicación, hacemos que un servicio implemente dicha interfaz y lo usamos en el constructor de los distintos ViewModels.&lt;/p&gt;
&lt;p&gt;Un servicio de navegación que utilice NavController quedaría como el siguiente:&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;public interface &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;INavigatorService
&lt;/span&gt;{
    &lt;span style="color:blue;"&gt;void &lt;/span&gt;GotoMvvmView1();
    &lt;span style="color:blue;"&gt;void &lt;/span&gt;GotoMvvmView1(&lt;span style="color:#2b91af;"&gt;DataItem &lt;/span&gt;param);

    &lt;span style="color:blue;"&gt;void &lt;/span&gt;GoBack();
}

&lt;span style="color:blue;"&gt;public class &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;NavigatorService &lt;/span&gt;: &lt;span style="color:#2b91af;"&gt;INavigatorService
&lt;/span&gt;{
    &lt;span style="color:blue;"&gt;public void &lt;/span&gt;GotoMvvmView1()
    {
        &lt;span style="color:#2b91af;"&gt;NavController&lt;/span&gt;.Current.NavigateTo(&lt;span style="color:#2b91af;"&gt;NavController&lt;/span&gt;.&lt;span style="color:#2b91af;"&gt;Pages&lt;/span&gt;.MvvmView1);
    }

    &lt;span style="color:blue;"&gt;public void &lt;/span&gt;GotoMvvmView1(&lt;span style="color:#2b91af;"&gt;DataItem &lt;/span&gt;param)
    {
        &lt;span style="color:#2b91af;"&gt;NavController&lt;/span&gt;.Current.NavigateTo(&lt;span style="color:#2b91af;"&gt;NavController&lt;/span&gt;.&lt;span style="color:#2b91af;"&gt;Pages&lt;/span&gt;.MvvmView1, 
            args =&amp;gt;
            {
                &lt;span style="color:blue;"&gt;if &lt;/span&gt;(args.NavigationMode != &lt;span style="color:#2b91af;"&gt;NavigationMode&lt;/span&gt;.New) &lt;span style="color:blue;"&gt;return&lt;/span&gt;;

                &lt;span style="color:blue;"&gt;var &lt;/span&gt;view1Model = ((&lt;span style="color:#2b91af;"&gt;FrameworkElement&lt;/span&gt;) (args.Content)).DataContext &lt;span style="color:blue;"&gt;as &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;View1ViewModel&lt;/span&gt;;
                &lt;span style="color:blue;"&gt;if &lt;/span&gt;(view1Model != &lt;span style="color:blue;"&gt;null&lt;/span&gt;) view1Model.Initialize(param);
            });
    }

    &lt;span style="color:blue;"&gt;public void &lt;/span&gt;GoBack()
    {
        &lt;span style="color:#2b91af;"&gt;NavController&lt;/span&gt;.Current.NavigateToBack();
    }
}
&lt;/pre&gt;
&lt;p&gt;Observen como estamos ejecutando una acción en el momento en que llegamos a la vista a la que deseamos navegar. Esta acción accede al ViewModel e inicializa parámetros necesarios con los datos que se pasan al método GotoMvvmView1.&lt;/p&gt;
&lt;p&gt;A mi este mecanismo no me gusta&amp;nbsp; (cuestión personal), no sé si será buena o mala práctica, pero me cuesta tener que acceder a métodos del ViewModel desde este punto.&lt;/p&gt;
&lt;p&gt;Para solucionar este problema he incorporado a la clase NavController un Dicctionary para pasar datos entre vistas.&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color:gray;"&gt;/// &amp;lt;summary&amp;gt;
/// &lt;/span&gt;&lt;span style="color:green;"&gt;Navigation Parameters 
&lt;/span&gt;&lt;span style="color:gray;"&gt;/// &amp;lt;/summary&amp;gt;
&lt;/span&gt;&lt;span style="color:blue;"&gt;public static &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;IDictionary&lt;/span&gt;&amp;lt;&lt;span style="color:blue;"&gt;string&lt;/span&gt;, &lt;span style="color:blue;"&gt;object&lt;/span&gt;&amp;gt; Parameters { &lt;span style="color:blue;"&gt;get&lt;/span&gt;; &lt;span style="color:blue;"&gt;set&lt;/span&gt;; }
&lt;/pre&gt;
&lt;p&gt;Como NavNavigator es independiente de nuestros ViewModels mediante una interfaz, tenemos que adicionar a la misma la utilización del Dictionary. La interfaz vista anteriormente ahora nos quedaría así:&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;public interface &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;INavigatorService
&lt;/span&gt;{
    &lt;span style="color:#2b91af;"&gt;IDictionary&lt;/span&gt;&amp;lt;&lt;span style="color:blue;"&gt;string&lt;/span&gt;, &lt;span style="color:blue;"&gt;object&lt;/span&gt;&amp;gt; Parameters { &lt;span style="color:blue;"&gt;get&lt;/span&gt;; &lt;span style="color:blue;"&gt;set&lt;/span&gt;; }

    &lt;span style="color:blue;"&gt;void &lt;/span&gt;GotoMvvmView1();
    &lt;span style="color:blue;"&gt;void &lt;/span&gt;GotoMvvmView1(&lt;span style="color:#2b91af;"&gt;DataItem &lt;/span&gt;param);

    &lt;span style="color:blue;"&gt;void &lt;/span&gt;GoBack();
}
&lt;/pre&gt;
&lt;p&gt;y su implementación sería…&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;public class &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;NavigatorService &lt;/span&gt;: &lt;span style="color:#2b91af;"&gt;INavigatorService
&lt;/span&gt;{
    &lt;span style="color:blue;"&gt;public &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;IDictionary&lt;/span&gt;&amp;lt;&lt;span style="color:blue;"&gt;string&lt;/span&gt;, &lt;span style="color:blue;"&gt;object&lt;/span&gt;&amp;gt; Parameters
    {
        &lt;span style="color:blue;"&gt;get &lt;/span&gt;{ &lt;span style="color:blue;"&gt;return &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;NavController&lt;/span&gt;.Parameters; }
        &lt;span style="color:blue;"&gt;set &lt;/span&gt;{ &lt;span style="color:#2b91af;"&gt;NavController&lt;/span&gt;.Parameters = &lt;span style="color:blue;"&gt;value&lt;/span&gt;; }
    }

    &lt;span style="color:blue;"&gt;public void &lt;/span&gt;GotoMvvmView1()
    {
        &lt;span style="color:#2b91af;"&gt;NavController&lt;/span&gt;.Current.NavigateTo(&lt;span style="color:#2b91af;"&gt;NavController&lt;/span&gt;.&lt;span style="color:#2b91af;"&gt;Pages&lt;/span&gt;.MvvmView1);
    }

    &lt;span style="color:blue;"&gt;public void &lt;/span&gt;GotoMvvmView1(&lt;span style="color:#2b91af;"&gt;DataItem &lt;/span&gt;param)
    {
        &lt;span style="color:#2b91af;"&gt;NavController&lt;/span&gt;.Current.NavigateTo(&lt;span style="color:#2b91af;"&gt;NavController&lt;/span&gt;.&lt;span style="color:#2b91af;"&gt;Pages&lt;/span&gt;.MvvmView1, 
            args =&amp;gt;
            {
                &lt;span style="color:blue;"&gt;if &lt;/span&gt;(args.NavigationMode == &lt;span style="color:#2b91af;"&gt;NavigationMode&lt;/span&gt;.Back) &lt;span style="color:blue;"&gt;return&lt;/span&gt;;

                &lt;span style="color:#2b91af;"&gt;NavController&lt;/span&gt;.Parameters = &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;Dictionary&lt;/span&gt;&amp;lt;&lt;span style="color:blue;"&gt;string&lt;/span&gt;, &lt;span style="color:blue;"&gt;object&lt;/span&gt;&amp;gt; { { &lt;span style="color:#a31515;"&gt;&amp;quot;item&amp;quot;&lt;/span&gt;, param} };
            });
    }

    &lt;span style="color:blue;"&gt;public void &lt;/span&gt;GoBack()
    {
        &lt;span style="color:#2b91af;"&gt;NavController&lt;/span&gt;.Current.NavigateToBack();
    }
}
&lt;/pre&gt;
&lt;p&gt;Después de tener esto solo nos queda pasar el servicio de navegación en el constructor de nuestros ViewModels y acceder a los distintos métodos para navegar.&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color:gray;"&gt;/// &amp;lt;summary&amp;gt;
/// &lt;/span&gt;&lt;span style="color:green;"&gt;Initializes a new instance of the MainViewModel class.
&lt;/span&gt;&lt;span style="color:gray;"&gt;/// &amp;lt;/summary&amp;gt;
&lt;/span&gt;&lt;span style="color:blue;"&gt;public &lt;/span&gt;MainViewModel(&lt;span style="color:#2b91af;"&gt;IDataService &lt;/span&gt;dataService, &lt;span style="color:#2b91af;"&gt;INavigatorService &lt;/span&gt;navigator)
&lt;/pre&gt;&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;private void &lt;/span&gt;GotoView1Command()
{
    _navigator.GotoMvvmView1(_item);
}
&lt;/pre&gt;
&lt;p&gt;Quizás pienses que a esta altura, cuando ya WP7 solo tendrá una próxima actualización y las cosas cambiarán de cara a WP8 y a la nueva interfaz de W8 (antes Metro), ya no tienen mucho sentido. Puedes echarle una ojeada a &lt;a href="http://geeks.ms/blogs/jyeray/archive/2012/04/02/windows-8-apps-metro-para-desarrolladores-windows-phone-7-5-1-de-x.aspx" target="_blank"&gt;este post sobre W8&lt;/a&gt; del propio Josue y seguramente habrá cosas que te resulten familiar. &lt;img style="border-bottom-style:none;border-left-style:none;border-top-style:none;border-right-style:none;" class="wlEmoticon wlEmoticon-winkingsmile" alt="Winking smile" src="http://www.odelvalle.com/wp-content/uploads/2012/08/wlEmoticon-winkingsmile.png" /&gt;&lt;/p&gt;
&lt;p&gt;Salu2 &lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.odelvalle.com/downloads/sources/NavigatorManager.rar" target="_blank"&gt;Código del ejemplo&lt;/a&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=206375" width="1" height="1"&gt;</description></item><item><title>AsyncWorkManagerHelper para WP7</title><link>http://geeks.ms/blogs/omarvr/archive/2012/07/28/asyncworkmanagerhelper-para-wp7.aspx</link><pubDate>Sat, 28 Jul 2012 17:24:26 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:206282</guid><dc:creator>Omar del Valle Rodríguez</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/omarvr/rsscomments.aspx?PostID=206282</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/omarvr/commentapi.aspx?PostID=206282</wfw:comment><comments>http://geeks.ms/blogs/omarvr/archive/2012/07/28/asyncworkmanagerhelper-para-wp7.aspx#comments</comments><description>&lt;p&gt;Hace mucho que tenía este artículo y este código en el tintero por repasar y publicar. Se trata de un Helper para ejecutar tareas en un agente de WP7 de manera asíncrona.&lt;/p&gt; &lt;p&gt;Hace 1 año aproximadamente, &lt;a href="http://blogs.msdn.com/3021/ProfileUrlRedirect.ashx" target="_blank"&gt;Peter Torr&lt;/a&gt; publicaba un artículo en tres partes explicando el trabajo con los agentes en background para WP7. Los enlaces a las tres partes son:&lt;/p&gt; &lt;p&gt;1- &lt;a href="http://blogs.msdn.com/b/ptorr/archive/2011/07/11/background-agents-part-1-of-3.aspx" target="_blank"&gt;Background Agents - Part 1 of 3&lt;/a&gt;&lt;br /&gt;2- &lt;a href="http://blogs.msdn.com/b/ptorr/archive/2011/07/12/background-agents-part-2-of-3.aspx" target="_blank"&gt;Background Agents - Part 2 of 3&lt;/a&gt;&lt;br /&gt;3- &lt;a href="http://blogs.msdn.com/b/ptorr/archive/2011/07/12/background-agents-part-3-of-3.aspx" target="_blank"&gt;Background Agents - Part 3 of 3&lt;/a&gt;&lt;/p&gt; &lt;p&gt;En la segunda parte de la seria se discute un Helper para realizar tareas en segundo plano y esperar que estas terminen para poder notificar al agente el resultado de la ejecución.&lt;/p&gt; &lt;p&gt;El helper da una limpieza a nuestro código muy buena y nos permite olvidarnos de todo el proceso asíncrono. Sin embargo, si queremos extender el uso del helper más allá de un agente y utilizarlo en nuestra aplicación, encontramos que carece de alguna funcionalidad.&lt;/p&gt; &lt;p&gt;1- No se tiene control de lo que va sucediendo con las tareas que se van ejecutando hasta que no termina todo el proceso.&lt;br /&gt;2- Si yo necesito que las tareas se ejecuten de 1 en 1 o de 2 en 2, o de N en N, tampoco tendría el control sobre ello.&lt;/p&gt; &lt;p&gt;Entiéndase que el helper fue escrito para ayudar con las tareas en background de un agente y en estos casos pocas veces importa lo que está sucediendo hasta que no termina todo el proceso.&lt;/p&gt; &lt;p&gt;Dispuesto a poder utilizar el código del Helper en cualquier tarea asíncrona que necesite ejecutar mi aplicación de WP7, le hice algunas modificaciones al código.&lt;/p&gt; &lt;h3&gt;FIFO para las tareas.&lt;/h3&gt; &lt;p&gt;First In, First Out. El código de Peter ejecuta directamente cada tarea cuando se adiciona la misma al Helper. En realidad estas ejecuciones son bloqueadas hasta que un ManualResetEvent es seteado cuando se ejecuta el Start o el WaitAll&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color:gray;"&gt;/// &amp;lt;summary&amp;gt;
/// &lt;/span&gt;&lt;span style="color:green;"&gt;Schedules a work item to begin
&lt;/span&gt;&lt;span style="color:gray;"&gt;/// &amp;lt;/summary&amp;gt;
/// &amp;lt;param name=&amp;quot;work&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:green;"&gt;The work to perform&lt;/span&gt;&lt;span style="color:gray;"&gt;&amp;lt;/param&amp;gt;
/// &amp;lt;remarks&amp;gt;&lt;/span&gt;&lt;span style="color:green;"&gt;The worker thread is blocked on the startEvent so that the work
&lt;/span&gt;&lt;span style="color:gray;"&gt;/// &lt;/span&gt;&lt;span style="color:green;"&gt;doesn&amp;#39;t complete before the client is ready to handle the completion event
&lt;/span&gt;&lt;span style="color:gray;"&gt;/// &amp;lt;/remarks&amp;gt;
&lt;/span&gt;&lt;span style="color:blue;"&gt;void &lt;/span&gt;BeginWorkItem(&lt;span style="color:#2b91af;"&gt;WorkloadInfo&lt;/span&gt;&amp;lt;TParam, TResult&amp;gt; work)
{
  &lt;span style="color:blue;"&gt;lock &lt;/span&gt;(&lt;span style="color:blue;"&gt;this&lt;/span&gt;)
  {
    outstandingItems++;
  }

  &lt;span style="color:#2b91af;"&gt;ThreadPool&lt;/span&gt;.QueueUserWorkItem(&lt;span style="color:blue;"&gt;delegate
  &lt;/span&gt;{
    &lt;span style="color:green;"&gt;// Wait until it&amp;#39;s OK to start
    &lt;/span&gt;startEvent.WaitOne();
    &lt;span style="color:blue;"&gt;try
    &lt;/span&gt;{
      &lt;span style="color:green;"&gt;// Method is responsible for completing itself if it didn&amp;#39;t fail
      &lt;/span&gt;work.Method(work.Parameter, work);
    }
    &lt;span style="color:blue;"&gt;catch &lt;/span&gt;(&lt;span style="color:#2b91af;"&gt;Exception &lt;/span&gt;ex)
    {
      &lt;span style="color:green;"&gt;// Complete with a failure case
      &lt;/span&gt;work.NotifyFailure(ex);
    }
  });
}&lt;/pre&gt;
&lt;p&gt;&lt;br /&gt;Si queremos controlar la cantidad de tareas ejecutándose a la vez, este mecanismo no nos vale, por lo que he creado un Queue (FIFO en NET) para almacenar las tareas y poder controlar su ejecución.&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color:gray;"&gt;/// &amp;lt;summary&amp;gt;
/// &lt;/span&gt;&lt;span style="color:green;"&gt;FIFO to Tasks
&lt;/span&gt;&lt;span style="color:gray;"&gt;/// &amp;lt;/summary&amp;gt;
&lt;/span&gt;&lt;span style="color:blue;"&gt;private readonly &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;Queue&lt;/span&gt;&amp;lt;&lt;span style="color:#2b91af;"&gt;WorkloadInfo&lt;/span&gt;&amp;lt;TParam, TResult&amp;gt;&amp;gt; _queue;
&lt;/pre&gt;
&lt;p&gt;El la clase AsyncWorkManager ahora tiene 2 constructores, en uno de ellos podemos indicar el límite de tareas que se ejecutan simultáneamente. &lt;/p&gt;
&lt;p&gt;Para poder conocer el estado de cada tarea en el momento en que se ejecutan, se ha adicionado un evento (OnCompleteWorkItem) a la clase WorkLoadInfo que es disparado justo al concluir la ejecución de la misma.&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color:gray;"&gt;/// &amp;lt;summary&amp;gt;
/// &lt;/span&gt;&lt;span style="color:green;"&gt;Completes the work item with a successful result
&lt;/span&gt;&lt;span style="color:gray;"&gt;/// &amp;lt;/summary&amp;gt;
/// &amp;lt;param name=&amp;quot;result&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:green;"&gt;The result of the operation&lt;/span&gt;&lt;span style="color:gray;"&gt;&amp;lt;/param&amp;gt;
/// &amp;lt;remarks&amp;gt;&lt;/span&gt;&lt;span style="color:green;"&gt;This method is called by the worker Method once it has completed its task&lt;/span&gt;&lt;span style="color:gray;"&gt;&amp;lt;/remarks&amp;gt;
&lt;/span&gt;&lt;span style="color:blue;"&gt;public void &lt;/span&gt;NotifySuccess(TResult result)
{
    MarkAsComplete();
    Result = result;

    &lt;span style="color:blue;"&gt;if &lt;/span&gt;(OnCompleteWorkItem != &lt;span style="color:blue;"&gt;null&lt;/span&gt;) OnCompleteWorkItem(&lt;span style="color:blue;"&gt;this&lt;/span&gt;, &lt;span style="color:#2b91af;"&gt;EventArgs&lt;/span&gt;.Empty);
    _parent.CompleteWorkItem();
}

&lt;span style="color:gray;"&gt;/// &amp;lt;summary&amp;gt;
/// &lt;/span&gt;&lt;span style="color:green;"&gt;Completes the work item with an error
&lt;/span&gt;&lt;span style="color:gray;"&gt;/// &amp;lt;/summary&amp;gt;
/// &amp;lt;param name=&amp;quot;error&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:green;"&gt;The error to report&lt;/span&gt;&lt;span style="color:gray;"&gt;&amp;lt;/param&amp;gt;
/// &amp;lt;remarks&amp;gt;&lt;/span&gt;&lt;span style="color:green;"&gt;This method is called by the worker Method if it fails its task&lt;/span&gt;&lt;span style="color:gray;"&gt;&amp;lt;/remarks&amp;gt;
&lt;/span&gt;&lt;span style="color:blue;"&gt;public void &lt;/span&gt;NotifyFailure(&lt;span style="color:#2b91af;"&gt;Exception &lt;/span&gt;error)
{
    MarkAsComplete();
    Error = error;

    &lt;span style="color:blue;"&gt;if &lt;/span&gt;(OnCompleteWorkItem != &lt;span style="color:blue;"&gt;null&lt;/span&gt;) OnCompleteWorkItem(&lt;span style="color:blue;"&gt;this&lt;/span&gt;, &lt;span style="color:#2b91af;"&gt;EventArgs&lt;/span&gt;.Empty);
    _parent.CompleteWorkItem();
}
&lt;/pre&gt;
&lt;p&gt;La clase AsyncWorkManager tiene dos métodos por los cuales se puede iniciar el proceso. Start y WaitAll. &lt;/p&gt;
&lt;h3&gt;Start&lt;/h3&gt;
&lt;p&gt;El método inicia la ejecución de todas las tareas y no espera por su finalización. En la versión original del Helper el Start se ejecuta en el mismo hilo desde el cual es llamado y, si en nuestro caso queremos controlar la cantidad de tareas que se van ejecutando esto tampoco nos vale, así que también se ha modificado para que se ejecute en un ThreadPool diferente.&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color:gray;"&gt;/// &amp;lt;summary&amp;gt;
/// &lt;/span&gt;&lt;span style="color:green;"&gt;Starts performing work, if not already happening.
&lt;/span&gt;&lt;span style="color:gray;"&gt;/// &amp;lt;/summary&amp;gt;
/// &amp;lt;remarks&amp;gt;&lt;/span&gt;&lt;span style="color:green;"&gt;This method is implicitly called by the WaitAll methods&lt;/span&gt;&lt;span style="color:gray;"&gt;&amp;lt;/remarks&amp;gt;
&lt;/span&gt;&lt;span style="color:blue;"&gt;public void &lt;/span&gt;Start()
{
    _startNewEvent.Set();

    &lt;span style="color:blue;"&gt;lock &lt;/span&gt;(&lt;span style="color:blue;"&gt;this&lt;/span&gt;)
    {
        &lt;span style="color:blue;"&gt;if &lt;/span&gt;(_queue.Count == 0)
        {
            CompleteWorkload();
            &lt;span style="color:blue;"&gt;return&lt;/span&gt;;
        }

        &lt;span style="color:green;"&gt;// Work has already been completed
        &lt;/span&gt;&lt;span style="color:blue;"&gt;if &lt;/span&gt;(_completionEvent.WaitOne(0)) &lt;span style="color:blue;"&gt;return&lt;/span&gt;;

        &lt;span style="color:green;"&gt;// Reset the completion event to be waited on
        &lt;/span&gt;_completionEvent.Reset();

        _outstandingItems = _queue.Count;
    }

    &lt;span style="color:#2b91af;"&gt;ThreadPool&lt;/span&gt;.QueueUserWorkItem(&lt;span style="color:blue;"&gt;delegate
    &lt;/span&gt;{
        &lt;span style="color:green;"&gt;// Release the threads waiting to do work
        &lt;/span&gt;&lt;span style="color:blue;"&gt;while &lt;/span&gt;(&lt;span style="color:blue;"&gt;true&lt;/span&gt;)
        {
            &lt;span style="color:blue;"&gt;if &lt;/span&gt;(_executingOperations == _concurrentOperations &amp;amp;&amp;amp; _concurrentOperations != 0) _startNewEvent.Reset();

            _startNewEvent.WaitOne();

            &lt;span style="color:blue;"&gt;var &lt;/span&gt;work = _queue.Dequeue();
            BeginWorkItem(work);

            &lt;span style="color:blue;"&gt;if &lt;/span&gt;(_queue.Count == 0) &lt;span style="color:blue;"&gt;break&lt;/span&gt;;
        }
    });
}
&lt;/pre&gt;
&lt;p&gt;Una particularidad del cambio realizado es que si usamos el constructor sin parámetros de la clase AsyncWorkManager, no se controla la concurrencia y todas las tareas son ejecutadas a la vez.&lt;/p&gt;
&lt;h3&gt;WaitAll&lt;/h3&gt;
&lt;p&gt;Este método tiene dos sobrecargas, una sin parámetros que espera infinitamente a que todas las tareas se hayan ejecutado (ojo que esto detiene el hilo en el que se haga la llamada al método) y otro que espera un tiempo (timeout) y aborta en caso de que todas las tareas no se hayan finalizado.&lt;/p&gt;
&lt;p&gt; Después de los cambios, un ejemplo de cómo se podría usar el Helper sería este:&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;var &lt;/span&gt;calendarsWorkManager = &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;AsyncWorkManager&lt;/span&gt;&amp;lt;&lt;span style="color:#2b91af;"&gt;Account&lt;/span&gt;, &lt;span style="color:#2b91af;"&gt;IEnumerable&lt;/span&gt;&amp;lt;&lt;span style="color:#2b91af;"&gt;Calendar&lt;/span&gt;&amp;gt;&amp;gt;(concurrentsTask:1); 

GetAccounts(&lt;span style="color:blue;"&gt;delegate&lt;/span&gt;(&lt;span style="color:blue;"&gt;object &lt;/span&gt;o, &lt;span style="color:#2b91af;"&gt;AccountsEventArgs &lt;/span&gt;args)
{
    &lt;span style="color:blue;"&gt;foreach &lt;/span&gt;(&lt;span style="color:blue;"&gt;var &lt;/span&gt;account &lt;span style="color:blue;"&gt;in &lt;/span&gt;args.EntityList)
    {
        &lt;span style="color:blue;"&gt;switch &lt;/span&gt;(account.Source)
        {
            &lt;span style="color:blue;"&gt;case &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;Enums&lt;/span&gt;.&lt;span style="color:#2b91af;"&gt;SourceProvider&lt;/span&gt;.Google:

                &lt;span style="color:blue;"&gt;var &lt;/span&gt;rGoogle = calendarsWorkManager.AddWorkItem(SyncGoogleCalendars, account);
                rGoogle.OnCompleteWorkItem += &lt;span style="color:blue;"&gt;delegate
                &lt;/span&gt;{
                    &lt;span style="color:blue;"&gt;if &lt;/span&gt;(rGoogle.Error == &lt;span style="color:blue;"&gt;null&lt;/span&gt;) calendarList.AddRange(rGoogle.Result);
                };

                &lt;span style="color:blue;"&gt;break&lt;/span&gt;;
            &lt;span style="color:blue;"&gt;case &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;Enums&lt;/span&gt;.&lt;span style="color:#2b91af;"&gt;SourceProvider&lt;/span&gt;.Live:

                &lt;span style="color:blue;"&gt;var &lt;/span&gt;rLive = calendarsWorkManager.AddWorkItem(SyncLiveCalendars, account);
                rLive.OnCompleteWorkItem += &lt;span style="color:blue;"&gt;delegate
                &lt;/span&gt;{
                    &lt;span style="color:blue;"&gt;if &lt;/span&gt;(rLive.Error == &lt;span style="color:blue;"&gt;null&lt;/span&gt;) calendarList.AddRange(rLive.Result);
                };

                &lt;span style="color:blue;"&gt;break&lt;/span&gt;;
            &lt;span style="color:blue;"&gt;case &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;Enums&lt;/span&gt;.&lt;span style="color:#2b91af;"&gt;SourceProvider&lt;/span&gt;.Exchange:

                calendarList.Add(ExchangeCalendar(account));

                &lt;span style="color:blue;"&gt;break&lt;/span&gt;;
        }
    }

    calendarsWorkManager.WorkComplete += (sender, a) =&amp;gt; onCalendarList(&lt;span style="color:blue;"&gt;this&lt;/span&gt;, &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;CalendarsEventArgs&lt;/span&gt;(calendarList));
    calendarsWorkManager.Start();
});
&lt;/pre&gt;
&lt;p&gt;En principio la funcionalidad es la misma, excepto que podemos conocer y hacer algo cuando cada tarea se termina de ejecutar (onCompleteWorkItem), podemos indicar la cantidad de tareas ejecutándose a la vez (concurrentsTask:1) y ejecutar el inicio del proceso mediante Start sin que el hilo quede bloqueado. &lt;/p&gt;
&lt;p&gt;Adjunto el &lt;a href="http://www.odelvalle.com/downloads/sources/AsyncWorkManagerHelper.rar" target="_blank"&gt;código del Helper&lt;/a&gt; modificado por si a alguien le vale.&lt;/p&gt;
&lt;p&gt;Un salu2&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=206282" width="1" height="1"&gt;</description></item><item><title>#region en C#</title><link>http://geeks.ms/blogs/omarvr/archive/2012/07/28/region-en-c.aspx</link><pubDate>Fri, 27 Jul 2012 23:20:00 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:206274</guid><dc:creator>Omar del Valle Rodríguez</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/omarvr/rsscomments.aspx?PostID=206274</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/omarvr/commentapi.aspx?PostID=206274</wfw:comment><comments>http://geeks.ms/blogs/omarvr/archive/2012/07/28/region-en-c.aspx#comments</comments><description>&lt;p&gt;Acabo de leer en twitter un comentario que dice:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&amp;ldquo;&lt;/em&gt;&lt;a href="mailto:&amp;ldquo;&amp;rlm;@davybrion"&gt;&lt;em&gt;&amp;rlm;&lt;/em&gt;&lt;/a&gt;&lt;em&gt;#region in C# only has 2 purposes: to add unnecessary noise, or when you think it helps, it&amp;#39;s actually telling you how much your class sucks because if you feel the need to &amp;#39;group&amp;#39; things into regions, you generally need to separate the code into multiple classes&amp;rdquo;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;El comentario se refiere a dos formas diferentes de usar #region, uno ser&amp;iacute;a quien usa las regiones para identificar zonas privadas o p&amp;uacute;blicas, o para identificar constructores del resto de la l&amp;oacute;gica en una clase y, el otro grupo se refiere a quienes lo usan para agrupar funcionalidad o lo que es lo mismo, l&amp;oacute;gicas diferentes dentro de una misma clase. &lt;/p&gt;
&lt;p&gt;Al primer grupo, le define el uso de regiones como &amp;ldquo;ruido&amp;rdquo;, un calificativo desde mi punto de vista que pudiera ser discutible &lt;img src="http://www.odelvalle.com/wp-content/uploads/2012/07/wlEmoticon-winkingsmile.png" alt="Winking smile" class="wlEmoticon wlEmoticon-winkingsmile" style="border-bottom-style:none;border-left-style:none;border-top-style:none;border-right-style:none;" /&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Sobre el comentario hacia el segundo grupo no se le puede quitar una pizca de raz&amp;oacute;n. Si una clase es lo suficientemente grande como para que te sea &amp;ldquo;molesta a la vista&amp;rdquo;, puedes estar seguro que necesitas un refactoring antes que varios #region &lt;/p&gt;
&lt;p&gt;&amp;hellip; aqu&amp;iacute; tienes un claro ejemplo de lo que nunca se deber&amp;iacute;a hacer:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.odelvalle.com/wp-content/uploads/2012/07/Untitled.png"&gt;&lt;img height="379" width="681" src="http://www.odelvalle.com/wp-content/uploads/2012/07/Untitled_thumb.png" alt="Untitled" border="0" title="Untitled" style="background-image:none;border-bottom:0px;border-left:0px;padding-left:0px;padding-right:0px;display:inline;border-top:0px;border-right:0px;padding-top:0px;" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;cu&amp;hellip;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=206274" width="1" height="1"&gt;</description><category domain="http://geeks.ms/blogs/omarvr/archive/tags/POO/default.aspx">POO</category><category domain="http://geeks.ms/blogs/omarvr/archive/tags/NET/default.aspx">NET</category></item><item><title>[OT] Return to live…</title><link>http://geeks.ms/blogs/omarvr/archive/2012/07/27/ot-return-to-live.aspx</link><pubDate>Thu, 26 Jul 2012 22:29:00 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:206259</guid><dc:creator>Omar del Valle Rodríguez</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/omarvr/rsscomments.aspx?PostID=206259</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/omarvr/commentapi.aspx?PostID=206259</wfw:comment><comments>http://geeks.ms/blogs/omarvr/archive/2012/07/27/ot-return-to-live.aspx#comments</comments><description>&lt;p&gt;Hace ya bastante tiempo que un día sí y otro también, solo sabemos escuchar hablar sobre las nuevas tecnologías que nos vienen desde Microsoft: Metro, W8, WP8, nueva versión de NET, de MVC, de EF…&amp;#160; &lt;/p&gt;  &lt;p&gt;Si a eso le sumamos andadoras por WebGL con three.js, Kinect con javascript y HTML 5 que últimamente me tocan porque sí… poco tiempo queda para escribir algo.&lt;/p&gt;  &lt;p&gt;Aprovechando que agosto parece que viene más “relajado” y que finalmente, después de cambiar a WP, pienso empezar a publicar cosas en mi blog (&lt;a href="http://www.odelvalle.com"&gt;www.odelvalle.com&lt;/a&gt;) sería buen momento para retornar a la vida… &lt;img style="border-bottom-style:none;border-left-style:none;border-top-style:none;border-right-style:none;" class="wlEmoticon wlEmoticon-smile" alt="Smile" src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omarvr/wlEmoticon_2D00_smile_5F00_542EA74E.png" /&gt;&lt;/p&gt;  &lt;p&gt;Para no dejar abandonado (no podría) a geeks.ms, este primer post viene siendo algo así como un [TestMethod] desde Live Writer hacia el resto del mundo &lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;Pronto más…    &lt;br /&gt;salu2     &lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=206259" width="1" height="1"&gt;</description></item><item><title>DDD: 2- Framework de IoC (Service Pack 1)</title><link>http://geeks.ms/blogs/omarvr/archive/2011/11/22/ddd-2-framework-de-ioc-service-pack-1.aspx</link><pubDate>Tue, 22 Nov 2011 22:53:00 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:201837</guid><dc:creator>Omar del Valle Rodríguez</dc:creator><slash:comments>7</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/omarvr/rsscomments.aspx?PostID=201837</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/omarvr/commentapi.aspx?PostID=201837</wfw:comment><comments>http://geeks.ms/blogs/omarvr/archive/2011/11/22/ddd-2-framework-de-ioc-service-pack-1.aspx#comments</comments><description>&lt;p&gt;&lt;span style="font-family:calibri;font-size:small;"&gt;
&lt;p&gt;Despu&amp;eacute;s de la &amp;uacute;ltima sacudida recibida &lt;img src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omarvr/wlEmoticon_2D00_sadsmile_5F00_292C0F4F.png" alt="Sad smile" class="wlEmoticon wlEmoticon-sadsmile" style="border-bottom-style:none;border-left-style:none;border-top-style:none;border-right-style:none;" /&gt; por la encapsulaci&amp;oacute;n del Container que hicimos en el art&amp;iacute;culo anterior, sacamos este Service Pack 1 &lt;img src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omarvr/wlEmoticon_2D00_smile_5F00_4F8DF29A.png" alt="Smile" class="wlEmoticon wlEmoticon-smile" style="border-bottom-style:none;border-left-style:none;border-top-style:none;border-right-style:none;" /&gt; y de paso cuento un poco c&amp;oacute;mo llegamos aqu&amp;iacute;.&lt;/p&gt;
&lt;p&gt;Cuando me pasan estas cosas, siempre recuerdo el pasaje de una lectura que tengo por casa&amp;hellip;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&amp;ldquo;Denis Cochin preparo un estudio sobre Qu&amp;iacute;mica y lo presento a Pasteur. El trabajo comenzaba con las palabras. &amp;ldquo;Se sabe que...&amp;ldquo;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;- &amp;iquest;Que es lo que se sabe? - Interrumpi&amp;oacute; Pasteur al leerlo. - No se sabe nada. &lt;br /&gt;- Pero se&amp;ntilde;or - Contesto Cochin - lo que iba a citar es un trabajo de usted.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;- No importa - replico Pasteur. - Yo podr&amp;iacute;a haberme equivocado. Empiece Ud. de nuevo&amp;rdquo;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Tras los comentarios de &lt;a href="http://geeks.ms/blogs/unai/default.aspx"&gt;Unai&lt;/a&gt; y &lt;a href="http://geeks.ms/blogs/etomas/default.aspx"&gt;Eduard&lt;/a&gt; m&amp;aacute;s la referencia al art&amp;iacute;culo de &lt;a href="http://blog.ploeh.dk/2010/02/03/ServiceLocatorIsAnAntiPattern.aspx"&gt;Mark&lt;/a&gt; sobre el patr&amp;oacute;n o anti-patr&amp;oacute;n Service-Locator (Martin Fowler, 2004), hab&amp;iacute;a que profundizar m&amp;aacute;s en el tema, as&amp;iacute; que sin pensarlo dos veces me compr&amp;eacute; el libro de &amp;ldquo;&lt;a href="http://manning.com/seemann/"&gt;Dependency Injection in .NET&lt;/a&gt;&amp;rdquo; el cual recomiendo much&amp;iacute;simo por la claridad en el contenido, adem&amp;aacute;s de estar orientado directamente a NET.&lt;/p&gt;
&lt;p&gt;En el libro, cuando Mark habla del Service Locator como un anti-patr&amp;oacute;n, dice: &amp;ldquo;Some people consider it a proper design pattern, whereas others (me included) consider it an anti-pattern.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Tras esta definici&amp;oacute;n no puedo evitar preguntarme &amp;iquest;Y en qu&amp;eacute; bando me pongo yo? Es evidente que la opini&amp;oacute;n de Eduard, Unai, Mark y seguramente la de muchos otros, pesa much&amp;iacute;simo, as&amp;iacute; que lo m&amp;aacute;s probable es que termine m&amp;aacute;s r&amp;aacute;pido si busco alguna deficiencia en la implementaci&amp;oacute;n anterior que me lleve finalmente a verlo como ellos.&lt;/p&gt;
&lt;p&gt;Tras no mucho tiempo&amp;hellip; me imagin&amp;eacute; la siguiente situaci&amp;oacute;n:&lt;/p&gt;
&lt;p&gt;Tengo varios controladores (MVC) que usan inyecci&amp;oacute;n de dependencia con uno o varios servicios (Application services), tengo servicios que usan dependencias a uno o m&amp;aacute;s repositorios, tengo varios repositorios que usan dependencia a una unidad de trabajo, tengo una unidad de trabajo que depende de una cadena de conexi&amp;oacute;n. En esa situaci&amp;oacute;n, tendr&amp;eacute; en mis controladores llamadas al Resolve del container para crear los servicios, en los servicios llamadas al Resolve para crear instancias de los repositorios, tendr&amp;eacute; tambi&amp;eacute;n llamadas al Resolve en los repositorios para recuperar la unidad de trabajo y as&amp;iacute; en toda mi arquitectura... &lt;/p&gt;
&lt;p&gt;Salta a simple vista que mis controladores dependen de mis servicios y del Service Locator. Los servicios dependen de los repositorios y del Service Locator, los repositorios dependen de la unidad de trabajo y del Service Locator. &amp;iquest;Qu&amp;eacute; pasa si quiero reutilizar los repositorios? &amp;iquest;O si quiero reutilizar los servicios? &amp;iquest;O si quiero reutilizar mi unidad de trabajo? Pues que en todo momento depender&amp;eacute; del Service Locator&amp;hellip; &lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omarvr/wlEmoticon_2D00_sadsmile_5F00_292C0F4F.png" alt="Sad smile" class="wlEmoticon wlEmoticon-sadsmile" style="border-bottom-style:none;border-left-style:none;border-top-style:none;border-right-style:none;" /&gt; No segu&amp;iacute; buscando&amp;hellip; mi objetivo era estar desacoplado del Framework de IoC y termin&amp;eacute; atando toda la arquitectura.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&amp;iquest;C&amp;oacute;mo soluciono esto entonces?&lt;/strong&gt; &lt;/p&gt;
&lt;p&gt;-Constructor Inyection &lt;br /&gt;-Property Injection &lt;br /&gt;-&amp;hellip;&lt;/p&gt;
&lt;p&gt;Si mis controladores recibieran los servicios que necesitan para trabajar mediante el constructor, no necesitar&amp;iacute;a una referencia al Service Locator&amp;hellip; y lo mismo pasa en toda la cadena de inyecci&amp;oacute;n.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&amp;iquest;C&amp;oacute;mo funciona esto?&lt;/strong&gt; Imaginen que tengo&amp;hellip;&lt;/p&gt;
&lt;p&gt;Controller(IService srv) &amp;ndash; Service(IRepository repo) &amp;ndash; Repository(IUnitofWork uow) &amp;ndash; UnitOfWork()&lt;/p&gt;
&lt;p&gt;1- Un controlador necesita una instancia de un servicio, se intenta crear una instancia de ese servicio. &lt;br /&gt;2- Para crear el servicio se necesita un repositorio, se intenta crear una instancia del repositorio. &lt;br /&gt;3- Para crear el repositorio se necesita una unidad de trabajo, se intenta crear la unidad de trabajo. &lt;br /&gt;4- Se crea la unidad de trabajo (no depende de nadie). &lt;br /&gt;5- A partir de aqu&amp;iacute;, se inyecta la unidad de trabajo al repositorio, el repositorio al servicio y el servicio al controlador.&lt;/p&gt;
&lt;p&gt;Este algoritmo me dice que todo empieza desde un punto &amp;uacute;nico. A este punto Mark lo llama Composition Root. &amp;ldquo;A COMPOSITION ROOT is a (preferably) unique location in an application where modules are composed together.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Un DI Container es quien me dice qui&amp;eacute;n es el Container utilizado en mi aplicaci&amp;oacute;n y el encargado de componer todo el &lt;a href="http://es.wikipedia.org/wiki/Grafo"&gt;grafo de objetos&lt;/a&gt;. Este debe ser referenciado &amp;uacute;nicamente desde el Composition root (De aqu&amp;iacute; que Eduard y Unai no vean la necesidad de abstraer el Container) y se inicializa solo una vez en todo el ciclo de vida de la aplicaci&amp;oacute;n.&lt;/p&gt;
&lt;p&gt;Conociendo un poco m&amp;aacute;s que ayer, decid&amp;iacute; hacer &amp;ldquo;refactoring&amp;rdquo; a todo lo visto ayer (Por llamarle de una forma menos dura al hecho de borrar todas las interfaces e implementaciones de mi Service Locator). Despu&amp;eacute;s de un rato, me qued&amp;oacute; esto:&lt;/p&gt;
&lt;p&gt;Mi DI Container. &amp;hellip;&lt;/p&gt;
&lt;code class="prettyprint lang-cs"&gt;
&lt;p&gt;public static class UnityContainerFactory &lt;br /&gt;{ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; private static readonly IUnityContainer _container;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; static UnityContainerFactory() &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _container = new UnityContainer(); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Configure(); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; private static void Configure() &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var section = (UnityConfigurationSection)ConfigurationManager.GetSection(&amp;quot;unity&amp;quot;); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; section.Configure(_container);&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // Aditional Configuration &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // Container.RegisterType&amp;lt;IBaseType, ModuleAType&amp;gt;(&amp;quot;moduleA&amp;quot;) &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // Container.RegisterType&amp;lt;IBaseType, ModuleBType&amp;gt;(&amp;quot;moduleB&amp;quot;) &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public static IUnityContainer GetContainer() &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return _container; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;
&lt;p&gt;}&lt;/p&gt;
&lt;/code&gt;
&lt;p&gt;&lt;strong&gt;&amp;iquest;Qui&amp;eacute;n ser&amp;iacute;a mi Composition Root?&lt;/strong&gt; Pues ya esto depende del tipo de aplicaci&amp;oacute;n que se vaya a crear, ya que cada aplicaci&amp;oacute;n puede tener una definici&amp;oacute;n diferente para su &amp;ldquo;&amp;uacute;nico punto de entrada&amp;rdquo;. Por ejemplo, para una aplicaci&amp;oacute;n MVC, Mark aconseja un IControllerFactory, aunque si es para MVC3, yo prefiero el IDependencyResolver. &lt;/p&gt;
&lt;p&gt;Mi Composition Root para MVC3 ser&amp;iacute;a:&lt;/p&gt;
&lt;code class="prettyprint lang-cs"&gt;
&lt;p&gt;public class UnityDependencyResolver : IDependencyResolver &lt;br /&gt;{ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; private readonly IUnityContainer _container;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; #region Implementation of IDependencyResolver&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public UnityDependencyResolver(IUnityContainer container) &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _container = container; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public object GetService(Type serviceType) &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return _container.IsRegistered(serviceType) ? _container.Resolve(serviceType) : null; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public IEnumerable&amp;lt;object&amp;gt; GetServices(Type serviceType) &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return _container.ResolveAll&amp;lt;object&amp;gt;().Where(s =&amp;gt; s.GetType() == serviceType); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;br /&gt;} &lt;/p&gt;
&lt;/code&gt;
&lt;p&gt;Aqu&amp;iacute; puedes encontrar un peque&amp;ntilde;o &lt;a href="http://stevesmithblog.com/blog/how-do-i-use-structuremap-with-asp-net-mvc-3/"&gt;post&lt;/a&gt; de Steve explicando la implementaci&amp;oacute;n anterior.&lt;/p&gt;
&lt;p&gt;Para el caso de un servicio WCF me gust&amp;oacute; la forma en que lo implementaron en la &lt;a href="http://microsoftnlayerapp.codeplex.com/"&gt;gu&amp;iacute;a de arquitectura N Layer&lt;/a&gt; donde se implementa la interfaz IInstanceProvider:&lt;/p&gt;
&lt;code class="prettyprint lang-cs"&gt;
&lt;p&gt;public class UnityDependencyProvider : IInstanceProvider &lt;br /&gt;{ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; private readonly IUnityContainer _container; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; private readonly Type _serviceType;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public UnityDependencyProvider(Type serviceType) &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (serviceType == null) throw new ArgumentNullException(&amp;quot;serviceType&amp;quot;);&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _serviceType = serviceType; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _container = UnityContainerFactory.GetContainer();&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; #region Implementation of IInstanceProvider&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public object GetInstance(InstanceContext instanceContext) &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return GetInstance(instanceContext, null); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public object GetInstance(InstanceContext instanceContext, Message message) &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return _container.Resolve(_serviceType); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public void ReleaseInstance(InstanceContext instanceContext, object instance) &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (instance is IDisposable) ((IDisposable)instance).Dispose(); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; #endregion &lt;br /&gt;}&lt;/p&gt;
&lt;p&gt;Y luego creamos el atributo con el que marcaremos los servicios WCF que necesiten inyecci&amp;oacute;n de dependencias&amp;hellip;&lt;/p&gt;
&lt;p&gt;public class UnityDependencyProviderServiceBehavior : Attribute, IServiceBehavior &lt;br /&gt;{ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; #region Implementation of IServiceBehavior&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public void AddBindingParameters(ServiceDescription serviceDescription, &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ServiceHostBase serviceHostBase, &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Collection&amp;lt;ServiceEndpoint&amp;gt; endpoints, &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; BindingParameterCollection bindingParameters) &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; foreach (var dispatcher in serviceHostBase.ChannelDispatchers.OfType&amp;lt;ChannelDispatcher&amp;gt;()) &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; dispatcher.Endpoints.ToList(). &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ForEach(endpoint =&amp;gt; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; endpoint.DispatchRuntime.InstanceProvider = new UnityDependencyProvider(serviceDescription.ServiceType); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; #endregion &lt;br /&gt;}&lt;/p&gt;
&lt;/code&gt;
&lt;p&gt;&amp;quot;As you can see, it took me a couple of years of intense use to realize the shortcomings of SERVICE LOCATOR and that better alternatives existed. For this reason, I find it easy to understand why so many developers find it attractive&amp;hellip;&amp;rdquo; (Gracias Mark) &lt;img src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omarvr/wlEmoticon_2D00_smile_5F00_4F8DF29A.png" alt="Smile" class="wlEmoticon wlEmoticon-smile" style="border-bottom-style:none;border-left-style:none;border-top-style:none;border-right-style:none;" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Los test&amp;hellip;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;El problema de los test est&amp;aacute; en que no tenemos un evento al cual nos podamos subscribir ni interfaz que implementar&amp;hellip; Entonces, &lt;a href="http://scottdepouw.com/blog/testing-the-ioc-container/"&gt;&amp;iquest;C&amp;oacute;mo creo los test sobre el IoC Container?&lt;/a&gt; by Scott&amp;hellip;&lt;/p&gt;
&lt;p&gt;Basados en las interfaces IA, IB y las clases A y B que escribimos en el art&amp;iacute;culo anterior, tendr&amp;iacute;amos los siguientes test:&lt;/p&gt;
&lt;code class="prettyprint lang-cs"&gt;
&lt;p&gt;[TestClass] &lt;br /&gt;public class IocTest &lt;br /&gt;{ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; private readonly IUnityContainer _ioc;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// &amp;lt;summary&amp;gt; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// En los test, este es mi punto de entrada (Composition root) &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// &amp;lt;/summary&amp;gt; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public IocTest() &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _ioc = UnityContainerFactory.GetContainer(); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; [TestMethod] &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public void TestCreateObjetWithoutConstructorParameters() &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var a = _ioc.Resolve&amp;lt;IA&amp;gt;();&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Assert.IsNotNull(a); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Assert.AreEqual(1, a.ObjectId); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; [TestMethod] &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public void TestCreateObjetWithConstructorParameters() &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; //var a = new A();&amp;nbsp; Ya no necesitamos hacer esto... &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; //el framework de IoC se encarga de construir IA&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var b = _ioc.Resolve&amp;lt;IB&amp;gt;();&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Assert.IsNotNull(b); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Assert.AreEqual(1, b.ParamInjector.ObjectId); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;br /&gt;} &lt;/p&gt;
&lt;/code&gt;
&lt;p&gt;Los elementos de configuraci&amp;oacute;n, ya podemos inyectarlos tal y como nos ped&amp;iacute;a Juanma:&lt;/p&gt;
&lt;code class="prettyprint lang-cs"&gt;
&lt;p&gt;[TestClass] &lt;br /&gt;public class ConfigTest &lt;br /&gt;{ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; private readonly IUnityContainer _ioc;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public ConfigTest() &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _ioc = UnityContainerFactory.GetContainer(); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; [TestMethod] &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public void TestConfiguration() &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var global = new Global(new AppSettingsHelper()); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var settings = global.Settings;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Assert.AreEqual(&amp;quot;My Project DDD&amp;quot;, settings.Name); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Assert.AreEqual(&amp;quot;es-ES&amp;quot;, settings.LanguageDefault); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Assert.AreEqual(&amp;quot;dd-MM-yyyy HH:mm&amp;quot;, settings.DateTimeFormat); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Assert.AreEqual(1, settings.TimeZoneOffset);&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Assert.IsInstanceOfType(global.SettingsHelper.GetBoolean(&amp;quot;bool&amp;quot;), typeof(bool)); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; [TestMethod] &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public void TestIocConfiguration() &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var global = _ioc.Resolve&amp;lt;IGlobalSettings&amp;gt;();&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Assert.IsNotNull(global); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Assert.IsNotNull(global.Settings); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Assert.IsNotNull(global.SettingsHelper);&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Assert.IsInstanceOfType(global.Settings, typeof(AppConfigurationElement)); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Assert.IsInstanceOfType(global.SettingsHelper, typeof(AppSettingsHelper)); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;br /&gt;}&lt;/p&gt;
&lt;/code&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omarvr/test_2D00_config_5F00_4802832D.png"&gt;&lt;img height="342" width="741" src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omarvr/test_2D00_config_5F00_thumb_5F00_5F4D879E.png" alt="test-config" border="0" title="test-config" style="background-image:none;border-right-width:0px;padding-left:0px;padding-right:0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;padding-top:0px;" /&gt;&lt;/a&gt;&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;Gracias a Unai y a Eduard por hacer posible esta mejora&amp;hellip;&lt;/em&gt;&lt;/strong&gt; &lt;/p&gt;
&lt;p&gt;PD: A&amp;uacute;n no he probado los m&amp;oacute;dulos implementados para MVC3 o para WCF&amp;hellip; ya os contar&amp;eacute; &lt;img src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omarvr/wlEmoticon_2D00_winkingsmile_5F00_2D263754.png" alt="Winking smile" class="wlEmoticon wlEmoticon-winkingsmile" style="border-bottom-style:none;border-left-style:none;border-top-style:none;border-right-style:none;" /&gt;&lt;/p&gt;
&lt;p&gt;Salu2&lt;/p&gt;
&lt;/span&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=201837" width="1" height="1"&gt;</description><category domain="http://geeks.ms/blogs/omarvr/archive/tags/POO/default.aspx">POO</category><category domain="http://geeks.ms/blogs/omarvr/archive/tags/arquitectura/default.aspx">arquitectura</category><category domain="http://geeks.ms/blogs/omarvr/archive/tags/NET/default.aspx">NET</category><category domain="http://geeks.ms/blogs/omarvr/archive/tags/DDD/default.aspx">DDD</category><category domain="http://geeks.ms/blogs/omarvr/archive/tags/IoC/default.aspx">IoC</category></item><item><title>DDD: 2- Framework de IoC (parte 2)</title><link>http://geeks.ms/blogs/omarvr/archive/2011/11/20/ddd-2-framework-de-ioc-parte-2.aspx</link><pubDate>Sun, 20 Nov 2011 11:26:00 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:201779</guid><dc:creator>Omar del Valle Rodríguez</dc:creator><slash:comments>5</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/omarvr/rsscomments.aspx?PostID=201779</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/omarvr/commentapi.aspx?PostID=201779</wfw:comment><comments>http://geeks.ms/blogs/omarvr/archive/2011/11/20/ddd-2-framework-de-ioc-parte-2.aspx#comments</comments><description>&lt;p&gt;&lt;span style="font-family:calibri;font-size:small;"&gt;
&lt;p&gt;En el &lt;a href="http://geeks.ms/blogs/omarvr/archive/2011/11/19/ddd-2-framework-de-ioc-parte-1.aspx"&gt;art&amp;iacute;culo anterior&lt;/a&gt; implementamos todas las interfaces necesarias para usar algunos elementos de configuraci&amp;oacute;n a nivel de aplicaci&amp;oacute;n. Entre estos elementos estaba el Framework de IoC.&lt;/p&gt;
&lt;p&gt;En ese mismo art&amp;iacute;culo explic&amp;aacute;bamos por qu&amp;eacute; decidimos inyectar al Framework de dependecia, as&amp;iacute; que hoy nos dedicaremos a implementar todas las interfaces y realizar algunos test. &lt;/p&gt;
&lt;p&gt;Antes de empezar, deciros que he realizado una peque&amp;ntilde;a modificaci&amp;oacute;n a la interfaz &lt;strong&gt;IContainerConfiguration&lt;/strong&gt; que vimos en el art&amp;iacute;culo anterior. Soy de los que cree que cuando alg&amp;uacute;n c&amp;oacute;digo (mio o no) queda digno de &amp;ldquo;admirar&amp;rdquo; (lo cual no quiere decir &amp;ldquo;correcto&amp;rdquo; &lt;img src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omarvr/wlEmoticon_2D00_smilewithtongueout_5F00_64C74DEF.png" alt="Smile with tongue out" class="wlEmoticon wlEmoticon-smilewithtongueout" style="border-bottom-style:none;border-left-style:none;border-top-style:none;border-right-style:none;" /&gt;), me quedo rato mir&amp;aacute;ndolo a&amp;uacute;n d&amp;iacute;as o semanas despu&amp;eacute;s de haberlo implementado. Esto, adem&amp;aacute;s de parecer que pierdo el tiempo, me&amp;nbsp; ayuda a ver posibles refactoring que en su momento no vi. &lt;/p&gt;
&lt;p&gt;En uno de esos momentos de &amp;ldquo;bober&amp;iacute;a&amp;rdquo; me di cuenta que la interfaz IContainerConfiguration no necesita saber el QulifiedName para nada y que con el tipo era suficiente. Es verdad que de alguna forma debo recuperar el tipo, pero de eso que se encargue quien implemente la interfaz.&lt;/p&gt;
&lt;p&gt;IContainerConfiguration ahora quedar&amp;iacute;a as&amp;iacute;:&lt;/p&gt;
&lt;p&gt;&lt;code class="prettyprint lang-cs"&gt;public interface IContainerConfiguration &lt;br /&gt;{ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Type IocObjectType { get; } &lt;br /&gt;} &lt;br /&gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Despu&amp;eacute;s de hecho el cambio, entramos en materia. &lt;/p&gt;
&lt;p&gt;Pensando con el coraz&amp;oacute;n y no en el performance, voy a utilizar como Framework de inyecci&amp;oacute;n de dependencia el Unity de Microsoft, pero recuerden, de la forma que lo hemos implementado podr&amp;iacute;amos usar cualquiera siempre que implementemos la interfaz IContainer. &lt;/p&gt;
&lt;p&gt;Para temas de configuraci&amp;oacute;n, usar&amp;eacute; el archivo de configuraci&amp;oacute;n de la aplicaci&amp;oacute;n. Al igual que el framework de IoC, podr&amp;iacute;amos obtener la configuraci&amp;oacute;n de cualquier otro lado tan solo implementando las distintas interfaces.&lt;/p&gt;
&lt;p&gt;Empezamos con la implementaci&amp;oacute;n del UnityContainer, nuestro &amp;uacute;nico requerimiento es implementar la interfaz IContainer. &lt;/p&gt;
&lt;code class="prettyprint lang-cs"&gt;
&lt;p&gt;public sealed class UnityContainer : IContainer, IDisposable &lt;br /&gt;{ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; private readonly Microsoft.Practices.Unity.UnityContainer _container;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public UnityContainer() &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _container = new Microsoft.Practices.Unity.UnityContainer(); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; #region Miembros de IContainer&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public void InitializeContainer() &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var section = (UnityConfigurationSection)ConfigurationManager.GetSection(&amp;quot;unity&amp;quot;); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; section.Configure(_container); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// &amp;lt;summary&amp;gt; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// Retorna una nueva instancia del tipo T usando IoC &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// &amp;lt;/summary&amp;gt; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// &amp;lt;typeparam name=&amp;quot;T&amp;quot;&amp;gt;Tipo del nuevo objeto a instanciar&amp;lt;/typeparam&amp;gt; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// &amp;lt;returns&amp;gt;Instancia del tipo generico T&amp;lt;/returns&amp;gt; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public T GetInstanceOf&amp;lt;T&amp;gt;() &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return _container.Resolve&amp;lt;T&amp;gt;(); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// &amp;lt;summary&amp;gt; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// Retorna una nueva instancia del tipo T usando IoC &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// &amp;lt;/summary&amp;gt; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// &amp;lt;typeparam name=&amp;quot;T&amp;quot;&amp;gt;Tipo del nuevo objeto a instanciar&amp;lt;/typeparam&amp;gt; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// &amp;lt;typeparam name=&amp;quot;TParamType&amp;quot;&amp;gt; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// Un par&amp;aacute;metro de tipo TParamType que se le pasa al construnctor de T &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// &amp;lt;/typeparam&amp;gt; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// &amp;lt;returns&amp;gt;Instancia del tipo generico T&amp;lt;/returns&amp;gt; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public T GetInstanceOf&amp;lt;T, TParamType&amp;gt;(TParamType paramInjection) &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _container.RegisterInstance(typeof(TParamType), paramInjection); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return _container.Resolve&amp;lt;T&amp;gt;(); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; #endregion&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; #region Miembros de IDisposable&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// &amp;lt;summary&amp;gt; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// El Objeto UnityContainer del EnterpriseLibrary implementa IDisposable. &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// Al construir una instancia de este objeto dentro de nuestra clase, necesitamos &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// implementar dicha interfaz. &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// &amp;lt;/summary&amp;gt; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public void Dispose() &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _container.Dispose(); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; #endregion &lt;br /&gt;}&lt;/p&gt;
&lt;/code&gt;
&lt;p&gt;La idea no es entrar a analizar el UnityContainer de Microsoft, sino me gusta, uso otro y nada cambia en toda mi aplicaci&amp;oacute;n. De cualquier forma, por detallar un poco la implementaci&amp;oacute;n de la interfaz, vemos la inicializaci&amp;oacute;n de Unity en el m&amp;eacute;todo que provee la interfaz (InitializeContainer), luego usamos el Container para satisfacer los dos m&amp;eacute;todos de la interfaz que retornan una instancia de un objeto basado en su interfaz (con o sin par&amp;aacute;metro) y todo listo.&lt;/p&gt;
&lt;p&gt;&amp;iquest;Hacemos entonces unos Test a ver qu&amp;eacute; tal? Ah no, que no puedo, primero tengo que implementar todo el tema de configuraci&amp;oacute;n. Pues lo que adoro de esta arquitectura es precisamente esto, s&amp;iacute;, tengo que implementar el tema de configuraci&amp;oacute;n, pero como la misma sale de una interfaz, puedo hacerlo sin tener que llegar a implementar todo lo que se refiere al archivo de configuraci&amp;oacute;n. &lt;img src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omarvr/wlEmoticon_2D00_smile_5F00_3D20D1C5.png" alt="Smile" class="wlEmoticon wlEmoticon-smile" style="border-bottom-style:none;border-left-style:none;border-top-style:none;border-right-style:none;" /&gt;&lt;/p&gt;
&lt;code class="prettyprint lang-cs"&gt;
&lt;p&gt;class UnityConfiguration : IContainerConfiguration &lt;br /&gt;{ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; #region Implementation of IContainerConfiguration &lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public Type IocObjectType &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; get { return typeof(Project.IoC.EnterpriseLibrary.UnityContainer); } &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; #endregion &lt;br /&gt;} &lt;/p&gt;
&lt;/code&gt;
&lt;p&gt;Aqu&amp;iacute; implemento la interfaz de configuraci&amp;oacute;n para el IoC y retorno directamente el tipo que implementa el IContainer. (Nota: El tipo UnityContainer que retorno aqu&amp;iacute; no es el de Microsoft, es el m&amp;iacute;o que implementa la interfaz IContainer).&lt;/p&gt;
&lt;p&gt;Voy a crearme unos objetos bien simples para realizar los test &lt;/p&gt;
&lt;code class="prettyprint lang-cs"&gt;
&lt;p&gt;public interface IA &lt;br /&gt;{ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; int ObjectID { get; } &lt;br /&gt;} &lt;/p&gt;
&lt;p&gt;public interface IB &lt;br /&gt;{ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; IA ObjectInjection { get; } &lt;br /&gt;}&lt;/p&gt;
&lt;p&gt;public class A : IA &lt;br /&gt;{ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public A() &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ObjectID = 1; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; #region Implementation of IA&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public int ObjectID { get; private set; }&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; #endregion &lt;br /&gt;}&lt;/p&gt;
&lt;p&gt;public class B : IB &lt;br /&gt;{ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public B(IA paramInjection) &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ObjectInjection = paramInjection; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; #region Implementation of IB&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public IA ObjectInjection { get; private set; }&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; #endregion &lt;br /&gt;}&lt;/p&gt;
&lt;/code&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Configuramos el Unity de Microsft para crear los Alias y los mapeos y vamos por los test. &lt;/p&gt;
&lt;p&gt;&amp;lt;configSections&amp;gt; &lt;br /&gt;&amp;nbsp; &amp;lt;section name=&amp;quot;unity&amp;quot; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; type=&amp;quot;Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Microsoft.Practices.Unity.Configuration&amp;quot; /&amp;gt; &lt;br /&gt;&amp;lt;/configSections&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;unity&amp;gt; &lt;br /&gt;&amp;nbsp; &amp;lt;typeAliases&amp;gt; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;typeAlias alias=&amp;quot;IA&amp;quot; type=&amp;quot;Solution.Test.Infrastructure.IoC.IA, Solution.Test&amp;quot; /&amp;gt; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;typeAlias alias=&amp;quot;IB&amp;quot; type=&amp;quot;Solution.Test.Infrastructure.IoC.IB, Solution.Test&amp;quot; /&amp;gt; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;typeAlias alias=&amp;quot;A&amp;quot; type=&amp;quot;Solution.Test.Infrastructure.IoC.A, Solution.Test&amp;quot; /&amp;gt; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;typeAlias alias=&amp;quot;B&amp;quot; type=&amp;quot;Solution.Test.Infrastructure.IoC.B, Solution.Test&amp;quot; /&amp;gt; &lt;br /&gt;&amp;nbsp; &amp;lt;/typeAliases&amp;gt; &lt;br /&gt;&amp;nbsp; &amp;lt;containers&amp;gt; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;container&amp;gt; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;register type=&amp;quot;IA&amp;quot; mapTo=&amp;quot;A&amp;quot; /&amp;gt; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;register type=&amp;quot;IB&amp;quot; mapTo=&amp;quot;B&amp;quot; /&amp;gt; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/container&amp;gt; &lt;br /&gt;&amp;nbsp; &amp;lt;/containers&amp;gt; &lt;br /&gt;&amp;lt;/unity&amp;gt;&lt;/p&gt;
&lt;p&gt;Los test:&lt;/p&gt;
&lt;code class="prettyprint lang-cs"&gt;
&lt;p&gt;[TestClass] &lt;br /&gt;public class IocTest &lt;br /&gt;{ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; private readonly IContainer _ioc; &lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public IocTest() &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _ioc = new IocFactory().Create(new UnityConfiguration()); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; [TestMethod] &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public void TestCreateObjetWithoutConstructorParameters() &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var a = _ioc.GetInstanceOf&amp;lt;IA&amp;gt;();&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Assert.IsNotNull(a); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Assert.AreEqual(1, a.ObjectID); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; [TestMethod] &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public void TestCreateObjetWithConstructorParameters() &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var a = new A(); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var b = _ioc.GetInstanceOf&amp;lt;IB, IA&amp;gt;(a);&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Assert.IsNotNull(b); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Assert.AreEqual(1, b.ObjectInjection.ObjectID); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;br /&gt;}&lt;/p&gt;
&lt;/code&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omarvr/wlEmoticon_2D00_flirtmale_5F00_4A86E4CB.png" alt="Flirt male" class="wlEmoticon wlEmoticon-flirtmale" style="border-bottom-style:none;border-left-style:none;border-top-style:none;border-right-style:none;" /&gt; Me encanta este momento&amp;hellip; &lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omarvr/test_2D00_ioc_5F00_150E22A6.png"&gt;&lt;img height="175" width="522" src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omarvr/test_2D00_ioc_5F00_thumb_5F00_0F530900.png" alt="test-ioc" border="0" title="test-ioc" style="background-image:none;border-right-width:0px;padding-left:0px;padding-right:0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;padding-top:0px;" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Bien, pasemos del sentimentalismo y la adoraci&amp;oacute;n del color verde del Success &lt;img src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omarvr/wlEmoticon_2D00_openmouthedsmile_5F00_25C5A787.png" alt="Open-mouthed smile" class="wlEmoticon wlEmoticon-openmouthedsmile" style="border-bottom-style:none;border-left-style:none;border-top-style:none;border-right-style:none;" /&gt; y vayamos a la configuraci&amp;oacute;n. La implementaci&amp;oacute;n de la configuraci&amp;oacute;n del framework de IoC desde el archivo de configuraci&amp;oacute;n quedar&amp;iacute;a de la siguiente forma: &lt;/p&gt;
&lt;code class="prettyprint lang-cs"&gt;
&lt;p&gt;public class ContainerConfigurationElement : ConfigurationElement, IContainerConfiguration &lt;br /&gt;{ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; [ConfigurationProperty(&amp;quot;unityType&amp;quot;, IsRequired = true)] &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public string IocQualifiedName &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; get { return (string)this[&amp;quot;unityType&amp;quot;]; } &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; set { this[&amp;quot;unityType&amp;quot;] = value; } &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public Type IocObjectType &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; get { return Type.GetType(IocQualifiedName); } &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;br /&gt;} &lt;/p&gt;
&lt;/code&gt;
&lt;p&gt;Recuerden que ya la propiedad que nos da el QualifiedName no pertenece a la interfaz, sin embargo s&amp;iacute; que la implementamos cuando queremos obtener qui&amp;eacute;n ser&amp;aacute; nuestro&amp;nbsp; Framework de IoC desde la configuraci&amp;oacute;n. &lt;/p&gt;
&lt;p&gt;Hagamos lo mismo para los Settings de mi aplicaci&amp;oacute;n:&lt;/p&gt;
&lt;code class="prettyprint lang-cs"&gt;
&lt;p&gt;public class AppConfigurationElement : ConfigurationElement, IAppConfigurationElement &lt;br /&gt;{ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; #region Implementation of IAppConfigurationElement &lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; [ConfigurationProperty(&amp;quot;name&amp;quot;, IsRequired = true)] &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public string Name &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; get &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return (string)this[&amp;quot;name&amp;quot;]; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; set &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this[&amp;quot;name&amp;quot;] = value; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; [ConfigurationProperty(&amp;quot;datetimeFormat&amp;quot;, IsRequired = false, DefaultValue = null)] &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public string DateTimeFormat &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; get &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var dtFormat = (string)this[&amp;quot;datetimeFormat&amp;quot;] ?? &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; new CultureInfo(LanguageDefault, false).DateTimeFormat.ToString(); &lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return dtFormat; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; set &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this[&amp;quot;datetimeFormat&amp;quot;] = value; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; [ConfigurationProperty(&amp;quot;languageDefault&amp;quot;, IsRequired = true)] &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public string LanguageDefault &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; get &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return (string)this[&amp;quot;languageDefault&amp;quot;]; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; set &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this[&amp;quot;languageDefault&amp;quot;] = value; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; [ConfigurationProperty(&amp;quot;timeZoneOffset&amp;quot;, IsRequired = false, DefaultValue = 0D)] &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public double TimeZoneOffset &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; get &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return (double)this[&amp;quot;timeZoneOffset&amp;quot;]; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; set &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this[&amp;quot;timeZoneOffset&amp;quot;] = value; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; #endregion &lt;br /&gt;}&lt;/p&gt;
&lt;/code&gt;
&lt;p&gt;Ahora ya podemos&amp;nbsp; implementar la interfaz que agrupa los elementos de configuraci&amp;oacute;n.&lt;/p&gt;
&lt;code class="prettyprint lang-cs"&gt;
&lt;p&gt;public class AppConfigurationSection : ConfigurationSection, IAppConfigurationSection &lt;br /&gt;{ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; [ConfigurationProperty(&amp;quot;Setting&amp;quot;)] &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; private AppConfigurationElement ConfigSettings &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; get &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return (AppConfigurationElement)this[&amp;quot;Setting&amp;quot;]; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; set &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this[&amp;quot;Setting&amp;quot;] = value; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; [ConfigurationProperty(&amp;quot;IocConfiguration&amp;quot;)]&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private ContainerConfigurationElement ConfigIocConfiguration &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; get { return (ContainerConfigurationElement)this[&amp;quot;IocConfiguration&amp;quot;]; } &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; set { this[&amp;quot;IocConfiguration&amp;quot;] = value; } &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; #region Implementation of IAppConfigurationSection&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public IContainerConfiguration IocConfiguration &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; get { return ConfigIocConfiguration; } &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; set { ConfigIocConfiguration = (ContainerConfigurationElement) value; } &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public IAppConfigurationElement Settings &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; get { return ConfigSettings; } &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; set { ConfigSettings = (AppConfigurationElement) value; } &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; #endregion &lt;br /&gt;}&lt;/p&gt;
&lt;/code&gt;
&lt;p&gt;Vean que hemos tenido que definir propiedades que retornen un ConfigurationElement. Esto es requerido para poder leer las configuraciones del archivo de configuraci&amp;oacute;n, pero yo en ning&amp;uacute;n momento deseo que esos tipos sean conocidos por mi aplicaci&amp;oacute;n (recuerden que trabajamos ajenos a la tecnolog&amp;iacute;a que usemos). Es por eso que esta clase crea las propiedades concretas para la configuraci&amp;oacute;n como privadas y, las que usar&amp;aacute; mi aplicaci&amp;oacute;n (p&amp;uacute;blicas) retornan la interfaz del tipo creado.&lt;/p&gt;
&lt;p&gt;Por &amp;uacute;ltimo, implementamos IGlobalSettings. Aqu&amp;iacute; me implemento un Singleton a nivel de aplicaci&amp;oacute;n para acceder a mi configuraci&amp;oacute;n. Dos razones, tengo un &amp;uacute;nico punto de acceso (por eso el s&amp;iacute;ngleton) y los datos que guarda mi configuraci&amp;oacute;n no cambian durante todo el ciclo de vida de la aplicaci&amp;oacute;n (por eso digo que es a nivel de aplicaci&amp;oacute;n) &lt;/p&gt;
&lt;code class="prettyprint lang-cs"&gt;
&lt;p&gt;public sealed class Global : IGlobalSettings &lt;br /&gt;{ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// &amp;lt;summary&amp;gt; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// Singleton. Thread safe. &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// &amp;lt;/summary&amp;gt; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; private static readonly Lazy&amp;lt;Global&amp;gt; _instance = new Lazy&amp;lt;Global&amp;gt;(() =&amp;gt; new Global());&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// &amp;lt;summary&amp;gt; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// IocFactory. &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// &amp;lt;/summary&amp;gt; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; private readonly IContainer _ioc;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; private Global() &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var cfg = (IAppConfigurationSection)ConfigurationManager.GetSection(&amp;quot;Project&amp;quot;);&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _ioc = new IocFactory().Create(cfg.IocConfiguration); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Settings = cfg.Settings; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public static Global Application &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; get { return _instance.Value; } &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; #region IAppConfigurationSection Members&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public IContainer Ioc { get { return _ioc; } } &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public IAppConfigurationElement Settings { get; private set; }&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; #endregion &lt;br /&gt;}&lt;/p&gt;
&lt;/code&gt;
&lt;p&gt;Ya podemos ir a por los Test de configuraci&amp;oacute;n. El IoC ya lo probamos, por lo que con saber que el tipo retornado por la configuraci&amp;oacute;n es correcto (implementa IContainer), tengo suficiente &lt;/p&gt;
&lt;p&gt;Antes de escribir los test, creamos la configuraci&amp;oacute;n en el archivo de configuraci&amp;oacute;n de la aplicaci&amp;oacute;n.&lt;/p&gt;
&lt;p&gt;&amp;lt;configSections&amp;gt; &lt;br /&gt;&amp;nbsp; &amp;lt;section name=&amp;quot;Project&amp;quot; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; type=&amp;quot;Project.Settings.Config.AppConfigurationSection, Project.Settings.Config&amp;quot; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; requirePermission=&amp;quot;false&amp;quot; /&amp;gt; &lt;br /&gt;&amp;lt;/configSections&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;Project&amp;gt; &lt;br /&gt;&lt;br /&gt;&amp;nbsp; &amp;lt;Setting name=&amp;quot;My Project DDD&amp;quot; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; languageDefault=&amp;quot;es-ES&amp;quot; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; datetimeFormat=&amp;quot;dd-MM-yyyy HH:mm&amp;quot; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; timeZoneOffset=&amp;quot;1&amp;quot;&amp;nbsp; /&amp;gt; &lt;br /&gt;&lt;br /&gt;&amp;nbsp; &amp;lt;IocConfiguration unityType=&amp;quot;Project.IoC.EnterpriseLibrary.UnityContainer, &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Project.IoC.EnterpriseLibrary&amp;quot; /&amp;gt; &lt;br /&gt;&lt;br /&gt;&amp;lt;/Project&amp;gt;&lt;/p&gt;
&lt;p&gt;y ahora s&amp;iacute;&amp;hellip;&lt;/p&gt;
&lt;code class="prettyprint lang-cs"&gt;
&lt;p&gt;[TestClass] &lt;br /&gt;public class ConfigTest &lt;br /&gt;{&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;[TestMethod] &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public void TestConfiguration() &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var settings = Global.Application.Settings;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Assert.AreEqual(&amp;quot;My Project DDD&amp;quot;, settings.Name); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Assert.AreEqual(&amp;quot;es-ES&amp;quot;, settings.LanguageDefault); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Assert.AreEqual(&amp;quot;dd-MM-yyyy HH:mm&amp;quot;, settings.DateTimeFormat); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Assert.AreEqual(1, settings.TimeZoneOffset); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; [TestMethod] &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public void TestIocConfiguration() &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var ioc = Global.Application.Ioc; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Assert.IsInstanceOfType(ioc, typeof(Project.IoC.EnterpriseLibrary.UnityContainer)); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;br /&gt;}&lt;/p&gt;
&lt;/code&gt;
&lt;p&gt;Result:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omarvr/test_2D00_config_5F00_65235B17.png"&gt;&lt;img height="228" width="497" src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omarvr/test_2D00_config_5F00_thumb_5F00_0E4AF356.png" alt="test-config" border="0" title="test-config" style="background-image:none;border-right-width:0px;padding-left:0px;padding-right:0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;padding-top:0px;" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;y Chirrin-chirran&amp;hellip;. &lt;img src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omarvr/wlEmoticon_2D00_smile_5F00_3D20D1C5.png" alt="Smile" class="wlEmoticon wlEmoticon-smile" style="border-bottom-style:none;border-left-style:none;border-top-style:none;border-right-style:none;" /&gt;&lt;/p&gt;
&lt;/span&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=201779" width="1" height="1"&gt;</description><category domain="http://geeks.ms/blogs/omarvr/archive/tags/POO/default.aspx">POO</category><category domain="http://geeks.ms/blogs/omarvr/archive/tags/arquitectura/default.aspx">arquitectura</category><category domain="http://geeks.ms/blogs/omarvr/archive/tags/NET/default.aspx">NET</category><category domain="http://geeks.ms/blogs/omarvr/archive/tags/DDD/default.aspx">DDD</category><category domain="http://geeks.ms/blogs/omarvr/archive/tags/IoC/default.aspx">IoC</category></item><item><title>DDD: 2- Framework de IoC (parte 1)</title><link>http://geeks.ms/blogs/omarvr/archive/2011/11/19/ddd-2-framework-de-ioc-parte-1.aspx</link><pubDate>Sat, 19 Nov 2011 08:29:00 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:201763</guid><dc:creator>Omar del Valle Rodríguez</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/omarvr/rsscomments.aspx?PostID=201763</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/omarvr/commentapi.aspx?PostID=201763</wfw:comment><comments>http://geeks.ms/blogs/omarvr/archive/2011/11/19/ddd-2-framework-de-ioc-parte-1.aspx#comments</comments><description>&lt;p&gt;&lt;span style="FONT-FAMILY:Calibri;FONT-SIZE:small;"&gt;
&lt;p&gt;&amp;iquest;Por d&amp;oacute;nde empezamos hoy? Pues si conocemos de antemano la arquitectura DDD, sabremos que uno de los aspectos m&amp;aacute;s importante en su implementaci&amp;oacute;n es la inyecci&amp;oacute;n de dependencia. &lt;/p&gt;
&lt;p&gt;El concepto de aplicaciones orientadas al dominio explica claramente que debemos aislar la l&amp;oacute;gica del dominio de cualquier tipo de detalle t&amp;eacute;cnico.&lt;/p&gt;
&lt;p&gt;La &amp;ldquo;Gu&amp;iacute;a de arquitectura N-capas orientada al dominio&amp;rdquo; nos dice&amp;hellip;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&amp;ldquo;Esta capa debe ser responsable de representar conceptos de negocio, informaci&amp;oacute;n sobre la situaci&amp;oacute;n de los procesos de negocio e implementaci&amp;oacute;n de las reglas del dominio. Tambi&amp;eacute;n debe contener los estados que refleja n la situaci&amp;oacute;n de los procesos de negocio, aun cuando los detalles t&amp;eacute;cnicos se delegan a las capas inferiores&amp;hellip;.&amp;rdquo;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Resumiendo un poco, el dominio debe saber &amp;ldquo;Qu&amp;eacute;&amp;rdquo; se hace, pero nunca &amp;ldquo;C&amp;oacute;mo&amp;rdquo; se hace&amp;hellip;&lt;/p&gt;
&lt;p&gt;Por otro lado, el concepto de una interfaz es un contrato que indica lo que se debe hacer, pero nunca incluye c&amp;oacute;digo de c&amp;oacute;mo se debe hacer&amp;hellip; De aqu&amp;iacute;, que la forma de aislar el dominio en una arquitectura DDD de su implementaci&amp;oacute;n, sea mediante interfaces.&lt;/p&gt;
&lt;p&gt;La importancia de la inyecci&amp;oacute;n de dependencia en este tipo de arquitectura es precisamente esta, inyectar instancias de objetos que saben &amp;ldquo;c&amp;oacute;mo&amp;rdquo; hacer algo mediante interfaces que indican &amp;ldquo;qu&amp;eacute;&amp;rdquo; se debe hacer.&amp;nbsp; Es l&amp;oacute;gico que los objetos que se inyecten deban implementar la interfaz, pero si no lo hacen ya se encargar&amp;aacute; el framework de avisarnos con un ruidoso error. &lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omarvr/4_5F00_3.gif"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/omarvr/4_5F00_3.gif" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Para usar inyecci&amp;oacute;n de dependencia existen muchos frameworks. Algunos de ellos son:&lt;/p&gt;
&lt;p&gt;-&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Ninject&lt;br /&gt;-&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Unity &lt;br /&gt;-&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Castle.Windsor&lt;br /&gt;-&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Autofac&lt;br /&gt;-&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; StructureMap&lt;/p&gt;
&lt;p&gt;Aqu&amp;iacute; encontraras un buen debate sobre cu&amp;aacute;l es mejor o peor o cu&amp;aacute;les son sus ventajas o desventajas.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://stackoverflow.com/questions/4581791/how-do-the-major-c-sharp-di-ioc-frameworks-compare"&gt;http://stackoverflow.com/questions/4581791/how-do-the-major-c-sharp-di-ioc-frameworks-compare&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A m&amp;iacute; en esta parte siempre me entra la duda, si hablamos de un dominio que no es afectado por los detalles t&amp;eacute;cnicos entonces, &amp;iquest;deber&amp;iacute;a preocuparme por saber cu&amp;aacute;l debe ser el Framework que usar&amp;eacute; para inyectar dependencias? Bueno, tampoco pasemos ol&amp;iacute;mpicamente de esto, claro que deb&amp;iacute;a preocuparme por temas de performance&amp;hellip; pero estos frameworks evolucionan y el que es mejor hoy, ma&amp;ntilde;ana puede ser peor.&lt;/p&gt;
&lt;p&gt;&amp;iquest;Qu&amp;eacute; hago entonces? &amp;iquest;Pues no les gustar&amp;iacute;a poder inyectar a quien te inyecta? &amp;iquest;Nunca han querido pagar con la misma moneda?&amp;nbsp; Yo decid&amp;iacute; inyectar el framework de inyecci&amp;oacute;n&amp;hellip; &lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omarvr/imagesCAAD8XIG.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/omarvr/imagesCAAD8XIG.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;De lo que hemos visto, el objetivo para m&amp;iacute; de un Framework de inyecci&amp;oacute;n de dependencia es precisamente retornarme una instancia de un objeto mediante su interfaz. Entonces, lo que necesito ser&amp;iacute;a algo como esto:&lt;/p&gt;
&lt;p&gt;&lt;code class="prettyprint lang-cs"&gt;public interface IContainer &lt;br /&gt;{ &lt;br /&gt;&amp;nbsp; void InitializeContainer(); &lt;br /&gt;&amp;nbsp; T GetInstanceOf&amp;lt;T&amp;gt;(); &lt;br /&gt;&amp;nbsp; T GetInstanceOf&amp;lt;T, TParamType&amp;gt;(TParamType paramInjection); &lt;br /&gt;} &lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Ahora necesito alg&amp;uacute;n elemento de configuraci&amp;oacute;n que me indique c&amp;oacute;mo instanciar mi framework de IoC. &amp;iquest;De d&amp;oacute;nde sale la configuraci&amp;oacute;n? Pues no lo s&amp;eacute;, lo que realmente me importa es su contrato, no c&amp;oacute;mo lo haga. La interfaz para la configuraci&amp;oacute;n contiene una propiedad que me retorna el QualifiedName usado para crear el tipo concreto del framework de IoC.&lt;/p&gt;
&lt;p&gt;&lt;code class="prettyprint lang-cs"&gt;public interface IContainerConfiguration &lt;br /&gt;{ &lt;br /&gt;&amp;nbsp; string IocQualifiedName { get; set; } &lt;br /&gt;&amp;nbsp; Type IocObjectType { get; } &lt;br /&gt;} &lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Para combinar el Container con su configuraci&amp;oacute;n nos implementamos un Factory:&lt;/p&gt;
&lt;p&gt;
&lt;div&gt;&lt;code class="prettyprint lang-cs"&gt;public sealed class IocFactory &lt;br /&gt;{ &lt;br /&gt;&amp;nbsp; public IContainer Create(IContainerConfiguration cfg) &lt;br /&gt;&amp;nbsp; { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; var container = (IContainer)Activator.CreateInstance(cfg.IocObjectType);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; container.InitializeContainer(); &lt;/code&gt;&lt;/div&gt;
&lt;/p&gt;
&lt;code class="prettyprint lang-cs"&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return container;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;} &lt;br /&gt;} &lt;/p&gt;
&lt;/code&gt;
&lt;p&gt;Hasta aqu&amp;iacute; ya tenemos definidas las interfaces&amp;hellip;&amp;nbsp; pero &amp;iquest;qui&amp;eacute;n implementa estas interfaces? y lo m&amp;aacute;s importante, &amp;iquest;c&amp;oacute;mo se usar&amp;iacute;a al final?&lt;/p&gt;
&lt;p&gt;Cada aplicaci&amp;oacute;n que hago, &amp;ldquo;deber&amp;iacute;a&amp;rdquo; tener aspectos que son generales a nivel de toda la aplicaci&amp;oacute;n. Me refiero a par&amp;aacute;metros c&amp;oacute;mo:&lt;/p&gt;
&lt;p&gt;-&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Formato de fecha que usar&amp;eacute; por defecto&lt;br /&gt;-&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Idioma que usar&amp;eacute; por defecto&lt;br /&gt;-&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Zona horaria en que se encuentra la aplicaci&amp;oacute;n&lt;/p&gt;
&lt;p&gt;Estos par&amp;aacute;metros son un poco a mi gusto personal, quiero olvidarme de si el formato de fecha/Hora tiene que ser o no independiente al idioma o si el servidor donde hospedo la aplicaci&amp;oacute;n est&amp;aacute; en Am&amp;eacute;rica o el viejo continente, por eso predefino este tipo de datos. A estos par&amp;aacute;metros se suma ahora mi Framework de IoC, que tambi&amp;eacute;n ser&amp;aacute; de uso general por toda la aplicaci&amp;oacute;n.&lt;/p&gt;
&lt;p&gt;C&amp;oacute;mo hemos repetido durante todo el art&amp;iacute;culo, en este punto no s&amp;eacute; de d&amp;oacute;nde saldr&amp;aacute; esta informaci&amp;oacute;n. A algunos les ser&amp;aacute; m&amp;aacute;s &amp;uacute;til sacarlo de base de datos y a otros del archivo de configuraci&amp;oacute;n de la aplicaci&amp;oacute;n, as&amp;iacute; que sigo creando interfaces. &lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omarvr/1_5F00_45.gif"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/omarvr/1_5F00_45.gif" border="0" alt="" /&gt;&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;code class="prettyprint lang-cs"&gt;public interface IAppConfigurationElement &lt;br /&gt;{ &lt;br /&gt;&amp;nbsp; string Name { get; set; } &lt;br /&gt;&amp;nbsp; string DateTimeFormat { get; set; } &lt;br /&gt;&amp;nbsp; string LanguageDefault { get; set; } &lt;br /&gt;&amp;nbsp; double TimeZoneOffset { get; set; } &lt;br /&gt;} &lt;/code&gt;
&lt;p&gt;Esta interfaz define los par&amp;aacute;metros generales de mi aplicaci&amp;oacute;n. En la siguiente interfaz, combinamos estos par&amp;aacute;metros de configuraci&amp;oacute;n con la interfaz de IoC.&lt;/p&gt;
&lt;p&gt;&lt;code class="prettyprint lang-cs"&gt;public interface IAppConfigurationSection &lt;br /&gt;{ &lt;br /&gt;&amp;nbsp; IAppConfigurationElement Parameters { get; set; } &lt;br /&gt;&amp;nbsp; IContainerConfiguration Ioc { get; set; } &lt;br /&gt;}&amp;nbsp; &lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Finalmente combinamos las interfaces que dar&amp;aacute;n a nuestra aplicaci&amp;oacute;n los par&amp;aacute;metros que hemos definido y el Framework de IoC que usaremos&lt;/p&gt;
&lt;p&gt;&lt;code class="prettyprint lang-cs"&gt;public interface IGlobalSettings &lt;br /&gt;{ &lt;br /&gt;&amp;nbsp; IContainer Ioc { get; } &lt;br /&gt;&amp;nbsp; IAppConfigurationElement Parameters { get; } &lt;br /&gt;} &lt;/code&gt;&lt;/p&gt;
&lt;/p&gt;
&lt;p&gt;Con esto mejor cerramos el art&amp;iacute;culo de hoy, creo que me he pasado de largo&amp;nbsp;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omarvr/3_5F00_6.gif"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/omarvr/3_5F00_6.gif" border="0" alt="" /&gt;&lt;/a&gt; as&amp;iacute; que dejamos la implementaci&amp;oacute;n y los test para otro d&amp;iacute;a&amp;hellip;&lt;/p&gt;
&lt;p&gt;
&lt;p&gt;&amp;nbsp;Hasta la pr&amp;oacute;xima... &lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;/p&gt;
&lt;/span&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=201763" width="1" height="1"&gt;</description><category domain="http://geeks.ms/blogs/omarvr/archive/tags/POO/default.aspx">POO</category><category domain="http://geeks.ms/blogs/omarvr/archive/tags/arquitectura/default.aspx">arquitectura</category><category domain="http://geeks.ms/blogs/omarvr/archive/tags/DDD/default.aspx">DDD</category><category domain="http://geeks.ms/blogs/omarvr/archive/tags/IoC/default.aspx">IoC</category></item><item><title>DDD: 1- Introducción a un esquema genérico…</title><link>http://geeks.ms/blogs/omarvr/archive/2011/11/14/ddd-1-introducci-243-n-a-un-esquema-gen-233-rico.aspx</link><pubDate>Mon, 14 Nov 2011 08:22:00 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:201685</guid><dc:creator>Omar del Valle Rodríguez</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/omarvr/rsscomments.aspx?PostID=201685</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/omarvr/commentapi.aspx?PostID=201685</wfw:comment><comments>http://geeks.ms/blogs/omarvr/archive/2011/11/14/ddd-1-introducci-243-n-a-un-esquema-gen-233-rico.aspx#comments</comments><description>&lt;p class="MsoNormal"&gt;&lt;span lang="ES" style="mso-ansi-language:ES;"&gt;&lt;span style="font-family:Calibri;"&gt;&lt;span style="font-size:small;"&gt;Me ha costado trabajo decidirme, hay tantos ejemplos de aplicaciones con arquitectura DDD publicados en internet en el que cada uno desarrolla un esquema distinto que uno se piensa una y otra vez si lo que est&amp;aacute; haciendo estar&amp;aacute; bien o ser&amp;aacute; un simple disparate. &lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omarvr/9u3y44.png"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/omarvr/9u3y44.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES" style="mso-ansi-language:ES;"&gt;&lt;span style="font-family:Calibri;"&gt;&lt;span style="font-size:small;"&gt;Partiendo de esta duda, el objetivo de esta serie no es crear una gu&amp;iacute;a para orquestar una arquitectura DDD, ni siquiera pretendo que sea un modelo a seguir. Mi objetivo es m&amp;aacute;s bien ir compartiendo por aqu&amp;iacute; las cosas que se me van ocurriendo y de ser posible, generar un debate que nos ayude a todos a tener puntos de vista diferentes.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span style="font-size:small;"&gt;&lt;span lang="ES" style="mso-ansi-language:ES;"&gt;&lt;span style="font-family:Calibri;"&gt;Sin m&amp;aacute;s, empiezo por donde se empieza cualquier arquitectura&amp;nbsp;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omarvr/3_5F00_6.gif"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/omarvr/3_5F00_6.gif" border="0" alt="" /&gt;&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;span lang="ES" style="mso-ansi-language:ES;"&gt;&lt;span style="font-family:Calibri;"&gt; El diagrama de capas:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span style="font-size:small;"&gt;&lt;span lang="ES" style="mso-ansi-language:ES;"&gt;&lt;span style="font-family:Calibri;"&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omarvr/DDD.layers.png"&gt;&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES" style="mso-ansi-language:ES;"&gt;&lt;span style="font-size:small;"&gt;&lt;span style="font-family:Calibri;"&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omarvr/Untitled.png"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/omarvr/Untitled.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES" style="mso-ansi-language:ES;"&gt;&lt;span style="font-size:small;"&gt;&lt;span style="font-family:Calibri;"&gt;Esta parte es la que casi siempre tengo clara&amp;hellip; La distribuci&amp;oacute;n de las capas en Dominio, Aplicaci&amp;oacute;n, Infraestructura, la capa de servicios WCF (opcional) y las interfaces de usuario, cada una con su flujo de informaci&amp;oacute;n.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES" style="mso-ansi-language:ES;"&gt;&lt;span style="font-size:small;"&gt;&lt;span style="font-family:Calibri;"&gt;No quiero entrar a analizar qu&amp;eacute; va dentro de cada capa porque precisamente la idea es ir comentando el desarrollo que vayamos realizando paso a paso. Solo aclarar que en muchas arquitecturas DDD, puede existir un flujo de informaci&amp;oacute;n entre la interfaz de usuario y el dominio. &lt;span style="mso-spacerun:yes;"&gt;&amp;nbsp;&lt;/span&gt;Este flujo se ve en muchas arquitecturas que muestran inyecci&amp;oacute;n de dependencia de los repositorios dentro de los controladores de un proyecto MVC (incluso ASP.NET MVC est&amp;aacute; preparado para inyectar dependencias a los controladores). En este caso, no vamos a tener ese flujo y es por eso que no lo represento. &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES" style="mso-ansi-language:ES;"&gt;&lt;span style="font-size:small;"&gt;&lt;span style="font-family:Calibri;"&gt;&amp;iquest;Por qu&amp;eacute;? &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span lang="ES" style="mso-ansi-language:ES;"&gt;&lt;span style="font-size:small;"&gt;&lt;span style="font-family:Calibri;"&gt;Hoy en d&amp;iacute;a es poco habitual que desarrollemos una sola aplicaci&amp;oacute;n, normalmente nuestros proyectos requieren que para un mismo dominio tengamos varios frentes por el que lo atacamos (UI para m&amp;oacute;viles, UI para desktop, servicios que expongan funcionalidad a terceros, etc.). Con el objetivo de centralizar la l&amp;oacute;gica de aplicaci&amp;oacute;n (servicios en la capa aplicaci&amp;oacute;n) y permitir la reutilizaci&amp;oacute;n de c&amp;oacute;digo, es que ninguna interfaz de usuario llega al dominio si no es mediante la capa de aplicaci&amp;oacute;n. &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES" style="mso-ansi-language:ES;"&gt;&lt;span style="font-size:small;"&gt;&lt;span style="font-family:Calibri;"&gt;En Visual Studio cada capa est&amp;aacute; definida como un &amp;ldquo;&lt;strong&gt;Solution Folder&lt;/strong&gt;&amp;rdquo;, por lo que la estructura de mi arquitectura queda m&amp;aacute;s o menos as&amp;iacute;&amp;hellip;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omarvr/DDD_2D00_Projects.png"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/omarvr/DDD_2D00_Projects.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES" style="mso-ansi-language:ES;"&gt;&lt;span style="font-size:small;"&gt;&lt;span style="font-family:Calibri;"&gt;Creo que se ve que existen 12 proyectos dentro de la soluci&amp;oacute;n, por lo que el desarrollo va mucho m&amp;aacute;s adelantado que esta serie de art&amp;iacute;culos. Espero a medida de que el tiempo me lo permita, ir poni&amp;eacute;ndome al d&amp;iacute;a&amp;hellip;&amp;nbsp;&amp;nbsp;pero sobre todo,&amp;nbsp;espero que se diviertan tanto como yo... &lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omarvr/1_5F00_45.gif"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/omarvr/1_5F00_45.gif" border="0" alt="" /&gt;&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES" style="mso-ansi-language:ES;"&gt;&lt;span style="font-size:small;"&gt;&lt;span style="font-family:Calibri;"&gt;Salu2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=201685" width="1" height="1"&gt;</description><category domain="http://geeks.ms/blogs/omarvr/archive/tags/patrones+dise_26002300_241_3B00_o+ORM+herencia+arquitectura/default.aspx">patrones dise&amp;#241;o ORM herencia arquitectura</category><category domain="http://geeks.ms/blogs/omarvr/archive/tags/POO/default.aspx">POO</category><category domain="http://geeks.ms/blogs/omarvr/archive/tags/arquitectura/default.aspx">arquitectura</category><category domain="http://geeks.ms/blogs/omarvr/archive/tags/NET/default.aspx">NET</category><category domain="http://geeks.ms/blogs/omarvr/archive/tags/ORM/default.aspx">ORM</category></item><item><title>Es la hora del cambio…</title><link>http://geeks.ms/blogs/omarvr/archive/2011/11/08/es-la-hora-del-cambio.aspx</link><pubDate>Tue, 08 Nov 2011 09:53:00 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:201585</guid><dc:creator>Omar del Valle Rodríguez</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/omarvr/rsscomments.aspx?PostID=201585</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/omarvr/commentapi.aspx?PostID=201585</wfw:comment><comments>http://geeks.ms/blogs/omarvr/archive/2011/11/08/es-la-hora-del-cambio.aspx#comments</comments><description>&lt;p class="MsoNormal"&gt;&lt;span lang="ES" style="mso-ansi-language:ES;"&gt;&lt;span style="font-size:small;"&gt;&lt;span style="font-family:Calibri;"&gt;Primero que todo disculparme si alguien entra en este post pensando que voy a hablar de pol&amp;iacute;tica :P siento que no sea as&amp;iacute;. Ya me sobra con el rega&amp;ntilde;o que me dieron ayer por decir que &amp;ldquo;insidiar&amp;rdquo; era un verbo. ;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES" style="mso-ansi-language:ES;"&gt;&lt;span style="font-size:small;"&gt;&lt;span style="font-family:Calibri;"&gt;Entrando en la materia que nos ocupa&amp;hellip; Muchas veces cuando escuchamos hablar de arquitecturas del tipo DDD, TDD o N capas orientadas al dominio pensamos que todo eso es cosa de unos cuantos frikis que se pasan el d&amp;iacute;a sin nada que hacer e intentando complicarnos la vida y, nada m&amp;aacute;s lejos de la realidad. La arquitectura de un proyecto puede muchas veces llevarnos a escribir un mal c&amp;oacute;digo.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES" style="mso-ansi-language:ES;"&gt;&lt;span style="font-size:small;"&gt;&lt;span style="font-family:Calibri;"&gt;Ayer a un colega le pas&amp;oacute; algo curioso respecto a eso. Introducir una arquitectura orientada al dominio en un grupo de trabajo con apenas experiencia es complicado, la curva de aprendizaje cuando se parte de cero es realmente alta y son muchos los conceptos y paradigmas que nos vemos obligados a cambiar. Entidades, DTO, Inversi&amp;oacute;n de control, Inyecci&amp;oacute;n de dependencias, etc&amp;hellip; todo esto puede ocasionar un retraso en el proyecto que nadie est&amp;aacute; de acuerdo&amp;nbsp;en asumir.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES" style="mso-ansi-language:ES;"&gt;&lt;span style="font-size:small;"&gt;&lt;span style="font-family:Calibri;"&gt;Para evitar todo esto, dise&amp;ntilde;&amp;oacute; una arquitectura N capas de toda la vida con posibilidades de dividirla en niveles, pero a su vez fue insertando conceptos como: Dominio, entidades, DTO, capas, niveles, servicios del dominio, repositorios, etc. toda una base que&amp;nbsp;le permitiera en un momento dado, dar el cambio definitivo a arquitecturas verdaderamente orientadas al dominio.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES" style="mso-ansi-language:ES;"&gt;&lt;span style="font-size:small;"&gt;&lt;span style="font-family:Calibri;"&gt;Ayer se le present&amp;oacute; una problem&amp;aacute;tica, necesitaba mandar a encender desde un panel de administraci&amp;oacute;n un conjunto de dispositivos por un tiempo determinado. Ya ten&amp;iacute;a funcionando toda la l&amp;oacute;gica de encendido y solo deb&amp;iacute;a insertar el nuevo requerimiento de definir el tiempo que dicho dispositivo iba a permanecer encendido.&lt;span style="mso-no-proof:yes;"&gt; &lt;span style="mso-spacerun:yes;"&gt;&amp;nbsp;&lt;/span&gt;La secuencia para encender dispositivos era la siguiente:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omarvr/antes.png"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/omarvr/antes.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES" style="mso-ansi-language:ES;"&gt;&lt;span style="font-size:small;"&gt;&lt;span style="font-family:Calibri;"&gt;Con el nuevo requerimiento la secuencia qued&amp;oacute; de la siguiente manera:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES" style="mso-ansi-language:ES;"&gt;&lt;span style="font-size:small;"&gt;&lt;span style="font-family:Calibri;"&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omarvr/despues.png"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/omarvr/despues.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES" style="mso-ansi-language:ES;"&gt;&lt;span style="font-size:small;"&gt;&lt;span style="font-family:Calibri;"&gt;La soluci&amp;oacute;n dada no me gust&amp;oacute; porque rompe con la naturaleza propia del m&amp;eacute;todo, se est&amp;aacute; actualizando estados en un m&amp;eacute;todo destinado a seleccionar. Esto evita que dicho m&amp;eacute;todo pueda ser reutilizado para lo que fue pensado, traer un listado de dispositivos.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span lang="ES" style="line-height:115%;font-family:&amp;#39;Calibri&amp;#39;,&amp;#39;sans-serif&amp;#39;;font-size:11pt;mso-ansi-language:ES;mso-ascii-theme-font:minor-latin;mso-fareast-font-family:Calibri;mso-fareast-theme-font:minor-latin;mso-hansi-theme-font:minor-latin;mso-bidi-font-family:&amp;#39;Times New Roman&amp;#39;;mso-bidi-theme-font:minor-bidi;mso-fareast-language:EN-US;mso-bidi-language:AR-SA;"&gt;Cuando le dije c&amp;oacute;mo lo hubiera hecho yo, el diagrama de secuencia qued&amp;oacute; de la siguiente forma:&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span lang="ES" style="line-height:115%;font-family:&amp;#39;Calibri&amp;#39;,&amp;#39;sans-serif&amp;#39;;font-size:11pt;mso-ansi-language:ES;mso-ascii-theme-font:minor-latin;mso-fareast-font-family:Calibri;mso-fareast-theme-font:minor-latin;mso-hansi-theme-font:minor-latin;mso-bidi-font-family:&amp;#39;Times New Roman&amp;#39;;mso-bidi-theme-font:minor-bidi;mso-fareast-language:EN-US;mso-bidi-language:AR-SA;"&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omarvr/propuesta.png"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/omarvr/propuesta.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES" style="mso-ansi-language:ES;"&gt;&lt;span style="font-size:small;"&gt;&lt;span style="font-family:Calibri;"&gt;Ummm&amp;hellip; &amp;iquest;Qu&amp;eacute; pasa aqu&amp;iacute;? Yo viajo al dominio mediante los servicios WCF dos veces para realizar una acci&amp;oacute;n. Al final, &amp;eacute;l pens&amp;oacute; una soluci&amp;oacute;n que desde el punto de vista de arquitectura est&amp;aacute; mal, pero es mucho m&amp;aacute;s eficiente que la m&amp;iacute;a.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES" style="mso-ansi-language:ES;"&gt;&lt;span style="font-size:small;"&gt;&lt;span style="font-family:Calibri;"&gt;&amp;iquest;Por qu&amp;eacute; nos pasa esto? Si miramos el &amp;uacute;ltimo diagrama de secuencia vemos como si algo faltara en la arquitectura que permita hacerlo bien y adem&amp;aacute;s que sea eficiente. Si me llevo esto a DDD &amp;iquest;c&amp;oacute;mo queda?&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES" style="mso-ansi-language:ES;"&gt;&lt;span style="font-size:small;"&gt;&lt;span style="font-family:Calibri;"&gt;Diagrama de secuencia:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omarvr/DDD.png"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/omarvr/DDD.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES" style="mso-ansi-language:ES;"&gt;&lt;span style="font-family:Calibri;"&gt;&lt;span style="font-size:small;"&gt;Feliz y contento&amp;hellip; toda la l&amp;oacute;gica que estaba en el UI ahora pasa a mi capa de aplicaci&amp;oacute;n, por lo que solo viajar&amp;iacute;a una vez por la capa de servicios WCF y todo lo que est&amp;aacute; dentro del ApplicationLayer, podr&amp;iacute;a ser reutilizado desde otros UI.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span style="font-size:small;"&gt;&lt;span lang="ES" style="mso-ansi-language:ES;"&gt;&lt;span style="font-family:Calibri;"&gt;Nada, que llegamos a la conclusi&amp;oacute;n que&amp;hellip; es la hora del cambio &lt;/span&gt;&lt;/span&gt;&lt;span lang="ES" style="font-family:Wingdings;mso-ansi-language:ES;mso-ascii-theme-font:minor-latin;mso-hansi-theme-font:minor-latin;mso-ascii-font-family:Calibri;mso-hansi-font-family:Calibri;mso-char-type:symbol;mso-symbol-font-family:Wingdings;"&gt;&lt;span style="mso-char-type:symbol;mso-symbol-font-family:Wingdings;"&gt;J&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span lang="ES" style="mso-ansi-language:ES;"&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Salu2&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=201585" width="1" height="1"&gt;</description><category domain="http://geeks.ms/blogs/omarvr/archive/tags/POO/default.aspx">POO</category><category domain="http://geeks.ms/blogs/omarvr/archive/tags/arquitectura/default.aspx">arquitectura</category><category domain="http://geeks.ms/blogs/omarvr/archive/tags/NET/default.aspx">NET</category></item><item><title>El Daily Stand-Ups (Scrum) ¿Insuficiente?</title><link>http://geeks.ms/blogs/omarvr/archive/2011/11/03/el-daily-stand-ups-scrum-191-insuficiente.aspx</link><pubDate>Thu, 03 Nov 2011 08:27:00 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:201503</guid><dc:creator>Omar del Valle Rodríguez</dc:creator><slash:comments>4</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/omarvr/rsscomments.aspx?PostID=201503</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/omarvr/commentapi.aspx?PostID=201503</wfw:comment><comments>http://geeks.ms/blogs/omarvr/archive/2011/11/03/el-daily-stand-ups-scrum-191-insuficiente.aspx#comments</comments><description>&lt;p class="MsoNormal"&gt;&lt;span lang="ES" style="mso-ansi-language:ES;"&gt;&lt;span style="font-size:small;"&gt;&lt;span style="font-family:Calibri;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES" style="mso-ansi-language:ES;"&gt;&lt;span style="font-size:small;"&gt;&lt;span style="font-family:Calibri;"&gt;En el proyecto en el que me encuentro actualmente (equipo de 4 personas) hemos logrado poner en pr&amp;aacute;ctica toda la teor&amp;iacute;a conocida sobre SCRUM. Algunas aplicadas 100% seg&amp;uacute;n la documentaci&amp;oacute;n, otras, adaptadas a los requerimientos del proyecto en s&amp;iacute;.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES" style="mso-ansi-language:ES;"&gt;&lt;span style="font-size:small;"&gt;&lt;span style="font-family:Calibri;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span lang="ES" style="mso-ansi-language:ES;"&gt;&lt;span style="font-size:small;"&gt;&lt;span style="font-family:Calibri;"&gt;Esto no es nuevo, todos sabemos que la gu&amp;iacute;a para el desarrollo &amp;aacute;gil existe, podemos aprender y usar de ella todo lo que ense&amp;ntilde;a, pero al final&amp;hellip; cada proyecto es un libro aparte que se escribe a su forma y bajo sus propios requerimientos.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES" style="mso-ansi-language:ES;"&gt;&lt;span style="font-size:small;"&gt;&lt;span style="font-family:Calibri;"&gt;Uno de los puntos que no puede faltar (adaptado o no) en un desarrollo &amp;aacute;gil es el Daily Stand-Ups. Esas reuniones de 15 minutos en las que intercambiamos qu&amp;eacute; hacemos, qu&amp;eacute; hemos hecho y qu&amp;eacute; problemas tenemos.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES" style="mso-ansi-language:ES;"&gt;&lt;span style="font-size:small;"&gt;&lt;span style="font-family:Calibri;"&gt;Este tipo de reuni&amp;oacute;n est&amp;aacute; definida en el desarrollo SCRUM de la siguiente manera:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES" style="mso-ansi-language:ES;"&gt;&lt;span style="font-size:small;"&gt;&lt;span style="font-family:Calibri;"&gt;&lt;strong&gt;Daily Stand-Ups (Scrums)&lt;/strong&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES" style="mso-ansi-language:ES;"&gt;&lt;span style="font-size:small;"&gt;&lt;span style="font-family:Calibri;"&gt;During a sprint, the team, the ScrumMaster, &lt;span style="text-decoration:line-through;"&gt;and the product owner&lt;/span&gt; (mejor no invitarle a todas :P ) commit to meeting once daily in the same place and at the same time to discuss any issues that are preventing work from being done. Meetings are held with everyone standing and time boxed to no longer than 15 minutes. Anyone interested is invited to attend these meetings; however, only the people classified as Pigs are allowed to speak at these meetings.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES" style="mso-ansi-language:ES;"&gt;&lt;span style="font-size:small;"&gt;&lt;span style="font-family:Calibri;"&gt;&amp;nbsp;At the meeting, each team member answers the following three questions:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES" style="mso-ansi-language:ES;"&gt;&lt;span style="font-size:small;"&gt;&lt;span style="font-family:Calibri;"&gt;&amp;bull; What have you done since yesterday?&lt;br /&gt;&amp;bull; What are you planning to do today?&lt;br /&gt;&amp;bull; Do you have any problems preventing you from accomplishing your goal? What progress has been made on existing impediments? Can the blockage be removed or must it be escalated? (The ScrumMaster looks after this area.)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span lang="ES" style="mso-ansi-language:ES;"&gt;&lt;span style="font-size:small;"&gt;&lt;span style="font-family:Calibri;"&gt;
&lt;p class="MsoNormal"&gt;La aplicaci&amp;oacute;n de este tipo de reuniones dentro de un proyecto crea un entorno de trabajo sumamente favorable. Todos conocemos qu&amp;eacute; ha hecho o qu&amp;eacute; est&amp;aacute; haciendo cada miembro del equipo, todos aportamos soluci&amp;oacute;n a los posibles problemas y todos estamos capacitados en un momento dado de asumir una tarea determinada. Los cuellos de botella en un entorno as&amp;iacute;, son detectados muy pronto y permite a su vez, darle una pronta soluci&amp;oacute;n.&lt;/p&gt;
&lt;p class="MsoNormal"&gt;A grandes rasgos, el problema sobre qu&amp;eacute; hace cada miembro del equipo estaba resuelto. Todos &amp;eacute;ramos capaces, sin p&amp;eacute;rdida alguna de tiempo, de asumir o colaborar con la tarea de otro. Pero&amp;hellip; (&lt;strong&gt;&lt;em&gt;Grrrrrr!!!... siempre hay peros&lt;/em&gt;&lt;/strong&gt;) &lt;/p&gt;
&lt;p class="MsoNormal"&gt;Nos dimos cuenta que algo m&amp;aacute;s detallado se nos estaba escapando. Cada tarea asignada a un miembro del equipo normalmente est&amp;aacute; compuesta por Bugs, Tasks, o Issues. La soluci&amp;oacute;n a nivel de c&amp;oacute;digo que se daba a cada elemento muchas veces no contaba con la calidad suficiente, o simplemente no se aplicaba una soluci&amp;oacute;n que pudiera ser reutilizable. A este nivel de detalle en los Daily Stand-ups, no lleg&amp;aacute;bamos.&lt;/p&gt;
&lt;p class="MsoNormal"&gt;Una primera soluci&amp;oacute;n fue enviarnos un correo al final del d&amp;iacute;a en el que cada uno cont&amp;aacute;bamos&amp;nbsp; qu&amp;eacute; hab&amp;iacute;a hecho (a nivel de Bugs, Tasks o Issues) hablando un poco de la soluci&amp;oacute;n implementada en cada caso, pero ( y m&amp;aacute;s peros&amp;hellip;) Somos inform&amp;aacute;ticos, odiamos trabajar de m&amp;aacute;s :D&amp;nbsp; y, escribir este correo a final del d&amp;iacute;a iba a terminar perdi&amp;eacute;ndose.&amp;nbsp; &lt;/p&gt;
&lt;p class="MsoNormal"&gt;Pensando un poco en el correo y la informaci&amp;oacute;n que recog&amp;iacute;amos nos dimos cuenta que esto al final era lo mismo que mirar toda la actividad realizada durante el d&amp;iacute;a en el TFS (Team Fundation Server) &amp;iquest;Por qu&amp;eacute; entonces no preguntarle al TFS lo que cada miembro del equipo hab&amp;iacute;a hecho durante el d&amp;iacute;a? Incluso, &amp;iquest;Por qu&amp;eacute; no preguntarle al TFS lo que hab&amp;iacute;a hecho por s&amp;iacute; solo durante el d&amp;iacute;a? (Builds de integraci&amp;oacute;n continua fallidos, Works Items creados, etc.)&lt;/p&gt;
&lt;p class="MsoNormal"&gt;Si pudi&amp;eacute;ramos tener acceso al TFS desde internet, la soluci&amp;oacute;n hubiera sido m&amp;aacute;s simple, pero en la mayor&amp;iacute;a de los casos esto no es as&amp;iacute;. Al final, desarrollamos una tarea que recoge toda la informaci&amp;oacute;n del TFS realizada en el d&amp;iacute;a y nos env&amp;iacute;a&amp;nbsp;un resumen por correo :)&lt;/p&gt;
&lt;p class="MsoNormal"&gt;La soluci&amp;oacute;n nos pareci&amp;oacute; interesante y por si pudiera ser reutilizada por alguien m&amp;aacute;s, la publicaremos ac&amp;aacute; en cuanto le apliquemos un poco de Refactoring y le pongamos una cara bonita.&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&amp;nbsp;&lt;/p&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES" style="mso-ansi-language:ES;"&gt;&lt;span style="font-size:small;"&gt;&lt;span style="font-family:Calibri;"&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omarvr/TFS_5F00_1.png"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x441/__key/CommunityServer.Blogs.Components.WeblogFiles/omarvr/TFS_5F00_1.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omarvr/TFS_5F00_1.png"&gt;&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES" style="mso-ansi-language:ES;"&gt;&lt;span style="font-size:small;"&gt;&lt;span style="font-family:Calibri;"&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omarvr/TFS.png"&gt;&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=201503" width="1" height="1"&gt;</description><category domain="http://geeks.ms/blogs/omarvr/archive/tags/TFS/default.aspx">TFS</category><category domain="http://geeks.ms/blogs/omarvr/archive/tags/SCRUM/default.aspx">SCRUM</category><category domain="http://geeks.ms/blogs/omarvr/archive/tags/ALM/default.aspx">ALM</category></item><item><title>Evento de ADO.NET con SNUG</title><link>http://geeks.ms/blogs/omarvr/archive/2011/09/12/evento-de-ado-net-con-snug.aspx</link><pubDate>Mon, 12 Sep 2011 06:52:00 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:200438</guid><dc:creator>Omar del Valle Rodríguez</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/omarvr/rsscomments.aspx?PostID=200438</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/omarvr/commentapi.aspx?PostID=200438</wfw:comment><comments>http://geeks.ms/blogs/omarvr/archive/2011/09/12/evento-de-ado-net-con-snug.aspx#comments</comments><description>&lt;p&gt;Hola a todos...&lt;/p&gt;
&lt;p&gt;El martes 20 de septiembre, que es el martes pr&amp;oacute;ximo (ma&amp;ntilde;ana no, el pr&amp;oacute;ximo&amp;hellip; o sea&amp;hellip; la semana que viene&amp;hellip; en fin, que me l&amp;iacute;o) :-p, dar&amp;eacute; un evento con los chicos de &lt;a target="_blank" href="http://www.secondnug.com/"&gt;SNUG&lt;/a&gt; sobre ADO.NET&lt;/p&gt;
&lt;p&gt;De ADO.NET hay mucha informaci&amp;oacute;n, libros, eventos, blogs en Internet que contienen material excelente sobre toda la arquitectura, clases, m&amp;eacute;todos, propiedades y eventos que lo componen.&lt;/p&gt;
&lt;p&gt;Para no hacer de este evento uno m&amp;aacute;s de esos tantos, nos vamos a centrar en las buenas pr&amp;aacute;cticas &amp;iquest;&lt;b&gt;qu&amp;eacute; debemos y qu&amp;eacute; no debemos hacer cuando usamos ADO.NET&lt;/b&gt;? Esto no quiere decir que no expliquemos su arquitectura o no vayamos a contar qu&amp;eacute; es un Command, Connection o DataReader, solo que no nos quedaremos ah&amp;iacute;, sino que profundizaremos con ejemplos (Visual Studio 2010 + C#) c&amp;oacute;mo poner en un proyecto real toda esa informaci&amp;oacute;n.&lt;/p&gt;
&lt;p&gt;Espero verlos ah&amp;iacute;, y que aprendamos que no solo usando la &amp;uacute;ltima moda como Entity Framework, Linq2Sql o NHibernate, podemos tener buenas pr&amp;aacute;cticas en nuestros desarrollos.&lt;/p&gt;
&lt;p&gt;La URL de registro para el evento es esta: &lt;a target="_blank" href="https://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032493902&amp;amp;Culture=es-ES"&gt;https://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032493902&amp;amp;Culture=es-ES&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://mseventsww.microsoft.com/BannerImages/70e9f3d4-49e6-46cd-9e17-293ed1dfe403.jpg" style="max-width:550px;" border="0" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;Nos vemos ;)&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=200438" width="1" height="1"&gt;</description><category domain="http://geeks.ms/blogs/omarvr/archive/tags/POO/default.aspx">POO</category><category domain="http://geeks.ms/blogs/omarvr/archive/tags/arquitectura/default.aspx">arquitectura</category><category domain="http://geeks.ms/blogs/omarvr/archive/tags/EF/default.aspx">EF</category><category domain="http://geeks.ms/blogs/omarvr/archive/tags/ORM/default.aspx">ORM</category><category domain="http://geeks.ms/blogs/omarvr/archive/tags/ADO.NET/default.aspx">ADO.NET</category></item></channel></rss>