Uso de receptores de eventos en SharePoint Foundation 2010 (parte 2 de 2)
Resumen: los receptores de eventos de Microsoft SharePoint Foundation 2010 permiten que el código personalizado responda cuando se producen acciones específicas en un objeto de SharePoint. En los ejemplos prácticos de este artículo se muestra cómo usar los eventos para mejorar las aplicaciones de SharePoint.
Última modificación: lunes, 09 de marzo de 2015
Hace referencia a: Business Connectivity Services | Open XML | SharePoint Designer 2010 | SharePoint Foundation 2010 | SharePoint Online | SharePoint Server 2010 | Visual Studio
En este artículo
Ejemplos prácticos del uso de eventos
Ejemplo 1: difusión de anuncios
Ejemplo 2: división de elementos
Ejemplo 3: realización de un seguimiento de orígenes de documentos
Ejemplo 4: cancelación y redireccionamiento
Ejemplo 5: registro de eventos
Conclusión
Recursos adicionales
Se aplica a: Microsoft SharePoint Foundation 2010
Proporcionado por: Ali Badereddin, Microsoft Corporation | Nick Gattuccio, Microsoft Corporation
Contenido
Ejemplos prácticos del uso de eventos
Ejemplo 1: difusión de anuncios
Ejemplo 2: división de elementos
Ejemplo 3: realización de un seguimiento de orígenes de documentos
Ejemplo 4: cancelación y redireccionamiento
Ejemplo 5: registro de eventos
Conclusión
Recursos adicionales
Este artículo es una continuación de Uso de receptores de eventos en SharePoint Foundation 2010 (parte 1 de 2).
Ejemplos prácticos del uso de eventos
Ahora que comprende bien el modelo de eventos de Microsoft SharePoint Foundation 2010, puede empezar a crear controladores de eventos en su propio código. El resto de este artículo presenta cinco ejemplos que usan el modelo de eventos de SharePoint de varias maneras:
Difusión de anuncios Todos los anuncios que se agregan a cualquiera de los cientos de sitios de una colección de sitios aparecen en el elemento web de anuncios en el sitio raíz.
División de elementos Cuando se agrega un elemento a una lista, se divide automáticamente en dos o más elementos. En este ejemplo también se muestra cómo cancelar un evento sin errores y se describe el uso de contenedores de propiedades en un receptor de eventos previos.
Realización de un seguimiento de orígenes de documentos Cuando se edita un documento de una biblioteca de documentos, se actualiza una propiedad de metadatos. En este ejemplo se describe la promoción y la disminución de nivel de propiedades.
Cancelación y redireccionamiento Cuando se cancela una operación de usuario, se redirige al usuario a una página de error.
Registro de eventos Todos los eventos que se producen en una colección de sitios se registran como un elemento de lista en una lista que se almacena en el sitio.
Para cada uno de estos ejemplos, puede descargar una solución de Microsoft Visual Studio:
SharePoint 2010: usar receptores de eventos; ejemplo 1: difundir anuncios (en inglés)
SharePoint 2010: usar receptores de eventos; ejemplo 2: dividir elementos (en inglés)
SharePoint 2010: usar receptores de eventos: ejemplo 3: seguir orígenes de documentos (en inglés)
SharePoint 2010: usar receptores de eventos; ejemplo 4: cancelar y redirigir (en inglés)
SharePoint 2010: usar receptores de eventos; ejemplo 5: registrar eventos (en inglés)
Para facilitar la navegación a través de los ejemplos, proporcionamos la siguiente información general del modelo de eventos de SharePoint. En la tabla 3 se enumeran todos los receptores de eventos de SharePoint Foundation 2010 por ámbito, y se especifican las clases a las que pertenecen y los hosts de eventos con los que se pueden asociar.
Tabla 3. Receptores de eventos agrupados por ámbito
Ámbito |
Métodos |
Clase |
Hosts |
---|---|---|---|
Colección de sitios |
|
|
|
Web |
|
|
|
Lista |
|
|
|
Lista |
|
|
|
Campo |
|
|
|
Elemento |
|
|
|
Flujo de trabajo |
|
|
Ejemplo 1: difusión de anuncios
En este ejemplo, existe una colección de sitios con cientos de sitios individuales; en el sitio raíz, hay un elemento web de anuncios. El objetivo de este escenario es que todos los anuncios que se expongan en cualquiera de los sitios individuales aparezcan en el elemento web de anuncios que colocó en el sitio raíz de la colección de sitios.
Descargue el ejemplo de código: SharePoint 2010: usar receptores de eventos; ejemplo 1: difundir anuncios (en inglés)
Diseño
Si se supone que el sitio raíz de la colección de sitios tiene una lista de anuncios, lo primero que se debe hacer es agregar el elemento web para esta lista a la página principal del sitio raíz.
Para agregar un elemento web de anuncios
Navegue hasta la página principal del sitio raíz de la colección de sitios.
Haga clic en la pestaña Página y después haga clic en Editar página.
Haga clic en la pestaña Insertar y después haga clic en Lista existente. Podrá ver todas las listas y bibliotecas de documentos del sitio raíz.
Seleccione la lista Anuncios y haga clic en Agregar.
A continuación, deberá copiar todos los anuncios que se hayan expuesto en cualquiera de los subsitios en la lista de anuncios del sitio raíz. Para ello, cree un receptor de eventos ItemAdded que copie todos los elementos que se hayan agregado a una lista (en función de la plantilla de lista de anuncios) en la lista de anuncios del sitio raíz. La lógica del evento debe desencadenarse en cada lista de anuncios que se encuentre en cualquier sitio de la colección de sitios (con excepción de la lista de anuncios del sitio raíz).
Implementación
En Microsoft Visual Studio 2010, cree un proyecto basado en la plantilla de proyecto de receptor de eventos de SharePoint 2010. Elija implementar la solución en el espacio aislado. En el Asistente para la personalización de SharePoint, seleccione la lista de anuncios como el origen del evento e ItemAdded como el evento que se va a invalidar, tal como se muestra en la figura 6.
Figura 6. Asistente para la personalización de SharePoint
Con esta acción se crea una nueva característica en el ámbito web, con un elemento <Receivers> que enlaza el receptor de eventos ItemAdded con la plantilla de lista de anuncios (ListTemplateId="104"), tal como se muestra en el siguiente fragmento.
<Receivers ListTemplateId="104">
<Receiver>
<Name>EventReceiver1ItemAdded</Name>
<Type>ItemAdded</Type>
<Assembly>$SharePoint.Project.AssemblyFullName$</Assembly>
<Class>BroadcastAnn.EventReceiver1.EventReceiver1</Class>
<SequenceNumber>10000</SequenceNumber>
</Receiver>
</Receivers>
En la tabla 4 se explican los diversos elementos dentro del elemento <Receiver>.
Tabla 4. Elementos del elemento Receiver
Elemento |
Descripción |
Valor en este ejemplo |
---|---|---|
Name |
El nombre del enlace del receptor de eventos. |
EventReceiver1ItemAdded. Puede proporcionar su propio nombre. |
Type |
El tipo del evento, que puede ser una representación textual de cualquiera de los valores de la enumeración SPEventType. |
ItemAdded. |
Assembly |
El nombre completo del ensamblado del archivo DLL que contiene el código del receptor de eventos. |
$SharePoint.Project.AssemblyFullName$. Este nombre se convierte en el nombre completo del ensamblado cuando Visual Studio 2010 genera la solución. |
Class |
El espacio de nombres y la clase (en el formato espacioDeNombres.clase) que hereda de SPEventReceiverBase y contiene el código del receptor de eventos. |
BroadcastAnn.EventReceiver1.EventReceiver1, donde "BroadcastAnn.EventReceiver1" es el espacio de nombres y "EventReceiver1" es el nombre de clase. |
SequenceNumber |
El orden de ejecución para el evento. Por ejemplo, si dos eventos ItemAdding se enlazan con el mismo host de eventos, el que tiene el número de secuencia menor se desencadena primero. |
10000. Este es, básicamente, un valor predeterminado. |
Synchronization |
Indica si el evento es sincrónico o asincrónico. Los eventos posteriores son asincrónicos. |
Debido a que no se ha especificado la sincronización y que ItemAdded es un evento posterior, el modo predeterminado es asincrónico. |
Para que el evento se desencadene en todos los sitios de la colección, debe cambiarse el ámbito de la característica al sitio; de esta forma, se habilita la función cuando se activa la característica en la colección de sitios, en lugar de tener que activar la característica en cada subsitio. Tenga en cuenta que el ámbito del sitio de una característica hace referencia a la colección de sitios (vea la figura 7); el ámbito web hace referencia a los sitios.
Figura 7. Configuración del ámbito de la característica
A continuación, debe abrir el archivo EventReceiver1.cs y agregar código al evento ItemAdded. Como resultado, se toma el elemento que se agregó a la lista de anuncios en la subweb y se copia en la lista de anuncios de la web raíz. El código también anexa al título el nombre de la persona que realizó el anuncio y al cuerpo la dirección URL de la subweb donde se realizó.
public override void ItemAdded(SPItemEventProperties properties)
{
// Get a reference to the site collection.
SPSite site = properties.OpenSite();
// Get a reference to the current site.
SPWeb currentWeb = properties.OpenWeb();
// Get a reference to the root site.
SPWeb rootWeb = site.RootWeb;
// Skip if the root web is the same as the current web.
if (rootWeb.Url == currentWeb.Url)
{
return;
}
// Get the current list.
SPList currentList = properties.List;
// Get the announcement list on the root site.
SPList rootList = rootWeb.Lists["Announcements"];
// Get the list item that was added.
SPListItem currentListItem = properties.ListItem;
// Add the announcement item to the list on the root web.
SPListItem rootListItem = rootList.Items.Add();
foreach (SPField field in currentList.Fields)
{
if (!field.ReadOnlyField)
{
rootListItem[field.Id] = currentListItem[field.Id];
}
}
// Append the user display name to the title.
rootListItem["Title"] += " - " + properties.UserDisplayName;
// Append the web URL to the body.
rootListItem["Body"] += string.Format("This announcements was made by {0} on subweb {1}",
properties.UserLoginName, properties.WebUrl);
rootListItem.Update();
}
Ahora puede generar la solución e iniciar el depurador. Este proceso crea la solución, la implementa en la colección de sitios de SharePoint e inicia el explorador en la página principal de la colección de sitios. Asegúrese de que la colección de sitios contenga la lista de anuncios.
Finalmente, cree un nuevo subsitio basado en la plantilla de sitio de grupo. A continuación, agregue un elemento a la lista de anuncios y confirme que se muestra una copia del elemento en la lista de anuncios del sitio raíz, tal como se muestra en la figura 8.
Figura 8. Elemento agregado a la lista de anuncios del sitio raíz
Ejemplo 2: división de elementos
En este ejemplo, el objetivo es agregar un elemento a una lista y hacer que ese elemento se divida en dos nuevos elementos. Por ejemplo, cuando un usuario agrega un paquete Xbox 360, es posible que desee evitar que se agregue ese elemento y, en su lugar, agregar otros dos elementos a la lista: "Xbox 360" y "Kinect". Un ejemplo aún mejor es un escenario en el que se carga un archivo .zip y después se extrae el contenido del archivo con cada uno de sus archivos agregados como un elemento independiente.
Para admitir el escenario de división de elementos, este ejemplo también muestra cómo cancelar una acción sin errores en un receptor de eventos previos.
Descargue el ejemplo de código: SharePoint 2010: usar receptores de eventos; ejemplo 2: dividir elementos (en inglés)
Diseño
Este proyecto necesita tres tipos de contenido para representar los tres elementos, "Xbox 360 Bundle", "Xbox 360" y "Kinect", respectivamente. En este escenario, solo se necesitan los títulos de los elementos, por lo que cada uno de los tipos de contenido se hereda del tipo de contenido "Items" sin agregar campos adicionales.
Cuando se agrega un nuevo elemento basado en el tipo de contenido "Xbox 360 Bundle", querrá eliminar ese elemento o cancelar la adición y después crear otros dos elementos basados en los tipos de contenido "Xbox 360" y "Kinect".
Para ello, primero debemos enlazar el evento previo ItemAdding al tipo de contenido "Xbox 360 Bundle". El evento ItemAdding crea los otros dos elementos y cancela la adición del elemento actual. Puesto que no se desea que se desencadene una lógica cuando se agrega un elemento "Xbox 360" o "Kinect", no se enlazarán estos tipos de contenido con ningún receptor de eventos. Para simplificar las cosas, no se tratarán las actualizaciones; es decir, cuando el tipo de contenido de un elemento cambia de "Xbox 360" a "Xbox 360 Bundle" o "Kinect".
Al cancelar la adición del tipo de contenido "Xbox 360 Bundle", no es deseable recibir un mensaje de error. Debido a que se accede al elemento que se va a agregar en un evento previo (antes de que los cambios se realicen en la base de datos de contenido), la propiedad properties.ListItem sigue siendo null. Para acceder a los campos de elemento, es necesario usar el contenedor de propiedades properties.AfterProperties; esto permite acceder a los datos que se quieren copiar (en este ejemplo, solo el título), en función de los nombres internos de los campos en el esquema de lista.
Implementación
Cree un proyecto de Visual Studio 2010 basado en la plantilla de proyecto de SharePoint vacío. Elija implementar la solución en el espacio aislado. Haga clic con el botón secundario en el proyecto y seleccione Agregar nuevo elemento. Seleccione Tipo de contenido, asigne al elemento el nombre Xbox360Bundle y haga clic en Agregar. Visual Studio crea el tipo de contenido con el nombre "nombreDelProyecto - Xbox360Bundle".
Importante |
---|
Asegúrese de cambiar el nombre a Xbox360Bundle en el archivo Element.xml. |
Repita los pasos para los otros dos tipos de contenido, aplicando los nombres Xbox360 y Kinect.
A continuación, haga clic con el botón secundario en el proyecto y agregue un nuevo elemento de receptor de eventos con el nombre BundleEventReceiver. Seleccione Se va a agregar un elemento y haga clic en Finalizar. En este paso se crea una clase de receptor de eventos que invalida el evento ItemAdding. Sin embargo, de manera predeterminada, también enlaza el evento con una plantilla de lista. Se desea enlazar el evento con el tipo de contenido Xbox360Bundle en lugar de la plantilla de lista. Por lo tanto, se debe eliminar el evento que enlaza Elements.xml (que se muestra como seleccionado en la figura 9) y agregar el enlace dentro de Element.xml del tipo de contenido Xbox360Bundle.
Figura 9. Enlace de Elements.xml
Antes de agregar el enlace de receptor de eventos, compruebe que el atributo Inherits del tipo de contenido de Elements.xml esté establecido en FALSE en lugar de TRUE; de lo contrario, el enlace de receptor de eventos del tipo de contenido no funcionará. Debido a que ya no se hereda, deberá definir todas las referencias de campo manualmente. Por lo tanto, debe agregar una referencia de campo al campo Title. Element.xml del tipo de contenido Xbox360Bundle se parecerá a lo siguiente.
<Elements xmlns="https://schemas.microsoft.com/sharepoint/">
<!-- Parent ContentType: Item (0x01) -->
<ContentType ID="0x01004497ac28eb9a47fbabee43f48c3f5973"
Name="Xbox360Bundle"
Group="Custom Content Types"
Description="My Content Type"
Inherits="FALSE"
Version="0">
<FieldRefs>
<FieldRef ID="{fa564e0f-0c70-4ab9-b863-0177e6ddd247}"
Name="Title"
Required="TRUE"
ShowInNewForm="TRUE"
ShowInEditForm="TRUE"/>
</FieldRefs>
<XmlDocuments>
<XmlDocument NamespaceURI="https://schemas.microsoft.com/sharepoint/events">
<spe:Receivers xmlns:spe="https://schemas.microsoft.com/sharepoint/events">
<Receiver>
<Name>Item Adding Event</Name>
<Type>ItemAdding</Type>
<Assembly>$SharePoint.Project.AssemblyFullName$</Assembly>
<Class>ItemSplitting.BundleEventReceiver.BundleEventReceiver</Class>
<SequenceNumber>10000</SequenceNumber>
</Receiver>
</spe:Receivers>
</XmlDocument>
</XmlDocuments>
</ContentType>
</Elements>
Ahora, se pasa al archivo BundleEventReceiver.cs y se agrega código al evento ItemAdding que cancela la adición del elemento Xbox360Bundle y crea dos nuevos elementos en función de los tipos de contenido Xbox360 y Kinect.
public override void ItemAdding(SPItemEventProperties properties)
{
// Get a reference to the current list.
SPList list = properties.List;
// Get the "Xbox360" content type.
SPContentType xboxContentType = list.ContentTypes["XBox360"];
// Get the "Kinect" content type.
SPContentType kinectContentType = list.ContentTypes["Kinect"];
// If any of the content types are null, they were not created.
if (xboxContentType == null || kinectContentType == null)
{
properties.Status = SPEventReceiverStatus.CancelWithError;
properties.ErrorMessage = "The Xbox360 and Kinect content types must be present.";
return;
}
// Disable event firing so that ItemAdding is not called recursively.
this.EventFiringEnabled = false;
// Create the "Xbox360" item.
SPListItem xboxItem = list.AddItem();
xboxItem["Title"] = properties.AfterProperties["Title"] + " (Xbox 360)";
xboxItem["ContentTypeId"] = xboxContentType.Id;
xboxItem.Update();
// Create the "Kinect" item.
SPListItem kinectItem = list.AddItem();
kinectItem["Title"] = properties.AfterProperties["Title"] + " (Kinect)";
kinectItem["ContentTypeId"] = kinectContentType.Id;
kinectItem.Update();
// Re-enable event firing.
this.EventFiringEnabled = true;
// Cancel the creation of the "Xbox360Bundle" item but don't throw an error.
properties.Status = SPEventReceiverStatus.CancelNoError;
}
Tenga en cuenta los siguientes detalles importantes sobre el código anterior:
Si alguno de los tipos de contenido no está enlazado con la lista, cancele el evento ItemAdding; se mostrará un mensaje de error que dice que los tipos de contenido Xbox360 y Kinect deben estar presentes. Tenga en cuenta que no es necesario agregar la instrucción properties.Cancel = true.
Para evitar que ItemAdding se llame a sí mismo de manera recursiva (hasta un límite en la pila de llamadas), deshabilite el desencadenamiento de eventos antes de agregar elementos en el evento ItemAdding. Después de agregar todos los elementos, vuelva a habilitar el desencadenamiento de eventos.
Se usa la expresión properties.AfterProperties["field"] en lugar de properties.ListITem["field"] porque ItemAdding es un evento previo, lo que significa que el elemento de lista aún no se ha creado y que properties.ListItem es null.
No se desea agregar el elemento que se va a dividir. Debido a ello, se debe cancelar el evento sin generar un error, mediante la instrucción properties.Status = SPEventReceiverStatus.CancelNoError. No agregue properties.Cancel=true; si lo hace, se invalidará el comportamiento y, por tanto, se producirá un error.
Ya está listo para generar la solución e iniciar el depurador. Al hacerlo, se creará la solución, se implementará en la colección de sitios de SharePoint y se iniciará el explorador en la página principal de la colección de sitios.
El siguiente paso es crear una nueva lista y enlazarla con los tres tipos de contenido. En primer lugar, asegúrese de que los tipos de contenido puedan agregarse a la lista. Para ello, establezca Permitir la administración de tipos de contenido en Sí en la página Configuración avanzada de la lista. A continuación, agregue los tres tipos de contenido, tal como se muestra en la figura 10.
Figura 10. Tipos de contenido de enlace
Ahora puede crear en la lista un nuevo elemento basado en el tipo de contenido Xbox360Bundle, tal como se muestra en la figura 11.
Figura 11. Creación de un nuevo elemento
Al hacer clic en Guardar, observe que no se agrega el elemento. En su lugar, se agregan otros dos elementos: Xbox360 y Kinect. Si quita el tipo de contenido Xbox360 o Kinect de la lista, obtendrá un mensaje de error al intentar guardar.
Ejemplo 3: realización de un seguimiento de orígenes de documentos
La posibilidad de usar receptores de eventos para manipular propiedades del documento es una característica muy eficaz. En este ejemplo se muestra cómo realizar esta tarea mediante la implementación de promociones y disminuciones de nivel de propiedades con receptores de eventos. Mediante el uso de la promoción y disminución de nivel de propiedades puede leer, agregar o actualizar metadatos de documentos directamente desde el código del receptor de eventos en el momento en que se agrega un documento a una biblioteca de documentos o incluso cuando se edita un documento de una biblioteca.
En este ejemplo, se establece el valor de la propiedad de metadatos Source en el título de la biblioteca de documentos cuando se edita el documento.
Descargue el ejemplo de código: SharePoint 2010: usar receptores de eventos; ejemplo 3: seguir orígenes de documentos (en inglés)
Diseño
En este ejemplo se crea un receptor de eventos ItemUpdating, que se enlaza con todas las bibliotecas de documentos del sitio. Cuando se guarda un documento en la biblioteca, el código del controlador de eventos agrega o actualiza la propiedad de metadatos Source con el valor del título de la biblioteca de documentos.
Para probar este comportamiento, debe crear dos bibliotecas de documentos y agregar un campo Source en cada una de ellas. A continuación, cargue un documento de Microsoft Word en la primera biblioteca de documentos y guárdelo. Luego, descargue el documento de Word, use el cliente de Word para inspeccionar sus metadatos y cargue el documento en la otra biblioteca de documentos. Al cargarlo, el valor del campo Source todavía debe ser igual al título de la biblioteca de documentos en la que se cargó primero. Sin embargo, cuando se guarda el documento en la nueva biblioteca, el valor de su propiedad Source debe cambiar por el título de la nueva biblioteca de documentos. Inspeccione los metadatos del documento recién guardado para confirmar esta suposición.
Implementación
Con el siguiente código se implementa el evento ItemUpdating.
public override void ItemUpdating(SPItemEventProperties properties)
{
string fieldInternalName = properties.List.Fields["Source"].InternalName;
properties.AfterProperties[fieldInternalName] = properties.ListTitle;
}
Genere la solución e inicie el depurador. Mediante estas acciones, se realiza todo el trabajo necesario para crear la solución, implementarla en la colección de sitios de SharePoint y después iniciar el explorador en la página principal de la colección de sitios.
Cree una nueva biblioteca de documentos y agréguele el campo Source. Para ello, vaya a la configuración de la biblioteca de documentos, haga clic en Agregar desde columnas de sitio existentes, seleccione el campo Source, haga clic en Agregar y haga clic en Aceptar.
A continuación, cargue un documento de Word en esa biblioteca de documentos. Observe que el valor del campo Source está vacío. Al hacer clic en Guardar, sin embargo, el valor del campo Source cambia por el título de la biblioteca de documentos.
Descargue una copia del documento en el equipo local. Cree una nueva biblioteca de documentos y agregue el campo Source. Cargue el documento en esta biblioteca nueva. Al hacerlo, tenga en cuenta que el valor del campo Source aún es igual al título de la biblioteca de documentos en la que se guardó el documento por última vez.
Ahora haga clic en Save. El valor del campo Source cambia por el título de la nueva biblioteca de documentos.
Ejemplo 4: cancelación y redireccionamiento
Este ejemplo se basa en un escenario en el que se cancela una operación de usuario (debido a un error o por otras razones) y se redirige al usuario a una página de error personalizado.
Descargue el ejemplo de código: SharePoint 2010: usar receptores de eventos; ejemplo 4: cancelar y redirigir (en inglés)
Diseño
En este ejemplo, se crea un receptor de eventos web y se agrega código al evento WebMoving que cancela la acción de cambiar el nombre de la dirección URL del sitio y redirige al usuario a la página Configuración del sitio. (Se usa la página Configuración del sitio para que el ejemplo sea más sencillo; puede redirigir al usuario a una página de mensaje de error personalizado).
Implementación
Cree un proyecto de Visual Studio 2010 basado en la plantilla de proyecto de receptor de eventos de SharePoint 2010. Elija implementar la solución en el espacio aislado. En el asistente para la personalización, seleccione Eventos web como el origen del evento y Se va a mover un sitio como el evento. Cambie el ámbito de la característica al sitio.
Agregue el código siguiente, que cancela el evento de cambio de nombre y redirige al usuario a la página Configuración del sitio.
public override void WebMoving(SPWebEventProperties properties)
{
properties.Status = SPEventReceiverStatus.CancelWithRedirectUrl;
properties.RedirectUrl = properties.Web.ServerRelativeUrl +
"/_layouts/settings.aspx";
}
Genere la solución e inicie el depurador. Esto realiza todo el trabajo necesario para crear la solución, implementarla en la colección de sitios de SharePoint y después iniciar el explorador en la página principal de la colección de sitios.
A continuación, cree un subsitio e intente cambiarle el nombre. (Se debe crear un nuevo subsitio porque no se puede cambiar el nombre de un sitio raíz). Para cambiar el nombre del sitio, vaya a la página Configuración del sitio. En la sección Aspecto, haga clic en Título, descripción e icono. En el cuadro Nombre de la dirección URL, escriba un nuevo nombre para el sitio. Haga clic en Aceptar.
Se produce un error al intentar cambiar el nombre del sitio y después se le redirige a la página Configuración del sitio.
Ejemplo 5: registro de eventos
En este ejemplo, se explora un escenario en el que el código de registro de eventos captura todos los eventos que se producen en una colección de sitios y graba cada evento como un elemento en una lista que se mantiene en el sitio.
Descargue el ejemplo de código: SharePoint 2010: usar receptores de eventos; ejemplo 5: registrar eventos (en inglés)
Diseño
En la tabla 5 se enumeran todos los eventos de SharePoint y se identifica la lista en la que se registra cada evento. No se registran los eventos SiteDeleting ni SiteDeleted, ya que se desencadenan cuando se elimina la colección de sitios.
Tabla 5. Eventos y registros
Eventos |
Clase |
Lista de registro |
---|---|---|
SiteDeleting, SiteDeleted |
SPWebEventReceiver |
[no registrado] |
WebAdding, WebProvisioned, WebDeleting, WebDeleted, WebMoving, WebMoved |
SPWebEventReceiver |
WebEventLogger |
ListAdding, ListAdded, ListDeleting, ListDeleted |
SPListEventReceiver |
ListEventLogger |
EmailReceived |
SPEmailEventReceiver |
ListEventLogger |
FieldAdding, FieldAdded, FieldUpdating, FieldUpdated, FieldDeleting, FieldDeleted |
SPListEventReceiver |
ListEventLogger |
ItemAdding, ItemAdded, ItemUpdating, ItemUpdated, ItemDeleting, ItemDeleted, ItemCheckingIn, ItemCheckedIn, ItemCheckingOut, ItemCheckedOut, ItemFileMoving, ItemFileMoved, ItemFileConverted, ItemAttachmentAdding, ItemAttachmentAdded, ItemAttachmentDeleting, ItemAttachmentDeleted |
SPItemEventReceiver |
ListItemEventLogger |
WorkflowStarting, WorkflowStarted, WorkflowCompleted, WorkflowPostponed |
SPWorkflowEventReceiver |
WorkflowEventLogger |
En el ejemplo, se invalidan todos los métodos de evento de todas las clases que heredan de SPEventReceiverBase. También se crea una clase adicional en Common.cs que contiene métodos auxiliares. A continuación, se enlazan los eventos posteriores como sincrónicos para que se actualicen las listas correspondientes antes de que se complete la operación de usuario. La característica que permite los enlaces de eventos tiene como ámbito el nivel del sitio, para que pueda controlar todos los eventos desencadenados en todos los sitios de la colección.
Implementación
Cree un proyecto de Visual Studio 2010 basado en la plantilla de proyecto de SharePoint vacío. Elija implementar la solución en el espacio aislado.
Para cada tipo de evento de la tabla 6, haga clic con el botón secundario en el proyecto, haga clic en Agregar, apunte a Nuevo elemento y haga clic en Receptor de eventos. Seleccione las propiedades del evento que se enumeran en la tabla y haga clic en Finalizar.
Tabla 6. Propiedades para los nuevos receptores de eventos
Tipo de eventos |
Elemento |
Eventos |
---|---|---|
Web |
Ninguno |
Todos los eventos |
Lista |
Ninguno |
Todos los eventos |
Elemento de lista |
Lista personalizada |
Todos los eventos excepto los de contexto |
Correo electrónico de lista |
Lista personalizada |
Todos los eventos |
Flujo de trabajo de lista |
Lista personalizada |
Todos los eventos |
Para controlar todos los eventos de elemento de lista, de correo electrónico y de flujo de trabajo desencadenados en cualquier lista (no solo en listas personalizadas), quite los atributos ListTemplateId de los elementos <Receivers>. (Cambie <Receivers ListTemplateId="100"> por <Receivers>).
De manera predeterminada, los eventos posteriores son asincrónicos. Sin embargo, todos los eventos posteriores deben ser sincrónicos, por lo que debe agregar el elemento <Synchronization> y establecer su valor en "Synchronous" bajo cada uno de los elementos <Receiver> de todos los archivos Elements.xml. Por ejemplo, el evento WebDeleted debe ser similar a lo siguiente.
<Receiver>
<Name>EventReceiver1WebDeleted</Name>
<Type>WebDeleted</Type>
<Assembly>$SharePoint.Project.AssemblyFullName$</Assembly>
<Class>PTCEventLogger.EventReceiver1.EventReceiver1</Class>
<SequenceNumber>10000</SequenceNumber>
<Synchronization>Synchronous</Synchronization>
</Receiver>
Cambie el ámbito de la característica al sitio para controlar eventos desencadenados en toda la colección de sitios. Tenga en cuenta que la creación de un nuevo subsitio implica que se desencadenen eventos de creación de sitios y todo lo demás que se agrega al sitio. Esto puede consumir demasiados recursos en una solución de espacio aislado y, por consiguiente, la creación de una web podría generar un error. Puede evitar este problema cambiando Solución de espacio aislado a False en las propiedades del proyecto o cambiando el ámbito de la característica de nuevo a web.
A continuación, agregue al proyecto una clase denominada common y colóquela en un archivo denominado Common.cs. Agregue los siguientes tres métodos auxiliares a esta clase.
IsBeforeEvent Indica si un evento es previo o posterior.
/// <summary> /// Indicates whether an event is a Before event or an After event. /// </summary> /// <param name="eventType"></param> /// <returns></returns> private static bool IsBeforeEvent(SPEventReceiverType eventType) { return (eventType < SPEventReceiverType.ItemAdded) ? true : false; }
EnsureLogList Determina si ya existe una lista de registros. De ser así, obtiene una referencia a ella. De lo contrario, debe crear la lista y devolver una referencia a ella.
/// <summary> /// Ensures that the Logs list with the specified name is created. /// </summary> /// <param name="web"></param> /// <param name="listName"></param> /// <returns></returns> private static SPList EnsureLogList(SPWeb web, string listName) { SPList list = null; try { list = web.Lists[listName]; } catch { // Create list. Guid listGuid = web.Lists.Add(listName, listName, SPListTemplateType.GenericList); list = web.Lists[listGuid]; list.OnQuickLaunch = true; // Add the fields to the list. // No need to add "Title" because it is added by default. // We use it to set the event name. list.Fields.Add("Event", SPFieldType.Text, true); list.Fields.Add("Before", SPFieldType.Boolean, true); list.Fields.Add("Date", SPFieldType.DateTime, true); list.Fields.Add("Details", SPFieldType.Note, false); // Specify which fields to view. SPView view = list.DefaultView; view.ViewFields.Add("Event"); view.ViewFields.Add("Before"); view.ViewFields.Add("Date"); view.ViewFields.Add("Details"); view.Update(); list.Update(); } return list; }
LogEvent Crea un nuevo elemento en la lista especificada y registra los detalles del evento en ese elemento.
/// <summary> /// Log the event to the specified list. /// </summary> /// <param name="web"></param> /// <param name="listName"></param> /// <param name="eventType"></param> /// <param name="details"></param> public static void LogEvent(SPWeb web, string listName, SPEventReceiverType eventType, string details) { SPList logList = Common.EnsureLogList(web, listName); SPListItem logItem = logList.Items.Add(); logItem["Title"] = string.Format("{0} triggered at {1}", eventType, DateTime.Now); logItem["Event"] = eventType.ToString(); logItem["Before"] = Common.IsBeforeEvent(eventType); logItem["Date"] = DateTime.Now; logItem["Details"] = details; logItem.Update(); }
Para cada clase que hereda de SPWebEventReceiver, SPListEventReceiver, SPEmailEventReceiver, SPItemEventReceiver o SPWorkflowEventReceiver, debe crear un método Log para controlar el registro de las propiedades del evento en la lista correspondiente. También debe modificar todos los métodos invalidados para llamar a esos métodos Log. Los listados de código siguientes muestran cómo realizar esta tarea para cada receptor de eventos.
SPWebEventReceiver Cambie todos los eventos invalidados. A continuación se proporciona un ejemplo de cómo cambiar uno de esos eventos.
public override void WebProvisioned(SPWebEventProperties properties) { this.LogWebEventProperties(properties); }
Agregue el método Log, como se muestra en el siguiente código.
private void LogWebEventProperties(SPWebEventProperties properties) { // Specify the log list name. string listName = "WebEventLogger"; // Create string builder object. StringBuilder sb = new StringBuilder(); // Add properties that do not throw exceptions. sb.AppendFormat("Cancel: {0}\n", properties.Cancel); sb.AppendFormat("ErrorMessage: {0}\n", properties.ErrorMessage); sb.AppendFormat("EventType: {0}\n", properties.EventType); sb.AppendFormat("FullUrl: {0}\n", properties.FullUrl); sb.AppendFormat("NewServerRelativeUrl: {0}\n", properties.NewServerRelativeUrl); sb.AppendFormat("ParentWebId: {0}\n", properties.ParentWebId); sb.AppendFormat("ReceiverData: {0}\n", properties.ReceiverData); sb.AppendFormat("RedirectUrl: {0}\n", properties.RedirectUrl); sb.AppendFormat("ServerRelativeUrl: {0}\n", properties.ServerRelativeUrl); sb.AppendFormat("SiteId: {0}\n", properties.SiteId); sb.AppendFormat("Status: {0}\n", properties.Status); sb.AppendFormat("UserDisplayName: {0}\n", properties.UserDisplayName); sb.AppendFormat("UserLoginName: {0}\n", properties.UserLoginName); sb.AppendFormat("WebId: {0}\n", properties.WebId); sb.AppendFormat("Web: {0}\n", properties.Web); // Log the event to the list. this.EventFiringEnabled = false; Common.LogEvent(properties.Web, listName, properties.EventType, sb.ToString()); this.EventFiringEnabled = true; }
SPListEventReceiver Cambie todos los eventos invalidados. A continuación se proporciona un ejemplo de cómo cambiar uno de esos eventos.
public override void FieldAdded(SPListEventProperties properties) { this.LogListEventProperties(properties); }
Agregue el método Log, como se muestra en el siguiente código.
private void LogListEventProperties(SPListEventProperties properties) { // Specify the log list name. string listName = "ListEventLogger"; // Create the string builder object. StringBuilder sb = new StringBuilder(); // Add properties that do not throw exceptions. sb.AppendFormat("Cancel: {0}\n", properties.Cancel); sb.AppendFormat("ErrorMessage: {0}\n", properties.ErrorMessage); sb.AppendFormat("EventType: {0}\n", properties.EventType); sb.AppendFormat("FeatureId: {0}\n", properties.FeatureId); sb.AppendFormat("FieldName: {0}\n", properties.FieldName); sb.AppendFormat("FieldXml: {0}\n", properties.FieldXml); sb.AppendFormat("ListId: {0}\n", properties.ListId); sb.AppendFormat("ListTitle: {0}\n", properties.ListTitle); sb.AppendFormat("ReceiverData: {0}\n", properties.ReceiverData); sb.AppendFormat("RedirectUrl: {0}\n", properties.RedirectUrl); sb.AppendFormat("SiteId: {0}\n", properties.SiteId); sb.AppendFormat("Status: {0}\n", properties.Status); sb.AppendFormat("TemplateId: {0}\n", properties.TemplateId); sb.AppendFormat("UserDisplayName: {0}\n", properties.UserDisplayName); sb.AppendFormat("UserLoginName: {0}\n", properties.UserLoginName); sb.AppendFormat("WebId: {0}\n", properties.WebId); sb.AppendFormat("WebUrl: {0}\n", properties.WebUrl); sb.AppendFormat("Web: {0}\n", properties.Web); sb.AppendFormat("List: {0}\n", properties.List); // Add properties that might throw exceptions. try { sb.AppendFormat("Field: {0}\n", properties.Field); } catch (Exception e) { sb.AppendFormat("\nError accessing properties.Field:\n\n {0}", e); } // Log the event to the list. this.EventFiringEnabled = false; Common.LogEvent(properties.Web, listName, properties.EventType, sb.ToString()); this.EventFiringEnabled = true; }
SPEmailEventReceiver Cambie el evento EmailReceived de la siguiente manera.
public override void EmailReceived(SPList list, SPEmailMessage emailMessage, String receiverData) { // Specify the log list name. string listName = "ListEmailEventLogger"; // Create the string builder object. StringBuilder sb = new StringBuilder(); // Add the email message properties. sb.AppendFormat("From:\t {0}\n", emailMessage.Sender); sb.AppendFormat("To:\t {0}\n", emailMessage.Headers["To"]); sb.AppendFormat("Subject:\t {0}\n", emailMessage.Headers["Subject"]); sb.AppendFormat("Body:\t {0}\n", emailMessage.PlainTextBody); // Log the event to the list. Common.LogEvent(list.ParentWeb, listName, SPEventReceiverType.EmailReceived, sb.ToString()); }
SPItemEventReceiver Cambie todos los eventos invalidados. A continuación se proporciona un ejemplo de cómo cambiar uno de esos eventos.
public override void ItemAttachmentAdded(SPItemEventProperties properties) { this.LogItemEventProperties(properties); } Add the log method. private void LogItemEventProperties(SPItemEventProperties properties) { // Specify the log list name. string listName = "ListItemEventLogger"; // Create the string builder object. StringBuilder sb = new StringBuilder(); // Add properties that do not throw exceptions. sb.AppendFormat("AfterUrl: {0}\n", properties.AfterUrl); sb.AppendFormat("BeforeUrl: {0}\n", properties.BeforeUrl); sb.AppendFormat("Cancel: {0}\n", properties.Cancel); sb.AppendFormat("CurrentUserId: {0}\n", properties.CurrentUserId); sb.AppendFormat("ErrorMessage: {0}\n", properties.ErrorMessage); sb.AppendFormat("EventType: {0}\n", properties.EventType); sb.AppendFormat("ListId: {0}\n", properties.ListId); sb.AppendFormat("ListItemId: {0}\n", properties.ListItemId); sb.AppendFormat("ListTitle: {0}\n", properties.ListTitle); sb.AppendFormat("ReceiverData: {0}\n", properties.ReceiverData); sb.AppendFormat("RedirectUrl: {0}\n", properties.RedirectUrl); sb.AppendFormat("RelativeWebUrl: {0}\n", properties.RelativeWebUrl); sb.AppendFormat("SiteId: {0}\n", properties.SiteId); sb.AppendFormat("Status: {0}\n", properties.Status); sb.AppendFormat("UserDisplayName: {0}\n", properties.UserDisplayName); sb.AppendFormat("UserLoginName: {0}\n", properties.UserLoginName); sb.AppendFormat("Versionless: {0}\n", properties.Versionless); sb.AppendFormat("WebUrl: {0}\n", properties.WebUrl); sb.AppendFormat("Web: {0}\n", properties.Web); sb.AppendFormat("Zone: {0}\n", properties.Zone); sb.AppendFormat("Context: {0}\n", properties.Context); // Add properties that might throw exceptions. try { sb.AppendFormat("ListItem: {0}\n", properties.ListItem); } catch (Exception e) { sb.AppendFormat("\nError accessing properties.ListItem:\n\n {0}", e); } // Add AfterProperties property bag. sb.AppendFormat("AfterProperties: {0}\n", properties.AfterProperties); IEnumerator afterProperties = properties.AfterProperties.GetEnumerator(); int i = 0; while (afterProperties.MoveNext()) { DictionaryEntry entry = (DictionaryEntry)afterProperties.Current; sb.AppendFormat("[{0}]: ({1}, {2})\n", i++, entry.Key, entry.Value); } sb.AppendFormat("AfterProperties.ChangedProperties: {0}\n", properties.AfterProperties.ChangedProperties); IEnumerator changedAfterProperties = properties.AfterProperties.ChangedProperties.GetEnumerator(); i = 0; while (changedAfterProperties.MoveNext()) { DictionaryEntry entry = (DictionaryEntry)changedAfterProperties.Current; sb.AppendFormat("[{0}]: ({1}, {2})\n", i++, entry.Key, entry.Value); } // Add BeforeProperties property bag. sb.AppendFormat("BeforeProperties: {0}\n", properties.BeforeProperties); IEnumerator beforeProperties = properties.BeforeProperties.GetEnumerator(); i = 0; while (beforeProperties.MoveNext()) { DictionaryEntry entry = (DictionaryEntry)beforeProperties.Current; sb.AppendFormat("[{0}]: ({1}, {2})\n", i++, entry.Key, entry.Value); } sb.AppendFormat("BeforeProperties.ChangedProperties: {0}\n", properties.BeforeProperties.ChangedProperties); IEnumerator changedBeforeProperties = properties.BeforeProperties.ChangedProperties.GetEnumerator(); i = 0; while (changedBeforeProperties.MoveNext()) { DictionaryEntry entry = (DictionaryEntry)changedBeforeProperties.Current; sb.AppendFormat("[{0}]: ({1}, {2})\n", i++, entry.Key, entry.Value); } // Log the event to the list. this.EventFiringEnabled = false; Common.LogEvent(properties.Web, listName, properties.EventType, sb.ToString()); this.EventFiringEnabled = true; }
SPWorkflowEventReceiver Cambie todos los eventos invalidados. A continuación se proporciona un ejemplo de cómo cambiar uno de esos eventos.
public override void WorkflowStarting(SPWorkflowEventProperties properties) { this.LogWorkflowEventProperties(properties); }
Agregue el método Log, como se muestra en el siguiente código.
private void LogWorkflowEventProperties(SPWorkflowEventProperties properties) { // Specify the log list name. string listName = "WorkflowEventLogger"; // Create the string builder object. StringBuilder sb = new StringBuilder(); // Add properties that do not throw exceptions. sb.AppendFormat("AssociationData: {0}\n", properties.AssociationData); sb.AppendFormat("Cancel: {0}\n", properties.Cancel); sb.AppendFormat("CompletionType: {0}\n", properties.CompletionType); sb.AppendFormat("ErrorMessage: {0}\n", properties.ErrorMessage); sb.AppendFormat("EventType: {0}\n", properties.EventType); sb.AppendFormat("InitiationData: {0}\n", properties.InitiationData); sb.AppendFormat("InstanceId: {0}\n", properties.InstanceId); sb.AppendFormat("PostponedEvent: {0}\n", properties.PostponedEvent); sb.AppendFormat("ReceiverData: {0}\n", properties.ReceiverData); sb.AppendFormat("RedirectUrl: {0}\n", properties.RedirectUrl); sb.AppendFormat("RelativeWebUrl: {0}\n", properties.RelativeWebUrl); sb.AppendFormat("SiteId: {0}\n", properties.SiteId); sb.AppendFormat("Status: {0}\n", properties.Status); sb.AppendFormat("TerminatedByUserId: {0}\n", properties.TerminatedByUserId); sb.AppendFormat("WebUrl: {0}\n", properties.WebUrl); // Get activation properties. SPWorkflowActivationProperties activationProperties = properties.ActivationProperties; if (activationProperties != null) { sb.AppendFormat("ActivationProperties.AssociationData: {0}\n", activationProperties.AssociationData); sb.AppendFormat("ActivationProperties.HistoryListId: {0}\n", activationProperties.HistoryListId); sb.AppendFormat("ActivationProperties.HistoryListUrl: {0}\n", activationProperties.HistoryListUrl); sb.AppendFormat("ActivationProperties.InitiationData: {0}\n", activationProperties.InitiationData); sb.AppendFormat("ActivationProperties.ItemId: {0}\n", activationProperties.ItemId); sb.AppendFormat("ActivationProperties.ItemUrl: {0}\n", activationProperties.ItemUrl); sb.AppendFormat("ActivationProperties.ListId: {0}\n", activationProperties.ListId); sb.AppendFormat("ActivationProperties.ListUrl: {0}\n", activationProperties.ListUrl); sb.AppendFormat("ActivationProperties.Originator: {0}\n", activationProperties.Originator); sb.AppendFormat("ActivationProperties.OriginatorEmail: {0}\n", activationProperties.OriginatorEmail); sb.AppendFormat("ActivationProperties.SiteId: {0}\n", activationProperties.SiteId); sb.AppendFormat("ActivationProperties.SiteUrl: {0}\n", activationProperties.SiteUrl); sb.AppendFormat("ActivationProperties.TaskListId: {0}\n", activationProperties.TaskListId); sb.AppendFormat("ActivationProperties.TaskListUrl: {0}\n", activationProperties.TaskListUrl); sb.AppendFormat("ActivationProperties.TemplateName: {0}\n", activationProperties.TemplateName); sb.AppendFormat("ActivationProperties.WebId: {0}\n", activationProperties.WebId); sb.AppendFormat("ActivationProperties.WebUrl: {0}\n", activationProperties.WebUrl); sb.AppendFormat("ActivationProperties.WorkflowId: {0}\n", activationProperties.WorkflowId); // Add properties that might throw exceptions. try { sb.AppendFormat("ActivationProperties.Context: {0}\n", activationProperties.Context); sb.AppendFormat("ActivationProperties.HistoryList: {0}\n", activationProperties.HistoryList); sb.AppendFormat("ActivationProperties.Item: {0}\n", activationProperties.Item); sb.AppendFormat("ActivationProperties.List: {0}\n", activationProperties.List); sb.AppendFormat("ActivationProperties.OriginatorUser: {0}\n", activationProperties.OriginatorUser); sb.AppendFormat("ActivationProperties.Site: {0}\n", activationProperties.Site); sb.AppendFormat("ActivationProperties.TaskList: {0}\n", activationProperties.TaskList); sb.AppendFormat("ActivationProperties.Web: {0}\n", activationProperties.Web); sb.AppendFormat("ActivationProperties.Workflow: {0}\n", activationProperties.Workflow); } catch (Exception e) { sb.AppendFormat("\nError accessing ActivationProperties property:\n\n {0}", e); } } else { sb.AppendFormat("ActivationProperties is null\n"); } // Log the event to the list. this.EventFiringEnabled = false; Common.LogEvent(properties.ActivationProperties.Web, listName, properties.EventType, sb.ToString()); this.EventFiringEnabled = true; }
Conclusión
Ahora conoce todo el modelo de eventos de SharePoint 2010, y sabe cómo crear receptores de eventos e implementar proyectos que implementen receptores de eventos. (También sabe cuánto trabajo puede ahorrar si usa la plantilla de proyecto de receptor de eventos de Visual Studio 2010). Además, tiene varios ejemplos prácticos que puede adaptar a sus necesidades. Si desea obtener aún más detalles sobre el modelo de eventos de SharePoint, revise el SDK de SharePoint 2010, comenzando por Eventos de SharePoint Foundation 2010.
Recursos adicionales
Para más información, vea los siguientes recursos: