Integración de Silverlight + RIA Services con ASP.NET MVC

Antes de irme de vacaciones, he estado peleándome unos días para integrar una aplicación Silverlight 4.0 dentro de un sitio web ASP.NET MVC, y por fin lo he conseguido. Aunque este no es el caso del que voy a hablar hoy, ya que después de lograr que funcionara decidí probar como sería realizar el mismo proceso pero con RIA Services, y la verdad es que facilita bastante el trabajo. Por lo que es de este último caso del que voy a hablar hoy.

Antes de empezar a trabajar con nuestra aplicación es necesario que instalemos el SDK de Silverlight 4.0WCF RIA Services V1.0 for Silverlight 4 and Visual Studio 2010. Una vez instalados estos plugins, abrimos Visual Studio y creamos un proyecto de tipo Silverlight Application al que llamaremos RiaApp. Si vamos siguiendo el wizard de creación, vemos que en la primera pantalla nos pregunta en que tipo de proyecto web vamos a alojar la aplicación, donde debemos indicar ASP.NET MVC Web Project. En la parte de abajo de dicha pantalla indicamos que la versión de Silverlight que vamos a utilizar es la 4.0.  y además activamos la casilla que habilita los servicios RIA para que podamos trabajar con ellos. Por último al alojar nuestro proyecto en una aplicación ASP.NET MVC nos pregunta si queremos crea un proyecto de pruebas unitarias a lo que diremos que no

 image image image

De forma que se crea la estructura específica de nuestra aplicación tal y como podemos observar a continuación en la siguiente imagen:

image

Siguiendo con el procedimiento normal de una aplicación ASP.NET MVC lo primero que hacemos es crear nuestro modelo de objeto, para lo cual es necesario añadir la fuente de datos de la cual extraeremos la información. Para ello hacemos clic con el botón derecho sobre App_Data > Add > Existing item, y seleccionamos la base de datos AdventureWorks_Data. A continuación vamos a definir el modelo que nos permita trabajar con la base de datos, para ello dentro de la carpeta Models hacemos clic con el botón derecho Add> New Item> ADO.NET Entity Data Model y vamos siguiendo el Wizard hasta llegar al punto en el que tenemos que seleccionar la tabla o tablas que queremos agregar y que en nuestro caso será Product

image imageimage image

Por último depuramos(F6) la aplicación para que se actualicen todas las modificaciones y podamos utilizar la base de datos.

El siguiente paso que vamos a dar es la creación de un servicio de dominio para que podamos conectar con nuestro objeto de datos, desde el cliente. Para ello hacemos clic con el botón derecho sobre el proyecto web Add>New Item> Domain Service y le damos el nombre de  AdventureService. A continuación nos aparece una pantalla para seleccionar el contexto de objeto con el que vamos a trabajar que en nuestro caso es la tabla Product, y para la cual activaremos la opción de editar, de forma que podamos modificar los valores de la misma, y la de generación de metadatos, de forma que podamos validarlos.

image image

Por último lo que vamos a hacer es añadir nuestra tabla a la aplicación Silverlight en forma de DataGrid. Para ello, si hacemos clic en la pestaña de Data Sources , cuando estamos en la aplicación Silverlight, nos aparece el contexto de datos que hemos creado. De forma que si expandimos Product y arrastramos el modelo en forma de Datagrid a la página MainPage.xaml este se genera de forma automática

image image

Tras realizar algunas modificaciones sobre el DataGrid para que sólo se muestren algunos de los campos de la lista, compilamos(F5) nuestra aplicación y vemos que se abre la página RiaAppTestPage.aspx donde aparecen nuestros datos:

image

Por último lo que vamos a hacer es integrar el objeto Silverlight creado dentro de nuestra página principal. Para ello abrimos la vista Index del controlador Home que se encuentra en Views >Home, y añadimos el código que se genera al crear nuestra aplicación, que se encuentra dentro de la página RiaAppTestPage.aspx:

  1. <object data=”data:application/x-silverlight-2,” type=”application/x-silverlight-2″ width=”100%” height=”100%”>
  2.           <param name=”source” value=”ClientBin/RiaApp.xap”/>
  3.           <param name=”onError” value=”onSilverlightError” />
  4.           <param name=”background” value=”white” />
  5.           <param name=”minRuntimeVersion” value=”4.0.50401.0″ />
  6.           <param name=”autoUpgrade” value=”true” />
  7.           <a href=”http://go.microsoft.com/fwlink/?LinkID=149156&v=4.0.50401.0″ style=”text-decoration:none”>
  8.               <img src=”http://go.microsoft.com/fwlink/?LinkId=161376″ alt=”Get Microsoft Silverlight” style=”border-style:none”/>
  9.           </a>
  10.         </object>

Y el resultado final sería el siguiente, donde gracias a Silverlight 4.0 podemos mostrar e interactuar con los distintos elementos del DataGrid desde nuestra aplicación ASP.NET MVC, y lo mejor de todo sin escribir nada de código:

image 

¡¡¡Fácil, sencillo y para toda la familia!!!

Aquí dejo el código para su descarga, teniendo en cuenta que hay que añadir la base de datos AdventureWorks_Data para que funcione correctamente.

ASP.NET MVC 3 Preview 1

Scott Gu publico ayer en su blog un post en el que habla sobre algunas de las novedades que introduce la nueva versión de ASP.NET MVC, y cuya preview1 ya podemos descargar aquí.

El post es bastante completo ya que detalla las mejoras agrupadas por secciones por lo que recomiendo su lectura sin duda alguna. A continuación os dejo con una pequeña reseña de lo que comenta Scott a modo de resumen:

  • Mejoras a nivel de vistas
    • Dialogo de motor de vista (View Engine). Permite elegir la sintaxis con la que queremos trabajar para crear nuestras vistas.

 

image

  • Mejoras a nivel de controlador
    • Filtros globales. Se pueden aplicar filtros globales a todos los controladores de una aplicación
    • Nueva propiedad dinámica de modelo de vista(ViewModel). Viene a realizar la misma labor que ViewData. Permite pasar los datos de un modelo a una vista pero de forma dinámica.
    • Nuevos tipos de resultados de acciones(ActionResult):
      • HttpNotFoundResult: se usa para indicar que el recurso requerido por la petición web no se encuentra
      • PermanentRedirects: se usa para indicar una redirección permanente
      • HttpStatusCodeResult: se utiliza para establecer una respuesta específica de estado de código y descripción
  • Mejoras a nivel de Modelo
    • Validación(soporte de propiedades del Framework 4.0):
      • Soporte de los atributos de metadatos de DataAnnotations
      • Soporte de la interfaz IValidatableObject
  • Mejoras de JavaScript y AJAX
    • Soporte a Json binding
  • Mejoras en la inyección de dependencias (DI)
    • Soporte de las siguientes dependencias:
      • Controllers (registering & injecting controller factories, injecting controllers)
      • Views (registering & injecting view engines, injecting dependencies into view pages)
      • Action Filters (locating & injecting filters)
    • Se esta trabajando para que en versiones futuras se puedan añadir soporte a las siguientes dependencias
      • Model Binders (registering & injecting)
      • Value Providers (registering & injecting)
      • Validation Providers (registering & injecting)
      • Model metadata Providers (registering & injecting)

Podéis encontrar el post completo de Scott aquí:

http://weblogs.asp.net/scottgu/archive/2010/07/27/introducing-asp-net-mvc-3-preview-1.aspx

[ASP.NET MVC] ActionResult personalizado para la descargar de documentos

Ya de vuelta al mundo ASP.NET MVC, y antes del parón vacacional, vamos a ver una pequeña aplicación para cargar y descargar documentos de nuestra web.

En primer lugar, implementaremos el método de carga. Nuestra proyecto nos debe permitir cargar documentos dentro del sitio web, de forma que estos puedan ser descargados posteriormente por cualquier usuario. ASP.NET MVC soporta la carga de archivos, pero para ello son necesarios dos componentes:

  • un formulario cuyo atributo enctype tenga el valor "multipart/form-data" y contenga una etiqueta de tipo <input type="file"…>
  • una acción del controlador que reciba la información de la carga y la ejecute.

Para ello tras crear nuestro proyecto de tipo ASP.NET MVC 2 Web Application, que llamaremos ManageFiles:

image image

Añadimos un controlador que llamaremos ManageController, y que se encargará de gestionar tanto la carga como la descarga de los documentos:

image

Dentro de este:

  1. Añadimos la referencia
    1. using System.IO;

        de forma que podamos utilizar operaciones de tipo Entrada/Salida con los documentos.

  2. Creamos un ActionResult llamado Upload, que se encargará de cargar el archivo seleccionado en nuestra carpeta Content, y que tendrá el siguiente código:
  1. public ActionResult Upload(HttpPostedFileBase file)
  2.         {
  3.             var fileName = Path.GetFileName(file.FileName);//obtenemos el nombre del archivo a cargar
  4.             file.SaveAs(Server.MapPath(@"~\Content\" + fileName));//guardamos el archivo en la ruta física que corresponde a la ruta virtual del archivo
  5.             return RedirectToAction("Index");//volvemos a la página principal
  6.         }

* Para cargar un archivo en una ruta específica del servidor es necesario usar la clase HttpPostedFileBase

A continuación, abrimos la vista Index que se crea por defecto y dentro del apartado de contenido principal, añadimos el siguiente código que se encargará de mostrarnos el formulario que nos permite navegar por los archivos de nuestro equipo, y que ejecuta la acción de Upload:

  1. <form action="/Manage/Upload" method="post" enctype="multipart/form-data"/>
  2.     <label>Filename:<input type ="file" name="file"/></label>
  3.     <input type="submit" value="Guardar"/>

Para que podamos acceder de forma sencilla a este área de la aplicación, añadimos una nueva pestaña dentro del menú de la página maestra que se encuentra dentro de la carpeta ViewsShared, mediante el siguiente código:

  1. <li><%: Html.ActionLink("Gestión Documental", "Index", "Manage")%></li>

Si ejecutamos la aplicación y accedemos a la sección Gestión Documental, al pulsar al botón Examinar ya podemos navegar por los documentos de nuestro equipo sin problema, y una vez que pulsamos al botón Guardar podemos ver como el archivo examinado se guarda en la ruta indicada:

image image image

Por otro lado, después de ver el proceso de carga, el cual la mayoría ya habrá implementado de una forma u otra, llegamos a la parte que da título al articulo, el proceso de descarga. Este viene a complementar la carga de archivos con la posibilidad de poder abrir o descargar archivos almacenados en el servidor. Para ello es necesario implementar una clase personalizada que herede de ActionResult, y a la cual llamaremos GetFile

Hacemos clic con el botón derecho sobre nuestro proyecto y seleccionamos Add >Class 

image image

En dicha clase:

  1. Añadimos la referencia
    1. using System.Web.Mvc;

  2. Configuramos nuestra clase para que herede de ActionResult
  3. Inicializamos los parámetros que necesitamos para poder acceder a nuestros archivos, y que son el nombre y la ruta de los mismos:
  1. public string FileName { get; set; }
  2.         public string Path { get; set; }

    4. Y sobrescribimos el método ExecuteResult, que se encargará de implementar la ventana de descarga ( “content-disposition” ) utilizando el siguiente código:

 

  1. public override void ExecuteResult(ControllerContext context)
  2.         {
  3.             context.HttpContext.Response.Buffer = true;
  4.             context.HttpContext.Response.Clear();
  5.             context.HttpContext.Response.AddHeader("content-disposition", "attachment; filename=" + FileName);
  6.             context.HttpContext.Response.WriteFile(context.HttpContext.Server.MapPath(Path));
  7.         }

A continuación vamos al controlador ManagerController, y añadimos el código, que nos permita descargar el archivo Objetivo.docx, que hemos subido anteriormente a nuestra carpeta Content mediante el proceso de carga :

  1. public GetFile DownloadFile()
  2.         {
  3.  
  4.             return new GetFile
  5.             {
  6.                 
  7.                 FileName = "Objetivo.docx",
  8.                 Path = @"~/Content/Objetivo.docx"
  9.  
  10.             };
  11.         }

Por último añadimos, dentro de la vista Index, un Html.ActionLink que ejecute la acción de descarga:

  1. <%: Html.ActionLink("Descarga de documentos", "DownloadFile", "Manage")%>

Al ejecutar la aplicación, y seleccionar la opción Descarga de documentos vemos que aparece la siguiente pantalla:

image 

Esta sería la forma más básica de implementar la descarga, pero vemos que esta opción no es muy flexible ya que tenemos que indicar el nombre de un archivo en concreto a través del código para poder realizar la descargar, cuando lo ideal seria poder seleccionar el archivo dinámicamente. Por ello en el próximo artículo veremos como mejorar esto para que podamos seleccionar el archivo que nosotros queramos y descargarlo, todo ello a través de la interfaz de usuario.

ECMAScript Client Object Model SharePoint 2010

Después de un pequeño parón en mi blog, debido a los Sanfermines, y ya para terminar con la serie de artículos relacionados con el modelo de objetos cliente de SharePoint 2010, hoy vamos a ver el último tipo de cliente con el que podemos trabajar y que se trata de ECMAScript.

Para ello abrimos Visual Studio 2010, y creamos un nuevo proyecto de tipo New Project > Sharepoint2010 > VisualWebPart, indicando el sitio sobre el que vamos a implementar nuestra aplicación http://sharepoint2010:200 y el alcance de la misma, que en este caso será a nivel de granja de servidores. Es necesario tener en cuenta que para que podamos ejecutar nuestra aplicación correctamente a este nivel, debemos contar con permisos de administrador.

image image

Esta implementación del cliente se puede realizar de dos formas: añadiendo nuestro código a un archivo y llamándolo desde nuestro control .ascx, o integrando el propio código dentro del control de usuario. En nuestro caso vamos a hacer la implementación más sencilla, y el código se lanzara al acceder a la página en la que insertemos nuestra web part ya que lo que pretendemos es ver el funcionamiento del mismo. Pero esta bien saber que esta misma aplicación se puede implementar de forma más “elegante” si por ejemplo, lanzamos nuestro código Javascript desde un botón.

A continuación es necesario añadir el siguiente código dentro del archivo VisualWebPart1UserControl.ascx:

  1. <SharePoint:ScriptLink ID="ScriptLink" Name="SP.js" runat="server" OnDemand="true" Localizable="false"></SharePoint:ScriptLink>

Esto nos permite trabajar con el modelo de objeto JavaScript que viene definido en el archivo sp.js. Este archivo al igual que el encargado de la lógica de transporte necesaria para procesar peticiones al servidor (spruntime.js) se encuentran dentro de la carpeta LAYOUTS dentro de la ruta de definición de los sitios SharePoint 2010.

Una vez establecida la referencia al archivo de definición del modelo de objeto, añadimos el código de nuestra función que en este caso se encargará de crear un sitio, como vimos en el cliente .NET, con las siguientes características:

  1. <script type="text/javascript">
  2.         var clientContext = null;
  3.         var web = null;
  4.         ExecuteOrDelayUntilScriptLoaded(Initialize, "sp.js");
  5.         function Initialize() {
  6.             clientContext = new SP.ClientContext.get_current();
  7.             web = clientContext.get_web();
  8.             var webCreateInfo = new SP.WebCreationInformation();
  9.             webCreateInfo.set_description("Este es mi blog personal");
  10.             webCreateInfo.set_title("Blog personal de Goretti");
  11.             webCreateInfo.set_url("BlogPersonal");
  12.             webCreateInfo.set_useSamePermissionsAsParentSite(true);
  13.             webCreateInfo.set_webTemplate("BLOG#0");
  14.  
  15.             this.oNewWebsite = this.web.get_webs().add(webCreateInfo);
  16.  
  17.             clientContext.load(this.oNewWebsite, 'ServerRelativeUrl', 'Created');
  18.  
  19.             clientContext.executeQueryAsync(Function.createDelegate(this, this.onCreateWebSuccess),
  20.  
  21. Function.createDelegate(this, this.onQueryFailed));
  22.         }
  23.         function onCreateWebSuccess(sender, args) {
  24.             alert("Web site url : " + this.oNewWebsite.get_serverRelativeUrl());
  25.         }
  26.  
  27.         function onQueryFailed(sender, args) {
  28.             alert('request failed ' + args.get_message() + '\n' + args.get_stackTrace());
  29.         }
  30.     </script>​

Como podemos ver, la estructura de implementación del modelo es similar a la que utilizamos en cualquiera de los otros dos clientes.

1. Definimos el contexto de nuestro cliente

2. Definimos que es lo queremos cargar cuando se ejecute la query (clientContext.Load)

3. Ejecutamos la query (clientContext.executeQueryAsunc), que se encarga de mirar que es lo que esta definido en el método de carga  y en función de ello establecer la comunicación entre cliente y servidor para obtener los objetos con los que queremos trabajar

*Además, en este cliente en particular, hay que tener en cuenta que es necesario lanzar el método ExecuteOrDelayUntilScriptLoaded(Initialize, "sp.js"). Este se encarga de que el código JavaScript se ejecute después de que finalice la carga del código sp.js. Si no es así nuestra función no se ejecutará correctamente

Por último una vez compilada nuestra aplicación (F5), añadimos la web part implementada en el sitio donde queremos que esta se ejecute.

image 

De forma que en el momento que accedamos a la página que contenga dicha web part se ejecute nuestro código. Si el sitio con los parámetros que nosotros indicamos ya esta creado, nos salta la siguiente alerta, tal y como lo hemos definido:

image

Sin embargo, si no esta creado, dicho sitio se creará y nos aparecerá la siguiente alerta indicándonoslo, de esta forma ya podremos acceder a nuestro blog:

image image

Esta es sólo una de las muchas funciones que se pueden implementar desde un cliente JavaScript. Aquí os dejo otras funciones relacionadas como: borrar un sitio, borrar una lista, actualizar elemento de una lista…and ¡¡so on!!, para que probeis

Como ya hemos comentado antes esta aplicación se podría implementar de manera más “elegante”, pero esa parte la dejamos para más adelante. Así, con este artículo termino la serie de posts relacionados con el Modelo de Objeto Cliente en SP2010, y vuelvo al mundo ASP.NET MVC, que últimamente lo tengo un poco abandonado. ¡¡Será el verano!!