jueves, 16 de febrero de 2017

El servidor web, conceptos avanzados



Validando
  • Qué es la validación? Imagínense que ustedes tienen una página web, donde la gente se registra. O sea, crea su usuario. Eso lo hacen diariamente para obtener una cuenta de correo electrónico, o darse de alta en una red social.
  • En esa pantalla de registración, les piden un montón de información, como ser: nombre, apellido, fecha de nacimiento, teléfono, dirección, país, ciudad, dirección de correo electrónico, etc. Cada uno de estos datos tiene alguna naturaleza o tipo. Qué significa eso? La fecha de nacimiento tiene la forma de una fecha. El nombre y el apellido son palabras. El correo electrónico tiene el símbolo “@” y un “.” , el número telefónico está compuesto por números, y en algunos casos por “-“, o paréntesis.
  • Pero qué ocurre en la realidad? Como el lugar para ingresar estos datos a veces no está bien programado, el usuario podría ingresar datos de naturaleza errónea en nuestra interfaz y nosotros tendríamos información incorrecta, o datos sucios. Así el usuario podría decirnos que su correo electrónico es por ejemplo “johndoe@hello”. O que su fecha de nacimiento es “milnovecientos”.
  • Por este motivos, es que se realiza lo que llamamos validación de los datos. Y esto consiste básicamente en corroborar que los datos tengan el tipo y forma que corresponde. Esto no significa que el usuario no pueda mentir, pero por lo menos nos aseguraremos que los datos cumplan con ciertas reglas.
Validación en el servidor
  • La validación se puede hacer enviando la información al servidor para que este la analice y luego la aplicación decida si la misma tiene el formato correcto y la apruebe o si se mostrarán en la interfaz mensajes con los errores encontrados.
  • Esto lo haremos utilizando nuevamente la estructura de mi modelo MVC, donde la vista se mostrará de forma tal que le requiera al usuario el ingreso de información, para que luego el controlador envíe la misma al modelo, quien decidirá a continuación como se actualizará la vista de acuerdo a la correctitudo no de lo ingresado.
  • Como ejemplo, mostraremos cuales serían los componentes MVC para el ingreso de un nuevo dato Persona y otra interfaz para poder consultar los datos.
Validación en el servidor - Modelo

usingSystem;
usingSystem.Collections.Generic;
using System.Linq;
using System.Web;
namespace MvcSimpleModelBinding.Models
{
public class Person
{
public intId { get; set; }
public string Name { get; set; }
public intAge { get; set; }
public string Street { get; set; }
public string City { get; set; }
public string State { get; set; }
public intZipcode{ get; set; }
}
}

Validación en el servidor - Controller

public class PersonController: Controller
{
static List people = new List();
public ActionResultIndex()
{
return View(people);
}
public ActionResultDetails(Person person)
{
return View(person);
}
public ActionResultCreate()
{
return View();
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResultCreate(Person person)
{
if (!ModelState.IsValid)
{
return View("Create", person);
}
people.Add(person);
return RedirectToAction("Index");
}

Validación en el servidor – Vista Index

<h2>Index</h2>
<table>
<tr>
<th></th>
<th>
Id
</th>
<th>
Name
</th>
</tr>
<% foreach(varperson in Model) { %>
<tr>
<td><%= Html.ActionLink("Details", "Details", person )%></td>
<td><%= Html.Encode(person.Id) %></td>
<td><%= Html.Encode(person.Name) %></td>
</tr>
<% } %>
</table>
<p>
<%= Html.ActionLink("Create New", "Create") %>
</p>

Validación en el servidor – Vista Create

<h2>Create</h2>
<%= Html.ValidationSummary("Create was unsuccessful. Please correct the errors and try again.") %>
<% using (Html.BeginForm()) {%>
<fieldset><legend>Fields</legend>
<p>
<label for="Id">Id:</label><%= Html.TextBox("Id") %><%= Html.ValidationMessage("Id", "*") %>
</p>
<p>
<label for="Name">Name:</label><%= Html.TextBox("Name") %><%= Html.ValidationMessage("Name", "*") %>
</p>
<p>
<label for="Age">Age:</label><%= Html.TextBox("Age") %><%= Html.ValidationMessage("Age", "*") %>
</p>
<p>
<label for="Street">Street:</label><%= Html.TextBox("Street") %><%= Html.ValidationMessage("Street", "*") %>
</p>
<p>
<label for="City">City:</label><%= Html.TextBox("City") %><%= Html.ValidationMessage("City", "*") %>
</p>
<p>
<label for="State">State:</label><%= Html.TextBox("State") %><%= Html.ValidationMessage("State", "*") %>
</p>
<p>
<label for="Zipcode">Zipcode:</label><%= Html.TextBox("Zipcode") %><%= Html.ValidationMessage("Zipcode", "*") %>
</p>
<p><input type="submit" value="Create" /> </p>
</fieldset>
<% } %>
<div><%=Html.ActionLink("Back to List", "Index") %></div>

Validación en el servidor – Vista Details

<h2>Details</h2>
<fieldset>
<legend>Fields</legend>
<p>
Id:<%= Html.Encode(Model.Id) %>
</p>
<p>
Name:<%= Html.Encode(Model.Name) %>
</p>
<p>
Age:<%= Html.Encode(Model.Age) %>
</p>
<p>
Street:<%= Html.Encode(Model.Street) %>
</p>
<p>
City:<%= Html.Encode(Model.City) %>
</p>
<p>
State:<%= Html.Encode(Model.State) %>
</p>
<p>
Zipcode:<%= Html.Encode(Model.Zipcode) %>
</p>
</fieldset>
<p><%=Html.ActionLink("Back to List", "Index") %></p>

Validación en el servidor - Contras
  • Cuál es el problema de esta aproximación? Nuevamente, la realidad nos indica que por otros medios es mas sencillo hacer las validaciones en la computadora del usuario en vez de sobrecargar nuestra aplicación con tareas innecesarias. Para ello, se usan tecnologías como Javascripto jQueryque directamente realizan validaciones del formato de los datos directamente en el navegador de los usuarios, ahorrando procesamiento al servidor.
Validación en el cliente -Javascript

<!DOCTYPE html>
<html>
<head>
<script>
function validateForm()
{
varx=document.forms["myForm"]["fname"].value;
if (x==null || x=="")
{
alert("First name must be filled out");
return false;
}
}
</script>
</head>
<body>
<form name="myForm" action="demo_form.asp" onsubmit="return validateForm()" method="post">
First name: <input type="text" name="fname">
<input type="submit" value="Submit">
</form>
</body>
</html>
  • En la función anterior, lo que hacemos cuando enviamos el formulario, es llamar a una función de Javascriptllamada validateFormque se fija si el contenido de ese campo es nullo vacío. En caso positivo abrirá un popupinformando el error. Lo mismo se puede hacer para validar un email:
function validateForm()
{
varx=document.forms["myForm"]["email"].value;
varatpos=x.indexOf("@");
vardotpos=x.lastIndexOf(".");
if(atpos<1 || dotpos<atpos+2 || dotpos+2>=x.length)
{
alert("Not a valid e-mail address");
return false;
}
}
</script>

Validación en el cliente
  • Y finalmente, existen otro tipo de validaciones utilizando la tecnología jQueryque es muy sencilla y pueden ver algunos ejemplos en: http://jqueryvalidation.org/
  • Cualquiera de estos últimos dos tipos de validaciones se realizan del lado del usuario, ahorrando recursos en el servidor para que nuestra aplicación pueda enfocarse en otro tipo de procesamientos.
Enviando correos
  • Existen diversas formas de enviar correos electrónicos desde nuestra aplicación. Las hay mas sencillas y mas complicadas. Intentaremos en este caso hacer en pocos pasos el envío de email utilizando librerías gratuitas que funcionarán con nuestro modelo MVC.
  • Creamos un nuevo proyecto en Visual Studio como ya vimos anteriormente, seleccionando un proyecto web MVC.
  • Luego crearemos una nueva clase en la carpeta Model, llamada correoModel.cs, cuyo código será el siguiente:
Enviando correos -Modelo

public class CorreoModel
{
public string From { get; set; }
public string To { get; set; }
public string Subject { get; set; }
public string Body { get; set; }
}
  • Luego en la carpeta Controllercrearemos un nuevo controlador llamado EnviarCorreoController
Enviando correos - Controlador

usingSystem;
usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Net.Mail;usingSystem.Web;usingSystem.Web.Mvc;
namespaceEnviarCorreo.Controllers
{publicclassEnviarCorreoController: Controller{//// GET: /EnviarCorreo/public ActionResultIndex()
{
return View();
}
[HttpPost]
public ViewResultIndex(EnviarCorreo.Models.CorreoModel_objModelMail)
{
if (ModelState.IsValid)
{
MailMessagemail = new MailMessage();
mail.To.Add(_objModelMail.To);
mail.From= new MailAddress(_objModelMail.From);
mail.Subject= _objModelMail.Subject;
string Body = _objModelMail.Body;
mail.Body= Body;
mail.IsBodyHtml= true;
SmtpClientsmtp= new SmtpClient();
smtp.Host= "smtp.outlook.com";
smtp.Port= 587;
smtp.UseDefaultCredentials= false;
smtp.Credentials= new System.Net.NetworkCredential
("username", "password");// Enter sedersUser name and password
smtp.EnableSsl= true;
smtp.Send(mail);
return View("Index", _objModelMail);
}
else
{
return View();
}
}}}
  • Y finalmente, en la carpeta de vistas, tendremos Index.cshtml
Enviando correos -Vista

@model EnviarCorreo.Models.CorreoModel
@{
ViewBag.Title= "Index";
}
<h2>Index</h2>
<fieldset>
<legend>
Send Email
</legend>
@using (Html.BeginForm())
{
@Html.ValidationSummary()
<p>From: </p>
<p>@Html.TextBoxFor(m=>m.From)</p>
<p>To: </p>
<p>@Html.TextBoxFor(m=>m.To)</p>
<p>Subject: </p>
<p>@Html.TextBoxFor(m=>m.Subject)</p>
<p>Body: </p>
<p>@Html.TextAreaFor(m=>m.Body)</p>
<input type ="submit" value ="Send" />
} </fieldset>

Explicando nuestro ejemplo
  • En el controlador tenemos un código que dice:
    • ViewResult Index (EnviarCorreo.Models.CorreoModel _objModelMail)
  • En este método, tenemos un dato que tiene la forma de nuestro CorreoModel. Luego creamos un dato MailMessage y le completamos toda la información que necesita:
    • To
    • From
    • Cc
    • Bcc
    • Subject
    • Body
  • Luego configuramos los datos del servidor de correo que enviará nuestro email con lo siguientes datos:
    • Host: el nombre del servidor
    • Port: el puerto en el cual nos conectamos para enviar el correo
    • UseDefaultCredential: indica si tiene algún usuario preconfigurado
    • Credentials: usuario y contraseña
    • EnableSsl: indica si se encripta la información con un tipo de seguridad llamada SSL
  • Y finalmente, le indicamos al servidor que envíe el correo utilizando la función Send
Interfaces avanzadas
  • Con funciones como la validación, y la utilización de controladores y modelos, podemos construir interfaces cada vez mas complejas y avanzadas, que permitirán una mayor interacción del usuario, sin necesidad de tener un alto procesamiento del lado del servidor contantemente. Si a esto le sumamos tecnologías como AJAX o jQuery, mas HTML y CSS, nos encontraremos con un sinfín de posibilidades para brindarle a nuestros usuarios y para representar de mejor manera nuestros modelo de negocio.
  • Para el desarrollo de interfaces avanzadas siempre deberemos hacer uso de múltiples tecnologías que se complementarán para ayudarnos a lograr nuestros objetivos. Algunas funcionalidades avanzadas de interfaz gráfica se pueden alcanzar mediante librerías como jQueryUI: https://jqueryui.com/
Persistiendo
  • Hasta ahora, hemos estado guardando nuestros datos en variables dentro de nuestra aplicación, o enviándolos por correo electrónico. Pero ninguna de estas opciones suele ser muy óptima. Guardar nuestros datos en variables significa que los mismos son almacenados en la memoria volátil de nuestra computadora. Cada vez que apaguemos la computadora perderemos los datos y deberemos arrancar nuevamente con la carga.
  • De igual manera, guardar la información en correos electrónicos dista de ser una opción viable, dado que estaremos trabajando con información escrita solamente, y consultarla luego no será sencillo, debido a que estamos generando archivos por cada una de las transacciones que realicemos
  • Por ello es que aparece como una necesidad el concepto de persistencia, que se refiere a la propiedad de los datos para que estos sobrevivan de alguna manera.
  • La persistencia de aplicación es la capacidad para que los datos sobrevivan a la ejecución del programa que los ha creado.
  • Este tipo de persistencia requiere que los datos sean almacenados en algún lugar no volátil (o sea, que no desaparezca cuando se apaga la computadora), para la posterior utilización.
  • Se puede a modo ejemplo, guardar información en un archivo que está almacenado en disco. Es común en muchas aplicaciones guardar en disco una copia de las opciones de configuración cada vez que el usuario realiza cambios. Si dichos cambios no se guardaran en disco, la próxima vez que el usuario ejecute la aplicación tendría que volver a definir las opciones de preferencia.
  • Otra forma de guardar la información, es mediante los servidores de bases de datos. Pero eso es algo que veremos en el próximo capítulo



Espero haber ayudado en algo. Hasta la próxima oportunidad!











  

No hay comentarios:

Publicar un comentario

       

Etiquetas

Academy (23) Accediendo a datos con ADO .NET (30) Acceso a la red (30) Algoritmo (34) Algoritmos en JAVA (2) Ampliación de clases (2) APRENDA A PROGRAMAR COMO SI ESTUVIERA EN PRIMERO - Autores : IKER AGUINAGA (3) APRENDA A PROGRAMAR COMO SI ESTUVIERA EN PRIMERO - Autores : IKER AGUINAGA (10) Aprendiendo a desarrollar en Windows 8 (5) Aprendiendo UML en 24 Horas (Autor : Joseph Schmuller ) (30) Arquitectura (29) Arquitectura del Computador (3) Arquitectura del Computador - Historia de la informática (1) Asignación de direcciones IP (2) Aspectos fundamentales de bases de datos (5) Auditoría de la dirección (2) Auditoría de Sistemas (3) Auditoría Informática - Un enfoque práctico - Mario G . Piattini y Emilio del Peso (7) Avanzado (23) Base de Datos (66) Básico (23) Bios (29) Business Productivity Online Suite - BPOS (3) Capa de Red (22) Capa de Transporte (16) Capítulo 1 - Documentos HTML5 (6) Capítulo 10. API Web Storage (2) Capítulo 11. API IndexedDB (4) Capítulo 12. API File (1) Capítulo 2. Estilos CSS y modelos de caja (7) Capítulo 3. Propiedades CSS3 (4) Capítulo 4. Javascript (6) Capítulo 5. Video y audio (6) Capítulo 6. Formularios y API Forms (8) Capítulo 7. API Canvas (5) Capítulo 8. API Drag and Drop (2) Capítulo 9. API Geolocation (2) CCNA1 v5.0 (179) CCNA1 v6.0 (23) CCNA2 v5.0 (26) CCNA3 v5.0 (25) CCNA4 v5.0 (23) CD-ROM (3) Chapter 1 How does Xamarin.Forms fit in? (7) Chapter 2 Anatomy of an app (5) Cisco (281) Cloud Computing (3) CNNA v5.0 Routing & Switching (200) CNNA v6.0 Routing & Switching (2) Codigo (2) Computadora (32) Configuración (29) Configuración de un sistema operativo de red (21) Control (29) Creación de tipos de datos y tablas (3) Creación y Administración de bases de datos (3) Creando la Interface de la Aplicación Windows (50) Creating Mobile Apps with Xamarin.Forms (13) Cuenta (29) Curso (32) Curso Aprendiendo a Programar (25) Datos (3) Desarrollando en Windows 8 - AVANZADO (2) Desarrollando en Windows 8 - BÁSICO (3) Desarrollando en Windows 8 - INTERMEDIO (2) Desarrollo (2) Desarrollo .Net (21) Desarrollo avanzado de Windows Store Apps usando C# (1) Desarrollo basado en conceptos de Ingeniería de Software para Visual Studio (2) DESARROLLO DE APLICACIONES WINDOWS CON MICROSOFT .NET (37) DESARROLLO DE APLICACIONES WINDOWS CON MICROSOFT .NET (Autor: Luis Dueñas Huaroto) (29) Desarrollo en Microsoft Visual Studio (44) Desarrollo en Microsoft Visual Studio - AVANZADO (15) Desarrollo en Microsoft Visual Studio - BÁSICO (14) Desarrollo en Microsoft Visual Studio - INTERMEDIO (18) Desarrollo en Windows Phone 8 (13) Diagnostico (4) Diagrama (3) Diagramas de actividades (2) Diagramas de colaboraciones (2) Diagramas de secuencias (2) Digital (2) Diplomado (2) Disco (29) Disco Duro (4) Diseño de aplicaciones de Windows 8 en HTML 5 (7) Dispositivos Electrónicos (11) Doctorado (2) Ejemplos (3) Ejemplos de algoritmos (27) El camino hacia el CSS3 (3) El diseño web flexible (6) El elemento de diseño Canvas (3) El enfoque de los sistemas (3) El flujo de un programa (2) El gran libro de HTML5 - CSS3 y Javascript - Autor: Juan Diego Gauchat (55) El principio de organicidad (7) Electrónica (2) Elementos de un sistema (5) Empresas (2) Entrada y salida (4) Entropía y neguentropía (7) Estrategia (2) Estructura de un programa Java (12) Estructuras de almacenamiento (10) Estructuras de control (6) Estructuras de las tablas en SQL Server (2) Estructuras fundamentales de los datos (2) Ethernet (21) Evolución y Familias de los Microprocesadores (15) Exámen (23) Exploración de la red (23) Extensión de clases (4) Facebook (4) Familia Intel (15) Forefront (8) Función (3) Funciones de una red (12) Funciones de una red informática (1) Fundamentos de C# para absolutos principiantes (17) Fundamentos de programación en Java (50) Generaciones de la computadora (5) Gestión (3) Gestión de riesgos - Auditoría de Sistemas (1) GONZALO MARTÍNEZ (1) Grupos Facebook (1) Harvard (29) Historia de las computadoras (11) HTML5 y CSS3 - Autor: Christophe Aubry (99) HTML5 y CSS3 aplicadal texto (7) HTML5 y CSS3 para los formularios (15) Imágenes (2) Implementación de Windows 7 (11) Información (31) Informática (29) Ingeniería (4) Instalar (29) Inteligencia (2) Inteligencia de Negocios con SQL Server (3) Intermedio (23) Internet (29) Internet Explorer 9 (3) Introducción a ASP.NET 5 (8) Introducción a Java (7) Introducción a jQuery (8) Introducción a la Auditoría de Sistemas (2) Introducción a la teoría general de sistemas (Oscar Johansen Bertoglio) (39) Introducción a Networking (2) Introducción a Window Forms (5) Introducción al acceso a datos con ADO .NET (9) Investigación de Operaciones (12) Java (52) Jump Start de consultas en las bases de datos de Microsoft SQL Server 2012 (8) La definición de un Sistema (6) La evolución del HTML y del CSS (3) La nueva sintaxis HTML5 (12) LA QUINTA DISCIPLINA en la práctica (Autor : Peter Senge) (28) Las animaciones en CSS3 (5) Las transformaciones CSS3 (11) Las transiciones con CSS3 (8) Licenciamiento Microsoft (3) Local Area Network (LAN) - Red de Area Local (2) Lógico (2) Los elementos de la estructura en html5 (9) Los elementos multimedia: audio y vídeo (2) Los estilos de caja en CSS3 (13) Los nuevos selectores de CSS3 (6) Maestría (2) Mantenimiento de Mouse y Teclado (2) Manual de Microsoft SQL Server - Full Transact SQL (67) Manual de soporte técnico para escuelas sobre windows 7 (42) Marco Teorico de Investigación de Operaciones (6) Medios de Almacenamiento (11) Medios de Networking (2) Mejorando la Interface de las Aplicaciones Windows (26) Memoria Tipos y Clases (5) Método (2) Metodología (1) Microsoft (324) Microsoft Lync 2010 (7) Microsoft Silverlight 4.0 (2) Microsoft Virtual Academy (356) Modelo (2) Modelo OSI y TCP-IP (2) Modelos con poco grado de dificultad de Programación Lineal - Investigación de Operaciones (13) Modelos con razonable grado de dificultad de Programación Lineal - Investigación de Operaciones (10) Modelos de desafio de Programación Lineal - Investigación de Operaciones (5) Modelos difíciles de Programación Lineal - Investigación de Operaciones (5) Modelos Fáciles de Programación Lineal - Investigación de Operaciones (13) Modelos lineales con solver (3) Modulo (23) Movimiento (2) Mozilla (29) MS SQL Server (76) MS Virtualization para Profesionales VMware - Gestión (3) MS Virtualization para Profesionales VMware- Plataforma (4) MVA (263) Negocio (2) Nivel Avanzado Desarrollo .Net (6) Nivel Básico Desarrollo .Net (11) Nivel Intermedio Desarrollo .Net (8) Normas técnicas peruanas y su evolución - Auditoría de Sistemas (1) Nube Privada - Avanzado (6) Nube Privada - Básico (6) Nube Privada - Intermedio (6) Office 365 (3) Optimización de Escritorio (10) Optimización de Escritorio - Avanzado (4) Optimización de Escritorio - Básico (3) Optimización de Escritorio - Intermedio (3) ORACLE 10g - ADMINISTRACIÓN Y ANÁLISIS (3) Oracle 10g y el Grid Computing (3) Organización aleatoria y secuencial (1) Partes principales de la Mainboard (12) Perceptron (2) Perfil (2) Periféricos de Entrada / Salida (15) Pesi (2) PHP y MySQL - Manual de aprendizaje para crear un sitio web - Autor : Olivier ROLLET (79) Plan (2) Plataforma (29) PMBOK (24) PMBOK - Guía de los fundamentos para la dirección de proyectos (24) PMBOK - INFLUENCIA DE LA ORGANIZACIÓN Y CICLO DE VIDA DEL PROYECTO (6) PMBOK - Introducción (11) PMBOK - PROCESOS DE LA DIRECCIÓN DE PROYECTOS (5) Prevención - Herramientas e Instrumentos de Medida (9) Principios básicos de enrutamiento y switching (153) Proceso (2) Proceso de auditoría de sistemas informáticos (2) Programación en Android - Auor : Salvador Gómez Oliver (46) Programación paso a paso de C# - Autor : Nacho Cabanes (16) Protocolos y comunicaciones de red (17) Proyecto (2) Qué es un sistema (4) Red de Área Local Inalámbrica (WLAN) (4) Redes (30) Redes inalámbricas - WIRELESS - Conocimiento general (15) Redes neuronales (2) Redes y Comunicaciones (45) Reparación de Fuentes - UPS - Estabilizadores (10) Reparación de Impresoras (9) Reparación de Monitores (16) Router (29) Seguridad en la Nube (3) Seminario (23) Server (24) Sharepoint 2010 - Nivel Básico (6) Sharepoint 2010 - Niveles Avanzados (18) Sharepoint 2010 - Niveles Avanzados - Básico (8) Sharepoint 2010 - Niveles Avanzados - Intermedio (9) Sinergia y recursividad (4) Sistema (33) Sistema de Cableado Estructurado (9) Software (30) SOLUCIÓN GRÁFICA DE MODELOS DE PROGRAMACIÓN LINEALES - INVOPE (8) Soporte a Infraestructura (3) SQL (38) SQL Azure - Introducción (3) Subsistemas de control (4) Tablas (4) Tarjeta Principal del Sistema (10) Tarjetas de Interfaces (7) Tecnología (31) Tecnologías LAN (1) TEORÍA GENERAL DE SISTEMAS (1) Tic (2) Tipo (2) TML5 y CSS3 - Autor: Christophe Aubry (12) Trabajando con el Formulario (7) Un diseño HTML5/CSS3: dConstruct 2011 (3) Un diseño HTML5/CSS3: FlipThru (2) Un diseño HTML5/CSS3: The Cat Template (2) Usando Controles Windows Forms (12) Usando Herramientas de Datos de Visual Studio (6) Ventas (2) Virtualización Hyper - V Nivel Básico (5) Virtualización Hyper - V Nivel Intermedio (5) What’s New in Windows 8.1 Security (4) Window (29) Windows 7 Segunda Fase - AVANZADO (4) Windows 7 Segunda Fase - BÁSICO (6) Windows 7 Segunda Fase - INTERMEDIO (4) Windows 8 - Vista Previa (4) Windows 8.1 To Go (2) Windows Azure (3) Windows Phone 7 (2) Windows Server 2008 R2 (3) Windows Server 2012 - Gestión y Automatización (3) Windows Server 2012 R2 Essentials (7) Windows Server 2012: Almacenamiento (5) Windows Server 2012: Identidad y Acceso (4) Windows Server 2012: Revisión Técnica (7) Xamarin (1)

Páginas vistas en total según Google