Test Automation .NET

Les comparto los materiales que utilizo para facilitar talleres de "Test Automation .NET", para que todos puedan aprovecharlos en sus comunidades o trabajo. 


No es una guía paso a paso pero creo que cualquiera podrá entenderlos.
Si pueden brindar algún tipo de feedback o contribución sería buenísimo.

Espero les sea de utilidad.
Saludos
@Snahider

Cómo aprender a utilizar Resharper

Resharper es un complemento indispensable para aquellos que utilizamos Visual Studio, ya que provee una gran cantidad de funcionalidad que potencia el IDE e incrementa notablemente la productividad del desarrollador.

Debido a que cada vez son los más desarrolladores y empresas que utilizamos esta herramienta, se escucha bastante la pregunta “¿Cómo puedo aprender yo y mi equipo a utilizar bien Resharper ?”.

Resharper_Pequeño

Les comparto estos consejos y recursos de aprendizaje que los ayudarán a dominar esta increíble herramienta.

  1. Free Pluralsight Training for ReSharper Customers: Si ya han adquirido la licencia de R#, seguramente les ha llegado un email con una suscripción por un mes para la capacitación online Resharper Fundamentals; consiste en casi 4 horas de videos separados por capítulos sobre las diversas características de R# que permiten mejorar nuestra productividad.
  2. Si no tienen tiempo para ver las 4 horas, también pueden ver la estupenda VAN sobre Resharper de la comunidad Alt.Net Hispano, es un webinar de 2 horas donde se muestran diversos casos de uso donde se puede aprovechar al máximo R#.

    Asimismo, la comunidad Alt.Net Hispano tiene una gran cantidad de webinars grabados sobre temas como Agile, .NET, Arquitectura, Patrones de Software, etc.
  3. Algunas de las funcionalidades más útiles e impresionantes de R# se encuentran a nivel de Generación de Código, Refactoring y Pruebas Unitarias. Si quieren perfeccionar el uso de estas funcionalidades les recomiendo realizar algún Kata de Refactoring, uno muy bueno es el Gumball Machine Kata ya que adicionalmente los ayudará a practicar sobre Code Smells y Desing Patterns, pueden practicarlos por sí mismos o realizar un taller dirigido junto con todo tu equipo.
  4. Tener a la mano los Hotkeys (VS Scheme o IDEA Scheme) y utilizarlos siempre que se pueda. Les recomiendo imprimirlos o guardarlos en un marcador dentro del navegador. Cuando estén programando y utilicen el mouse pregúntense ¿cómo podría haber hecho lo mismo utilizando un shortcut?.

    Utilizar los shortcuts del teclado nos permiten trabajar mucho más rápido y distraernos menos. Toda la funcionalidad de R# combinada con los shortcuts puede incrementar muchísimo la productividad.
  5. Para reforzar el uso y la práctica de R# les recomiendo asistir a Coding Dojos u organizarlos de manera interna en su empresa. Adicionalmente, les aconsejo elegir una kata sencilla y utilizar como restricción que “no está permitido utilizar el mouse”, pueden dividir el Coding Dojo en 2 sesiones consecutivas: la primera realizando el kata normalmente y la segunda utilizando la restricción.
  6. De más está decir que la documentación es una muy buena fuente de consulta.
  7. Busquen en su comunidad personas con quienes puedan compartir conocimiento o algún Partner local de JetBrains que pueda brindar capacitación y consultoría a su empresa.

Espero que les sea de mucha utilidad.

Saludos,
@Snahider

Videos para aprender HTML5 y CSS3

Hola a todos, les comparto una serie de 21 videos gratuitos que nos enseñaran los fundamentos de HTML5 y CSS3. 

Desde aquí podemos acceder a los videos y al código fuente de los ejercicios, estos se encuentran alojados en Channel 9 por lo que podremos descargarlos o verlos online.

HTML5

Los videos han sido realizados por Bob Tabor que es muy conocido por crear otros varios recursos de aprendizaje sobre la plataforma .NET.

Saludos,
@Snahider

Single Page Applications – Parte 5 – Comunicación entre ViewModels

En este post veremos como comunicar las 2 vistas que hemos creado anteriormente(Seleccionar Producto e Ingresar Pedido), de tal manera que cuando seleccionemos un producto en la primera pantalla, desaparezca esta pantalla y se muestre la pantalla de ingreso de pedido con los datos del producto seleccionado.

Para lograr que nuestros 2 viewmodels se comuniquen tenemos las siguientes opciones: crear un objeto padre que se encargue de coordinar todas los view models; utilizar las urls, hasbangs (#!) y routing; o utilizar el patrón publish/suscribe entre las vistas.

En esta oportunidad utilizaremos un objeto padre para coordinar todos los viewmodels del proceso de delivery, pero en los siguientes posts veremos las otras alternativas.

Implementamos este objeto dentro del archivo /Scripts/App/ViewModels/deliveryviewmodel.js, este objeto tendrá una propiedad por cada uno de los viewmodels que esté coordinando.

var DeliveryViewModel = function () {
   
var self = this;

    self.chooseProduct = ko.observable();
    self.placeOrder = ko.observable();
};

Asimismo, este objeto tendrá métodos que serán responsables de mostrar cada una de las vistas del proceso de delivery.

var DeliveryViewModel = function () {
   
var self = this
;

    self.chooseProduct = ko.observable();
    self.placeOrder = ko.observable();

    self.showChooseProduct =
function
() {
       
//TODO: Mostrar la primera vista y ocultar las demás
    };

    self.showPlaceOrder =
function
(productId) {
       
//TODO: Mostrar la segunda vista y ocultar las demás
    };

    self.showConfirmation =
function
() {
       
//TODO: Mostrar la tercera vista y ocultar las demás
    };

    self.showChooseProduct();

};

Los viewmodels ChooseProductViewModel y PlaceOrderViewModel dependerán este nuevo objeto padre y le delegarán la responsabilidad de mostrar la vista adecuada.

var ChooseProductViewModel = function (parent) {
   
var self = this
;
    self.products = ko.observableArray();

    self.goToPlaceOrder =
function
(product) {
        parent.showPlaceOrder(product.id);
    };

    self.init =
function
() {
        ProductsDataSource.getAll(
function (data) {
            self.products(data);
        });
    };

    self.init();
};
var PlaceOrderViewModel = function (productId, parent) {
   
var self = this
;

    self.order = ko.observable();

    self.postOrder =
function
() {
        OrdersDataSource.create(self.order,
function
() {
            parent.showConfirmation();
        });
    };

    self.init =
function
() {
        ProductsDataSource.get(productId,
function
(product) {
            self.order(
new Order(product));
        });
    };

    self.init();
};

El objeto DeliveryViewModel, cada vez que los objetos hijos le delegen mostrar una nueva vista, instanciará el viewmodel adecuado para esta vista.

var DeliveryViewModel = function () {
   
var self = this
;

    self.chooseProduct = ko.observable();
    self.placeOrder = ko.observable();

    self.showChooseProduct =
function
() {
        self.chooseProduct(
new
ChooseProductViewModel(self));
        self.placeOrder(
null
);
    };

    self.showPlaceOrder =
function
(productId) {
        self.chooseProduct(
null
);
        self.placeOrder(
new
PlaceOrderViewModel(productId, self));
    };

    self.showConfirmation =
function
() {
       
//TODO: Mostrar la Tercera vista y ocultar las demás
    };

    self.showChooseProduct();
};

Podemos observar que para ocultar una vista simplemente asignamos null a la propiedad, esto se debe a que Knockoutjs automáticamente eliminará toda la sección HTML si es que el valor del binding es null.

Necesitamos enlazar toda la aplicación al nuevo objeto DeliveryViewModel, para esto modificamos el archivo /Scripts/application.js donde se inicializan los viewmodels.

function initializeApplication() {
    initializeViewModels();
}

function
initializeViewModels() {
    ko.applyBindings(
new DeliveryViewModel());
}

Enlazamos cada vista de manera individual a una propiedad del DeliveryViewModel, para esto modificamos el archivo /Views/Home/Index.cshtml.

<div data-bind="with: chooseProduct">
    @Html.Partial("_ChooseProduct")
</div>

<div data-bind="with: placeOrder">
    @Html.Partial("_PlaceOrder")
</div>

<script type="text/javascript">
    $(function
() {
        initializeApplication();
    });

</script
>

Por último agregamos las referencias a todos los nuevos scripts dentro del archivo /Views/Shared/Layout.cshtml.

<script src="~/Scripts/Lib/jquery-1.6.2.min.js" type="text/javascript"></script>
<
script src="~/Scripts/Lib/knockout-2.1.0.js" type="text/javascript"></script
>
<
script src="~/Scripts/App/Data/productsdatasource.js" type="text/javascript"></script
>
<
script src="~/Scripts/App/Data/ordersdatasource.js" type="text/javascript"></script
>
<
script src="~/Scripts/App/Models/order.js" type="text/javascript"></script
>
<
script src="~/Scripts/App/ViewModels/deliveryviewmodel.js" type="text/javascript"></script
>
<
script src="~/Scripts/App/ViewModels/chooseproductviewmodel.js" type="text/javascript"></script
>
<
script src="~/Scripts/App/ViewModels/placeorderviewmodel.js" type="text/javascript"></script
>
<
script src="~/Scripts/application.js" type="text/javascript"></script>

Si ejecutamos la aplicación podremos ver el listado de productos.

ChooseProd_Small

Si seleccionamos alguno de los productos aparecerá la pantalla para completar los datos de la orden.

placeorder

En el siguiente post veremos la tercera pantalla del proceso de delivery.

Saludos
Angel Núñez Salazar

Single Page Applications – Parte 4 – Más KnockoutJS

En este post vamos a implementar la segunda pantalla de nuestra panadería online.

Pantalla: Ingresar Pedido

Pantalla a través de la cuál un usuario ingresa los datos del pedido para que este sea enviado a la dirección especificada.

PlaceOrder

Creamos el ViewModel para esta pantalla dentro del archivo /Scripts/App/ViewModels/placeorderviewmodel.js. Este ViewModel recibirá como parámetro el código del producto seleccionado para el pedido.

var PlaceOrderViewModel = function (productId) {
   
var self = this
;

    self.order = ko.observable();

    self.postOrder =
function
() {
        OrdersDataSource.create(self.order,
function
() {
           
//TODO: Ir a la pantalla de confirmación
        });
    };

};

Delegamos la creación de la orden al objeto OrdersDataSource y lo implementamos dentro del archivo /Scripts/App/Data/ordersdatasource.js.

var OrdersDataSource = (function () {
   
return
{
        create:
function
(order, success) {
            $.ajax({
                type:
"POST"
,
                url:
"/api/orders"
,
                dataType:
"json"
,
                contentType:
"application/json;charset=utf-8",
                data: ko.toJSON(order),
                success: success
            });
        }
    };
} ());

Completamos el código del PlaceOrderViewModel para cargar los datos del producto que serán mostrados en el formulario de la orden.

var PlaceOrderViewModel = function (productId) {
   
var self = this
;

    self.order = ko.observable();

    self.postOrder =
function
() {
        OrdersDataSource.create(self.order,
function
() {
           
//TODO: Ir a la pantalla de confirmación
        });
    };

    self.init =
function
() {
        ProductsDataSource.get(productId,
function
(product) {
           
//TODO: Crear una instancia de la Orden con los datos del producto
        });
    };

    self.init();

};

Agregamos un nuevo método dentro del objeto ProductsDataSource.

var ProductsDataSource = (function () {
   
return
{
        getAll:
function
(success) {
            $.ajax({
                type:
"GET"
,
                url:
"/api/products"
,
                contentType:
"application/json;charset=utf-8"
,
                dataType:
"json"
,
                success: success
            });
        },
        get:
function
(id, success) {
            $.ajax({
                type:
"GET"
,
                url:
"/api/products/"
+ id,
                contentType:
"application/json;charset=utf-8"
,
                dataType:
"json"
,
                success: success
            });
        }

    };
} ());

Creamos la clase Order  dentro del archivo /Scripts/App/Models/order.js, esta clase contendrá los datos del pedido que serán enviados al servicio REST.

var Order = function (product) {
   
var self = this
;
    self.address = ko.observable();
    self.email = ko.observable();
    self.quantity = ko.observable(1);
    self.productId = product.id;
    self.product = product;
    self.total = ko.computed(
function
() {
       
return (self.product.price * self.quantity()).toFixed(2);
    });
}

Utilizamos la sentencia ko.observable() para relacionar las propiedades de esta clase con los campos del formulario. También utilizamos la sentencia ko.computed() para crear una función observable que dependa de otros observables, esto permitirá que el monto total de la orden se actualice automáticamente cuando el valor de la cantidad cambie.

Completamos el código del PlaceOrderViewModel para instanciar una nueva orden apenas se reciba los datos del producto.

var PlaceOrderViewModel = function (productId) {
   
var self = this
;

    self.order = ko.observable();

    self.postOrder =
function
() {
        OrdersDataSource.create(self.order,
function
() {
           
//TODO: Ir a la pantalla de confirmación
        });
    };

    self.init =
function
() {
        ProductsDataSource.get(productId,
function
(product) {
            self.order(
new Order(product));
        });
    };

    self.init();
};

Creamos la vista parcial /Views/Home/_PlaceOrder.cshtml y agregamos el código HTML correspondiente esta pantalla.

<!-- ko with: order -->
<h1 data-bind
="text: 'Place Your Order: '+product.name">
</
h1
>
<
form action="" method="post">
    <fieldset class="no-legend">
        <legend>Place Your Order</legend>
        <img class="product-image order-image"
 
            
data-bind=
"attr:{ src:'/content/images/products/thumbnails/' + product.imagename,
                        alt:product.name }"
 />
        <ol>
            <li>
                <label for="orderEmail">Your Email Address</label>
                <input type="text" id="orderEmail" name="orderEmail" data-bind="value:email" />
            </li>
            <li>
                <label for="orderShipping">Shipping Address</label>
                <textarea rows="4" cols="20" id="orderShipping" name="orderShipping"
 
                         
data-bind="value:address">
                </textarea>
            </li>
            <li class="quantity">
                <label for="orderQty">Quantity</label>
                <input type="text" id="quantity" name="quantity"
 
                      
data-bind="value:quantity, valueUpdate: 'afterkeydown'" />
                x <span id="orderPrice" data-bind="text:product.price"></span>
                = <span id="orderTotal" data-bind="text:total()"></span></li>
        </ol>
        <p>
            <input type="submit" value="Place Order" data-bind="click:$parent.postOrder" />
        </p>
    </fieldset
>
</
form>
<!-- /ko –>

Examinemos brevemente los nuevos “bindings” que estamos utilizando.

  • with: Crea un “contexto” dentro del cuál todos los bindings hacen referencia al objeto asignado. Una característica de este binding es que lo podemos utilizarlo dentro de un comentario sin la necesidad de crear un nuevo tag.
  • value: Asocia el atributo “value” con el valor de una propiedad dentro del ViewModel. Típicamente usado con elementos dentro de un formulario como: <input>, <select>, <textarea>, etc.
  • valueUpdate: Por defecto los bindings se actualizan cuando se el usuario cambia el foco del elemento. Esta propiedad nos permite controlar cuando se actualizarán los cambios, por ejemplo: “afterkeydown”, “keyup”, “keypress”, etc.

Desde el archivo /Views/Home/Index.cshtml hacemos referencia a la vista parcial recién creada.

<div>
    @Html.Partial("_ChooseProduct");
</div>

<div>
    @Html.Partial("_PlaceOrder");
</div>


<script type="text/javascript">
    $(function
() {
        initializeApplication();
    });

</script
>

Agregamos las referencias de los nuevos scripts dentro del archivo /Views/Shared/Layout.cshtml.

<script src="~/Scripts/Lib/jquery-1.6.2.min.js" type="text/javascript"></script>
<
script src="~/Scripts/Lib/knockout-2.1.0.js" type="text/javascript"></script
>
<
script src="~/Scripts/App/Data/productsdatasource.js" type="text/javascript"></script
>
<
script src="~/Scripts/App/Data/ordersdatasource.js" type="text/javascript"></script
>
<
script src="~/Scripts/App/Models/order.js" type="text/javascript"></script
>
<
script src="~/Scripts/App/ViewModels/chooseproductviewmodel.js" type="text/javascript"></script
>
<
script src="~/Scripts/App/ViewModels/placeorderviewmodel.js" type="text/javascript"></script
>
<
script src="~/Scripts/application.js" type="text/javascript"></script>

Luego de todos estos cambios, la estructura final de archivos ha quedado de la siguiente manera.

structureSP4

En el siguiente post veremos como comunicar nuestros 2 ViewModels para permitir que la segunda vista recién se muestre luego de seleccionado un producto.

Saludos
Angel Núñez Salazar

Single Page Applications – Parte 3 – UI Patterns, KnockoutJS

En esta oportunidad vamos a hablar sobre como estructurar la aplicación y como organizar el código. Los patrones más comúnmente usados para organizar aplicaciones en el “front-end” son 2: MVC y MVVM.

MVC en Javascript

MVC es probablemente el patrón de presentación más antiguo que existe y es utilizado en múltiples lenguajes de programación. Dentro de Javascript existen las siguientes implementaciones:

Examinemos los componentes de este patrón dentro de Javascript:

Models: Contienen los datos que se van a manejar en la aplicación, muchas veces implementan el Observer Pattern(Publisher/Subscriber Pattern) para notificar a las vistas que necesitan actualizarse cuando se ha producido algún cambio en el modelo.

Views: No necesariamente constituyen directamente el HTML que se va a mostrar, sino son los encargados de renderizar el modelo, en varios de los casos utilizando “Templates”.

Controllers: Intermediarios entre las Vistas y el Modelo, coordinan la actualización del Modelo de acuerdo a los cambios producidos en las vistas y viceversa. Varias implementaciones MVC en Javascript tienen un concepto diferente de lo que es convencionalmente llamado un “Controller”, por esto podemos encontrar que la “C” puede estar representada por “Colecciones” de objetos o “Rutas” o dependiendo del caso.

MVVM en Javascript

Es otro patrón que busca separar el desarrollo de la interfaz de usuario, de la lógica de la aplicación. Fue originalmente definido por Microsoft para ser usado junto con WPF, pero ha sido adoptado por otros lenguajes.

En estos últimos años se han creados algunas implementaciones de este patrón dentro de Javascript:

Examinemos los componentes de este patrón dentro de Javascript:

Models: Representan la información del dominio sobre el cuál trabajará la aplicación. Dentro de este patrón, no siempre los miembros del modelo se encuentran directamente en código Javascript, muchas veces los objetos del modelo se encuentran en el lado del servidor.

Views: A diferencia del patrón MVC, estas vistas son “activas” es decir no solo se encargan de mostrar los datos sino también envían al ViewModel información sobre eventos. Generalmente son documentos HTML que contienen “bindings” hacia el ViewModel.

ViewModels: Representan a las vistas, a sus datos y operaciones que se realizan sobre estas. Se mantienen sincronizados con las vistas a través de los “bindings” que funcionan en doble sentido.

Para nuestra aplicación vamos a utilizar el Patrón MVVM junto con KnockoutJS.

Lo primero que haremos será agregar los scripts necesarios para usar KnockoutJS dentro del archivo /Views/Shared/Layout.cshtml. KnockoutJS lo podemos descargar desde su página web o utilizando Nuget.

<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width" />
    <title>Fourth Coffee</title>
    <link href="~/Content/Site.css" rel="stylesheet" type="text/css" />
    <script src="~/Scripts/Lib/jquery-1.6.2.min.js" type="text/javascript"></script>
    <script src="~/Scripts/Lib/knockout-2.1.0.js" type="text/javascript"></script>
</head>

Creamos la siguiente estructura de directorios para nuestros archivos Javascript.

FolderStructure

  • App: Contendrá los archivos de la aplicación que han sido desarrollados por nosotros..
    • Data: Contendrá los objetos mediante los cuales accederemos a los servicios REST.
    • Models: Contendrá a los objetos que constituyen el Modelo de la aplicación.
    • ViewModels: Contendrá a los ViewModels de la aplicación.
  • Lib: Contendrá los archivos pertenecientes a frameworks y librerías externas: Jquery, KnockoutJS, etc.

Creamos el HomeController, la acción Index y el archivo /Views/Home/Index.cshtml sin ningún contenido.

public class HomeController : Controller
{
   
public ActionResult
Index()
    {
       
return View();
    }
}

Luego de esto, podremos levantar la aplicación y ver una pantalla inicial.

fourthcoffee

Ahora crearemos las Vistas, Modelos y ViewModels de nuestra aplicación. En este post nos vamos a enfocar únicamente en la primera pantalla y vamos a crear los elementos necesarios para su funcionamiento.

Pantalla: Selección de Producto

Pantalla a través de la cuál un usuario puede seleccionar cuál será el producto que desea comprar.

spa_primerapagina

Creamos el ViewModel para esta pantalla dentro del archivo /Scripts/App/ViewModels/chooseproductviewmodel.js. Recordemos que un ViewModel es una representación de los datos y operaciones que se pueden realizar en la pantalla, entonces lo que vamos a encontrar en este ViewModel será una propiedad que representé al “Listado de “Productos” que vamos a mostrar en la pantalla y una función que nos permita gestionar el click al botón “Order Now”.

var ChooseProductViewModel = function () {
   
var self = this
;
    self.products = ko.observableArray();

    self.goToPlaceOrder =
function
(product) {
       
//TODO: Mostrar la vista para ingresar la orden de compra del producto 
    };

};

Podemos observar la sentencia ko.observableArray(), de esta manera le indicamos a KnockoutJS que cree una sincronización en doble sentido entre la propiedad y la vista. Si el valor de una propiedad “observable” es actualizado en el ViewModel este se verá automáticamente reflejado en la vista; de la misma manera, si este valor es cambiado en la vista, este se actualizará automáticamente dentro del ViewModel.

Completamos el código del ChooseProductViewModel para cargar los productos desde los servicios REST.

var ChooseProductViewModel = function () {
   
var self = this
;
    self.products = ko.observableArray();

    self.goToPlaceOrder =
function
(product) {
       
//TODO: Mostrar la vista para ingresar la orden de compra del producto 
    };

    self.init =
function
() {
        ProductsDataSource.getAll(
function
(data) {
            self.products(data);
        });
    };

    self.init();

};

Delegamos la responsabilidad de obtener los productos al objeto ProductsDataSource y lo implementamos dentro del archivo /Scripts/App/Data/productsdatasource.js. Podemos observar que la función getAll recibe como parámetro un ”callback” que será ejecutado cuando se reciban los datos del servicio.

var ProductsDataSource = (function () {
   
return
{
        getAll:
function
(success) {
            $.ajax({
                type:
"GET"
,
                url:
"/api/products"
,
                contentType:
"application/json;charset=utf-8"
,
                dataType:
"json",
                success: success
            });
        }
    };
} ());

Utilizaremos “Partial Views” para organizar nuestras vistas. Creamos la vista parcial /Views/Home/_ChooseProduct.cshtml y agregamos el código HTML correspondiente esta pantalla.

<ul id="products" data-bind="foreach: products">
    <li class="product">
        <div class="productInfo">
            <h3 data-bind="text: name">
            </h3>
            <img class="product-image"
 
                
data-bind
="attr:{
                        src:'/content/images/products/thumbnails/' + imagename,
                        alt:name }"
 />
            <p class="description" data-bind="text: description"></p>
        </div>
        <div>
            <p class="price" data-bind="text: price"></p>
            <a class="order-button"
 
              
data-bind="attr:{ title:name }, click:$parent.goToPlaceOrder">
                Order Now
           
</a>
        </div>
    </li
>
</
ul
>

Podemos observar la presencia de atributos data-bind dentro de los tags HTML, estos son los “bindings” a través de los cuales enlazamos los elementos de las vistas a las propiedades del ViewModel. Existen “bindings” de todo tipo: texto (value, text), apariencia (css, html, attr, style), control (foreach, if, with), etc.

Examinemos brevemente los “bindings” que estamos utilizando en esta oportunidad.

  • foreach: Duplica una sección por cada elemento dentro del arreglo. En este caso creará un bloque “<li></li>” por cada producto que tengamos.
  • text: Establece como texto el valor de la propiedad asociada.
  • attr: Establece el valor de cualquier atributo HTML.
  • click: Establece un evento que será llamado cada vez que se haga click sobre el elemento. En esta oportunidad estamos utilizando la sentencia $parent para referirnos al padre del objeto producto, ya que la función goToPlaceOrder se encuentra en el ViewModel.

Desde el archivo /Views/Home/Index.cshtml hacemos referencia a la vista parcial recién creada.

<div>
    @Html.Partial("_ChooseProduct");
</div
>

Necesitamos enlazar la vista al ChooseProductViewModel, para esto creamos el archivo /Scripts/application.js donde inicializaremos los viewmodels. Utilizaremos este archivo para configurar todo lo necesario para el funcionamiento de la aplicación.

function initializeApplication() {
    initializeViewModels();
}

function
initializeViewModels() {
    ko.applyBindings(
new ChooseProductViewModel());
}

Agregamos el siguiente script al final del archivo /Views/Home/Index.cshtml para inicializar la aplicación.

<div>
    @Html.Partial("_ChooseProduct");
</div>

<script type="text/javascript">
    $(function
() {
        initializeApplication();
    });

</script
>

Por último agregamos las referencias a todos los nuevos scripts dentro del archivo /Views/Shared/Layout.cshtml.

<script src="~/Scripts/Lib/jquery-1.6.2.min.js" type="text/javascript"></script>
<
script src="~/Scripts/Lib/knockout-2.1.0.js" type="text/javascript"></script
>
<
script src="~/Scripts/App/Data/productsdatasource.js" type="text/javascript"></script
>
<
script src="~/Scripts/App/ViewModels/chooseproductviewmodel.js" type="text/javascript"></script
>
<
script src="~/Scripts/application.js" type="text/javascript"></script>

Luego de todos estos cambios, la estructura final de archivos ha quedado de la siguiente manera.

structureSPA3

Si ejecutamos la aplicación podremos observar el listado de productos.

image

En los siguientes posts veremos el resto de pantallas del proceso de delivery.

Saludos
Angel Núñez Salazar