Reemplazar tipos de contenido de SharePoint y columnas de sitio en soluciones de granja de servidores
En este artículo se describe el proceso de transformación que se va a usar al reemplazar tipos de contenido y columnas de sitio, agregar columnas de sitio a nuevos tipos de contenido y, a continuación, reemplazar tipos de contenido anteriores por nuevos tipos de contenido mediante el modelo de objetos del lado cliente (CSOM) de SharePoint.
Importante
Las soluciones de granja no se pueden migrar a SharePoint Online. Mediante la aplicación de las técnicas y el código descritos en este artículo, puede crear una nueva solución que use tipos de contenido actualizados y columnas de sitio y proporcione una funcionalidad similar a las soluciones de granja de servidores o a las soluciones de espacio aislado declarativo. La nueva solución se puede implementar en SharePoint Online.
El código de este artículo requiere código adicional para ofrecer una solución que funcione completamente. Por ejemplo, en este artículo no se explica cómo autenticar Office 365, cómo implementar excepciones necesarias, etc. Para obtener ejemplos de código adicionales, consulte el Proyecto de patrones y prácticas para desarrolladores de Office 365.
Nota:
El código de este artículo se proporciona tal cual, sin garantía de ningún tipo, expresa o implícita, incluidas las garantías implícitas de aptitud para un propósito particular, comerciabilidad o ausencia de infracción.
Para reemplazar tipos de contenido y columnas de sitio mediante CSOM:
Cree un nuevo tipo de contenido.
Cree una nueva columna de sitio (también denominada campo).
Agregue la nueva columna de sitio al nuevo tipo de contenido.
Reemplace las referencias de tipo de contenido antiguas por el nuevo tipo de contenido.
En el código siguiente, Main muestra el orden de las operaciones que se deben realizar para reemplazar tipos de contenido y columnas de sitio mediante CSOM.
static void Main(string[] args)
{
using (var clientContext = new ClientContext("http://contoso.sharepoint.com"))
{
Web web = clientContext.Web;
CreateContentType(clientContext, web);
CreateSiteColumn(clientContext, web);
AddSiteColumnToContentType(clientContext, web);
// Replace the old content type with the new content type.
ReplaceContentType(clientContext, web);
}
}
En el código siguiente, GetContentTypeByName obtiene un tipo de contenido del sitio actual mediante:
Usar la propiedad Web.ContentTypes para obtener ContentTypeCollection, que es una colección de tipos de contenido en el sitio actual.
Buscar y, a continuación, devolver un tipo de contenido del sitio, haciendo coincidir el nombre del tipo de contenido del sitio con el nombre del tipo de contenido existente, que se envía mediante el parámetro name .
private static ContentType GetContentTypeByName(ClientContext cc, Web web, string name)
{
ContentTypeCollection contentTypes = web.ContentTypes;
cc.Load(contentTypes);
cc.ExecuteQuery();
return contentTypes.FirstOrDefault(o => o.Name == name);
}
Creación de un nuevo tipo de contenido
En el código siguiente, CreateContentType crea un nuevo tipo de contenido mediante:
Crear una constante denominada contentTypeName para almacenar el nombre del tipo de contenido. El nombre del nuevo tipo de contenido se establece en el nombre del tipo de contenido anterior.
Llamar a GetContentTypeByName para buscar un tipo de contenido coincidente en el sitio.
Si el tipo de contenido ya existe, no es necesario realizar ninguna acción adicional y el control vuelve a Main cuando se llama a return .
Si el tipo de contenido no existe, las propiedades del tipo de contenido se establecen mediante un objeto ContentTypeCreationInformation denominado newCt.
El nuevo identificador de tipo de contenido se asigna a newCt.Id mediante el identificador de tipo de contenido del documento base 0x0101. Para obtener más información, vea Base Content Type Hierarchy.
Agregar el nuevo tipo de contenido mediante ContentTypeCollection.Add.
private static void CreateContentType(ClientContext cc, Web web)
{
// The new content type will be created using this name.
const string contentTypeName = "ContosoDocumentByCSOM";
// Determine whether the content type already exists.
var contentType = GetContentTypeByName(cc, web, contentTypeName);
// The content type exists already. No further action required.
if (contentType != null) return;
// Create the content type using the ContentTypeInformation object.
ContentTypeCreationInformation newCt = new ContentTypeCreationInformation();
newCt.Name = "ContosoDocumentByCSOM";
// Create the new content type based on the out-of-the-box document (0x0101) and assign the ID to the new content type.
newCt.Id = "0x0101009189AB5D3D2647B580F011DA2F356FB2";
// Assign the content type to a specific content type group.
newCt.Group = "Contoso Content Types";
ContentType myContentType = web.ContentTypes.Add(newCt);
cc.ExecuteQuery();
}
Creación de una nueva columna de sitio
En el código siguiente, CreateSiteColumn crea una nueva columna de sitio mediante:
Crear una constante denominada fieldName para almacenar el nombre del campo. El nombre del nuevo campo se establece en el nombre del campo anterior.
Obtener las columnas de sitio definidas en el sitio mediante la propiedad Web.Fields .
Buscar un campo coincidente en el sitio haciendo coincidir los nombres de campo del sitio con fieldName. Si el campo ya existe, no es necesario realizar ninguna acción adicional y el control vuelve a Main cuando se llama a return . Si el campo no existe, se asigna una cadena CAML que especifica el esquema de campo a FieldAsXML y, a continuación, el campo se crea mediante FieldCollection.AddFieldAsXml.
private static void CreateSiteColumn(ClientContext cc, Web web)
{
// The new field will be created using this name.
const string fieldName = "ContosoStringCSOM";
// Load the list of fields on the site.
FieldCollection fields = web.Fields;
cc.Load(fields);
cc.ExecuteQuery();
// Check fields on the site for a match.
var fieldExists = fields.Any(f => f.InternalName == fieldName);
// The field exists already. No further action required.
if (fieldExists) return;
// Field does not exist, so create the new field.
string FieldAsXML = @"<Field ID='{CB8E24F6-E1EE-4482-877B-19A51B4BE319}'
Name='" + fieldName + @"'
DisplayName='Contoso String by CSOM'
Type='Text'
Hidden='False'
Group='Contoso Site Columns'
Description='Contoso Text Field' />";
Field fld = fields.AddFieldAsXml(FieldAsXML, true, AddFieldOptions.DefaultValue);
cc.ExecuteQuery();
}
Agregar la nueva columna de sitio al nuevo tipo de contenido
En el código siguiente, AddSiteColumnToContentType crea una conexión entre el tipo de contenido y el campo mediante:
Cargar el tipo de contenido y, a continuación, el campo hace referencia a ese tipo de contenido mediante la propiedad ContentType.FieldLinks .
Carga del campo.
Determinar si el tipo de contenido hace referencia al campo mediante contentType.FieldLinks.Any(f => f.Name == fieldName) para que coincida con el nombre del campo.
Si el tipo de contenido ya hace referencia al campo, no es necesario realizar ninguna acción adicional y el control vuelve a Main cuando se llama a return . Si el tipo de contenido no hace referencia al campo, las propiedades de referencia de campo se establecen en un objeto FieldLinkCreationInformation .
Agregar el objeto FieldLinkCreationInformation a la propiedad ContentType.FieldLinks .
private static void AddSiteColumnToContentType(ClientContext cc, Web web)
{
// The name of the content type.
const string contentTypeName = "ContosoDocumentByCSOM";
// The field name.
const string fieldName = "ContosoStringCSOM";
// Load the content type.
var contentType = GetContentTypeByName(cc, web, contentTypeName);
if (contentType == null) return; // content type was not found
// Load field references in the content type.
cc.Load(contentType.FieldLinks);
cc.ExecuteQuery();
// Load the new field.
Field fld = web.Fields.GetByInternalNameOrTitle(fieldName);
cc.Load(fld);
cc.ExecuteQuery();
// Determine whether the content type refers to the field.
var hasFieldConnected = contentType.FieldLinks.Any(f => f.Name == fieldName);
// A reference exists already, no further action is required.
if (hasFieldConnected) return;
// The reference does not exist, so we have to create the reference.
FieldLinkCreationInformation link = new FieldLinkCreationInformation();
link.Field = fld;
contentType.FieldLinks.Add(link);
contentType.Update(true);
cc.ExecuteQuery();
}
Reemplazar referencias de tipo de contenido antiguas por el nuevo tipo de contenido
En el código siguiente, ReplaceContentType comprueba todos los elementos de todas las bibliotecas para el contenido que hace referencia al tipo de contenido anterior y, a continuación, reemplaza esas referencias por el nuevo tipo de contenido (ContosoDocumentByCSOM) por:
Asignación del identificador de tipo de contenido antiguo a una constante.
Obtener el nuevo tipo de contenido mediante GetContentTypeByName.
Obtener todas las listas del sitio mediante Web.Lists.
Cargar todas las listas del sitio y todos los tipos de contenido de cada lista mediante cc.Load(lists, l => l.Include(list => list. ContentTypes).
Para cada lista devuelta, busque los tipos de contenido de la lista para que coincidan con un tipo de contenido con el identificador de tipo de contenido anterior mediante la lista. ContentTypes.Any(c => c.StringId.StartsWith(oldContentTypeId)). Si se encuentra una coincidencia, la lista con el tipo de contenido anterior se agrega a listsWithContentType.
Para cada lista de listsWithContentType:
Determinar si el nuevo tipo de contenido está asociado a la lista. Si el nuevo tipo de contenido no está asociado a la lista, use ContentTypeCollection.AddExistingContentType para adjuntar el nuevo tipo de contenido a la lista.
Obtener todos los elementos de lista de la lista.
Para cada elemento de lista, obtiene el identificador de tipo de contenido del elemento de lista. Determine si el identificador de tipo de contenido del elemento de lista es igual al identificador de tipo de contenido anterior. Si los identificadores de tipo de contenido no son iguales, vaya al siguiente elemento de lista. Si los identificadores de tipo de contenido son iguales, use ContentType.StringId para asignar el nuevo identificador de tipo de contenido al elemento de lista.
Nota:
El tipo de contenido anterior sigue estando en la lista, pero ya no se usa. Ahora puede eliminar el tipo de contenido antiguo de las listas y, a continuación, retirarlo. En este artículo se describe cómo reemplazar solo los tipos de contenido de documento. Si va a reemplazar los tipos de contenido en los diseños de página, asegúrese de actualizar la propiedad AssociatedContentType en cada diseño de página de la colección de sitios.
private static void ReplaceContentType(ClientContext cc, Web web)
{
// The old content type.
const string oldContentTypeId = "0x010100C32DDAB6381C44868DCD5ADC4A5307D6";
// The new content type name.
const string newContentTypeName = "ContosoDocumentByCSOM";
// Get the new content type and lists on the site.
ContentType newContentType = GetContentTypeByName(cc, web, newContentTypeName);
ListCollection lists = web.Lists;
// Load the new content type and the content types on all lists on the site.
cc.Load(newContentType);
cc.Load(lists,
l => l.Include(list => list.ContentTypes));
cc.ExecuteQuery();
var listsWithContentType = new List<List>();
foreach (List list in lists)
{
bool hasOldContentType = list.ContentTypes.Any(c => c.StringId.StartsWith(oldContentTypeId));
if (hasOldContentType)
{
listsWithContentType.Add(list);
}
}
foreach (List list in listsWithContentType)
{
// Determine whether the new content type is already attached to the list.
var listHasContentTypeAttached = list.ContentTypes.Any(c => c.Name == newContentTypeName);
if (!listHasContentTypeAttached)
{
// Attach content type to list.
list.ContentTypes.AddExistingContentType(newContentType);
cc.ExecuteQuery();
}
// Get all list items.
CamlQuery query = CamlQuery.CreateAllItemsQuery();
ListItemCollection items = list.GetItems(query);
cc.Load(items);
cc.ExecuteQuery();
// For each list item, determine whether the old content type is used, and then update to the new content type.
foreach (ListItem listItem in items)
{
// Get the current content type for this list item.
var currentContentTypeId = listItem["ContentTypeId"] + "";
var isOldContentTypeAssigned = currentContentTypeId.StartsWith(oldContentTypeId);
// This item does not use the old content type - skip to next list item.
if (!isOldContentTypeAssigned) continue;
// Update the list item content type to the new content type.
listItem["ContentTypeId"] = newContentType.StringId; // new content type Id;
listItem.Update();
}
// Save all changes.
cc.ExecuteQuery();
}
}