<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Juanma Santoyo &#187; .net</title>
	<atom:link href="http://www.juanmasantoyo.es/index.php/category/net/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.juanmasantoyo.es</link>
	<description>En ocasiones me llaman friki</description>
	<lastBuildDate>Wed, 07 Jul 2010 04:57:03 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Animar transformaciones en WPF con el método BeginAnimation.</title>
		<link>http://www.juanmasantoyo.es/index.php/2010/07/06/animar-transformaciones-en-wpf-con-el-metodo-beginanimation/</link>
		<comments>http://www.juanmasantoyo.es/index.php/2010/07/06/animar-transformaciones-en-wpf-con-el-metodo-beginanimation/#comments</comments>
		<pubDate>Tue, 06 Jul 2010 22:17:31 +0000</pubDate>
		<dc:creator>Juanma</dc:creator>
				<category><![CDATA[.net]]></category>
		<category><![CDATA[surface]]></category>

		<guid isPermaLink="false">http://www.juanmasantoyo.es/?p=475</guid>
		<description><![CDATA[Me preguntaron hace poco cómo animar elementos en Microsoft Surface. En esencia se haría como en cualquier entorno basado en WPF.
Hay varias formas de animar, pero quizás una de las más sencilla y potente sea la animación de transformaciones con el método BeginAnimation.

Las transformaciones.
En WPF existen varios tipos de transformaciones:

RotateTransform. Cambia la orientación de un [...]]]></description>
			<content:encoded><![CDATA[<p>Me preguntaron hace poco cómo animar elementos en Microsoft Surface. En esencia se haría como en cualquier entorno basado en WPF.</p>
<p>Hay varias formas de animar, pero quizás una de las más sencilla y potente sea la animación de transformaciones con el método <em>BeginAnimation</em>.<br />
<span id="more-475"></span></p>
<h3>Las transformaciones.</h3>
<p>En WPF existen varios tipos de transformaciones:</p>
<ul>
<li><em><a href="http://msdn.microsoft.com/es-es/library/system.windows.media.rotatetransform.aspx">RotateTransform</a></em>. Cambia la orientación de un elemento.</li>
<li><em><a href="http://msdn.microsoft.com/es-es/library/system.windows.media.scaletransform.aspx">ScaleTransform</a></em>. Cambia el tamaño de un elemento.</li>
<li><em><a href="http://msdn.microsoft.com/es-es/library/system.windows.media.translatetransform.aspx">TranslateTransform</a></em>. Cambia la posición de un elemento.</li>
<li><em><a href="http://msdn.microsoft.com/es-es/library/system.windows.media.transformgroup.aspx">TransformGroup</a></em>. Es un tipo de transformación especial, ya que consiste en una combinación de las tres anteriores.</li>
</ul>
<h3>Animar transformaciones.</h3>
<p>La idea es simple: Una animación consiste en modificar progresivamente el valor de una propiedad durante un periodo de tiempo. En principio, se puede animar cualquier propiedad de dependencia del API de WPF.</p>
<p>Concretamente, las transformaciones usan propiedades de dependencia para modificar el aspecto del elemento en el que se aplican; así que si aplicamos una animación sobre una propiedad de una transformación de cualquier tipo, el resultado será una animación sobre el elemento.</p>
<p>El código para aplicar una transformación es sencillo. Se puede aplicar desde XAML o desde C#, pero en lo personal prefiero hacerlo en XAML:</p>
<pre class="brush:xml">	&lt;Image x:Name="MyImage" Source="images/myimage.png" Width="100" Height="100"&gt;
		&lt;Image.RenderTransform&gt;
			&lt;TransformGroup&gt;
				&lt;TranslateTransform x:Name="Translacion" X="85" /&gt;
				&lt;RotateTransform x:Name="Rotacion" Angle="0" CenterX="15" CenterY="15" /&gt;
			&lt;/TransformGroup&gt;
		&lt;/Image.RenderTransform&gt;
	&lt;/Image&gt;
</pre>
<p>Fijaos que al usar el nodo <em>&#8220;TransformGroup&#8221;</em> podemos aplicar más de una transformación. De no usarlo sólo podríamos aplicar una, ya que el nodo <em>&#8220;Image.RenderTransform&#8221;</em> sólo admite un nodo hijo. Notad también que las transformaciones se aplican desde la última a la primera. No es lo mismo mover y rotar, que rotar y mover.</p>
<h3>Las animaciones y el método BeginAnimation.</h3>
<p>A nivel práctico, una animación es un objeto con una serie de propiedades configuradas, como por ejemplo la duración de la animación, la aceleración, el valor inicial y final de la propiedad, etc. Dependiendo del tipo de dato que queramos animar, el objeto de animación cambia. No es lo mismo animar un color (<em>ColorAnimation</em>) que una orientación (<em>DoubleAnimation</em>). Se pueden ver todos los tipos de animación posible en la especificación de la clase madre: <em><a href="http://msdn.microsoft.com/es-es/library/system.windows.media.animation.animationtimeline.aspx">AnimationTimeLine</a></em>.</p>
<p>Para aplicar una animación sobre una transformación, contamos con un potente aliado: el método <em>BeginAnimation</em>, presente en todas las transformaciones. Al método <em>BeginAnimation</em> se le pasan dos parámetros: la propiedad de dependencia a animar, y la animación. La animación deberemos construirla en base a lo que queremos animar, la propiedad de dependencia es una propiedad estática de la clase a la que pertenece el elemento que queremos animar. Por ejemplo, si queremos animar el ángulo de un <em>RotateTransform</em>, tendremos una propiedad estática &#8220;<em>RotateTransform.AngleProperty</em>&#8220;. Más fácil con un poco de código C#:</p>
<pre class="brush:csharp">
	DoubleAnimation animacion = new DoubleAnimation();

	animacion.To = 180;
	animacion.Duration = new Duration(TimeSpan.FromMilliseconds(1000));

	Rotacion.BeginAnimation(RotateTransform.AngleProperty, animacion);
</pre>
<h3>Es todo por el momento.</h3>
<p>Y en realidad no hay mucho más que decir sobre animaciones. Sólo destacar que, como imagináis, el objeto animación tiene eventos que informarán del estado del proceso, y que no son bloqueantes (es decir, mientras una animación se ejecuta, el flujo del programa no se detiene, por lo que necesitan una gestión asíncrona). También destacar que la animación se iniciará en el instante en que se ejecute el método <em>BeginAnimation</em>.</p>
<p>Si queréis aprender sobre animaciones más complejas, os recomiendo que miréis el objeto <em><a href="http://msdn.microsoft.com/en-us/library/system.windows.media.animation.storyboard.aspx">StoryBoard</a></em>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.juanmasantoyo.es/index.php/2010/07/06/animar-transformaciones-en-wpf-con-el-metodo-beginanimation/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Charla sobre Microsoft Surface</title>
		<link>http://www.juanmasantoyo.es/index.php/2010/05/28/charla-sobre-microsoft-surface/</link>
		<comments>http://www.juanmasantoyo.es/index.php/2010/05/28/charla-sobre-microsoft-surface/#comments</comments>
		<pubDate>Fri, 28 May 2010 15:15:12 +0000</pubDate>
		<dc:creator>Juanma</dc:creator>
				<category><![CDATA[.net]]></category>
		<category><![CDATA[surface]]></category>

		<guid isPermaLink="false">http://www.juanmasantoyo.es/?p=455</guid>
		<description><![CDATA[Ayer dí una charla sobre Microsoft Surface en el centro de Innovación de Microsoft de Palma para el grupo de desarrolladores de .Net en Baleares.
Hablamos un poco de todo lo que implica la Surface y el desarrollo de aplicaciones para este dispositivo. Fue una experiencia muy gratificante.
Dejo la descarga del Power Point que redacté para [...]]]></description>
			<content:encoded><![CDATA[<p>Ayer dí una charla sobre Microsoft Surface en el centro de Innovación de Microsoft de Palma para el grupo de desarrolladores de .Net en Baleares.</p>
<p>Hablamos un poco de todo lo que implica la Surface y el desarrollo de aplicaciones para este dispositivo. Fue una experiencia muy gratificante.</p>
<p>Dejo la descarga del Power Point que redacté para la ocasión, por si os interesa.</p>
<p><a href='http://www.juanmasantoyo.es/wp-content/uploads/2010/05/Microsoft-Surface.zip'>Microsoft Surface</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.juanmasantoyo.es/index.php/2010/05/28/charla-sobre-microsoft-surface/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>ScatterViewItem invisibles en Microsoft Surface</title>
		<link>http://www.juanmasantoyo.es/index.php/2010/05/18/scatterviewitem-invisibles-en-microsoft-surface/</link>
		<comments>http://www.juanmasantoyo.es/index.php/2010/05/18/scatterviewitem-invisibles-en-microsoft-surface/#comments</comments>
		<pubDate>Tue, 18 May 2010 06:00:57 +0000</pubDate>
		<dc:creator>Juanma</dc:creator>
				<category><![CDATA[.net]]></category>
		<category><![CDATA[surface]]></category>
		<category><![CDATA[scatterviewitem invisible]]></category>

		<guid isPermaLink="false">http://www.juanmasantoyo.es/?p=449</guid>
		<description><![CDATA[Cuando empecé a desarrollar para Microsoft Surface, me di cuenta de tres cosas:

El control ScatterViewItem es la base de toda aplicación.
La mayoría de las veces, no queremos que el ScatterViewItem tenga la apariencia tan horrible que tiene por defecto, es más, nos interesará que sea &#8220;invisible&#8221;.
El control ScatterViewItem no proporciona ningun sistema simple para volverse [...]]]></description>
			<content:encoded><![CDATA[<p>Cuando empecé a desarrollar para Microsoft Surface, me di cuenta de tres cosas:</p>
<ol>
<li>El control ScatterViewItem es la base de toda aplicación.</li>
<li>La mayoría de las veces, no queremos que el ScatterViewItem tenga la apariencia tan horrible que tiene por defecto, es más, nos interesará que sea &#8220;invisible&#8221;.</li>
<li>El control ScatterViewItem no proporciona ningun sistema simple para volverse invisible.</li>
</ol>
<p>Así que despues de trastear un poco con Microsoft Expression Blend, conseguí montar un pequeño estilo que podemos aplicar a nuestros ScatterViewItem para que estos sean invisibles. Esto es, inapreciables para el usuario. Por lo tanto, el contenido se verá perfectamente, pero las sombras, reflejos, destellos y demás tonterías, no.<br />
<span id="more-449"></span><br />
Este es el estilo en cuestión:</p>
<pre class="brush:xml">
&lt;Style x:Key=&quot;InvisibleScatterViewItem&quot; TargetType=&quot;{x:Type s:ScatterViewItem}&quot;&gt;
    &lt;Setter Property=&quot;Template&quot;&gt;
        &lt;Setter.Value&gt;
            &lt;ControlTemplate TargetType=&quot;{x:Type s:ScatterViewItem}&quot;&gt;
                &lt;ContentPresenter /&gt;
            &lt;/ControlTemplate&gt;
        &lt;/Setter.Value&gt;
    &lt;/Setter&gt;
&lt;/Style&gt;
</pre>
<p>Espero que os sirva tanto como a mí.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.juanmasantoyo.es/index.php/2010/05/18/scatterviewitem-invisibles-en-microsoft-surface/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Introducción al componente ScatterView de Surface (1: ScatterViews con XAML)</title>
		<link>http://www.juanmasantoyo.es/index.php/2010/04/08/introduccion-al-componente-scatterview-de-surface-parte-1/</link>
		<comments>http://www.juanmasantoyo.es/index.php/2010/04/08/introduccion-al-componente-scatterview-de-surface-parte-1/#comments</comments>
		<pubDate>Thu, 08 Apr 2010 12:30:16 +0000</pubDate>
		<dc:creator>Juanma</dc:creator>
				<category><![CDATA[.net]]></category>
		<category><![CDATA[surface]]></category>
		<category><![CDATA[scatterview]]></category>

		<guid isPermaLink="false">http://www.juanmasantoyo.es/?p=332</guid>
		<description><![CDATA[El multitouch es probablemente una de las características más atractivas de Surface. Esto se debe a que plantea una serie de posibilidades al usuario que convierte su experiencia en algo mucho más intuitivo y sencillo.
El componente ScatterView es quizás uno de los mejores ejemplos de esto. Este es el primero de varios artículos en el [...]]]></description>
			<content:encoded><![CDATA[<p>El multitouch es probablemente una de las características más atractivas de Surface. Esto se debe a que plantea una serie de posibilidades al usuario que convierte su experiencia en algo mucho más intuitivo y sencillo.</p>
<p>El componente <em>ScatterView</em> es quizás uno de los mejores ejemplos de esto. Este es el primero de varios artículos en el que veremos cómo se usan y qué posiblides nos ofrecen.<br />
<span id="more-332"></span></p>
<h3>Sobre el componente <em>ScatterView</em></h3>
<p>Un <em>ScatterView</em> representa un elemento que reacciona a los contactos sobre Surface y que se puede mover, rotar o redimensionar.</p>
<p>El ejemplo más clásico sería un puñado de fotografías. Cada una de esas fotografías puede ser un <em>ScatterView</em>.</p>
<h3>Preparamos el proyecto</h3>
<p>Antes de iniciar el Visual Studio, debemos haber iniciado el emulador de Surface que viene con el SDK. Si no lo has hecho así, cierra el Visual Studio y inícialo todo en el orden correcto.</p>
<h4>Creamos el proyecto</h4>
<p>Nuestro proyecto va a ser una aplicación para Surface basada en WPF. Lo llamaremos HelloScatterView.</p>
<p>Al crear nuestro proyecto se nos ha creado una ventana por defecto: SurfaceWindow1. La renombraremos, y le pondremos el nombre de &#8220;<strong>XamlSample</strong>&#8220;.</p>
<h4>Añadimos unas imágenes</h4>
<p>Para poder trabajar con los <strong>ScatterViews</strong>, necesitaremos algunas imágenes.</p>
<p>Dentro de nuestro proyecto Surface tenemos una carpeta llamada Resources. Crearemos otra carpeta en su interior llamada Img y ubicaremos ahí nuestras imágenes.</p>
<h3>Añadir <em>ScatterViews</em> desde XAML</h3>
<h4><em>ScatterView</em> simple con XAML</h4>
<p>Comenzaremos usando los <em>ScatterViews</em> desde XAML. En realidad añadir un <em>ScatterView</em> es muy simple:</p>
<pre class="brush:xml">
&lt;s:ScatterView&gt;
    &lt;Image Source=&quot;Resources/Img/fuente_tres_chorros.jpg&quot;/&gt;
&lt;/s:ScatterView&gt;
</pre>
<p><img src="http://www.juanmasantoyo.es/wp-content/uploads/2010/02/01-300x225.jpg" alt="" title="Ejemplo de ScatterView" width="300" height="225" class="aligncenter size-medium wp-image-333" /></p>
<p>Este es el código que añade un <em>ScatterView</em>. Fijaos en un detalle: añadir un <em>ScatterView</em> no es sólo añadir el nodo <em>ScatterView</em>, también es añadir el recurso que se manejará, en este caso la imagen. Y es que un <em>ScatterView</em> no es una imagen, sino la capacidad que tiene un elemento (en este caso una imagen) de ser rotado, redimensionado y movido.</p>
<p>El XAML completo de la ventana es este:</p>
<pre class="brush:xml">
&lt;s:SurfaceWindow
    x:Class=&quot;HelloScatterView.SurfaceWindow1&quot;
    xmlns=&quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;
    xmlns:x=&quot;http://schemas.microsoft.com/winfx/2006/xaml&quot;
    xmlns:s=&quot;http://schemas.microsoft.com/surface/2008&quot;
    Title=&quot;HelloScatterView&quot;&gt;
    &lt;s:SurfaceWindow.Resources&gt;
        &lt;ImageBrush x:Key=&quot;WindowBackground&quot;
                  Stretch=&quot;None&quot; Opacity=&quot;0.6&quot;
                  ImageSource=&quot;pack://application:,,,/Resources/WindowBackground.jpg&quot;/&gt;
    &lt;/s:SurfaceWindow.Resources&gt;
    &lt;s:ScatterView&gt;
        &lt;Image Source=&quot;Resources/Img/fuente_tres_chorros.jpg&quot;/&gt;
    &lt;/s:ScatterView&gt;
&lt;/s:SurfaceWindow&gt;
</pre>
<p>Si ahora compilamos nuestro proyecto, podremos jugar un poco con nuestra foto sobre el emulador de Surface. Incluso, si conectas dos ratones por USB puedes simular multitouch.</p>
<p>Vamos a hacerlo un poco más espectacular añadiendo varias imágenes:</p>
<pre class="brush:xml">
&lt;s:ScatterView&gt;
    &lt;Image Source=&quot;Resources/Img/fuente_tres_chorros.jpg&quot;/&gt;
    &lt;Image Source=&quot;Resources/Img/kiyoumizu_dera.jpg&quot;/&gt;
    &lt;Image Source=&quot;Resources/Img/laputa_robot.jpg&quot;/&gt;
    &lt;Image Source=&quot;Resources/Img/fuente_tres_chorros.jpg&quot;/&gt;
    &lt;Image Source=&quot;Resources/Img/kiyoumizu_dera.jpg&quot;/&gt;
    &lt;Image Source=&quot;Resources/Img/laputa_robot.jpg&quot;/&gt;
&lt;/s:ScatterView&gt;
</pre>
<p><img src="http://www.juanmasantoyo.es/wp-content/uploads/2010/02/02-300x225.jpg" alt="" title="Ejemplo de varios ScatterViews" width="300" height="225" class="aligncenter size-medium wp-image-334" /></p>
<h4><em>Scatterviews</em> complejos con XAML</h4>
<p>Probablemente ya te estés preguntando lo siguiente: ¿cómo determinar los parámetros por defecto de nuestro <em>ScatterView</em>? Vamos a ello.</p>
<p>La clave está en que la estructura que hemos usado ahora no acaba de ser la mejor. En realidad, nos está faltando crear un <em>ScatterViewItem</em>, que hasta el momento se estaba creando de forma automática para cada elemento en el <em>ScatterView</em>.</p>
<pre class="brush:xml">
&lt;s:ScatterView&gt;
	&lt;s:ScatterViewItem&gt;
		&lt;Image Source=&quot;Resources/Img/fuente_tres_chorros.jpg&quot;/&gt;
	&lt;/s:ScatterViewItem&gt;
&lt;/s:ScatterView&gt;
</pre>
<p>En el nodo <em>ScatterViewItem</em> podemos establecer muchas propiedades que afectarán al comportamiento de nuestro <em>ScatterView</em>.</p>
<p>Algunas de esas propiedades son:</p>
<ul>
<li><strong>MinWidth</strong>, <strong>MaxWidth</strong>, <strong>MinHeight</strong>, <strong>MaxHeight</strong>: Máximos y mínimos de anchura y altura.</li>
<li><strong>CanMove</strong>, <strong>CanRotate</strong>, <strong>CanScale</strong>: Activan o desactivan las capacidades de mover, rotar y redimensionar.</li>
<li><strong>Width</strong>, <strong>Height</strong>, <strong>Center</strong>, <strong>Orientation</strong>: Valores iniciales para el ancho, el alto, la posición, y la rotación.</li>
<li><strong>BorderBrush</strong>, <strong>BorderThikness</strong>: Color y grosor del borde.</li>
</ul>
<p>Un ejemplo sencillo:</p>
<pre class="brush:xml">
&lt;s:ScatterView&gt;
	&lt;s:ScatterViewItem Center=&quot;512,384&quot; Orientation=&quot;0&quot;&gt;
		&lt;Image Source=&quot;Resources/Img/fuente_tres_chorros.jpg&quot;/&gt;
	&lt;/s:ScatterViewItem&gt;

	&lt;s:ScatterViewItem Center=&quot;512,384&quot; Orientation=&quot;60&quot;&gt;
		&lt;Image Source=&quot;Resources/Img/kiyoumizu_dera.jpg&quot;/&gt;
	&lt;/s:ScatterViewItem&gt;

	&lt;s:ScatterViewItem Center=&quot;512,384&quot; Orientation=&quot;180&quot;&gt;
		&lt;Image Source=&quot;Resources/Img/laputa_robot.jpg&quot;/&gt;
	&lt;/s:ScatterViewItem&gt;

	&lt;s:ScatterViewItem Center=&quot;512,384&quot; Orientation=&quot;240&quot;&gt;
		&lt;Image Source=&quot;Resources/Img/fuente_tres_chorros.jpg&quot;/&gt;
	&lt;/s:ScatterViewItem&gt;

	&lt;s:ScatterViewItem Center=&quot;512,384&quot; Orientation=&quot;300&quot;&gt;
		&lt;Image Source=&quot;Resources/Img/kiyoumizu_dera.jpg&quot;/&gt;
	&lt;/s:ScatterViewItem&gt;

	&lt;s:ScatterViewItem Center=&quot;512,384&quot; Orientation=&quot;360&quot;&gt;
		&lt;Image Source=&quot;Resources/Img/laputa_robot.jpg&quot;/&gt;
	&lt;/s:ScatterViewItem&gt;
&lt;/s:ScatterView&gt;
</pre>
<p>Aunque de hecho, podemos centralizar la mayoría de estas propiedades en un único nodo, como un estilo:</p>
<pre class="brush:xml">
&lt;s:ScatterView&gt;
	&lt;s:ScatterView.ItemContainerStyle&gt;
		&lt;Style TargetType=&quot;{x:Type s:ScatterViewItem}&quot;&gt;
			&lt;Setter Property=&quot;Center&quot; Value=&quot;512,384&quot;/&gt;
			&lt;Setter Property=&quot;BorderBrush&quot; Value=&quot;Black&quot;/&gt;
			&lt;Setter Property=&quot;BorderThickness&quot; Value=&quot;3&quot;/&gt;
		&lt;/Style&gt;
	&lt;/s:ScatterView.ItemContainerStyle&gt;

	&lt;s:ScatterViewItem Orientation=&quot;0&quot;&gt;
		&lt;Image Source=&quot;Resources/Img/fuente_tres_chorros.jpg&quot;/&gt;
	&lt;/s:ScatterViewItem&gt;

	&lt;s:ScatterViewItem Orientation=&quot;60&quot;&gt;
		&lt;Image Source=&quot;Resources/Img/kiyoumizu_dera.jpg&quot;/&gt;
	&lt;/s:ScatterViewItem&gt;

	&lt;s:ScatterViewItem Orientation=&quot;180&quot;&gt;
		&lt;Image Source=&quot;Resources/Img/laputa_robot.jpg&quot;/&gt;
	&lt;/s:ScatterViewItem&gt;

	&lt;s:ScatterViewItem Orientation=&quot;240&quot;&gt;
		&lt;Image Source=&quot;Resources/Img/fuente_tres_chorros.jpg&quot;/&gt;
	&lt;/s:ScatterViewItem&gt;

	&lt;s:ScatterViewItem Orientation=&quot;300&quot;&gt;
		&lt;Image Source=&quot;Resources/Img/kiyoumizu_dera.jpg&quot;/&gt;
	&lt;/s:ScatterViewItem&gt;

	&lt;s:ScatterViewItem Orientation=&quot;360&quot;&gt;
		&lt;Image Source=&quot;Resources/Img/laputa_robot.jpg&quot;/&gt;
	&lt;/s:ScatterViewItem&gt;
&lt;/s:ScatterView&gt;
</pre>
<p><a href="http://www.juanmasantoyo.es/wp-content/uploads/2010/02/03.jpg"><img src="http://www.juanmasantoyo.es/wp-content/uploads/2010/02/03-300x225.jpg" alt="" title="Definiendo las propiedades por defecto de los ScatterViews" width="300" height="225" class="aligncenter size-medium wp-image-335" /></a></p>
<h3>Es todo por hoy</h3>
<p>El componente <em>ScatterView</em> es sencillo de usar y proporciona una característica muy interesante a nuestras aplicaciones.</p>
<p>Cuando se trabaja para Surface, hay que tener muy en cuenta que los diversos usuarios se colocan alrededor de la mesa, por lo que no existe el derecho ni el revés. Los ScatterViews nos solucionarán este problema más de una vez.</p>
<p>En la siguiente parte del artículo, veremos cómo trabajar con ScatterViews desde C#.</p>
<h3>Editado 7/5/2010:</h3>
<p>Me comentaron que los códigos fuente en XAML tenían mal la sintaxis, y efectívamente; cuando he pasado a revisarlo así era. Ni idea de que pudo pasar&#8230; Bueno, ya están arreglados.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.juanmasantoyo.es/index.php/2010/04/08/introduccion-al-componente-scatterview-de-surface-parte-1/feed/</wfw:commentRss>
		<slash:comments>15</slash:comments>
		</item>
		<item>
		<title>Enrutamiento Seo Friendly con asp.Net</title>
		<link>http://www.juanmasantoyo.es/index.php/2010/04/06/enrutamiento-seo-friendly-con-asp-net/</link>
		<comments>http://www.juanmasantoyo.es/index.php/2010/04/06/enrutamiento-seo-friendly-con-asp-net/#comments</comments>
		<pubDate>Tue, 06 Apr 2010 21:55:48 +0000</pubDate>
		<dc:creator>Juanma</dc:creator>
				<category><![CDATA[.net]]></category>
		<category><![CDATA[enrutamiento seo]]></category>
		<category><![CDATA[friendly url]]></category>
		<category><![CDATA[seo friendly]]></category>

		<guid isPermaLink="false">http://www.juanmasantoyo.es/?p=423</guid>
		<description><![CDATA[En los últimos años se ha ido estableciendo en los sitios web una buena práctica: las Seo Friendly URL. Friendly de amistoso, por que hace que nuestras rutas sean fáciles de indexar por los buscadores (los parámetros GET nunca les han gustado demasiado) y, mucho más importante; fáciles de comprender por los usuarios.
Es de sentido [...]]]></description>
			<content:encoded><![CDATA[<p>En los últimos años se ha ido estableciendo en los sitios web una buena práctica: las <em>Seo Friendly URL</em>. Friendly de amistoso, por que hace que nuestras rutas sean fáciles de indexar por los buscadores (los parámetros <em>GET</em> nunca les han gustado demasiado) y, mucho más importante; fáciles de comprender por los usuarios.</p>
<p>Es de sentido común que la URL de una página tenga que tener cierta relación con lo que contiene. A nadie le dice nada una URL de tipo http://www.dominio.com?seccion=5, pero la cosa es más interesante si es algo del tipo http://www.dominio.com/contacto. La propia URL de este artículo es un buen ejemplo.</p>
<p>En este artículo veremos un pequeño ejemplo de como podemos crear Friendly URLs en <em>asp.Net</em><br />
<span id="more-423"></span></p>
<h3>¿En que consisten técnicamente las <em>Friendly URL</em>?</h3>
<p>La idea es interceptar las peticiones por URL que se realizan a nuestro sitio web antes de que se sirva ningún contenido, de forma que podamos analizar la ruta y servir un archivo u otro en consecuencia. También podemos considerar que parte de la URL es un parámetro de entrada.</p>
<p>Por ejemplo, la URL de este artículo podría ser una como <em>http://www.dominio.com/articulos/enrutamiento-friendly-url/</em>, donde la parte &#8220;enrutamiento-friendly-url&#8221; es la que determina qué artículo se está mostrando.</p>
<h3>¿Cómo montamos el nuevo sistema de direccionamiento?</h3>
<p>Cada tecnología de servidor tiene su forma de hacerlo. En este artículo veremos un ejemplo sobre <em>asp.Net</em>.</p>
<p>La clave es el archivo <em>Global.asax</em>. Este es un archivo que proporciona manejadores para una serie de eventos producidos por la aplicación. A nosotros nos interesará el evento <em>Application_BeginRequest</em>: es ahí donde podemos interceptar las peticiones antes de que se sirva ningún contenido, y donde analizaremos las URL para reprogramar el direccionamiento a donde nos interese. Obviamente, el archivo <em>Global.asax</em> tiene más utilidades que el enrutamiento, pero de momento no nos interesan.</p>
<h3>Un ejemplo</h3>
<p>Vamos a programar un pequeño ejemplo que nos serviría para gestionar los direccionamientos de una red social.</p>
<p>Haremos una dirección para las secciones principales, y una dirección que será dinámica para cada usuario miembro de la red social.</p>
<h4>Diseñamos el nuevo enrutamiento</h4>
<p>Como siempre, antes de empezar a hacer nada; necesitamos tener claro qué queremos hacer. Vamos a considerar todas las rutas que tendremos.</p>
<ol>
<li>
		<strong><em>/inicio/</em></strong><br />
		Todos los sitios web, las redes sociales también; necesitan una página de inicio.
	</li>
<li>
		<strong><em>/buscar/</em></strong><br />
		Toda red social necesita un buscador.
	</li>
<li>
		<strong><em>/usuarios/</em></strong><br />
		Lo más importante de una red social son los usuarios. Esta es la página genérica de usuarios, que podría ser por ejemplo un formulario de Login.
	</li>
<li>
		<strong><em>/usuarios/&lt;nombre de usuario&gt;/</em></strong><br />
		Todos los usuarios tienen un perfil con su nombre, su foto, las cosas que hacen los domingos&#8230; Fijaos en que ya incluímos un parámetro, el nombre del usuario.
	</li>
<li>
		<strong><em>/usuarios/&lt;nombre de usuario&gt;/contacto/</em></strong><br />
		La gracia de una red social es poder contactar con los usuarios. Esta página proporcionaría funcionalidad a una red de mensajería interna. Tambien tenemos el parámetro de nombre de usuario.
	</li>
</ol>
<h4>Creamos el proyecto</h4>
<p>Vamos a crear un proyecto web normal y corrente desde el <em>Visual Studio</em>.</p>
<p>Crearemos cuatro <em>.aspx</em>, uno para cada una de nuestras rutas, excepto para <em>/inicio/</em>, que será el <em>Default.aspx</em> que se ha creado por defecto. Tambien crearemos una clase <em>.cs</em> para simular el origen de datos de los usuarios.</p>
<ul>
<li><em>Buscar.aspx</em></li>
<li><em>Usuarios.aspx</em></li>
<li><em>UsuariosPerfil.aspx</em></li>
<li><em>UsuariosContacto.aspx</em></li>
<li><em>Datos/Usuarios.cs</em></li>
</ul>
<h4>Algo de código para los <em>.aspx</em></h4>
<p>Vamos a añadir algo de código en los <em>.aspx</em>. Para diferenciarlos, más que nada; y para probar unos links.</p>
<h5><em>Default.aspx</em></h5>
<pre class="brush:xml">
	&lt;head runat=&quot;server&quot;&gt;
		&lt;title&gt;Inicio&lt;/title&gt;
	&lt;/head&gt;
	&lt;body&gt;
		&lt;form id=&quot;form1&quot; runat=&quot;server&quot;&gt;
		&lt;div&gt;
			&lt;h1&gt;Inicio&lt;/h1&gt;

			&lt;ul&gt;
				&lt;li&gt;&lt;asp:LinkButton runat=&quot;server&quot; ID=&quot;lbBuscar&quot; PostBackUrl=&quot;~/buscar/&quot;&gt;Buscar&lt;/asp:LinkButton&gt;&lt;/li&gt;
				&lt;li&gt;&lt;asp:LinkButton runat=&quot;server&quot; ID=&quot;lbUsuarios&quot; PostBackUrl=&quot;~/usuarios/&quot;&gt;Usuarios&lt;/asp:LinkButton&gt;&lt;/li&gt;
			&lt;/ul&gt;
		&lt;/div&gt;
		&lt;/form&gt;
	&lt;/body&gt;
</pre>
<h5><em>Buscar.aspx</em></h5>
<pre class="brush:xml">
	&lt;head runat=&quot;server&quot;&gt;
		&lt;title&gt;Buscar&lt;/title&gt;
	&lt;/head&gt;
	&lt;body&gt;
		&lt;form id=&quot;form1&quot; runat=&quot;server&quot;&gt;
		&lt;div&gt;
			&lt;h1&gt;Buscar&lt;/h1&gt;

			&lt;ul&gt;
				&lt;li&gt;&lt;asp:LinkButton ID=&quot;lbInicio&quot; runat=&quot;server&quot; PostBackUrl=&quot;~/inicio/&quot;&gt;Inicio&lt;/asp:LinkButton&gt;&lt;/li&gt;
				&lt;li&gt;&lt;asp:LinkButton ID=&quot;lbUsuarios&quot; runat=&quot;server&quot; PostBackUrl=&quot;~/usuarios/&quot;&gt;Usuarios&lt;/asp:LinkButton&gt;&lt;/li&gt;
			&lt;/ul&gt;
		&lt;/div&gt;
		&lt;/form&gt;
	&lt;/body&gt;
</pre>
<h5><em>Usuarios.aspx</em></h5>
<pre class="brush:xml">
	&lt;head runat=&quot;server&quot;&gt;
		&lt;title&gt;Usuarios&lt;/title&gt;
	&lt;/head&gt;
	&lt;body&gt;
		&lt;form id=&quot;form1&quot; runat=&quot;server&quot;&gt;
		&lt;div&gt;
			&lt;h1&gt;Usuarios&lt;/h1&gt;

			&lt;ul&gt;
				&lt;li&gt;&lt;asp:LinkButton ID=&quot;lbInicio&quot; runat=&quot;server&quot; PostBackUrl=&quot;~/inicio/&quot;&gt;Inicio&lt;/asp:LinkButton&gt;&lt;/li&gt;
				&lt;li&gt;&lt;asp:LinkButton ID=&quot;lbBuscar&quot; runat=&quot;server&quot; PostBackUrl=&quot;~/buscar/&quot;&gt;Buscar&lt;/asp:LinkButton&gt;&lt;/li&gt;
			&lt;/ul&gt;
		&lt;/div&gt;
		&lt;/form&gt;
	&lt;/body&gt;
</pre>
<h5><em>UsuariosPerfil.aspx</em></h5>
<pre class="brush:xml">
	&lt;head runat=&quot;server&quot;&gt;
		&lt;title&gt;Perfil de &lt;/title&gt;
	&lt;/head&gt;
	&lt;body&gt;
		&lt;form id=&quot;form1&quot; runat=&quot;server&quot;&gt;
		&lt;div&gt;
			&lt;h1 runat=&quot;server&quot; id=&quot;hTitle&quot;&gt;&lt;/h1&gt;

			&lt;ul&gt;
				&lt;li&gt;&lt;asp:LinkButton ID=&quot;lbInicio&quot; runat=&quot;server&quot; PostBackUrl=&quot;~/inicio/&quot;&gt;Inicio&lt;/asp:LinkButton&gt;&lt;/li&gt;
				&lt;li&gt;&lt;asp:LinkButton ID=&quot;lbUsuariosContacto&quot; runat=&quot;server&quot;&gt;Perfíl de &lt;/asp:LinkButton&gt;&lt;/li&gt;
			&lt;/ul&gt;
		&lt;/div&gt;
		&lt;/form&gt;
	&lt;/body&gt;
</pre>
<h5><em>UsuariosContacto.aspx</em></h5>
<pre class="brush:xml">
	&lt;head runat=&quot;server&quot;&gt;
		&lt;title&gt;Contactar con &lt;/title&gt;
	&lt;/head&gt;
	&lt;body&gt;
		&lt;form id=&quot;form1&quot; runat=&quot;server&quot;&gt;
		&lt;div&gt;
			&lt;h1 runat=&quot;server&quot; id=&quot;hTitle&quot;&gt;Contactar con &lt;/h1&gt;

			&lt;ul&gt;
				&lt;li&gt;&lt;asp:LinkButton ID=&quot;lbinicio&quot; runat=&quot;server&quot; PostBackUrl=&quot;~/inicio/&quot;&gt;Inicio&lt;/asp:LinkButton&gt;&lt;/li&gt;
				&lt;li&gt;&lt;asp:LinkButton ID=&quot;lbUsuariosPerfil&quot; runat=&quot;server&quot;&gt;Perfíl de &lt;%= getUserName() %&gt;&lt;/asp:LinkButton&gt;&lt;/li&gt;
			&lt;/ul&gt;
		&lt;/div&gt;
		&lt;/form&gt;
	&lt;/body&gt;
</pre>
<p>Debemos considerar, además, un poco de código en los <em>.cs</em>:</p>
<h5><em>Datos/Usuarios.cs</em></h5>
<p>Este será nuestro origen de datos. Normalmente será una tabla en base de datos, un xml, o algo por el estilo; pero para nuestro ejemplo nos basta una clase que extienda de List. Le hemos programado además dos nuevos métodos: uno para convertir un valor de la lista al formato que usamos en las URL, y otro para encontrar valores. Destacar que el algoritmo de búsqueda podría ser bastante mejor, pero para el caso ya nos sirve.</p>
<pre class="brush:csharp">
	using System;
	using System.Collections.Generic;

	namespace JuanmaSantoyoSeoFriendly.Datos
	{
		public class Usuarios : List&lt;string&gt;
		{
			public Usuarios()
			{
				this.Add("John Travolta");
				this.Add("Samuel L Jackson");
				this.Add("Bruce Willis");
				this.Add("Uma Thurman");
				this.Add("Quentin Tarantino");
			}
		}

		private string urlFormat(string str)
        {
            return str.ToLowerInvariant().Replace(&quot; &quot;, &quot;-&quot;);
        }

        public int search(string username)
        {
            int userid = -1;
            int i = 0;

            while(this.Count &gt; i)
            {
                if (urlFormat(this[i]) == username)
                {
                    userid = i;
                    break;
                }

                i  ;
            }

            return userid;
        }
	}
</pre>
<h5><em>UsuariosPerfil.aspx.cs</em></h5>
<p>En este <em>.cs</em> daremos valores a algunos elementos del <em>.aspx</em>, y además proporcionaremos métodos que rescatarán de sesión el ID del usuario y devolverán su nombre. Hay dos versiones para este método, uno devolverá el nombre tal cual, y el otro nos dará la posiblidad de devolver el nombre formateado para URL.</p>
<pre class="brush:csharp">
	protected void Page_Load(object sender, EventArgs e)
	{
		this.hTitle.InnerText = this.getUserName();

		Page.Title  = this.getUserName();

		lbUsuariosContacto.PostBackUrl = &quot;~/usuarios/&quot;   this.getUserName(true)   &quot;/contacto/&quot;;
		lbUsuariosContacto.Text  = this.getUserName();
	}

	public string getUserName()
	{
		Datos.Usuarios usu = new Datos.Usuarios();

		if (HttpContext.Current.Items.Contains(&quot;userid&quot;) &amp;&amp; HttpContext.Current.Items[&quot;userid&quot;].ToString() != &quot;-1&quot;)
		{
			return usu[Convert.ToInt32(HttpContext.Current.Items[&quot;userid&quot;])];
		}
		else
		{
			return &quot;user not found&quot;;
		}
	}

	public string getUserName(bool encode)
	{
		Datos.Usuarios usu = new Datos.Usuarios();

		if (HttpContext.Current.Items.Contains(&quot;userid&quot;))
		{
			return usu[Convert.ToInt32(HttpContext.Current.Items[&quot;userid&quot;])].ToLowerInvariant().Replace(&quot; &quot;, &quot;-&quot;);
		}
		else
		{
			return &quot;user not found&quot;;
		}
	}
</pre>
<h5><em>UsuariosContacto.cs</em></h5>
<p>Este <em>.cs</em> es bastante similar al anterior, así que no merece demasiados comentarios:</p>
<pre class="brush:csharp">
	protected void Page_Load(object sender, EventArgs e)
	{
		hTitle.InnerHtml  = getUserName();

		Page.Title  = this.getUserName();

		lbUsuariosPerfil.PostBackUrl = &quot;~/usuarios/&quot;   getUserName(true)   &quot;/&quot;;
		lbUsuariosPerfil.Text  = getUserName();
	}

	public string getUserName()
	{
		Datos.Usuarios usu = new Datos.Usuarios();

		if (HttpContext.Current.Items.Contains(&quot;userid&quot;))
		{
			return usu[Convert.ToInt32(HttpContext.Current.Items[&quot;userid&quot;])];
		}
		else
		{
			return &quot;user not found&quot;;
		}
	}

	public string getUserName(bool encode)
	{
		Datos.Usuarios usu = new Datos.Usuarios();

		if (HttpContext.Current.Items.Contains(&quot;userid&quot;) &amp;&amp; HttpContext.Current.Items[&quot;userid&quot;].ToString() != &quot;-1&quot;)
		{
			return usu[Convert.ToInt32(HttpContext.Current.Items[&quot;userid&quot;])].ToLowerInvariant().Replace(&quot; &quot;, &quot;-&quot;);
		}
		else
		{
			return &quot;user not found&quot;;
		}
	}
</pre>
<h4>Añadimos el <em>Global.asax</em></h4>
<p>Añadimos un nuevo elemento en el proyecto. El nuevo elemento será un Artchivo de aplicación global. No le cambiaremos el nombre: lo dejaremos como <em>&#8220;Global.asax&#8221;</em>.</p>
<p><a href="http://www.juanmasantoyo.es/wp-content/uploads/2010/04/01-global-asax.png"><img src="http://www.juanmasantoyo.es/wp-content/uploads/2010/04/01-global-asax.png" alt="Global.asax" title="01-global-asax" width="540" height="329" class="aligncenter size-full wp-image-427" /></a></p>
<h4>Configuramos las nuevas rutas</h4>
<p>Antes que nada, debemos agregar la librería <em>&#8220;System.Web.Routing&#8221;</em>.</p>
<p><a href="http://www.juanmasantoyo.es/wp-content/uploads/2010/04/02-system-web-routing.png"><img src="http://www.juanmasantoyo.es/wp-content/uploads/2010/04/02-system-web-routing.png" alt="System.Web.Routing" title="02-system-web-routing" width="503" height="390" class="aligncenter size-full wp-image-428" /></a></p>
<p>Programaremos nuestra propia función para aplicar el enrutamiento. La llamaremos <em>&#8220;ApplyRouting&#8221;</em>:</p>
<pre class="brush:csharp">
	private void ApplyRouting(RouteCollection Routes)
	{
		Routes.Add(new Route(&quot;&quot;, new RouteHandler(&quot;~/Default.aspx&quot;)));
		Routes.Add(new Route(&quot;inicio/&quot;, new RouteHandler(&quot;~/Default.aspx&quot;)));
		Routes.Add(new Route(&quot;buscar/&quot;, new RouteHandler(&quot;~/Buscar.aspx&quot;)));
		Routes.Add(new Route(&quot;usuarios/&quot;, new RouteHandler(&quot;~/Usuarios.aspx&quot;)));
		Routes.Add(new Route(&quot;usuarios/{username}/&quot;, new RouteHandler(&quot;~/UsuariosPerfil.aspx&quot;)));
		Routes.Add(new Route(&quot;usuarios/{username}/contacto/&quot;, new RouteHandler(&quot;~/UsuariosContacto.aspx&quot;)));
	}
</pre>
<p>Y la llamaremos desde el evento <em>Application_BeginRequest</em>:</p>
<pre class="brush:csharp">
	protected void Application_BeginRequest(object sender, EventArgs e)
	{
		ApplyRouting(RouteTable.Routes);
	}
</pre>
<p>Lo que hacemos es, básicamente; añadir nuevas rutas creadas por nosotros a la tabla de rutas de nuestra aplicación. Hay varias cosas destacables:</p>
<ol>
<li>El primer parámetro es la nueva ruta. Si escribimos el valor entre llaves, será un parámetro. Los parámetros que antes enviábamos por <em>GET</em> deberían ser sustituídos por estos.</li>
<li>Estamos creando instancias de RouteHandler. Esta clase no existe en la Api de C#, la tenemos que programar nosotros y será donde añadiremos toda la lógica de redireccionamiento.</li>
<li>Como la clase RouteHandler la programamos nosotros, tenemos ciertas ventajas. En este caso, pasamos como parámetro del constructor el archivo al cual redirigimos. No tendría por qué ser así, pero como una de las características de nuestras URL es que siempre redirigen a un único archivo; este sistema nos viene bastante bien.</li>
</ol>
<h4>Programamos la lógica de redireccionamiento</h4>
<p>Vamos a crear ahora la clase <em>Routing/RouteHandler.cs</em>. Esta clase, deberá heredar de <em>IRouteHandler</em> y por tanto deberá incorporar un método público llamado <em>GetHttpHandler</em>, que recibirá un único parámetro que es un <em>RequestContext</em> y que retornará un <em>IHttpHandler</em>.</p>
<p>En este método pasaran escencialmente dos cosas: por una parte, se meterán los parámetros recibidos en sesión. Por otra, se retornará un <em>IHttpHandler</em> que construiremos usando la ruta del <em>.aspx</em> al que queremos redirigir.</p>
<pre class="brush:csharp">
	public IHttpHandler GetHttpHandler(RequestContext requestContext)
	{
		/*
		 * Tratamos los parámetros de la URL:
		 * Si es el nombre de usuario, buscamos su ID y lo metemos en sesión.
		 * Si no, símplemente lo metemos en sesión
		 */
		foreach (KeyValuePair&lt;string, object&gt; val in requestContext.RouteData.Values)
		{
			if (val.Key == &quot;username&quot;)
			{
				Datos.Usuarios usu = new Datos.Usuarios();
				int userid = usu.search(val.Value.ToString());
				requestContext.HttpContext.Items[&quot;userid&quot;] = userid;
			}

			requestContext.HttpContext.Items[val.Key] = val.Value;
		}

		return (Page) BuildManager.CreateInstanceFromVirtualPath(VirtualPath, typeof(Page));
	}
</pre>
<p>Añadimos además un constructor y una variable global para el parámetro que indica el archivo al que redirigimos.</p>
<pre class="brush:csharp">
	string VirtualPath = string.Empty;

	public RouteHandler(string path)
	{
		this.VirtualPath = path;
	}
</pre>
<p>Hecho esto, nuestras nuevas rutas ya deberían estar funcionando. Sólo nos queda un detalle.</p>
<h4>Ignorando rutas</h4>
<p>Generalmente, no sólo nos va a interesar añadir rutas a nuestra aplicación, sino tambien quitarlas. Por ejemplo, no es una mala idea que se ignoren las rutas directas a un <em>.aspx</em>, o aquellas rutas que no acaben con el carácter <em>&#8220;/&#8221;</em> (para tener un sistema de rutas uniforme). Vamos a programar una función en <em>Global.asax</em>, a la cual llamaremos justo antes de <em>ApplyRouting</em> y que se encargará de comprobar si nuestra ruta debe ser ignorada y, en ese caso, redirigir a <em>/inicio/</em>.</p>
<p>El método <em>Application_BeginRequest</em> en <em>Global.asax</em> queraría de la siguiente forma:</p>
<pre class="brush:csharp">
	protected void Application_BeginRequest(object sender, EventArgs e)
	{
		Redirect();
		ApplyRouting(RouteTable.Routes);
	}
</pre>
<p>El método <em>Redirect</em>:</p>
<pre class="brush:csharp">
	private void Redirect()
	{
		string url = Request.Url.ToString();

		if (url.Contains(&quot;.aspx&quot;))
		{
			Response.Redirect(&quot;~/inicio/&quot;);
		}

		if (url[url.Length - 1] != '/' &amp;&amp; !url.Contains(&quot;?&quot;))
		{
			Response.Redirect(url + &quot;/&quot;);
		}
	}
</pre>
<h4>Descarga el código fuente</h4>
<p>Sé que me odias por no haber puesto este archivo al principio, pero más vale tarde que nunca ¿no?.</p>
<p><a href='http://www.juanmasantoyo.es/wp-content/uploads/2010/04/JuanmaSantoyoSeoFriendly.zip'>Código fuente</a>.</p>
<h3>¡Hemos acabado!</h3>
<p>Como véis, en asp.Net el enrutamiento Seo Friendly se reduce a dos clases: <em>Global.asax</em> y el manejador de rutas. Es bastante simple, y no requiere demasiado tiempo de implementación. Los beneficios de usar este tipo de enrutamiento son múltiples, desde aspectos de seguridad, hasta aspectos de usuabilidad y posicionamiento en buscadores. ¡Ya no hay excusa para no implementarlo!.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.juanmasantoyo.es/index.php/2010/04/06/enrutamiento-seo-friendly-con-asp-net/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Introducción al desarrollo sobre Microsoft Surface</title>
		<link>http://www.juanmasantoyo.es/index.php/2010/04/06/introduccion-al-desarrollo-para-microsoft-surface/</link>
		<comments>http://www.juanmasantoyo.es/index.php/2010/04/06/introduccion-al-desarrollo-para-microsoft-surface/#comments</comments>
		<pubDate>Tue, 06 Apr 2010 06:15:28 +0000</pubDate>
		<dc:creator>Juanma</dc:creator>
				<category><![CDATA[.net]]></category>
		<category><![CDATA[surface]]></category>
		<category><![CDATA[microsoft]]></category>

		<guid isPermaLink="false">http://www.juanmasantoyo.es/?p=158</guid>
		<description><![CDATA[Microsoft Surface (Surface a partir de ahora) es sin duda un desafío para los programadores. Acostumbrados a entornos gráficos basados en respuestas al ratón, una interfaz de usuario multitáctil nos plantea un nuevo reto a la mayoría de nosotros.

En este artículo, pretendo dos cosas: por una parte, informarte de qué necesitas para comenzar a desarrollar y cómo obtenerlo. Por otra parte, facilitarte esa documentación que a todos nos va tan bien para empezar con una nueva tecnología. Así que vamos a ello.]]></description>
			<content:encoded><![CDATA[<p>Microsoft Surface (Surface a partir de ahora) es sin duda un desafío para los programadores. Acostumbrados a entornos gráficos basados en respuestas al ratón, una interfaz de usuario multitáctil nos plantea un nuevo reto a la mayoría de nosotros.</p>
<p>En este artículo, pretendo dos cosas: por una parte, informarte de qué necesitas para comenzar a desarrollar y cómo obtenerlo. Por otra parte, facilitarte esa documentación que a todos nos va tan bien para empezar con una nueva tecnología. Así que vamos a ello.<br />
<span id="more-158"></span><br />
Lo primero que debes saber, es que una aplicación para Surface no es más que una aplicación WPF o XNA. Por si no lo sabías, WPF es un entorno muy potente para desarrollar aplicaciones de escritorio orientadas a los nuevos entornos gráficos de Windows Vista y Windows 7. XNA es un entorno para desarrollo de videojuegos también facilitado por Microsoft. Si has jugado con la Xbox 360 te habrás preguntado ¿de dónde salen los tantísimos juegos del bazar? Pues bien, la mayoría están desarrollados por compañías independientes con XNA.</p>
<p>Obviamente, optar por WPF o XNA dependerá de nuestra aplicación. Si necesitamos un motor rico en controles de usuario, optaríamos por WPF. Si necesitamos un motor potente en la renderización de gráficos 3D, optaríamos por XNA. Depende de las necesidades de nuestra aplicación.</p>
<p>En este artículo, pretendo dos cosas: por una parte, informarte de qué necesitas para comenzar a desarrollar y cómo obtenerlo. Por otra parte, facilitarte esa documentación que a todos nos va tan bien para empezar con una nueva tecnología. Así que vamos a ello.</p>
<p>Lo primero que debes saber, es que una aplicación para Surface no es más que una aplicación WPF o XNA. Por si no lo sabías, WPF es un entorno muy potente para desarrollar aplicaciones de escritorio orientadas a los nuevos entornos gráficos de Windows Vista y Windows 7. XNA es un entorno para desarrollo de videojuegos también facilitado por Microsoft. Si has jugado con la Xbox 360 te habrás preguntado ¿de dónde salen los tantísimos juegos del bazar? Pues bien, la mayoría están desarrollados por compañías independientes con XNA.Obviamente, optar por WPF o XNA dependerá de nuestra aplicación. Si necesitamos un motor rico en controles de usuario, optaríamos por WPF. Si necesitamos un motor potente en la renderización de gráficos 3D, optaríamos por XNA. Depende de las necesidades de nuestra aplicación.</p>
<h3>Instalación del entorno de desarrollo</h3>
<p>Para empezar, un detalle importante es nuestro sistema operativo: El SDK de Surface no funcionará en Windows XP, necesitaremos Windows Vista o superior.</p>
<p>Bien, empecemos a instalar los programas necesarios. Antes de empezar, no estaría mal asegurarse de que tenemos instalada la última versión del .Net Framework (3.5 SP1 en estos momentos).</p>
<p>La primera herramienta que debemos conseguir es un Visual Studio. Como sabrás, Visual Studio es un IDE desarrollado por Microsoft y orientado al desarrollo de aplicaciones en .Net. Si no lo tienes y eres estudiante universitario, puedes hacerte con una licencia de estudiante. Esta licencia es totalmente gratuita y sólo necesitaras proporcionar tu identificación como estudiante. Puedes obtenerla aquí: <a href="https://www.dreamspark.com/Products/Product.aspx?productid=24">Microsoft Visual Studio</a>.</p>
<p>Cuando tengamos el Visual Studio instalado, deberemos instalar el Framework de XNA (independientemente de que queramos desarrollar con WPF). Lo podemos obtener de aquí: <a href="http://www.microsoft.com/downloads/details.aspx?familyid=15fb9169-4a25-4dca-bf40-9c497568f102&#038;displaylang=en.">Microsoft XNA Framework</a>.</p>
<p>Finalmente, instalamos el SDK de Surface. Lo encontramos aquí: <a href="http://www.microsoft.com/downloads/details.aspx?displaylang=en&#038;FamilyID=3db8987b-47c8-46ca-aafb-9c3b36f43bcc">Microsoft Surface SDK</a>.</p>
<p>Con este software instalado, ya estamos listos para abrir el Visual Studio y crear un nuevo proyecto de Surface, no sin antes ejecutar el emulador de Surface que viene con el SDK. De esta forma, al depurar proyectos desde Visual Studio, se ejecutarán en el emulador.</p>
<p>Debes saber, además; que si conectas más de un ratón por USB el emulador los considerará dedos diferentes. ¡Eso es, soporte multitáctil en tu ordenador!.</p>
<h3>Recursos de documentación para empezar</h3>
<p>Ya tenemos todo lo necesario para empezar a desarrollar aplicaciones de Surface. Ahora, sólo nos falta algo de documentación que nos oriente para empezar a hacer cosas.</p>
<h4>Developing for Microsoft Surface</h4>
<p>Pero ¿dónde nos estamos metiendo realmente? En esta conferencia de Microsoft se ilustra cómo es el desarrollo de aplicaciones en Surface.<br />
<a href="http://channel9.msdn.com/pdc2008/PC17/">Developing for Microsoft Surface</a>.</p>
<h4>Hola Mundo Surface con WPF</h4>
<p>Siguiendo en la línea anterior, este artículo me ha aclarado algunos conceptos generales más a la hora de afrontar el desarrollo con Surface. Interesante sobre todo porque habla algo de los nuevos eventos de contacto de Surface.<br />
<a href="http://www.luisguerrero.net/post/2009/03/16/Hola-Mundo-Surface-con-WPF.aspx">Hola Mundo Surface con WPF</a>.</p>
<h4>MSDN .Net Framework Developer Center</h4>
<p>Pero vamos, ya está bien de conceptos generales, ¿verdad? Seguro que ya tienes ganas de meterle mano a Surface.</p>
<p>En MSDN nos facilitan información y ejemplos varios para empezar a programar algunas cosas. ¡Suerte!.<br />
<a href="http://msdn.microsoft.com/en-us/library/ee804767.aspx">MSDN .Net Framework Developer Center</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.juanmasantoyo.es/index.php/2010/04/06/introduccion-al-desarrollo-para-microsoft-surface/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>XML dinámicos con asp.Net</title>
		<link>http://www.juanmasantoyo.es/index.php/2010/03/16/xml-dinamicos-con-asp-net/</link>
		<comments>http://www.juanmasantoyo.es/index.php/2010/03/16/xml-dinamicos-con-asp-net/#comments</comments>
		<pubDate>Tue, 16 Mar 2010 19:04:33 +0000</pubDate>
		<dc:creator>Juanma</dc:creator>
				<category><![CDATA[.net]]></category>
		<category><![CDATA[ajax]]></category>
		<category><![CDATA[asmx]]></category>
		<category><![CDATA[asp.net]]></category>
		<category><![CDATA[webservice .net]]></category>
		<category><![CDATA[xml dinamicos]]></category>

		<guid isPermaLink="false">http://www.juanmasantoyo.es/?p=397</guid>
		<description><![CDATA[Desde que me inicié en el asp.Net (no hace demasiado de eso) me he estado preguntando cómo se podría hacer una llamada al servidor que devolviese un contenido XML dinámico. Dicho de otra forma, lo que yo quería era generar un contenido XML en base a un parámetro enviado por GET o POST. Estos XML son necesarios para cualquier aplicación basada en Ajax que se precie, además de ser especialmente útiles para otras situaciones (como por ejemplo, compartir contenido interno a un destinatario externo).

Pues bien, hace un par de días me surgió la necesidad y investigué un poco al respecto. En realidad, la solución que nos propone asp.Net no está nada mal: un archivo asmx que actúa como WebService.]]></description>
			<content:encoded><![CDATA[<p>Desde que me inicié en el asp.Net (no hace demasiado de eso) me he estado preguntando cómo se podría hacer una llamada al servidor que devolviese un contenido <em>XML</em> dinámico. Dicho de otra forma, lo que yo quería era generar un contenido XML en base a un parámetro enviado por GET o POST. Estos <em>XML</em> son necesarios para cualquier aplicación basada en <a href="http://www.juanmasantoyo.es/index.php/category/ajax/">Ajax</a> que se precie, además de ser especialmente útiles para otras situaciones (como por ejemplo, compartir contenido interno a un consumidor externo).</p>
<p>Pues bien, hace un par de días me surgió la necesidad y investigué un poco al respecto. En realidad, la solución que nos propone <em>.Net</em> no está nada mal: un archivo <em>.asmx</em> que actúa como <em>WebService</em>.<br />
<span id="more-397"></span></p>
<h3>Sobre los <em>.asmx</em></h3>
<p>De la misma forma que podemos añadir archivos <em>.aspx</em> a un proyecto web, también podemos añadir archivos <em>.asmx</em>. Estos archivos son la base de cualquier proyecto de <em>WebService</em> que desarrollemos en <em>.Net</em>, pero también podemos usarlos en los proyectos web normales.</p>
<h3>¿Cómo se usan los <em>.asmx</em>?</h3>
<p>El uso de los <em>.asmx</em> es simple: básicamente, lo que debemos hacer es crear un método, que devuelva un valor y que tenga la etiqueta [WebMethod]. Al final, la llamada a servidor: &#8220;http://&lt;ruta al asmx&gt;/&lt;nombre del método&gt;/&lt;parámetros get si hay&gt;&#8221; nos devolverá el resultado devuelto por el método.</p>
<p>Por supuesto, el método puede tener parámetros, que enviaremos por <em>GET</em> o por <em>POST</em>; en cuyo caso, al hacer la llamada los parámetros enviados deberán tener el mismo nombre que el parámetro en el método.</p>
<p>Es importante destacar que si queremos enviar parámetros por <em>GET</em> o <em>POST</em>, deberemos activar ambos protocolos en el <em>Web.config</em> de nuestra aplicación.</p>
<h3>Un ejemplo</h3>
<p>La mejor forma de ver cómo funciona un <em>.asmx</em> es viendo un pequeño ejemplo. Con poco esfuerzo podremos hacer algunas pruebas.</p>
<h4>Crear el proyecto</h4>
<p>Sólo necesitaremos crear un nuevo proyecto web en nuestro Visual Studio. Nos creará por defecto un <em>.aspx</em>, pero no nos interesa demasiado.</p>
<h4>Crear el asmx</h4>
<p>Añadiremos en el proyecto web un nuevo elemento, que será un Servicio web. Lo encontrarás entre los posibles elementos de la categoría &#8220;Web&#8221;. Lo llamaremos &#8220;<em>test.asmx</em>&#8220;.</p>
<p>Cuando tengamos nuestro <em>.asmx</em> creado, lo estableceremos como la página inicial de nuestro proyecto (es una opción que aparecerá si clicamos con el botón derecho en el <em>.asmx</em>).</p>
<h4>Un nuevo método en el <em>.asmx</em></h4>
<p>En el <em>.asmx</em> ya tenemos un método creado: <em>HelloWorld</em>. Es muy ilustrativo, ya que nos indica dos cosas: la primera, que nuestros métodos deberán tener al principio la etiqueta <strong>[WebMethod]</strong>. La segunda, que el valor retornado será lo que mostrará nuestro <em>WebService</em> al realizar una petición al método.</p>
<p>Vamos a programar un método más bien absurdo, pero que nos permitirá ver cómo funciona el envío de parámetros:</p>
<pre class="brush:csharp">
	[WebMethod]
	public string ReturnThisString(string str)
	{
		return str;

	}
</pre>
<p>Hay dos cosas a destacar:</p>
<ol>
<li>El parámetro que recibe este método se llama <strong>str</strong>.</li>
<li>El resultado que genera este método, es un <em>string</em>.</li>
</ol>
<h3>Activamos los protocolos <em>GET</em> y <em>POST</em></h3>
<p>Como dije unas líneas más arriba, debemos activar los protocolos de envío <em>GET</em> y <em>POST</em> si queremos usarlos en nuestro <em>WebService</em>. Todo lo que debemos hacer es incluir <strong>dentro</strong> del nodo <em>&lt;system.web/&gt;</em> de nuestro <em>Web.config</em> las siguientes líneas:</p>
<pre class="brush:xml">
	&lt;webServices&gt;
		&lt;protocols&gt;
			&lt;add name=&quot;HttpGet&quot; /&gt;
			&lt;add name=&quot;HttpPost&quot; /&gt;
		&lt;/protocols&gt;
	&lt;/webServices&gt;
</pre>
<h4>Probamos el <em>WebService</em></h4>
<p>Y toca inicar una depuración. La primera vez que lo hagamos nos pedirá que activemos el modo debug. Le decimos que sí, y arrancará el <em>.asmx</em>.</p>
<p><a href="http://www.juanmasantoyo.es/wp-content/uploads/2010/03/XmlDinamicosAspNet-01-e1268766894973.png"><img src="http://www.juanmasantoyo.es/wp-content/uploads/2010/03/XmlDinamicosAspNet-01-e1268766894973.png" alt="Métodos del WebService" title="Métodos del WebService" width="450" height="131" class="aligncenter size-full wp-image-403" /></a></p>
<p>Lo que veremos, será un resumen de los métodos que tiene el <em>.asmx</em> (esto no se vería en un entorno de producción). Podemos clicar en el nombre de nuestro método &#8220;<em>ReturnThisString</em>&#8221; para que nos muestre un pequeño formulario donde indicaremos el valor del parámetro &#8220;<em>str</em>&#8220;. Al enviarlo, veremos el resultado de nuestro método de <em>WebService</em>.</p>
<p><a href="http://www.juanmasantoyo.es/wp-content/uploads/2010/03/XmlDinamicosAspNet-02-e1268766971605.png"><img src="http://www.juanmasantoyo.es/wp-content/uploads/2010/03/XmlDinamicosAspNet-02-e1268766971605.png" alt="Formulario de envío de parámetros" title="Formulario de envío de parámetros" width="450" height="244" class="aligncenter size-full wp-image-404" /></a></p>
<p>Hay varias cosas interesantes en las que fijarse ahora:</p>
<ol>
<li>
		El resultado devuelto es un XML.	</p>
<p>		Sea cual sea el resultado, el asmx siempre nos dará una respuesta XML.
	</li>
<li>
		La ruta de la página.</p>
<p>		Como ves, la url de este xml es: &#8220;http://&lt;ruta al asmx&gt;/&lt;nombre del método&gt;/&lt;parámetros get si hay&gt;&#8221;. Esta es la dirección a la que accederemos para obtener resultados de nuestro <em>WebService</em>, ya sea con <em>Ajax</em> o con otra tecnología.
	</li>
<li>
		El nodo <em>string</em>.</p>
<p>		El resultado del método viene, en realidad, dentro de un nodo llamado <em>string</em>. Esto es, efectívamente, el tipo del dato devuelto. ¿imaginas lo que pasaría si en vez de un <em>string</em>, devolvemos una lista de <em>strings</em>? Efectivamente, el <em>XML</em> resultante sería una lista de nodos <em>string</em>.</p>
<p><a href="http://www.juanmasantoyo.es/wp-content/uploads/2010/03/XmlDinamicosAspNet-03-e1268766951190.png"><img src="http://www.juanmasantoyo.es/wp-content/uploads/2010/03/XmlDinamicosAspNet-03-e1268766951190.png" alt="Resultado de una llamada al método ReturnThisString" title="Resultado de una llamada al método ReturnThisString" width="450" height="114" class="aligncenter size-full wp-image-405" /></a>
	</li>
</ol>
<h4>Generamos un <em>XML</em> como respuesta del método</h4>
<p>Como ves, los <em>WebServices</em> <em>.asmx</em> no son demasiado complicados, aunque por el momento seguimos teniendo un pequeño problema: los <em>XML</em> que generamos como resultado son generados automáticamente y no tenemos control sobre ellos. Vamos a poner solución a esto.</p>
<p>La cuestión es que si en lugar de un <em>string</em>, devolvemos un objeto <em>XmlDocument</em>, el resultado devuelto por el <em>WebService</em> será el contenido del <em>XmlDocument</em> tal cual. Por lo tanto, se podría decir que el proceso para generar respuestas <em>XML</em> personalizadas (la razón de este artículo) es el siguiente:</p>
<ol>
<li>Creamos un método en el <em>.asmx</em> que devuelva un objeto <em>XmlDocument</em>.</li>
<li>Obtenemos todos los datos que queramos devolver.</li>
<li>Los metemos en un <em>XmlDocument</em>.</li>
<li>Retornamos el <em>XmlDocument</em>.</li>
</ol>
<h4>Un último ejemplo</h4>
<p>Vamos a crear un último ejemplo: un pequeño método que nos introducirá en la creación de <em>XML</em> dinámicos:</p>
<pre class="brush:csharp">
	[WebMethod]
	public XmlDocument ReturnXml()
	{
		XmlDocument xml = new XmlDocument();

		XmlNode rootNode = xml.CreateElement("RespuestaXml");
		XmlNode txtNode = xml.CreateTextNode("Xml generado automáticamente");
		XmlNode subNode = xml.CreateElement("HolaMundo");
		XmlNode commentNode = xml.CreateComment("Esto es un comentario");

		subNode.AppendChild(commentNode);
		rootNode.AppendChild(txtNode);
		rootNode.AppendChild(subNode);
		xml.AppendChild(rootNode);

		return xml;
	}
</pre>
<p>Esto generaría el siguiente resultado:</p>
<p><a href="http://www.juanmasantoyo.es/wp-content/uploads/2010/03/XmlDinamicosAspNet-04-e1268766930458.png"><img src="http://www.juanmasantoyo.es/wp-content/uploads/2010/03/XmlDinamicosAspNet-04-e1268766930458.png" alt="Resultado de una llamada al método ReturnXml" title="Resultado de una llamada al método ReturnXml" width="450" height="211" class="aligncenter size-full wp-image-406" /></a></p>
<h3>Descargar el ejemplo</h3>
<p>Puedes descargar el ejemplo si algo no te ha quedado claro. Recuerda también que puedes dejar comentarios.</p>
<p><a href='http://www.juanmasantoyo.es/wp-content/uploads/2010/03/JuanmaSantoyoXmlDinamicos.zip'>JuanmaSantoyoXmlDinamicos</a></p>
<h3>¡Hemos terminado!</h3>
<p>Y de momento no hay mucho más que decir. Con este ejemplo, hemos tocado un tema especialmente importante para la mayoría de proyectos web, ya que los <em>XML</em> dinámicos son importantes para las funcionalidades <em>Ajax</em> y para comunicarnos con otras aplicaciones externas. ¿Aún no tienes RSS en tu sitio web? <a href="http://www.rssboard.org/rss-specificationg">¡A qué esperas!</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.juanmasantoyo.es/index.php/2010/03/16/xml-dinamicos-con-asp-net/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Clase para acceso avanzado a las AppSettings del WebConfig</title>
		<link>http://www.juanmasantoyo.es/index.php/2010/02/08/clase-para-acceso-avanzado-a-las-appsettings-del-webconfig/</link>
		<comments>http://www.juanmasantoyo.es/index.php/2010/02/08/clase-para-acceso-avanzado-a-las-appsettings-del-webconfig/#comments</comments>
		<pubDate>Mon, 08 Feb 2010 17:41:54 +0000</pubDate>
		<dc:creator>Juanma</dc:creator>
				<category><![CDATA[.net]]></category>
		<category><![CDATA[appsettings]]></category>
		<category><![CDATA[asp.net]]></category>
		<category><![CDATA[webconfig]]></category>

		<guid isPermaLink="false">http://www.juanmasantoyo.es/?p=292</guid>
		<description><![CDATA[Para quien no lo sepa, el WebConfig de asp.Net es un archivo XML que contiene todos los aspectos de configuración de nuestra aplicación. Entre los distintos parámetros, hay un nodo llamado AppSettings que nos permite definir pares clave / valor para después acceder a ellas desde cualquier punto de la aplicación.

Pero, a pesar de que el api proporciona dos métodos diferentes de acceso a las AppSettings, ambos tienen algunos inconvenientes. Lo que haremos, es crear una pequeña clase que nos permitirá tratar las AppSettings de una forma más simple y con una funcionalidad mejorada.]]></description>
			<content:encoded><![CDATA[<p>Para quien no lo sepa, el WebConfig de asp.Net es un archivo XML que contiene todos los aspectos de configuración de nuestra aplicación. Entre los distintos parámetros, hay un nodo llamado AppSettings que nos permite definir pares clave / valor para después acceder a ellas desde cualquier punto de la aplicación.</p>
<p>Pero, a pesar de que el api proporciona dos métodos diferentes de acceso a las AppSettings, ambos tienen algunos inconvenientes. Lo que haremos, es crear una pequeña clase que nos permitirá tratar las AppSettings de una forma más simple y con una funcionalidad mejorada.<br />
<span id="more-292"></span></p>
<p><a href='http://www.juanmasantoyo.es/wp-content/uploads/2010/02/AppSettings.zip'>Clase AppSettings</a></p>
<h3>Los inconvenientes</h3>
<p>Los inconvenientes a la hora de trabajar con las variables de AppSettings son varios. Se podría decir que hay dos formas de acceder. Comentemos las dos formas:</p>
<h4>Primera forma: la clase ConfigurationManager</h4>
<p>La clase ConfigurationManager nos proporciona un diccionario estático que contiene los valores definidos en AppSettings:</p>
<pre class="brush:c-sharp">
ConfigurationManager.AppSettings["clave"];
</pre>
<p>A mi modo de ver, más largo de lo necesario y poco intuitivo (escribid &#8220;Configuration&#8221; en un VisualStudio y mirad cuantas entradas muestra el intellisense). Prometo que me costó un par de intentos memorizar esta línea.</p>
<p>Por otra parte, lo más grave es que el dato devuelto es siempre un <em>string</em>, lo cual nos obliga a hacer una conversión del dato inmediatamente después si queremos otro formato.</p>
<h4>Segunda forma: la clase AppSettingsReader</h4>
<p>Esta segunda clase, tiene algunas ventajas respecto a la anterior, pero también es mejorable.</p>
<p>Por una parte, su uso requiere de una instancia de AppSettingsReader y la posterior invocación a un método:</p>
<pre class="brush:c-sharp">
AppSettingsReader settings = new AppSettingsReader();
string valor = (string) settings.GetValue("clave", typeof(string));
</pre>
<p>Por no mencionar el casting obligatorio.</p>
<p>Por otra parte, aunque en principio se puede especificar el tipo del dato devuelto, hay poco control sobre él. ¿Qué pasa si es una fecha? Sinceramente, ni lo he probado.</p>
<h3>Una posible solución</h3>
<p>Yendo al grano, lo cierto es que el acceso a las AppSettings es mejorable. Vamos a considerar y a anotar algunas cosas sobre una posible alternativa que nos solucione los inconvenientes comentados:</p>
<ul>
<li>Se accede desde una clase estática, pero más simple que la vista en la primera forma de acceder. No debería ser mucho más complejo que <em>AppSettings.GetValue(&#8220;clave&#8221;)</em>.</li>
<li>Se ofrecen varios tipos básicos (pocos, pero controlados) como posibles retornos. Nuestra clase se encarga de hacer la conversión.</li>
<li>Además, la clase será capaz de realizar un tratamiento avanzado del contenido de las AppSettings: podrá retornar listas y diccionarios de los tipos básicos.</li>
</ul>
<h3>Definimos los diferentes tipos básicos de AppSettings</h3>
<p>Serán solamente cuatro, pero a cambio ganaremos el control absoluto sobre los valores que retornamos.</p>
<p>Los tipos serán:</p>
<ul>
<li><em>string</em></li>
<li><em>int</em></li>
<li><em>bool</em></li>
<li><em>DateTime</em></li>
</ul>
<h3>Definimos los diferentes formatos de las claves del AppSettings</h3>
<p>Vamos a estipular como deberán ser escritos los datos en el WebConfig. A partir de ahora, deberemos escribir los valores en AppSettings siguiendo uno de los formatos siguientes. aunque ante cualquier excepción, siempre podremos obtener los datos como un tipo básico <em>string</em> (que será como si no aplicásemos ninguna conversión). </p>
<h4>Datos básicos</h4>
<p>No consideraremos un formato para los datos básicos porque no lo necesitan (excepto las fechas, que las vemos ahora mismo). Las cadenas se escribirán como cadenas, los números como números, y los booleanos como <em>&#8220;true&#8221;</em> y <em>&#8220;false&#8221;</em>.</p>
<h4>Fechas</h4>
<p>Las fechas seguirán un formato típicamente español:</p>
<p>dia/mes/año</p>
<p>Donde los días van del 1 al 31, los meses del 1 al 12, y los años tienen cuatro cifras.</p>
<h4>Listas</h4>
<p>Separaremos los diferentes elementos con comas.</p>
<p>valor1, valor2, valor3, valor4</p>
<p>Los espacios en blanco entre los valores y las comas serán indiferentes.</p>
<h4>Diccionarios</h4>
<p> Separaremos los pares con comas, y los clave valor con dos puntos.</p>
<p>clave1: valor1, clave2: valor2, clave3: valor3</p>
<p>Al igual que antes, los espacios en blanco entre los separadores y los valores son indiferentes.</p>
<h3>Programamos la clase AppSettings</h3>
<p>Ya sabemos que formatos tenemos que considerar. Ahora vamos a programar nuestra clase.</p>
<p>Antes que nada, debemos tener más o menos claro cómo queremos hacerlo. Lo haremos así:</p>
<ul>
<li>Tendremos un método privado, llamado <em>Get</em>; que se encargará simplemente de obtener el dato de WebConfig como un <em>string</em>.</li>
<li>Tendremos tres métodos privados que se encargarán de convertir un <em>string</em> al resto de formatos. Se llamarán <em>ToInt</em>, <em>ToBool</em> y <em>ToDate</em>.</li>
<li>Tendremos varios métodos públicos, cada uno devolverá un tipo de dato. Los métodos se llamarán <em>GetAsString</em>, <em>GetAsStringList</em>, <em>GetAsStringDict</em>, <em>GetAsInt</em>, etc.</li>
</ul>
<h4>El método Get</h4>
<pre class="brush:c-sharp">
private static string Get(string key)
{
	AppSettingsReader settings = new AppSettingsReader();            

	return (string) settings.GetValue(key, typeof(string));
}
</pre>
<p>En este método tenemos la única instancia de AppSettingsReader que vamos a usar. El resto de métodos de la clase se apoyarán en este para obtener la información del WebConfig.</p>
<h4>Los métodos conversores</h4>
<p>Serán tres. Uno convertirá un <em>string</em> a <em>int</em>, otro a <em>bool</em> y el último a <em>DateTime</em>.</p>
<pre class="brush:c-sharp">
private static int ToInt(string value)
{
	int v = 0;

	if (int.TryParse(value, out v))
	{
		return v;
	}

	return 0;
}

private static bool ToBool(string value)
{
	bool v = false;

	if (bool.TryParse(value, out v))
	{
		return v;
	}

	return false;
}

private static DateTime ToDateTime(string value)
{
	DateTime v = DateTime.Today;

	if (DateTime.TryParseExact(value, "dd/MM/yyyy", new CultureInfo("es-ES"), DateTimeStyles.None, out v))
	{
		return v;
	}

	else return new DateTime();
}
</pre>
<h4>Los métodos que retornarán los datos</h4>
<p>Estos métodos se apoyarán en los anteriores para obtener los valores, darles un formato de salida y devolverlos. Hay uno por tipo de dato y tipo de salida (normal, lista o diccionario).</p>
<p>Además, a los métodos que requieran de un separador (los que devuelven listas y diccionarios) les haremos una sobrecarga que permita indicar un separador distinto. De esta forma podremos reaccionar ante posibles conflictos entre nuestros separadores por defecto y los valores que contengan las AppSettings.</p>
<pre class="brush:c-sharp">
public static string GetAsString(string key)
{
	string value = Get(key);

	return value;
}

public static int GetAsInt(string key)
{
	string value = Get(key);

	return ToInt(value);
}

public static bool GetAsBool(string key)
{
	string value = Get(key);

	return ToBool(value);
}

public static DateTime GetAsDateTime(string key)
{
	string value = Get(key);

	return ToDateTime(value);
}

public static List&lt;string&gt; GetAsStringList(string key, char sep)
{
	string value = Get(key);
	List&lt;string&gt; list = new List&lt;string&gt;();

	foreach (string s in value.Split(new char[] { sep }))
	{
		list.Add(s.Trim());
	}

	return list;
}

public static List&lt;string&gt; GetAsStringList(string key)
{
	return GetAsStringList(key, '|');
}

public static List&lt;int&gt; GetAsIntList(string key, char sep)
{
	string value = Get(key);
	List&lt;int&gt; list = new List&lt;int&gt;();

	foreach (string s in value.Split(new char[] { sep }))
	{
		list.Add(ToInt(s.Trim()));
	}

	return list;
}

public static List&lt;int&gt; GetAsIntList(string key)
{
	return GetAsIntList(key, '|');
}

public static List&lt;bool&gt; GetAsBoolList(string key, char sep)
{
	string value = Get(key);
	List&lt;bool&gt; list = new List&lt;bool&gt;();

	foreach (string s in value.Split(new char[] { sep }))
	{
		list.Add(ToBool(s.Trim()));
	}

	return list;
}

public static List&lt;bool&gt; GetAsBoolList(string key)
{
	return GetAsBoolList(key, '|');
}

public static List&lt;DateTime&gt; GetAsDateTimeList(string key, char sep)
{
	string value = Get(key);
	List&lt;DateTime&gt; list = new List&lt;DateTime&gt;();

	foreach (string s in value.Split(new char[] { sep }))
	{
		list.Add(ToDateTime(s.Trim()));
	}

	return list;
}

public static List&lt;DateTime&gt; GetAsDateTimeList(string key)
{
	return GetAsDateTimeList(key, '|');
}

public static Dictionary&lt;string, string&gt; GetAsStringDict(string key, char itemSep, char valueSep)
{
	string raw = Get(key);
	Dictionary&lt;string, string&gt; dict = new Dictionary&lt;string, string&gt;();

	foreach(string i in raw.Split(itemSep))
	{
		string item = i.Trim();

		string[] value = item.Split(valueSep);
		value[0] = value[0].Trim();
		value[1] = value[1].Trim();

		if (!dict.ContainsKey(value[0]))
		{
			dict.Add(value[0], value[1]);
		}
	}

	return dict;
}

public static Dictionary&lt;string, string&gt; GetAsStringDict(string key)
{
	return GetAsStringDict(key, ';', '|');
}

public static Dictionary&lt;string, int&gt; GetAsIntDict(string key, char itemSep, char valueSep)
{
	string raw = Get(key);
	Dictionary&lt;string, int&gt; dict = new Dictionary&lt;string, int&gt;();

	foreach (string i in raw.Split(itemSep))
	{
		string item = i.Trim();

		string[] value = item.Split(valueSep);
		value[0] = value[0].Trim();
		value[1] = value[1].Trim();

		if (!dict.ContainsKey(value[0]))
		{
			dict.Add(value[0], ToInt(value[1]));
		}
	}

	return dict;
}

public static Dictionary&lt;string, int&gt; GetAsIntDict(string key)
{
	return GetAsIntDict(key, ';', '|');
}

public static Dictionary&lt;string, bool&gt; GetAsBoolDict(string key, char itemSep, char valueSep)
{
	string raw = Get(key);
	Dictionary&lt;string, bool&gt; dict = new Dictionary&lt;string, bool&gt;();

	foreach (string i in raw.Split(itemSep))
	{
		string item = i.Trim();

		string[] value = item.Split(valueSep);
		value[0] = value[0].Trim();
		value[1] = value[1].Trim();

		if (!dict.ContainsKey(value[0]))
		{
			dict.Add(value[0], ToBool(value[1]));
		}
	}

	return dict;
}

public static Dictionary&lt;string, bool&gt; GetAsBoolDict(string key)
{
	return GetAsBoolDict(key, ';', '|');
}

public static Dictionary&lt;string, DateTime&gt; GetAsDateTimeDict(string key, char itemSep, char valueSep)
{
	string raw = Get(key);
	Dictionary&lt;string, DateTime&gt; dict = new Dictionary&lt;string, DateTime&gt;();

	foreach (string i in raw.Split(itemSep))
	{
		string item = i.Trim();

		string[] value = item.Split(valueSep);
		value[0] = value[0].Trim();
		value[1] = value[1].Trim();

		if (!dict.ContainsKey(value[0]))
		{
			dict.Add(value[0], ToDateTime(value[1]));
		}
	}

	return dict;
}

public static Dictionary&lt;string, DateTime&gt; GetAsDateTimeDict(string key)
{
	return GetAsDateTimeDict(key, ';', '|');
}
</pre>
<h3>¡Hemos terminado!</h3>
<p>Ahora ya tenemos una clase que, además de ser fácilmente utilizable desde cualquier parte del programa, nos proporciona los valores de AppSettings en el formato que necesitemos. Además hemos extendido la funcionalidad respecto al api de asp.Net por que también es capaz de obtener los datos en forma de listas y diccionarios.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.juanmasantoyo.es/index.php/2010/02/08/clase-para-acceso-avanzado-a-las-appsettings-del-webconfig/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
