Remplacer les types de contenu SharePoint et les colonnes de site dans les solutions de batterie de serveurs

Cet article décrit le processus de transformation à utiliser pour remplacer des types de contenu et des colonnes de site, ajouter des colonnes de site à de nouveaux types de contenu, puis remplacer les types de contenu précédents par de nouveaux types de contenu à l’aide du modèle objet côté client (CSOM) SharePoint.

Importante

Les solutions de batterie de serveurs ne peuvent pas être migrées vers SharePoint Online. En appliquant les techniques et le code décrits dans cet article, vous pouvez créer une nouvelle solution qui utilise des types de contenu et des colonnes de site mis à jour et fournit des fonctionnalités similaires à vos solutions de batterie de serveurs ou solutions de bac à sable déclaratif. La nouvelle solution peut ensuite être déployée sur SharePoint Online.

Le code dans cet article requiert un code supplémentaire pour offrir une solution totalement fonctionnelle. Par exemple, cet article ne traite pas de l’authentification à Office 365, de la manière d’implémenter la gestion des exceptions, etc. Pour plus d’exemples de code, reportez-vous à la rubrique Pratiques et modèles de développement Office 365.

Remarque

Le code dans cet article est fourni tel quel, sans garantie d’aucune sorte, expresse ou implicite, y compris mais sans s’y limiter, aucune garantie implicite d’adéquation à un usage particulier, à une qualité marchande ou une absence de contrefaçon.

Pour remplacer les types de contenu et les colonnes de site à l’aide de CSOM :

  1. Créez un type de contenu.

  2. Créez une colonne de site (également appelée champ).

  3. Ajoutez la nouvelle colonne de site au nouveau type de contenu.

  4. Remplacez les anciennes références de type de contenu par le nouveau type de contenu.

Dans le code suivant, Main affiche l’ordre des opérations à effectuer pour remplacer les types de contenu et les colonnes de site à l’aide de 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);
    }

}

Dans le code suivant, GetContentTypeByName obtient un type de contenu à partir du site actuel en :

  1. Utilisation de la propriété Web.ContentTypes pour obtenir un ContentTypeCollection, qui est une collection de types de contenu sur le site actuel.

  2. Recherche et retour d’un type de contenu à partir du site, en faisant correspondre le nom du type de contenu de site au nom du type de contenu existant, qui est soumis par le paramètre 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);
    }

Créer un type de contenu

Dans le code suivant, CreateContentType crée un type de contenu en :

  1. Création d’une constante appelée contentTypeName pour stocker le nom du type de contenu. Le nom du nouveau type de contenu est défini sur le nom du type de contenu précédent.

  2. Appel de GetContentTypeByName pour rechercher un type de contenu correspondant sur le site.

  3. Si le type de contenu existe déjà, aucune autre action n’est nécessaire et le contrôle revient à Main lors de l’appel de return .

    Si le type de contenu n’existe pas, les propriétés de type de contenu sont définies à l’aide d’un objet ContentTypeCreationInformation appelé newCt.

    Le nouvel ID de type de contenu est attribué à newCt.Id à l’aide de l’ID de type de contenu de document de base 0x0101. Pour plus d’informations, consultez Hiérarchie des types de contenu de base.

  4. Ajout du nouveau type de contenu à l’aide de 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();
}

Créer une colonne de site

Dans le code suivant, CreateSiteColumn crée une colonne de site en :

  1. Création d’une constante appelée fieldName pour stocker le nom du champ. Le nom du nouveau champ est défini sur le nom du champ précédent.

  2. Obtention des colonnes de site définies sur le site à l’aide de la propriété Web.Fields .

  3. Recherche d’un champ correspondant sur le site en faisant correspondre les noms de champs sur le site à fieldName. Si le champ existe déjà, aucune action supplémentaire n’est nécessaire et le contrôle revient à Main lorsque return est appelé. Si le champ n’existe pas, une chaîne CAML spécifiant le schéma de champ est affectée à FieldAsXML, puis le champ est créé à l’aide de 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();
}

Ajouter la nouvelle colonne de site au nouveau type de contenu

Dans le code suivant, AddSiteColumnToContentType crée une connexion entre le type de contenu et le champ en :

  1. Chargement du type de contenu, puis du champ référence ce type de contenu à l’aide de la propriété ContentType.FieldLinks .

  2. Chargement du champ.

  3. Déterminer si le type de contenu fait référence au champ à l’aide de contentType.FieldLinks.Any(f => f.Name == fieldName) pour faire correspondre le nom du champ.

  4. Si le type de contenu fait déjà référence au champ, aucune autre action n’est nécessaire et le contrôle revient à Main lorsque return est appelé. Si le type de contenu ne fait pas référence au champ, les propriétés de référence de champ sont définies sur un objet FieldLinkCreationInformation .

  5. Ajout de l’objet FieldLinkCreationInformation à la propriété 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();
}

Remplacer les anciennes références de type de contenu par le nouveau type de contenu

Dans le code suivant, ReplaceContentType vérifie tous les éléments de toutes les bibliothèques pour le contenu qui fait référence à l’ancien type de contenu, puis remplace ces références par le nouveau type de contenu (ContosoDocumentByCSOM) par :

  1. Affectation de l’ancien ID de type de contenu à une constante.

  2. Obtention du nouveau type de contenu à l’aide de GetContentTypeByName.

  3. Obtention de toutes les listes sur le site à l’aide de Web.Lists.

  4. Chargement de toutes les listes sur le site et de tous les types de contenu sur chaque liste à l’aide de cc.Load(lists, l => l.Include(list => list). ContentTypes).

  5. Pour chaque liste retournée, recherchez les types de contenu de la liste pour qu’ils correspondent à un type de contenu avec l’ancien ID de type de contenu à l’aide de la liste. ContentTypes.Any(c => c.StringId.StartsWith(oldContentTypeId))). Si une correspondance est trouvée, la liste avec l’ancien type de contenu est ajoutée à listsWithContentType.

  6. Pour chaque liste dans listsWithContentType :

  7. Déterminer si le nouveau type de contenu est attaché à la liste. Si le nouveau type de contenu n’est pas attaché à la liste, utilisez ContentTypeCollection.AddExistingContentType pour attacher le nouveau type de contenu à la liste.

  8. Obtention de tous les éléments de liste de la liste.

  9. Pour chaque élément de liste, obtenez l’ID de type de contenu de l’élément de liste. Déterminez si l’ID de type de contenu de l’élément de liste est égal à l’ancien ID de type de contenu. Si les ID de type de contenu ne sont pas égaux, passez à l’élément de liste suivant. Si les ID de type de contenu sont égaux, utilisez ContentType.StringId pour affecter le nouvel ID de type de contenu à l’élément de liste.

Remarque

L’ancien type de contenu figure toujours dans la liste, mais il n’est plus utilisé. Vous pouvez maintenant supprimer l’ancien type de contenu des listes, puis le retirer. Cet article explique comment remplacer uniquement les types de contenu de document. Si vous remplacez des types de contenu sur des mises en page, veillez à mettre à jour la propriété AssociatedContentType sur chaque mise en page de la collection de sites.

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();
    }
}

Voir aussi