Un nuevo CSOM, el Mobile Object Model de SharePoint 2013

Escrito por  Alberto Diaz Martin

Un punto diferenciador de SharePoint, con respecto a otras plataformas de colaboración, es la capacidad de ofrecer una capa de abstracción en cliente, permitiendo el desarrollo de aplicaciones o integraciones externas. Desde el primer día, los servicios Web de SharePoint han permitido interactuar con la plataforma de una forma sencilla y universal, permitiendo, sin tener que desarrollar ninguna API de servidor, acceder a cualquier tipo de contenido en SharePoint.

Con SharePoint 2010, se incluyeron dos opciones nuevas, el Cliend-Side Objet Model (CSOM) y la interfaz REST, que complementaban a los servicios Web de la plataforma, ofreciendo más posibilidades de desarrollo. Mientras que en el último SharePoint, la versión 2013, se han añadido nuevas funcionalidades al CSOM, así como una nueva y más limpia interfaz REST.

Dentro de las múltiples versiones del modelo de objetos de cliente de SharePoint 2013, nos encontramos con un nuevo SDK para el desarrollo de aplicaciones móviles, el Mobile Object  Model.

Una nueva oportunidad para mejorar la movilidad de las empresas que usan SharePoint, ya que pueden extender sus procesos empresariales de forma universal a todos los usuarios, estén donde estén y tanto con un ordenador como con un móvil. Pensemos en aplicaciones que permitan aprobar flujos de trabajo en SharePoint, consultar datos de clientes en listas o almacenar fotos geo-localizadas en una biblioteca de documentos en SharePoint.

En este artículo, haremos una introducción a la versión de Windows Phone, dejando para el siguiente la versión REST, que nos permitiría hacer un cliente más universal para Windows 8, iPhone o Android.

El CSOM de Windows Phone usa el servicio WCF, client.svc, que es el encargado de analizar y ejecutar las consultas del cliente, usando el modelo de objetos de servidor, y devolver el resultado en JSON al cliente para que pueda trabajar con los objetos que necesite. Siguiendo el siguiente diagrama de arquitectura.

Arquitectura del CSOM en SharePoint 2013

Si ya hemos trabajado con la implementación Silverlight del CSOM, trabajar con esta versión para Windows Phone es prácticamente lo mismo, básicamente hay que tener presente las llamadas asíncronas y que los objetos no se cargan hasta que ejecutemos la consulta en el servidor.

Autenticación

Hasta ahora, el principal problema que teníamos con Windows Phone y la integración con SharePoint es el de la autenticación del usuario frente a SharePoint. Para esto, tenemos una clase, Authenticator, que se encarga de realizar la autenticación por nosotros, aunque podemos realizarla manualmente.

var context = new ClientContext("https://xxx.sharepoint.com");

var authenticator = new Authenticator();

authenticator.CookieCachingEnabled = true;

context.Credentials = authenticator;

Consultas a lista

No tenemos cambios significativos cuando realizamos consultas a listas, básicamente obtenemos la lista, con o sin el CAML query, trabajando siempre desde el contexto de cliente y en el ExecuteQueryAsync obtenemos los elementos de esa lista o consulta.

1     var lista = new ObservableCollection<Announcement>();
2     var query = GetAnnouncementQuery();
3     var items = Context.Web.Lists.GetByTitle("Announcements").GetItems(query);
4     Context.Load(items);
5     Context.Load(items, listItems => listItems.Include(item => item.FieldValuesAsText));
6     Context.ExecuteQueryAsync(                
7         delegate(object sender, ClientRequestSucceededEventArgs args)
8         {
9             foreach (var item in items)
10             {
11                 var anuncio = new Announcement();
12                 anuncio.ID = item.Id.ToString();
13                 anuncio.Title = item.FieldValuesAsText["Title"];
14                 anuncio.Body = item.FieldValuesAsText["Body"];
15                 anuncio.Expires = item.FieldValuesAsText["Expires"];
16                 anuncio.Created = item.FieldValuesAsText["Created"];
17                 lista.Add(anuncio);
18             }
19         },
20         delegate(object sender, ClientRequestFailedEventArgs args)
21         {
22             //Manejamos el error de la consulta
23
24
25
26
27     var query = GetAnnouncementQuery();
28
29
30
31     var items = Context.Web.Lists.GetByTitle("Announcements").GetItems(query);
32
33
34
35     Context.Load(items);
36
37
38
39     Context.Load(items, listItems => listItems.Include(item => item.FieldValuesAsText));
40
41
42
43
44
45
46
47     Context.ExecuteQueryAsync(                
48
49
50
51         delegate(object sender, ClientRequestSucceededEventArgs args)
52
53
54
55         {
56
57
58
59             foreach (var item in items)
60
61
62
63             {
64
65
66
67                 var anuncio = new Announcement();
68
69
70
71                 anuncio.ID = item.Id.ToString();
72
73
74
75                 anuncio.Title = item.FieldValuesAsText["Title"];
76
77
78
79                 anuncio.Body = item.FieldValuesAsText["Body"];
80
81
82
83                 anuncio.Expires = item.FieldValuesAsText["Expires"];
84
85
86
87                 anuncio.Created = item.FieldValuesAsText["Created"];
88
89
90
91
92
93
94
95                 lista.Add(anuncio);
96
97
98
99             }
100
101
102
103
104
105
106
107         },
108
109
110
111         delegate(object sender, ClientRequestFailedEventArgs args)
112
113
114
115         {
116
117
118
119             //Manejamos el error de la consulta
120
121
122
123         });
124

Crear elementos en lista

Como siempre, nos creamos un objeto del tipo ListItemCreationInformation y lo envíanos al contexto.

1     var subscriptionList = Context.Web.Lists.GetByTitle("HubSubscribers");
2     Context.Load(subscriptionList);
3     deviceItem = subscriptionList.AddItem(new ListItemCreationInformation());
4     deviceItem["Title"] = displayName;
5     deviceItem["UserAccount"] = acccountName;
6     deviceItem["ChannelUri"] = pushChannel;
7     deviceItem["ChannelUriDate"] = System.DateTime.Now;
8     deviceItem["DeviceId"] = deviceId;
9     deviceItem.Update();
10
11
12
13     Context.Load(subscriptionList);
14
15
16
17     deviceItem = subscriptionList.AddItem(new ListItemCreationInformation());
18
19
20
21     deviceItem["Title"] = displayName;
22
23
24
25     deviceItem["UserAccount"] = acccountName;
26
27
28
29     deviceItem["ChannelUri"] = pushChannel;
30
31
32
33     deviceItem["ChannelUriDate"] = System.DateTime.Now;
34
35
36
37     deviceItem["DeviceId"] = deviceId;
38
39
40
41     deviceItem.Update();
42
43
44
45     Context.ExecuteQuery();
46

Obtener un perfil de usuario

En el CSOM de SharePoint 2013 tenemos acceso a los perfiles de usuario, y en Windows Phone también. Para esto, nos creamos un PeopleManager y obtenemos las propiedades que necesitemos.

1     var peopleManager = new PeopleManager(Context);
2     var personProperties = peopleManager.GetPropertiesFor(userAccount);
3     context.Load(personProperties, p => p.AccountName, p => p.DisplayName, p => p.Email, p => p.UserProfileProperties, 
4                  p => p.DirectReports, p => p.Peers, p => p.PictureUrl);
5     context.ExecuteQueryAsync(
6         delegate(object sender1, ClientRequestSucceededEventArgs args)
7         {
8             var profile = new Profile();
9             profile.AccountName = personProperties.AccountName;
10             profile.DirectReports = personProperties.DirectReports.ToList();
11             profile.Peers = personProperties.Peers.ToList();
12             profile.DisplayName = personProperties.DisplayName;
13             profile.PictureUrl = personProperties.PictureUrl;
14             profile.Email = personProperties.Email;
15             profile.Manager = personProperties.UserProfileProperties["Manager"];
16             profile.Status = personProperties.UserProfileProperties["SPS-StatusNotes"];
17             profile.WorkPhone = personProperties.UserProfileProperties["WorkPhone"];
18             profile.Department = personProperties.UserProfileProperties["Department"];
19             loadProfileCompletedCallback(new LoadProfileCompleteEventArgs { Profile = profile });
20         },
21         delegate(object sender1, ClientRequestFailedEventArgs args)
22         {
23             //Manejamos el error de la consulta
24
25
26
27     var personProperties = peopleManager.GetPropertiesFor(userAccount);
28
29
30
31
32
33
34
35     context.Load(personProperties, p => p.AccountName, p => p.DisplayName, p => p.Email, p => p.UserProfileProperties, 
36
37
38
39                  p => p.DirectReports, p => p.Peers, p => p.PictureUrl);
40
41
42
43     context.ExecuteQueryAsync(
44
45
46
47         delegate(object sender1, ClientRequestSucceededEventArgs args)
48
49
50
51         {
52
53
54
55             var profile = new Profile();
56
57
58
59             profile.AccountName = personProperties.AccountName;
60
61
62
63             profile.DirectReports = personProperties.DirectReports.ToList();
64
65
66
67             profile.Peers = personProperties.Peers.ToList();
68
69
70
71             profile.DisplayName = personProperties.DisplayName;
72
73
74
75             profile.PictureUrl = personProperties.PictureUrl;
76
77
78
79             profile.Email = personProperties.Email;
80
81
82
83             profile.Manager = personProperties.UserProfileProperties["Manager"];
84
85
86
87             profile.Status = personProperties.UserProfileProperties["SPS-StatusNotes"];
88
89
90
91             profile.WorkPhone = personProperties.UserProfileProperties["WorkPhone"];
92
93
94
95             profile.Department = personProperties.UserProfileProperties["Department"];
96
97
98
99
100
101
102
103             loadProfileCompletedCallback(new LoadProfileCompleteEventArgs { Profile = profile });
104
105
106
107         },
108
109
110
111         delegate(object sender1, ClientRequestFailedEventArgs args)
112
113
114
115         {
116
117
118
119             //Manejamos el error de la consulta
120
121
122
123         });
124

Conclusiones

¿A qué esperamos para desarrollar aplicaciones de negocio para Windows Phone? Personalmente, creo que nos puede abrir un nuevo abanico de posibilidades y de aplicaciones empresariales que no han terminado de llegar con SharePoint 2010. Por cierto, aunque no lo he probado al 100%, este modelo de objetos de cliente también funciona con SharePoint 2010, salvo las funcionalidades nuevas, como los perfiles, que no tenían soporte de cliente en SharePoint 2010.

Alberto Diaz Martin
MVP SharePoint
adiazcan@hotmail.com
@adiazcan
http://geeks.ms/blogs/adiazmartin

Siguemos en LinkedInSiguemos en Twitter
Powered by  ENCAMINA