Integración del complemento de evento corporativo con SharePoint
El ejemplo BusinessApps.CorporateEventsApp muestra cómo implementar un sistema de administración centralizada de eventos corporativos como un complemento hospedado por el proveedor que se integra con las aplicaciones de línea de negocio (LOB) existentes.
Más concretamente, el ejemplo BusinessApps.CorporateEventsApp muestra cómo implementar una aplicación web ASP.NET que interactúa con SharePoint como un almacén de datos de entidades LOB. También muestra cómo implementar varios pasos en una tarea empresarial compleja con un único complemento hospedado por el proveedor.
Esta aplicación de ejemplo implementa un sistema de administración centralizada que consta de entidades de SharePoint (tipos de contenido y listas). Para cada nuevo tipo de contenido, crea las entidades LOB correspondientes en una aplicación web ASP.NET. Los componentes de la aplicación web se ejecutan como elementos de complemento hospedado remotamente dentro de la interfaz de SharePoint y también como páginas que se ejecutan por completo en el host web remoto. El complemento reemplaza la página de bienvenida predeterminada del sitio de SharePoint para que pueda presentar una interfaz personalizada en la página principal del sitio.
Usar el ejemplo BusinessApps.CorporateEventsApp
Configuración del ejemplo
Al iniciar la aplicación de ejemplo BusinessApps.CorporateEventsApp, la página de inicio proporciona una opción para configurar la muestra. También indica una cantidad de recursos para obtener más información.
Al elegir Iniciar configuración, se cargará la página de configuración, como se muestra en la siguiente ilustración. Cuando elija Inicializar el almacén de datos en la página Configuración, la muestra implementa las entidades de SharePoint y los datos de ejemplo que soportan la muestra.
Tras inicializar el almacén de datos, puede volver al sitio para ver una nueva página de bienvenida (la página EventsHome.aspx), que consta de dos elementos web que el complemento ha implementado, como se muestra en la siguiente ilustración. En la columna izquierda, verá las cuatro nuevas listas instaladas por el complemento. La lista de Eventos de la empresa está formada por los datos del ejemplo.
Cada elemento web contiene vínculos a todos los eventos mostrados, donde puede ver los detalles del evento. Al seleccionar un vínculo, la página de detalles del evento se ejecuta por separado en el host remoto, como se muestra en la siguiente ilustración. Puede elegir Volver al sitio en la página para volver al sitio de SharePoint y registrarse para el evento.
La página de registro se ejecuta por separado en el host remoto y contiene un vínculo para volver al sitio del host de SharePoint. Cuando ha terminado de registrarse para el evento, su nombre aparece en la lista Registro de eventos recién instalada.
Archivo Models/DataInitializer.cs
El archivo Models/DataInitializer.cs contiene el código que se ejecuta al seleccionar este botón. El código de este archivo crea e implementa cuatro nuevas listas de SharePoint, junto con los cuatro tipos de contenido correspondientes:
- Eventos de la empresa
- Registros de eventos
- Oradores del evento
- Sesiones de eventos
El código de este archivo usa un método similar al que se usa en el ejemplo Core.ModifyPages para agregar una página personalizada al sitio.
// Create default wiki page.
web.AddWikiPage("Site Pages", "EventsHome.aspx");
AddWikiPage is an extension method from the Core.DevPnPCore project to add a new page to the site. This new page also becomes the new WelcomePage for the site. It also prepares to add the web parts to this page.
var welcomePage = "SitePages/EventsHome.aspx";
var serverRelativeUrl = UrlUtility.Combine(web.ServerRelativeUrl, welcomePage);
File webPartPage = web.GetFileByServerRelativeUrl(serverRelativeUrl);
if (webPartPage == null) {
return;
}
web.Context.Load(webPartPage);
web.Context.Load(webPartPage.ListItemAllFields);
web.Context.Load(web.RootFolder);
web.Context.ExecuteQuery();
web.RootFolder.WelcomePage = welcomePage;
web.RootFolder.Update();
web.Context.ExecuteQuery();
El archivo Models\DataInitializer.cs también define el XML de los dos elementos web que se muestran en la página nueva y, después, los agrega a la página. Los ejemplos siguientes muestran este funcionamiento para el elemento web Eventos destacados.
Definir el elemento web XML
var webPart1 = new WebPartEntity(){
WebPartXml = @"<webParts>
<webPart xmlns='http://schemas.microsoft.com/WebPart/v3'>
<metaData>
<type name='Microsoft.SharePoint.WebPartPages.ClientWebPart, Microsoft.SharePoint, Version=16.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c' />
<importErrorMessage>Cannot import this web part.</importErrorMessage>
</metaData>
<data>
<properties>
<property name='Description' type='string'>Displays featured events</property>
<property name='FeatureId' type='System.Guid, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'>3a6d7f41-2de8-4e69-b4b4-0325bd56b32c</property>
<property name='Title' type='string'>Featured Events</property>
<property name='ProductWebId' type='System.Guid, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'>12ae648f-27db-4a97-9c63-37155d3ace1e</property>
<property name='WebPartName' type='string'>FeaturedEvents</property>
<property name='ProductId' type='System.Guid, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'>3a6d7f41-2de8-4e69-b4b4-0325bd56b32b</property>
<property name='ChromeState' type='chromestate'>Normal</property>
</properties>
</data>
</webPart>
</webParts>",
WebPartIndex = 0,
WebPartTitle = "Featured Events",
WebPartZone = "Rich Content"
};
Agregar los elementos web a la página
var limitedWebPartManager = webPartPage.GetLimitedWebPartManager(Microsoft.SharePoint.Client.WebParts.PersonalizationScope.Shared);
web.Context.Load(limitedWebPartManager.WebParts);
web.Context.ExecuteQuery();
for (var i = 0; i < limitedWebPartManager.WebParts.Count; i++) {
limitedWebPartManager.WebParts[i].DeleteWebPart();
}
web.Context.ExecuteQuery();
var oWebPartDefinition1 = limitedWebPartManager.ImportWebPart(webPart1.WebPartXml);
var oWebPartDefinition2 = limitedWebPartManager.ImportWebPart(webPart2.WebPartXml);
var wpdNew1 = limitedWebPartManager.AddWebPart(oWebPartDefinition1.WebPart, webPart1.WebPartZone, webPart1.WebPartIndex);
var wpdNew2 = limitedWebPartManager.AddWebPart(oWebPartDefinition2.WebPart, webPart2.WebPartZone, webPart2.WebPartIndex);
web.Context.Load(wpdNew1);
web.Context.Load(wpdNew2);
web.Context.ExecuteQuery();
En el directorio de Modelos de su proyecto web, verá que la aplicación web ASP.NET MVC contiene cuatro nombres de clase que corresponden a las listas y los tipos de contenido que el complemento ha instalado:
- Event.cs (Eventos de la empresa)
- Registration.cs (Registro de eventos)
- Session.cs (Sesiones de eventos)
- Speaker.cs (Oradores del evento)
Estas cuatro clases junto con sus correspondientes tipos de contenido de SharePoint conforman las cuatro entidades LOB utilizadas en este complemento.
El archivo DataInitializer.cs agrega los datos de ejemplo de la Eventos de la empresa creando objetos evento de muestra que se corresponden con el tipo de contenido Eventos de la empresa y que el complemento agrega a la lista Eventos de la empresa.
Al registrarse para un evento, el complemento crea un objeto Registro que se corresponde con el tipo de contenido Registro de eventos y que el complemento agrega a la lista Registro de eventos. En el ejemplo todavía no se han implementado totalmente los objetos Sesión y Orador, por lo que el complemento no funciona con esos objetos en este momento.
La siguiente tabla enumera las propiedades que deben estar implementadas por las clases que heredan de la clase abstracta BaseListItem.
Member | Descripción |
---|---|
ContentTypeName | Obtiene el tipo de contenido asociado con el elemento. Si es null, se asignará el tipo de contenido de biblioteca predeterminado al elemento cuando se guarde. |
FieldInternalNames | Una lista de nombres de campo que puede almacenarse en caché para mejorar el rendimiento cuando se utiliza para comprobar los datos del campo antes de guardar. |
ListTitle | Obtiene el título de la lista (distingue mayúsculas de minúsculas). |
La siguiente tabla enumera los métodos que deben estar implementados por las clases que heredan de la clase abstracta BaseListItem. Estos métodos devuelven parámetros que deben establecerse en tipos blittables para que se puedan usar en varias plataformas.
Método | Descripción |
---|---|
ReadProperties(ListItem) | Lee las propiedades del objeto ListItem con los métodos BaseGet y BaseGetEnum y los asigna a propiedades de la subclase. |
SetProperties(ListItem) | Establece propiedades en el objeto ListItem con los métodos BaseSet y BaseSetTaxonomyField de la clase abstracta. |
La siguiente tabla enumera los métodos auxiliares de la clase BaseListItem que las subclases necesitan para implementar los métodos ReadProperties y SetProperties.
Método auxiliar | Descripción |
---|---|
BaseGet (elemento ListItem, cadena internalName) | Obtiene la propiedad definida por el parámetro internalName de /ListItem y los devuelve de tipo genérico T. |
BaseGet (elemento ListItem, cadena internalName, valor de objeto) | Establece la propiedad ListItem definida por el parámetro internalName. |
BaseSetTaxonomyField (elemento ListItem, cadena internalName, etiqueta de cadena, Guid termId) | Establece el campo de taxonomía ListItem definido por los parámetros internalName y termId. |
BaseGetEnum (elemento ListItem, cadena internalName, defaultValue T) | Obtiene el valor de la propiedad de enumeración definida por el parámetro internalName. Devuelve el valor del parámetro defaultValue si no se establece la propiedad. |
El archivo Event.cs contiene las siguientes implementaciones de los métodos ReadProperties y SetProperties.
ReadProperties
protected override void ReadProperties(ListItem item) {
RegisteredEventId = BaseGet<string>(item, FIELD_REGISTERED_EVENT_ID);
Description = BaseGet<string>(item, FIELD_DESCRIPTION);
Category = BaseGet<string>(item, FIELD_CATEGORY);
EventDate = BaseGet<DateTime?>(item, FIELD_DATE);
Location = BaseGet<string>(item, FIELD_LOCATION);
ContactEmail = BaseGet<string>(item, FIELD_CONTACT_EMAIL);
Status = BaseGetEnum<EventStatus>(item, FIELD_STATUS);
var imageUrl = BaseGet<FieldUrlValue>(item, FIELD_IMAGE_URL);
if (imageUrl != null)
ImageUrl = imageUrl.Url;
}
SetProperties
protected override void SetProperties(ListItem item) {
BaseSet(item, FIELD_REGISTERED_EVENT_ID, RegisteredEventId);
BaseSet(item, FIELD_DESCRIPTION, Description);
BaseSet(item, FIELD_CATEGORY, Category);
BaseSet(item, FIELD_DATE, EventDate);
BaseSet(item, FIELD_LOCATION, Location);
BaseSet(item, FIELD_CONTACT_EMAIL, ContactEmail);
BaseSet(item, FIELD_STATUS, Status.ToEnumDescription());
BaseSet(item, FIELD_IMAGE_URL, ImageUrl);
}
Los siguientes ejemplos de código muestran cómo se definen los métodos subyacentes BaseGet y BaseSet en BaseListItem.cs.
BaseGet
protected T BaseGet<T>(ListItem item, string internalName){
var field = _fields[internalName.ToLowerInvariant()];
var value = item[field.InternalName];
return (T)value;
}
BaseSet
protected void BaseSet(ListItem item, string internalName, object value) {
if (_fields.ContainsKey(internalName)) {
var field = _fields[internalName.ToLowerInvariant()];
if (field is FieldUrl && value is string) {
var urlValue = new FieldUrlValue() {
Url = value.ToString()
};
value = urlValue;
}
}
item[internalName] = value;
}
La clase BaseListItem también contiene un método Save que se utiliza para guardar cada entidad LOB que el complemento crea y manipula. Este método carga la lista y determina si el elemento actual tiene un identificador mayor que 0. Si el identificador no es mayor que 0, supone que no es válido y crea un nuevo elemento de lista. Utiliza el método SetProperties para establecer propiedades en el ListItem y, a continuación, establece las propiedades de la subclase mediante el método ReadProperties.
public void Save(Web web) {
var context = web.Context;
var list = web.GetListByTitle(ListTitle);
if (!IsNew && Id > 0) {
ListItem = list.GetItemById(Id);
}
else {
var listItemCreationInfo = new ListItemCreationInformation();
ListItem = list.AddItem(listItemCreationInfo);
}
// Ensure that the fields have been loaded.
EnsureFieldsRetrieved(ListItem);
// Set the properties on the list item.
SetProperties(ListItem);
BaseSet(ListItem, TITLE, Title);
// Use if you want to override the created/modified date.
//BaseSet(ListItem, CREATED, Created);
//BaseSet(ListItem, MODIFIED, Modified);
ListItem.Update();
if (!string.IsNullOrEmpty(ContentTypeName)) {
var contentType = list.GetContentTypeByName(ContentTypeName);
if (contentType != null)
BaseSet(ListItem, "ContentTypeId", contentType.Id.StringValue);
}
ListItem.Update();
// Execute the batch.
context.ExecuteQuery();
// Reload the properties.
ListItem.RefreshLoad();
UpdateBaseProperties(ListItem);
ReadProperties(ListItem);
}