popularidad - sharepoint manual
ActualizaciĆ³n de tipos de contenido de SharePoint ya implementados para manejar eventos de elementos adicionales (3)
Tengo un tipo de contenido de sitio que se utilizó para un puñado de listas en toda mi colección de sitios. En ese tipo de contenido, describo un receptor de eventos para manejar el evento ItemAdding. Esto funciona bien Ahora necesito actualizar el tipo de contenido para que también se maneje ItemUpdating. OTTOMH, intenté simplemente modificar el xml para mi tipo de contenido, ya que esto parecía permitir el seguimiento de la versión fácil. Esto funcionó en el sentido de que mis actualizaciones se aplicaron al tipo de contenido del sitio, pero no a mis listas que habían estado usando este tipo de contenido. Esto era esperado. Luego noté que el SDK de SharePoint tiene una visión sombría de eso:
Bajo ninguna circunstancia debe actualizar el archivo de definición de tipo de contenido para un tipo de contenido después de haber instalado y activado ese tipo de contenido. Windows SharePoint Services no realiza un seguimiento de los cambios realizados en el archivo de definición de tipo de contenido. Por lo tanto, no tiene ningún método para reducir los cambios realizados en los tipos de contenido del sitio a los tipos de contenido secundarios.
El SDK luego apunta a un par de secciones que describen cómo usar la UI o el código para impulsar cambios. Como la IU no ofrece ningún enlace a los receptores de eventos, creo que elegiré la ruta del código.
Pensé que sería capaz de hacer algo como esto y simplemente agregar un nuevo receptor de eventos a la copia de la lista del tipo de contenido:
SPList list = web.Lists["My list"];
SPContentType ctype = list.ContentTypes["My content type"];
// Doesn''t work -- EventReceivers is null below.
ctype.EventReceivers.Add(SPEventReceiverType.ItemUpdating,
"My assembly name", "My class name");
Pero la trampa es que ctype.EventReceivers es nulo aquí, aunque tengo ItemAdding ya conectado a esta lista. Parece que se movió a la lista en sí. Entonces, la lista tiene una colección válida de EventReceivers.
SPList list = web.Lists["My list"];
list.EventReceivers.Add(SPEventReceiverType.ItemUpdating,
"My assembly name", "My class name");
Entonces, tengo un par de preguntas:
- ¿Es la forma correcta de hacer esto solo agregar nuevos receptores de eventos directamente a la lista y simplemente olvidarse de mi tipo de contenido por completo?
- Para lograr este cambio, ¿cuál es la mejor manera de manejar esto en términos de gestión de configuración? ¿Debo crear una aplicación de consola simple para encontrar todas las listas apropiadas y modificar cada una de ellas? ¿O de alguna manera está creando una característica una mejor opción? De cualquier manera, parece que este cambio va a ser por sí solo y difícil de descubrir por futuros desarrolladores que podrían necesitar trabajar con este tipo de contenido.
¿Llamaste a ctype.Update (true) después de agregar el EventReceiver? Si no lo haces, no se mantendrá. Y no use el tipo de contenido de lista, use SPWeb.ContentTypes en su lugar.
Este código funciona para mí:
var docCt = web.ContentTypes[new SPContentTypeId("0x0101003A3AF5E5C6B4479191B58E78A333B28D")];
//while(docCt.EventReceivers.Count > 0)
// docCt.EventReceivers[docCt.EventReceivers.Count - 1].Delete();
docCt.EventReceivers.Add(SPEventReceiverType.ItemUpdated, "ASSEMBLYNAME, Version=1.0.0.0, Culture=neutral, PublicKeyToken=c5b857a999fb347e", "CLASSNAME");
docCt.Update(true);
El parámetro verdadero significa que también se aplica a todos los tipos de contenido secundarios. (es decir, a todas las listas que usan el tipo de contenido).
En cuanto a la segunda parte de su pregunta, quería transmitir lo que hemos hecho para situaciones similares en el pasado. En nuestra situación, necesitábamos un par de scripts diferentes: uno que nos permitiera propagar las actualizaciones de tipo de contenido a todas las listas en todas las webs y otra que restablecería las Páginas maestras / Diseños de página a la definición del sitio (formulario no personalizado) )
Por lo tanto, creamos algunos comandos de stsadm personalizados para cada una de estas acciones. Hacerlo de esta manera es bueno porque las secuencias de comandos se pueden colocar en el control de fuente e implementa la interfaz de stsadm ya existente.
Para responder a la segunda parte de su pregunta, esta es una cuestión complicada debido al hecho de que los cambios en los tipos de contenido de la colección de sitios no se incluirán en las listas donde se usan. Una "copia" se compone esencialmente de los campos de la colección de sitios y no hay más vínculos entre ellos después de agregar un tipo de contenido a la lista. Creo que esto se debe al hecho de que se supone que debes hacer cambios en las listas sin que afecte a la colección del sitio. De todos modos, mi contribución a este "problema", y cómo lo he solucionado, implica hacer que el xml sea el "maestro" y en un receptor de características extraigo el xml y encuentro todos los lugares donde se usa el tipo de contenido y de allí actualizo los tipos de contenido (realmente los campos de referencia) en el nivel de la lista para que coincida con el del xml. El código es algo así como:
var elementdefinitions = properties.Feature.Definition.GetElementDefinitions();
foreach (SPElementDefinition elementDefinition in elementdefinitions)
{
if (elementDefinition.ElementType == "ContentType")
{
XmlNode ElementXML = elementDefinition.XmlDefinition;
// get all fieldrefs nodes in xml
XmlNodeList FieldRefs = ElementXML.ChildNodes[0].ChildNodes;
// get reference to contenttype
string ContentTypeID = ElementXML.Attributes["ID"].Value.ToString();
SPContentType ContentType =
site.ContentTypes[new SPContentTypeId(ContentTypeID)];
// Get all all places where the content type beeing used
IList<SPContentTypeUsage> ContentTypeUsages =
SPContentTypeUsage.GetUsages(ContentType);
}
}
Lo siguiente es comparar las referencias de campo en xml xml con los campos de la lista (realizados por el atributo ID) y asegurarse de que sean iguales. Lamentablemente no podemos actualizar todas las cosas en la clase SPFieldLink (el campo de referencia) y (sí, sé que no es compatible) aquí, he utilizado la reflexión para actualizar esos valores (fe ShowInEditForm).