Mostrando las entradas con la etiqueta SharePoint Online. Mostrar todas las entradas
Mostrando las entradas con la etiqueta SharePoint Online. Mostrar todas las entradas

viernes, 7 de junio de 2024

Buenas Prácticas para la Estructura de Datos en SharePoint para Aplicaciones en PowerApps

 Introducción:

En el desarrollo de aplicaciones en PowerApps utilizando SharePoint como backend, es fundamental entender y aplicar buenas prácticas de estructura de datos. Aunque muchas de estas prácticas se derivan de conceptos de bases de datos relacionales, SharePoint requiere enfoques específicos debido a su naturaleza y manejo de datos.

 

1. Comprendiendo SharePoint como Fuente de Datos:

 

SharePoint almacena datos en listas y bibliotecas, cada una adecuada para diferentes tipos de datos y usos.

Las listas son ideales para datos estructurados, mientras que las bibliotecas se usan para documentos y archivos.

 

2. Principios Básicos de Modelado de Datos Relacionales:

 

Normalización: En bases de datos relacionales, la normalización es clave para evitar redundancias y asegurar la integridad referencial.

Sin embargo, en SharePoint, la normalización puede ser contraproducente debido a las limitaciones en las consultas y el rendimiento.

 

3. Diseño de Listas y Bibliotecas en SharePoint:

 

Diseña listas con columnas personalizadas para capturar los datos necesarios.

Utiliza tipos de contenido y metadatos para organizar y categorizar la información de manera eficiente.

4. Relaciones y Lookup Columns:

 

En lugar de utilizar columnas de búsqueda tradicionales (lookup columns) para crear relaciones entre listas, considera almacenar tanto el código como el nombre de la referencia directamente en la tabla de transacciones.

Este enfoque, aunque desnormalizado, mejora el rendimiento y facilita el manejo de datos históricos.

 

5. Manejo del Estado y Actualizaciones en PowerApps:

 

PowerApps permite manejar datos de SharePoint de manera eficiente, pero es crucial mantener la consistencia del estado.

Usa colecciones en memoria para manejar el estado de elementos pendientes de actualización y asegurarte de que los usuarios estén al tanto de que sus solicitudes están siendo procesadas.

 

6. Optimización y Buenas Prácticas:

 

Indexa columnas utilizadas frecuentemente en filtros y búsquedas para mejorar el rendimiento.

Limita el número de elementos en las listas para evitar problemas de rendimiento.

Utiliza fórmulas eficientes y minimiza la cantidad de consultas en PowerApps.

 

7. Preparación para Reportes Eficientes:

 

Diseña listas que ya contengan la información necesaria para generar reportes.

Actualiza estas listas con cada operación para que, al momento de generar un reporte, sea posible hacerlo de manera rápida y eficiente a través de una exportación de CSV.

Este enfoque asegura que los reportes se generen de forma inmediata y sin demoras en el procesamiento de información.

 

8. Consistencia en Tipos de Datos y Nombres de Columnas:

 

Mantén el tipo de dato y el nombre de las columnas exactamente igual en todas las listas que hagan referencia a esos datos.

Asegúrate de que, si una columna es numérica en una lista, sea numérica en todas las listas que la referencien, y lo mismo para texto y otros tipos de datos.

Esto facilita el desarrollo de software y evita conversiones innecesarias, garantizando coherencia y precisión en el manejo de datos.

 

9. Evitar Valores Predeterminados y Campos Obligatorios:

 

No utilices los valores predeterminados de las columnas de SharePoint, ya que esto puede ser contraproducente en los flujos de Power Automate.

Evita configurar campos como obligatorios a nivel de lista en SharePoint.

Maneja la captura de los campos obligatorios a nivel de la aplicación en Power Apps para evitar problemas en los flujos y asegurar que los valores no se actualicen involuntariamente.





Conclusión:

Aplicar estas buenas prácticas garantiza que tus aplicaciones en PowerApps sean robustas, escalables y fáciles de mantener.

La combinación de prácticas específicas para SharePoint y un enfoque práctico en el manejo de datos asegurará el éxito de tus aplicaciones.


lunes, 16 de octubre de 2017

Como publicar en SharePoint Online un reporte de Power BI Parte II

En la primera parte vimos como publicar desde el espacio de trabajo de una cuenta de Power BI Pro un reporte e incrustrarlo en SharePoint Online.  En esta segunda parte vamos a ver como desde un espacio de trabajo de Aplicación se comparte un reporte para que sea visualizado desde SPO o SharePoint Online.   La parte de incrustar el reporte desde SPO con ayuda del elemento web Power BI no las repetiré así que si no vieron la primera parte se los recomiendo.

Desde Power BI con una cuenta Power BI Pro.
Vamos a seleccionar Workspaces y Create app workspace


Vamos a colocarle el nombre Mi equipo de trabajo, vamos a indicar que es Privado dejando la opción Private - Only approved members can see what's inside y dejamos también la opción Members can edit Power BI content. En la casilla Add workspace members vamos a incluir al usuario en este ejemplo powerbicolaborador, que será el usuario que nos apoyará para elaborar el reporte en powerbi.


Ahora vamos a simular que el colaborador construye el reporte en Power BI para ello ingresamos con dicha cuenta a POWER BI.  Desde la cuenta powerbicolaborador seleccionamos Areas de trabajo y luego Mi equipo de trabajo.  Desplegará la opcion de Probar Power BI Pro gratis y Actualizar cuenta de lo cual seleccionaremos la primera.

Simulando un reporte vamos a seleccionar Ejemplos dentro de Obtener datos y seleccionamos el Ejemplo de análisis de minoristas y la opción conectar  ( si le da error, solo intentelo de nuevo y debería de obtener el reporte de ejemplo sin problema).



Listo el reporte esta ya construido


Ahora regresamos con la cuenta administradora para publicar el reporte y compartirlo.  Desde el Workspace Mi Equipo de trabajo seleccionamos la opción Publish App que aparece en la parte superior derecha de la página:


Y nos muestra 3 pestañas

Detalles podemos colocar una descripción y color.  Seleccionemos Content o Contenido.  Esta opción nos permitirá elegir que contenido deseamos publicar.  Para nuestro ejemplo selecionaremos la opción Report ya que es lo que publicaremos en SharePoint.


Luego seleccionamos la pestaña Access y seleccionamos al usuario jherrera para que pueda ver el reporte desde SPO.


Si deseamos darle permiso a otro usuario necesitamos agregarlo al espacio de trabajo primero para luego poderlo incluir en el app.

Para finalizar presionemos el botón amarillo Finish que esta en la parte superior derecha de la página



Ahora realizamos el mismo procedimiento que en la parte I; Creamos una pagina en SharePoint y agregamos el reporte.  Para el enlace del reporte necesitamos irnos al reporte y seleccionar la opción Embed in SharePoint Online y creamos el enlace en el QuickLaunch.



Y luego asigne permisos a la cuenta para que pueda ingresar al sitio de SharePoint.


Listo eso es todo!


Si el usuario intenta ver el reporte de IT Spend analysis le indicará que no puede verlo ya que no fue compartido con el.

Eso es todo por estos artículos, Enjoy!.

Juan Manuel Herrera Ocheita


Como publicar un reporte de Power Bi en SharePoint Online Parte I

A la fecha 16 de Octubre del 2017 hay dos formas de compatir un reporte de Power BI para incrustar en SharePoint Online.   En esta primera parte vamos a ver la forma habitual de compartir desde el espacio de trabajo individual de un usuario de Power BI, en la segunda parte lo veremos como se hace desde un equipo de trabajo.

Requisitos:

1. Tener una cuenta de Power BI Pro
2. Tener una cuenta de Office 365 que incluya SharePoint Online (preferencia E3)
3.  Tener permisos de Full Control sobre el sitio donde deseamos  incrustrar el reporte de Power BI.
4. Conocimientos básicos en el uso de reportes en Power BI, conocimiento básicos de SharePoint Online.


Primero lo primero
Desde My Workspace seleccionamos Get Data, hacemos clic sobre Samples, seleccionamos uno de los ejemplos disponibles en Powe BI, y presionamos el botón Connect.  Deberá mostrarle en el tablero el reporte.

Luego seleccionamos Reports y seleccionamos el reporte.

Luego seleccionamos Pin live Page



Luego nos vamos a Dashboards


Y sobre el reporte seleccionamos la opción de Share
Incluimos a los usuarios a los que les daremos el permiso de visualizar el reporte

Y presionamos el botón Share.

El siguiente paso es muy importante ya que el usuario debe de ingresar por lo menos una vez a Power Bi, si el usuario ya es usuario de Power Bi y ya ingreso por lo menos una vez al sitio ya no es necesario hacer este paso.

El usuario recibirá este correo:


El usuario debe de ingresar al enlace para que quede registrado su permiso en Power BI, si este paso no lo hace el usuario cuando incrustemos el reporte en SharePoint Online el no podrá verlo.


En nuestro caso para este ejemplo utilizaremos la opción Probar Power BI Pro gratis, actualizar cuenta es la opción Pagada.


Hacemos clic para iniciar el período de prueba y luego muestra otro mensaje de éxito que omití en el artículo ya que pienso no vale la pena.

Si hacemos clic sobre la opción Compartido conmigo deberías de ver el reporte compartido con la cuenta jherrera.



Si el usuario hace clic sobre el reporte debería poder verlo


Bueno ahora que compartimos de forma correcta el reporte y validamos que el usuario si tiene acceso al mismo nos toca ver la parte de SharePoint

Con la cuenta administradora del sitio donde vamos a publicar el reporte.  En Power Bi vamos a obtener el enlace para incrustarlo en SharePoint.  Seleccionamos Reports hacemos clic sobre el reporte y seleccionamos File y Embedded in SharePoint Online.



Ahora desde SharePoint Online


Seleccionamos Configuración o Tuerquita y elegimos la opción Add a page

Ahora colocamos el nombre y seleccionamos la opción + para agregar el elemento web Power BI


Presionamos el botón Add report y pegamos el enlace que copiamos desde Power BI .


Podemos seleccionar en Page Name el nombre de la pagina que deseamos mostrar (Esto puede demorar un poco así que espere un momento a que muestre en Page Name las páginas disponibles del reporte).  Si ya terminamos la configuración del elemento web presionamos la opción Save and Close en la parte superior izquierda como se muestra en la imagen.  Y por último presione el botón Publish.

Ahora necesitamos darle permiso al usuario En SharePoint para que por lo menos pueda ingresar al sitio.  Por ello le otorgaremos el permiso de lectura.  Vaya a Configuración o Tuerquita, y seleccione la opción Site Permisssions.  Ahora seleccione Share Site y escriba el nombre del usuario en este caso es jherrera y presione el Botón Add.


Un paso más y estamos listos.  Vamos a colocar un enlace en el Quick Launch (menú de lado izquierdo de la página) para que el usuario acceda al reporte desde SPO.  Haga clic en la opción Edit Link haga clic sobre el signo más y llene la casilla Address y Display Name similar a como se muestra en la imagen de abajo:



Presione el botón OK.

Listo ahora vamos con la cuenta del usuario Jherrera para que ingrese a SPO y validemos que puede ver el reporte.  Vamos a https://portal.office.com hacemos clic en el icono de SharePoint y hacemos clic sobre Frequent sites Guatemala  Team Site.  Hacemos clic sobre el enalce ITSpend analysis Sample in Power BI y esperamos un momento a que muestre el reporte y debería mostrarnos el reporte incrustrado de Power BI en el sitio de SharePoint como se muestra abajo en la imagen:



Eso es todo amigos!, en la segunda parte veremos otra forma de compartir el reporte desde Power BI.

Juan Manuel Herrera Ocheita

martes, 12 de septiembre de 2017

Importante cambio en el comportamiento de permisos en SharePoint Online

Los permisos en SharePoint en estos 15 años no han cambiando mucho.  Pero recientemente note un cambio que en el comportamiento de la administración de permisos en SharePoint que es importante tomarlo en cuenta.

Introducción

En SharePoint de forma predeterminada los permisos son heredados a lo largo y ancho de los objetos de SharePoint.  Como objetos podemos mencionar: Sub-sitios, Bibliotecas, Listas, elementos de una biblioteca o lista, carpetas y documentos o elementos.



Para crear permisos exclusivos sobre estos objetos es necesario indicarle a SharePoint que deseamos romper la herencia que heredamos el objeto superior que puede ser un sub-sitio, biblioteca y/o carpeta.  Eso dependerá donde estemos ubicados en el sitio, en la biblioteca o lista, en la carpeta.



La jerarquía de objetos de SharePoint para administrar el contenido es la siguiente:

Colección de Sitios
-> Sitio Primario
-->Sub-sitio
---> Biblioteca o Lista
----> Carpeta
----->Documento o Elemento



Si las Listas también pueden contener carpetas para agrupar elementos y los elementos de una lista también puede contener documentos como adjuntos.  Al final una biblioteca es una lista especializada para administrar documentos.

El Nuevo comportamiento

Cuando dejamos de heredar permisos de un objeto a otro los permisos del objeto superior son copiados o dejados en el objeto inferior facilitándonos la asignación de permisos basado en la herencia del objeto superior.  

El tema aquí es que aunque se haya roto la herencia del objeto superior si el usuario o grupo del objeto superior es eliminado en el objeto inferior también es eliminado.

Es no es el comportamiento predeterminado y es importante conocerlo porque podemos creer que el permiso sigue aún allí en el objeto inferior y no es así.  Si deseamos que ese objeto inferior tenga acceso entonces debemos explícitamente conceder el permiso asignándole de nuevo el grupo o usuario que fue eliminado en el sitio superior.  



Deduzco que este comportamiento fue modificado por solicitud de usuarios de negocio que siguen la regla que si un grupo o usuario es eliminado del objeto superior no debería tener acceso a objetos de nivel inferior.

Así que amigos estén conscientes de este cambio ya que puede afectar el acceso a los objetos dentro de SharePoint Online

SharePoint4Fun!,

Juan Manuel Herrera 

viernes, 29 de enero de 2016

Como migrar el contenido de un sitio de WordPress a las bibliotecas de SharePoint Online

La estrategia es muy sencilla y va ser la siguiente:
1) Descargar el contenido a un almacenamiento local a través de una herramienta FTP.
2) Definir una estrategia para almacenar el contenido en SharePoint Online
2) Crear un Script que lea el contenido migrado y suba los archivos a bibliotecas de SharePoint.
La herramienta
Describamos un poco la herramienta llamada FileZila.   Esta herramienta de FTP es gratuita y esta disponible para los sistemas operativos más populares.   Lo mas importante si estamos en un entrono Windows es que vamos a poder acceder el contenido de WordPress que esta en Linux.
El enlace para descargar la herramienta es el siguiente: https://filezilla-project.org/ 
Veamos ahora la conexión hacia el servicio ftp


La información que debes de solicitar para hacer la conexión es la siguiente:
Dirección IP del servidor Linux
Puerto (Opcional solo si el cliente utiliza un puerto en especifico diferente el predeterminado [21] colocarlo allí).
Luego Las credenciales un usuario con acceso y una contraseña.
Seleccionamos lo que deseamos descargar y con el clic derecho del ratón seleccionamos la opción Download.


La estrategia
Para la estrategia vamos a crear bibliotecas por cada carpeta principal ya que en SPO hay un límite de despliegue de documentos de 5,000 por razones de rendimiento.  Por lo que debemos de tomar eso en cuenta.








Para reducir el trabajo en el script vamos a crear manualmente las bibliotecas porque tampoco son muchas en mi este caso de lo contrario deberíamos tomar eso en cuenta en el script y crear con comandos de Powershell las bibliotecas.



El Script
A través de este script invocamos los comandos de CSOM Client SharePoint Object Model y no el Modelo de objetos de SharePoint.   Porque razón?, bueno porque SharePoint Online no esta local sino en la nube y la forma de acceder remotamente las librerias de SharePoint es através de CSOM que no es mas que llamadas de servicios Web por medio de un módelo de objetos definido para ese propósito.

Ahora vemos el script que hace la magia:
/* Cargamos las librerias de CSOM */
Add-Type -Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\15\ISAPI\Microsoft.SharePoint.Client.dll"
Add-Type -Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\15\ISAPI\Microsoft.SharePoint.Client.Runtime.dll"

/* El método Ensure_Folder nos asegurará que la carpeta este creada antes de copiar el contenido */
Function Ensure-Folder()
{
Param(
  [Parameter(Mandatory=$True)]
  [Microsoft.SharePoint.Client.Web]$Web,

  [Parameter(Mandatory=$True)]
  [Microsoft.SharePoint.Client.Folder]$ParentFolder,

  [Parameter(Mandatory=$True)]
  [String]$FolderUrl

)
    $folderNames = $FolderUrl.Trim().Split("/",[System.StringSplitOptions]::RemoveEmptyEntries)
    $folderName = $folderNames[0]
    Write-Host "Creating folder [$folderName] ..."
    $curFolder = $ParentFolder.Folders.Add($folderName)
    $Web.Context.Load($curFolder)
    $web.Context.ExecuteQuery()
    Write-Host "Folder [$folderName] has been created succesfully. Url: $($curFolder.ServerRelativeUrl)"

    if ($folderNames.Length -gt 1)
    {
        $curFolderUrl = [System.String]::Join("/", $folderNames, 1, $folderNames.Length - 1)
        Ensure-Folder -Web $Web -ParentFolder $curFolder -FolderUrl $curFolderUrl
    }
}

/* El método Upload-File  recibe como parametros el url relativo de la carpeta destino y la ubicación local del archivo */
Function Upload-File()
{
Param(
  [Parameter(Mandatory=$True)]
  [Microsoft.SharePoint.Client.Web]$Web,

  [Parameter(Mandatory=$True)]
  [String]$FolderRelativeUrl,

  [Parameter(Mandatory=$True)]
  [System.IO.FileInfo]$LocalFile

)
    try {
     $folderUrl = $LocalFile.Name.ToLower().Replace($SourceFolderPath.ToLower(),"")
    
     $fileUrl = $FolderRelativeUrl + "/" + $folderUrl

       write-host "FileUrl:" $fileUrl
       Write-Host "Uploading file [$($LocalFile.FullName)] ..."
       [Microsoft.SharePoint.Client.File]::SaveBinaryDirect($Web.Context, $fileUrl, $LocalFile.OpenRead(), $true)
       Write-Host "File [$($LocalFile.FullName)] has been uploaded succesfully. Url: $fileUrl"
    }
    catch {
       write-host "An error occured while uploading file [$($LocalFile.FullName)]"
    }
}

/* El método Upload-Files es la principal ya que localiza cata archivo local y define la url destino para subir el archivo  a SPO.  Este método recibe como parameto la url destino, el usuario de O365, la contraeña, el nombre de la biblioteca de SharePoint destino, y la rutal local donde esta ubicado el contenido.  Como es recursivo solo debemos de dar el punto de partida de donde deseamos iniciar la carga de información. */

function Upload-Files()
{

Param(
  [Parameter(Mandatory=$True)]
  [String]$Url,

  [Parameter(Mandatory=$True)]
  [String]$UserName,

  [Parameter(Mandatory=$False)]
  [String]$Password,

  [Parameter(Mandatory=$True)]
  [String]$TargetListTitle,

  [Parameter(Mandatory=$True)]
  [String]$SourceFolderPath

)
    if($Password) {
       $SecurePassword = $Password | ConvertTo-SecureString -AsPlainText -Force
    }
    else {
      $SecurePassword = Read-Host -Prompt "Enter the password" -AsSecureString
    }

# Abajo la autenticación a O365 para acceder los objetos de SharePoint Online
    $Context = New-Object Microsoft.SharePoint.Client.ClientContext($Url)
    $Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($UserName,$SecurePassword)
    $Context.Credentials = $Credentials
    #Instanciamos el Web Site que vamos acceder
    $web = $Context.Web
    $Context.Load($web)

    # Instanciamos la biblioteca destino
    $list = $web.Lists.GetByTitle($TargetListTitle);
    $Context.Load($list.RootFolder)

#Ejecutamos el conjunto de lineas anteriores
    $Context.ExecuteQuery()
#Recorremos cada directorio local del parametró de ruta origen que indicamos al ejecutar el método

    Get-ChildItem $SourceFolderPath -Recurse | % {
       if ($_.PSIsContainer -eq $True) {
          $folderUrl = $_.FullName.ToLower().Replace($SourceFolderPath.ToLower(),"")
          $folderUrl = $folderUrl.Replace("\","/").Replace(".","")  
          if($folderUrl) {
             Ensure-Folder -Web $web -ParentFolder $list.RootFolder -FolderUrl $folderUrl
          } 
       }
       else{

          # Basado en la ubicación local creamos un Url Relativo reciproco en la biblioteca de SPO
          $folderRelativeUrl = $list.RootFolder.ServerRelativeUrl + $_.DirectoryName.ToLower().Replace($SourceFolderPath.ToLower(),"").Replace("\","/").Replace(".","") 

          #Ejecutamos el métod que subira el archivo a la ruta destino
          Upload-File -Web $web -FolderRelativeUrl $folderRelativeUrl -LocalFile $_
       }
    }
}

#End of file
La ejecución
Para ejecutar el archivo uploadfiles-csom.ps1 deberemos declarar los siguientes parámetros:

$Url =
https://miempresa.sharepoint.com/sites/miSitio
$UserName = misuario@midominio.onmicrosoft.com
$Password = "******"
$TargetListTitle = "BibliotecaDestino"   #Target Library
$SourceFolderPath = "X:\www\data\uploads\CarpetaOrigen"  #Source Physical Path


#Comando
Upload-Files -Url $Url -UserName $UserName -Password $Password -TargetListTitle $TargetListTitle -SourceFolderPath $SourceFolderPath


Y eso es todo amigos.
Hasta la próxima, SharePoint4Fun!
Juan Manuel Herrera Ocheita

sábado, 26 de diciembre de 2015

Analizando como podemos consumir SharePoint OData con javascript

Pienso que es interesante las pruebas que realice para validar lo que me devuelve el servicio de Odata de SharePoint Online.

Cree una lista personalizada de SharePoint llamada Banners y adicione un par de columnas Url y Link.

Y el contenido es el siguiente: un solo elemento con una image y un enlace.


Si consumimos el servicio enviando la siguiente instrucción con jquery:
 
Lo que me devuelve al consumir json es lo siguiente:
{"odata.metadata":"https://infowareplus.sharepoint.com/sites/prueba/_api/$metadata#SP.ListData.BannersListItems"
,"value":[{"odata.type":"SP.Data.BannersListItem"
,"odata.id":"0589cb7b-2bb2-4ced-a7ea-704cd8e0dcea"
,"odata.etag":"\"4\""
,"odata.editLink":"Web/Lists(guid'2b6b9d83-4eeb-4716-86e4-5f6ee03a577e')/Items(1)"
,"FileSystemObjectType":0
,"Id":1
,"ContentTypeId":"0x01002C49C3B57506B541ABE2A829193FF712"
,"Title":"Noticias"
,"Imagen":{"Description":"Evento"
,"Url":"https://infowareplus.sharepoint.com/sites/prueba/SiteAssets/EventoMicrosoftAzureComunidadTecnica2.jpg"}
,"Link":{"Description":"Dirección de Prueba"
,"Url":"http://www.google.com"}
,"ID":1
,"Modified":"2015-12-14T19:54:56Z"
,"Created":"2015-12-10T20:47:48Z"
,"AuthorId":9
,"EditorId":9
,"OData__UIVersionString":"1.0"
,"Attachments":false
,"GUID":"f6a6e965-8f1a-436e-86c8-682e4f6368d5"}]}
Ahora observemos la siguiente prueba a tavés de javascript:





Create Object from JSON String













Lo que nos devuelve es lo siguiente:
{"odata.metadata":"https://infowareplus.sharepoint.com/sites/PRUEBA/_api/$metadata#SP.ListData.BannersListItems","value":[{"odata.type":"SP.Data.BannersListItem","odata.id":"0589cb7b-2bb2-4ced-a7ea-704cd8e0dcea","odata.etag":"'4'","odata.editLink":"Web/Lists(guid\'2b6b9d83-4eeb-4716-86e4-5f6ee03a577e\')/Items(1)","FileSystemObjectType":0,"Id":1,"ContentTypeId":"0x01002C49C3B57506B541ABE2A829193FF712","Title":"Noticias","Imagen":{"Description":"Evento","Url":"https://infowareplus.sharepoint.com/sites/prueba/SiteAssets/EventoMicrosoftAzureComunidadTecnica2.jpg"},"Link":{"Description":"Dirección de Prueba","Url":"http://www.google.com"},"ID":1,"Modified":"2015-12-14T19:54:56Z","Created":"2015-12-10T20:47:48Z","AuthorId":9,"EditorId":9,"OData__UIVersionString":"1.0","Attachments":false,"GUID":"f6a6e965-8f1a-436e-86c8-682e4f6368d5"}]}
Si accedemos  a la propiedad odata.detadata:
var obj = JSON.parse(text);
document.getElementById("demo2").innerHTML = obj["odata.metadata"];
Me retorna lo siguiente:
https://infowareplus.sharepoint.com/sites/prueba/_api/$metadata#SP.ListData.BannersListItems
Si accedemos la propiedad value obtendremos otro objeto de json que podemos acceder sus propiedades, de la siguiente forma:
var obj2 = obj["value"];
document.getElementById("demo3").innerHTML = obj2[0]["odata.type"];

Lo que nos retorna es lo siguiente:
SP.Data.BannersListItem
Asi podemos obtener otros atributos:
document.getElementById("demo4").innerHTML = obj2[0]["odata.id"];
document.getElementById("demo5").innerHTML = obj2[0]["odata.etag"];
document.getElementById("demo6").innerHTML = obj2[0]["odata.editLink"];
Lo que nos retorna es lo siguiente:
0589cb7b-2bb2-4ced-a7ea-704cd8e0dcea
'4'
Web/Lists(guid'2b6b9d83-4eeb-4716-86e4-5f6ee03a577e')/Items(1)
Y por ultimo vamos acceder la propiedad Imagen y Link de la siguiente forma:
var obj3 = obj2[0]["Imagen"];
document.getElementById("demo7").innerHTML = obj3["Url"];
var obj4 = obj2[0]["Link"];
document.getElementById("demo8").innerHTML = obj4["Url"];
Y los resultados serán las URL siguientes:
https://infowareplus.sharepoint.com/sites/PRUEBA/SiteAssets/EventoMicrosoftAzureComunidadTecnica2.jpg
http://www.google.com
Bueno como vemos podemos acceder con javascript la información que me devuelve el servicio OData de SharePoint, y como esta construído la estructura de datos de una lista Personalizada de SharePoint.  Para que observemos mejor la estructura lo mostraré de la siguiente forma:
'{
"odata.metadata":"https://infowareplus.sharepoint.com/sites/prueba/_api/$metadata#SP.ListData.BannersListItems"
,"value":[
     {"odata.type":"SP.Data.BannersListItem"
     ,"odata.id":"0589cb7b-2bb2-4ced-a7ea-704cd8e0dcea"
     ,"odata.etag":"\'4\'"
     ,"odata.editLink":"Web/Lists(guid\'2b6b9d83-4eeb-4716-86e4-5f6ee03a577e\')/Items(1)"
     ,"FileSystemObjectType":0
     ,"Id":1
     ,"ContentTypeId":"0x01002C49C3B57506B541ABE2A829193FF712"
     ,"Title":"Noticias"
     ,"Imagen":{"Description":"Evento","Url":"https://infowareplus.sharepoint.com/sites/prueba/SiteAssets/EventoMicrosoftAzureComunidadTecnica2.jpg"}
     ,"Link":{"Description":"Dirección de Prueba" ,"Url":"http://www.google.com"}
     ,"ID":1
     ,"Modified":"2015-12-14T19:54:56Z"
     ,"Created":"2015-12-10T20:47:48Z"
     ,"AuthorId":9
     ,"EditorId":9
     ,"OData__UIVersionString":"1.0"
     ,"Attachments":false
     ,"GUID":"f6a6e965-8f1a-436e-86c8-682e4f6368d5"}
     ]
}'
Espero que con eso los haya ayudado a comprender la estructura de las listas en SharePoint en formato JSON.
Hasta la próxma,
Juan Manuel Herrera Ocheita
 

P.D. utilice para las pruebas el siguiente enlace: http://www.w3schools.com/json/tryit.asp?filename=tryjson_parse .

domingo, 21 de junio de 2015

API´s disponibles para el Desarrollo de Aplicaciones en SharePoint

Las Interfaces de Programación de Aplicaciones o API en SharePoint tienen su historia y por ello hay una variedad de opciones disponibles hoy en día ningún API se aplica a todos los casos y en necesario conocer su historia para conocer su aplicación.

.NET Server Type o Modelo de Objetos de Servidor para SharePoint

Empecemos con .NET Server Type o el Modelo de Objetos de Servidor para SharePoint.  Esta API nació con la versión SharePoint 2007, la cual emergía de a poco, en Visual Studio 2005 no se tenía ningún plug-in al principio para soportar el desarrollo de soluciones para Extender SharePoint y había que definir manualmente archivos XML que definían las FEATURES que activarían las funcionalidades en los sitios de SharePoint.  Los Elementos web recuerdo eran y son en realidad controles de Usuario de ASP.NET que se enmascaraban a través de un archivo de XML para convertirlo en un elemento Web que reconociera SharePoint.

 

Recomiendo el siguiente enlace:Mejores Prácticas: Problemas comunes cuando utiliza el modelo de objetos de servidor

A continuación segmento de código del Modelo de Objeto de Servidor para SharePoint 2007-2010 y 2013 soluciones de granja (WSP)

sing (SPSite siteCollection = new SPSite("http://intranet.adicodes.com"))
{
  using (SPWeb site = siteCollection.OpenWeb())
  {
    try
    {
      SPList taskList = site.GetList("/Lists/MyTasks");
      Console.WriteLine("Success!");
    //Create a new item
SPListItem newItem = list.Items.Add;
newItem["Title"] = "Created Item " + DateTime.Now.ToLongDateString;
newItem.Update; //NOTE: Update must be called
 
//Read items by binding to grid
SPListItemCollection items = list.Items; //NOTE: This loads all items, folders, and fields!
itemGrid.DataSource = items; // Binding to grid to display items, just for scenario
itemGrid.DataBind;
 
//Delete the first item
list.Items[0].Delete;
 
//Update the first item
//Note the use of a temporary SPListItem
SPListItem updateItem = list.Items[0];
updateItem["Title"] = "Updated Item " + DateTime.Now.ToLongDateString;
updateItem.Update;

    }
    catch(FileNotFoundException)
    {
      Console.WriteLine("List does not exist");
    }
  }
}

CSOM o Client SharePoint Object Model

Este modelo de objetos para SharePoint que se ejecuta de lado del cliente surgió en la versión SharePoint 2010 que introdujo las SandBox Solution que pretendía apoyar la adopción de Silverlight, el cual era un “motor” tipo Java que ejecutaría el código en cualquier dispositivo y sistema operativo, bueno esa era la intención Microsoft desistió al ver nuevas tendencias en el mercado como la nube y saco a Silverlight y como consecuencia el modelo sandbox también marcándolo como obsoleto en las próximas versiones.  El nombre Sandbox solution se le debe a que se ejecuta en una caja cerrada es decir ya no se tiene acceso al servidor sino solamente a la colección de sitios donde se cargue la solución. 

Tiers in the sandboxed solutions service

Una de las interioridades de este tipo de solución es que el empacado era el mismo que las soluciones de granja de solución wsp, pero con el alcance limitado a colección de sitios y que no podía ejecutar código que instanciara el Modelo de Objetos de Servidor de las soluciones de granja del modelo anterior.  En SharePoint 2010, entonces hay dos posibilidades desarrollar soluciones de granja y soluciones Sandbox una consume el modelo de objetos de Servidor y la otra el modelo de objetos cliente.  No todo el modelo de objetos de Servidor se dispone en la versión CSOM ya que el alcance es mucho mas limitado en las soluciones Sandbox y fundamentalmente se tiene acceso al contenido dentro de los sitios de SharePoint, bibliotecas, listas, grupos y usuarios.

// Create ClientContext object

ClientContext ctxObj = new ClientContext("http://mysitecllection/mysite/");

// Get Site Collection object

Site siteObj = ctxObj.Site;

ctxObj.Load(siteObj);

// Get web object

Web webObj = siteObj.RootWeb;

ctxObj.Load(webObj);

// Build query to the list "EmployeeList"

List empListObj = webObj.Lists.GetByTitle("EmployeeList");

ctxObj.Load(empListObj);

// Execute the query against ClientContext

ctxObj.ExecuteQuery();

// Get the Title

Console.WriteLine(empListObj.Title);

// Build a query for all items in the list

CamlQuery query = new CamlQuery();

query.ViewXml = "<View/>";

ListItemCollection allEmploys  = empListObj.GetItems(query);

ctxObj.Load(allEmploys);

// Execute the query against ClientContext

ctxObj.ExecuteQuery();

// Get all the results

foreach (ListItem listItem in allEmploys) {

Console.WriteLine("Id: {0} - Firstname: {1} - LastName: {2} - Department: {3}",

listItem["ID"],

listItem["FirstName"],

listItem["LastName"],

listItem["Department"]

);

}

REST endpoint

También en la versión SharePoint 2010 vino una implementación de Rest para el contenido de SharePoint, también limitado al contenido de SharePoint como su contraparte CSOM.   Pero no fue sino hasta la versión 2013 que ya vino incluido desde su edición original.  La intención de Microsoft es proveer un protocolo de comunicación standard para que el contenido de SharePoint fuese consumido por cualquier tipo de aplicación.

PartsDataContext context = new PartsDataContext(
new Uri("http://localhost/sites/sharepointlist/_vti_bin/listdata.svc"));
var partsQuery = (DataServiceQuery<PartsItem>)
context.Parts.Where(p => p.SKU.StartsWith(SearchSku))
.Select(p => new PartsItem { Title = p.Title,
SKU = p.SKU,
Id = p.Id,
Description = p.Description
});

// Execute query.
query.BeginExecute(DisplayParts, query);
 

JSOM object


Con el advenimiento de la versión SharePoint 2013 trabajo consigo un nuevo modelo de desarrollo llamado App Model o Modelo de Aplicación, esto para apoyar la estrategia de Microsoft en la nube y proveer un modelo de extensibilidad de SharePoint en la nube a través de Office 365.  Para la versión SharePoint 2013 en premisas persiste el modelo de solución de granja que tiene acceso total a los recursos del servidor y el modelo Apps.  Pero para la versión en la nube solo esta disponible el modelo de Aplicación.  



Fundamentalmente solo se pueden desarrollas dos tipos de aplicaciones bajo este nuevo modelo  SharePoint Hosted y Provider Hosted.   La primera básicamente consume el contenido de SharePoint por medio de javascript y este modelo provee un conjunto de librerías de Json para consumir el contenido de SharePoint el cual devuelve los resultados en formato Json.  Si elegimos el Modelo Provider Hosted podemos utilizar cualquiera de las API Cliente (Csom, Jsom o Rest) pero el código debe de hospedarse fuera de SharePoint.


Ejemplo:

function createListItem(siteUrl,listName, itemProperties, success, failure) {

var itemType = getItemTypeForListName(listName);
itemProperties["__metadata"] = { "type": itemType };

$.ajax({
url: siteUrl + "/_api/web/lists/getbytitle('" + listName + "')/items",
type: "POST",
contentType: "application/json;odata=verbose",
data: JSON.stringify(itemProperties),
headers: {
"Accept": "application/json;odata=verbose",
"X-RequestDigest": $("#__REQUESTDIGEST").val()
},
success: function (data) {
success(data.d);
},
error: function (data) {
failure(data);
}
});
}


// Get List Item Type metadata
function getItemTypeForListName(name) {
return "SP.Data." + name.charAt(0).toUpperCase() + name.split(" ").join("").slice(1) + "ListItem";
}
//specify item properties
var itemProperties = {'Title':'Order task','Description': 'New task'};
//create item
createListItem(_spPageContextInfo.webAbsoluteUrl,'Tasks',itemProperties,
function(entity){
console.log('New task ' + entity.Title + ' has been created');
},
function(error){
console.log(JSON.stringify(error));
}
);

API disponibles en SharePoint para el desarrollo de Aplicaciones.











































































































































































































































































































































































.NET Server type
CSOM typeJSOM objectREST endpoint
SPAttachmentCollectionAttachmentCollectionSP.AttachmentCollection object (sp.js)…/_api/web/lists('<list id>')/items(<item id>)/attachmentfiles
SPBasePermissionsBasePermissionsSP.BasePermissions object (sp.js) 
SPCalendarTypeCalendarTypeSP.CalendarType enumeration (sp.js) 
SPChangeCollectionChangeCollectionSP.ChangeCollection object (sp.js)…/_api/web/getchanges(changequery)
SPChangeSiteChangeSiteSP.ChangeSite enumeration (sp.js) 
 ClientContextSP.ClientContext object (sp.js)…/_api/contextinfo
SPContentTypeContentTypeSP.ContentType object (sp.js)…/_api/web/contenttypes('<content type id>')
SPContentTypeCollectionContentTypeCollectionSP.ContentTypeCollection object (sp.js)…/_api/web/contenttypes
SPContext SP.RequestContext object (sp.js) 
SPEventReceiverDefinitionEventReceiverDefinitionSP.EventReceiverDefinition object (sp.js)…/_api/web/eventreceivers
SPEventReceiverDefinitionCollectionEventReceiverDefinitionCollectionSP.EventReceiverDefinitionCollection object (sp.js)…/_api/web/eventreceivers(eventreceiverid)
SPEventReceiverDefinitionCreationInformationEventReceiverDefinitionCreationInformationSP.EventReceiverDefinitionCreationInformation object (sp.js) 
SPEventReceiverTypeEventReceiverTypeSP.EventReceiverType enumeration (sp.js) 
SPFeatureFeatureSP.Feature object (sp.js)…/_api/web/features(featureid)
SPFeatureCollectionFeatureCollectionSP.FeatureCollection object (sp.js)…/_api/web/features
SPFeatureDefinitionScopeFeatureDefinitionScopeSP.FeatureDefinitionScope enumeration (sp.js) 
SPFieldFieldSP.Field object (sp.js)…/_api/web/fields('<field id>')
SPFieldCalculatedFieldCalculatedSP.FieldCalculated object (sp.js)…/_api/web/fields('<field id>')
SPFieldChoiceFieldChoiceSP.FieldChoice object (sp.js)…/_api/web/fields('<field id>')
SPFieldCollectionFieldCollectionSP.FieldCollection object (sp.js)…/_api/web/fields
SPFieldComputedFieldComputedSP.FieldComputed object (sp.js)…/_api/web/fields('<field id>')
SPFieldCurrencyFieldCurrencySP.FieldCurrency object (sp.js)…/_api/web/fields('<field id>')
SPFieldLinkFieldLinkSP.FieldLink object (sp.js)…/_api/web/contenttypes('<content type id>')/fieldlinks('<field link id>')
SPFieldLookupValueFieldLookupValueSP.FieldLookup object (sp.js) 
SPFieldMultiChoiceFieldMultiChoiceSP.FieldMultiChoice object (sp.js)…/_api/web/fields('<field id>')
SPFieldMultiLineTextFieldMultiLineTextSP.FieldMultiLineText object (sp.js)…/_api/web/fields('<field id>')
SPFieldNumberFieldNumberSP.FieldNumber object (sp.js)…/_api/web/fields('<field id>')
SPFieldTextFieldTextSP.FieldText object (sp.js)…/_api/web/fields('<field id>')
SPFieldUrlFieldUrlSP.FieldUrl object (sp.js)…/_api/web/fields('<field id>')
SPFieldUrlValueFieldUrlValueSP.FieldUrlValue object (sp.js) 
SPFieldUserFieldUserSP.FieldUser object (sp.js)…/_api/web/fields('<field id>')
SPFileFileSP.File object (sp.js)…/_api/web/getfilebyserverrelativeurl('/<folder name>/<file name>')
SPFileCollectionFileCollectionSP.FieldCollection object (sp.js)…/_api/web/getfolderbyserverrelativeurl('/<folder name>')/files
SPFolderFolderSP.Folder object (sp.js)…/_api/web/getfolderbyserverrelativeurl('/<folder name>')
SPFormFormSP.Form object (sp.js)…/_api/web/lists(guid'<list id>')/forms('<form id>')
SPGroupGroupSP.Group object (sp.js)…/_api/web/sitegroups(<group id>)
SPGroupCollectionGroupCollectionSP.GroupCollection object (sp.js)…/_api/web/sitegroups
SPLanguageLanguageSP.Language object (sp.js) 
SPListListSP.List object (sp.js)…/_api/web/lists(guid'<list id>')
SPListCollectionListCollectionSP.ListCollection object (sp.js)…/_api/web/lists
SPListDataSourceListDataSourceSP.ListDataSource object (sp.js) 
SPListItemListItemSP.ListItem object (sp.js)…/_api/web/lists(guid'<list id>')/items(<item id>)
SPListItemCollectionListItemCollectionSP.ListItemCollection object (sp.js)…/_api/web/lists(guid'<list id>')/items
SPListTemplateTypeListTemplateTypeSP.ListTemplateType enumeration (sp.js) 
SPNavigationNavigationSP.Navigation object (sp.js)…/_api/web/navigation
SPNavigationNodeNavigationNodeSP.NavigationNode object (sp.js) 
SPPrincipalPrincipalSP.Principal object (sp.js) 
SPQuery   
SPRecycleBinItemRecycleBinItemSP.RecycleBinItem object (sp.js)…/_api/web/RecycleBin(recyclebinitemid)
SPRecycleBinItemCollectionRecycleBinItemCollectionSP.RecycleBinItemCollection object (sp.js)…/_api/web/RecycleBin
SPRegionalSettingsRegionalSettingsSP.RegionalSettings object (sp.js)…/_api/web/RegionalSettings
SPRoleAssignmentRoleAssignmentSP.RoleAssignment object (sp.js)…/_api/web/roleassignments(<principal id>)
SPRoleAssignmentCollectionRoleAssignmentCollectionSP.RoleAssignmentCollection object (sp.js)…/_api/web/roleassignments
SPRoleDefinitionRoleDefinitionSP.RoleDefinition object (sp.js)…/_api/web/roledefinitions(<role definition id>)
SPRoleTypeRoleTypeSP.RoleType enumeration (sp.js) 
SPSecurableObjectSecurableObjectSP.SecurableObject object (sp.js) 
SPSiteSiteSP.Site object (sp.js)…/_api/site
SPTimeZoneTimeZoneSP.TimeZone object (sp.js)…/_api/web/RegionalSettings/TimeZones(timzoneid)
SPTimeZoneCollectionTimeZoneCollectionSP.TimeZoneCollection object (sp.js)…/_api/web/RegionalSettings/TimeZones
SPUserUserSP.User object (sp.js)…/_api/web/siteusers(@v)?@v='<login name>'
SPUserCollectionUserCollectionSP.UserCollection object (sp.js)…/_api/web/sitegroups(<group id>)/users
SPUtilityUtilitySP.Utilities.Utility object (sp.js) 
SPViewViewSP.View object (sp.js)…/_api/web/lists(guid'<list id>')/views('<view id>')
SPViewCollectionViewCollectionSP.ViewCollection object (sp.js)…/_api/web/lists(guid'<list id>')/views
SPViewFieldCollectionViewFieldCollectionSP.ViewFieldCollection object (sp.js)…/_api/web/lists(guid'<list id>')/views('<view id>')/fields
SPWebWebSP.Web object (sp.js)…/_api/web
SPWebCollectionWebCollectionSP.WebCollection object (sp.js)…/_api/web/webs
SPWebInfoWebInformationSP.WebInformation object (sp.js)…/_api/web/webinfos('<web information id>')
SPWebTemplateWebTemplateSP.WebTemplate object (sp.js)…/_api/web/GetAvailableWebTemplates(languageid,includecrosslanguage)/getbyname(templatename)
SPWebTemplateCollectionWebTemplateCollectionSP.WebTemplateCollection object (sp.js)…/_api/web/GetAvailableWebTemplates(languageid,includecrosslanguage



https://msdn.microsoft.com/EN-US/library/office/dn268594.aspx









Espero les sea de utilidad para elegir las diferentes API según lo escenarios con que estan desarrollando soluciones para las diferentes versiones de SharePoint.


Hasta la Proxima!,


Juan Manuel Herrera Ocheita