Modules dans le modèle de complément SharePoint

L’approche que vous utilisez pour déployer des artefacts dans un environnement SharePoint est différente dans le nouveau modèle de complément SharePoint et dans le code de confiance totale. Dans un scénario standard de code de confiance totale (FTC) / solution de batterie de serveurs, les modules définis dans le code déclaratif (fichiers XML de l’infrastructure de fonctionnalités) ont été ajoutés aux fonctionnalités SharePoint. Les modules comprenaient la liste des artefacts à déployer sur le serveur SharePoint. Les modules ont été ajoutés aux fonctionnalités SharePoint et déployés via des solutions SharePoint. Lors de l’activation des fonctionnalités, les artefacts définis dans les modules ont été déployés dans l’environnement SharePoint.

Dans un scénario de modèle de complément SharePoint, le modèle d’approvisionnement à distance est utilisé pour déployer des artefacts dans des environnements SharePoint.

Terminologie

Le terme artefacts est référencé tout au long de cet article. Les artefacts font référence aux éléments qui sont généralement déployés dans un environnement SharePoint. Les artefacts incluent généralement :

  • Des fichiers JavaScript
  • CSS, fichiers
  • Fichiers image (.jpg, .gif, .png, etc.)
  • Pages maîtres
  • Mises en page
  • Éléments de liste

Conseils généraux

En règle générale, nous aimerions fournir les instructions générales suivantes pour déployer des artefacts dans des environnements SharePoint.

  • Utilisez le modèle d’approvisionnement à distance (modèle objet côté client SharePoint et API REST SharePoint) pour déployer des artefacts dans des environnements SharePoint.
  • N’utilisez pas de modules de code déclaratif ou de fichiers XML d’infrastructure de fonctionnalités pour déployer des artefacts dans des environnements SharePoint.

Débogage

L’un des principaux avantages de l’utilisation du code pour déployer des artefacts est que vous êtes en mesure de déboguer le processus de déploiement lorsque vous utilisez du code. Il est impossible de déboguer le processus de déploiement lorsque vous utilisez des modules de code déclaratif ou des fichiers XML d’infrastructure de fonctionnalités pour déployer des artefacts dans des environnements SharePoint.

Prise en main

Les exemples de code Microsoft 365 PnP suivants montrent comment créer des compléments SharePoint qui utilisent le modèle d’approvisionnement à distance pour déployer des artefacts dans un environnement SharePoint.

Cet exemple montre comment créer un dossier dans la bibliothèque de styles et ajouter des fichiers et des images JavaScript aux nouveaux fichiers.

Créer un dossier et charger des fichiers JavaScript dans le dossier

void UploadJSFiles(Web web)
{
  //Delete the folder if it exists
  Microsoft.SharePoint.Client.List list = web.Lists.GetByTitle("Style Library");
  IEnumerable<Folder> results = web.Context.LoadQuery<Folder>(list.RootFolder.Folders.Where(folder => folder.Name == "JSLink-Samples"));
  web.Context.ExecuteQuery();
  Folder samplesJSfolder = results.FirstOrDefault();

  if (samplesJSfolder != null)
  {
      samplesJSfolder.DeleteObject();
      web.Context.ExecuteQuery();
  }

  //Create new folder
  samplesJSfolder = list.RootFolder.Folders.Add("JSLink-Samples");
  web.Context.Load(samplesJSfolder);
  web.Context.ExecuteQuery();

  //Upload JavaScript files to folder
  UploadFileToFolder(web, Server.MapPath("../Scripts/JSLink-Samples/Accordion.js"), samplesJSfolder);
  UploadFileToFolder(web, Server.MapPath("../Scripts/JSLink-Samples/ConfidentialDocuments.js"), samplesJSfolder);
  UploadFileToFolder(web, Server.MapPath("../Scripts/JSLink-Samples/DisableInput.js"), samplesJSfolder);
  UploadFileToFolder(web, Server.MapPath("../Scripts/JSLink-Samples/HiddenField.js"), samplesJSfolder);
  UploadFileToFolder(web, Server.MapPath("../Scripts/JSLink-Samples/PercentComplete.js"), samplesJSfolder);
  UploadFileToFolder(web, Server.MapPath("../Scripts/JSLink-Samples/PriorityColor.js"), samplesJSfolder);
  UploadFileToFolder(web, Server.MapPath("../Scripts/JSLink-Samples/ReadOnlySPControls.js"), samplesJSfolder);
  UploadFileToFolder(web, Server.MapPath("../Scripts/JSLink-Samples/RegexValidator.js"), samplesJSfolder);
  UploadFileToFolder(web, Server.MapPath("../Scripts/JSLink-Samples/SubstringLongText.js"), samplesJSfolder);
  UploadFileToFolder(web, Server.MapPath("../Scripts/JSLink-Samples/DependentFields.js"), samplesJSfolder);

  //Create another folder inside the folder that was just created
  Folder imgsFolder = samplesJSfolder.Folders.Add("imgs");
  web.Context.Load(imgsFolder);
  web.Context.ExecuteQuery();

  //Upload image files to folder
  UploadFileToFolder(web, Server.MapPath("../Scripts/JSLink-Samples/imgs/Confidential.png"), imgsFolder);
}

Créer un dossier et charger des fichiers image dans le dossier

public static void UploadFileToFolder(Web web, string filePath, Folder folder)
{
  //Create a FileStream to the file to upload
  using (FileStream fs = new FileStream(filePath, FileMode.Open))
  {
    //Create FileCreationInformation object to set file metadata
    FileCreationInformation flciNewFile = new FileCreationInformation();

    flciNewFile.ContentStream = fs;
    flciNewFile.Url = System.IO.Path.GetFileName(filePath);
    flciNewFile.Overwrite = true;

    //Upload file to SharePoint
    Microsoft.SharePoint.Client.File uploadFile = folder.Files.Add(flciNewFile);

    //Check in the file
    uploadFile.CheckIn("CSR sample js file", CheckinType.MajorCheckIn);

    folder.Context.Load(uploadFile);
    folder.Context.ExecuteQuery();
  }
}

Cet exemple montre comment charger master pages, définir master métadonnées de page et appliquer la page master au site en définissant la CustomMasterUrl propriété sur l’objet Web.

  • Branding.ApplyBranding (Exemple de code Microsoft 365 PnP)
    • Pour plus d’informations, consultez les méthodes UploadPageLayout, CreatePublishingPage et SetSupportCaseContent dans la classe BrandingHelper.cs .
    • En plus de créer des éléments dans SharePoint, cet exemple montre comment supprimer des éléments. Les méthodes qui suppriment des éléments sont répertoriées ci-dessous à titre de référence.

Supprimer un fichier

private static void DeleteFile(Web web, string fileName, string serverPath, string serverFolder)
{
  var fileUrl = string.Concat(serverPath, serverFolder, (string.IsNullOrEmpty(serverFolder) ? string.Empty : "/"), fileName);
  var fileToDelete = web.GetFileByServerRelativeUrl(fileUrl);
  fileToDelete.DeleteObject();
  web.Context.ExecuteQuery();
}

Supprimer un dossier

public static void RemoveFolder(ClientContext clientContext, string folder, string path)
{
  var web = clientContext.Web;
  var filePath = web.ServerRelativeUrl.TrimEnd(Program.trimChars) + "/" + path + "/";
  var folderToDelete = web.GetFolderByServerRelativeUrl(string.Concat(filePath, folder));
  Console.WriteLine("Removing folder {0} from {1}", folder, path);
  folderToDelete.DeleteObject();
  clientContext.ExecuteQuery();
}

Annuler l’affectation d’une page master et supprimer la page master

public static void RemoveMasterPage(ClientContext clientContext, string name, string folder)
{
  var web = clientContext.Web;
  clientContext.Load(web, w => w.AllProperties);
  clientContext.ExecuteQuery();

  Console.WriteLine("Deactivating and removing {0} from {1}", name, web.ServerRelativeUrl);

  //set master pages back to the defaults that were being used
  if (web.AllProperties.FieldValues.ContainsKey("OriginalMasterUrl"))
  {
    web.MasterUrl = (string)web.AllProperties["OriginalMasterUrl"];
  }
  if (web.AllProperties.FieldValues.ContainsKey("CustomMasterUrl"))
  {
    web.CustomMasterUrl = (string)web.AllProperties["CustomMasterUrl"];
  }
  web.Update();
  clientContext.ExecuteQuery();

  //now that the master page is set back to its default, re-reference the web from context and delete the custom master pages
  web = clientContext.Web;
  var lists = web.Lists;
  var gallery = web.GetCatalog(116);
  clientContext.Load(lists, l => l.Include(ll => ll.DefaultViewUrl));
  clientContext.Load(gallery, g => g.RootFolder.ServerRelativeUrl);
  clientContext.ExecuteQuery();
  var masterPath = gallery.RootFolder.ServerRelativeUrl.TrimEnd(new char[] { '/' }) + "/";
  DeleteFile(web, name, masterPath, folder);
}

Supprimer une mise en page

public static void RemovePageLayout(ClientContext clientContext, string name, string folder)
{
  var web = clientContext.Web;
  var lists = web.Lists;
  var gallery = web.GetCatalog(116);
  clientContext.Load(lists, l => l.Include(ll => ll.DefaultViewUrl));
  clientContext.Load(gallery, g => g.RootFolder.ServerRelativeUrl);
  clientContext.ExecuteQuery();

  Console.WriteLine("Removing page layout {0} from {1}", name, clientContext.Web.ServerRelativeUrl);

  var masterPath = gallery.RootFolder.ServerRelativeUrl.TrimEnd(Program.trimChars) + "/";

  DeleteFile(web, name, masterPath, folder);
}

Cet exemple contient un peu de tout. Il montre comment activer les fonctionnalités de publication, charger des mises en page, créer des pages de publication, créer des listes, des types de contenu et des éléments de liste, et créer des pages de publication et ajouter des composants WebPart et des composants de complément aux pages. Il montre également comment déployer des éléments de liste sur le site web hôte et le site web de complément.

Activer les fonctionnalités de publication au niveau du site et de la collection de sites

public static void ActivePublishingFeature(ClientContext ctx)
{
  Guid publishingSiteFeatureId = new Guid("f6924d36-2fa8-4f0b-b16d-06b7250180fa");
  Guid publishingWebFeatureId = new Guid("94c94ca6-b32f-4da9-a9e3-1f3d343d7ecb");

  Site clientSite = ctx.Site;
  ctx.Load(clientSite);

  FeatureCollection clientSiteFeatures = clientSite.Features;
  ctx.Load(clientSiteFeatures);

  //Activate the site feature
  clientSiteFeatures.Add(publishingSiteFeatureId, true, FeatureDefinitionScope.Farm);
  ctx.ExecuteQuery();

  FeatureCollection clientWebFeatures = ctx.Web.Features;
  ctx.Load(clientWebFeatures);

  //Activate the web feature
  clientWebFeatures.Add(publishingWebFeatureId, true, FeatureDefinitionScope.Farm);
  ctx.ExecuteQuery();
}

Créer une liste

public static List CreateList(ClientContext ctx,
                              int templateType,
                              string title,
                              string url,
                              QuickLaunchOptions quickLaunchOptions)
{
  ListCreationInformation listCreationInfo = new ListCreationInformation
  {
    TemplateType = templateType,
    Title = title,
    Url = url,
    QuickLaunchOption = quickLaunchOptions
  };
  List spList = ctx.Web.Lists.Add(listCreationInfo);
  ctx.Load(spList);
  ctx.ExecuteQuery();

  return spList;
}

Créer un type de contenu

public static ContentType CreateContentType(ClientContext ctx, string ctyName, string group, string ctyId)
{
  ContentTypeCreationInformation contentTypeCreation = new ContentTypeCreationInformation();
  contentTypeCreation.Name = ctyName;
  contentTypeCreation.Description = "Custom Content Type";
  contentTypeCreation.Group = group;
  contentTypeCreation.Id = ctyId;

  //Add the new content type to the collection
  ContentType ct = ctx.Web.ContentTypes.Add(contentTypeCreation);
  ctx.Load(ct);
  ctx.ExecuteQuery();

  return ct;
}

Charger une mise en page

public static void UploadPageLayout(ClientContext ctx, string sourcePath, string targetListTitle, string targetUrl)
{
  using (FileStream fs = new FileStream(sourcePath, FileMode.Open, FileAccess.Read))
  {
    byte[] data = new byte[fs.Length];
    fs.Read(data, 0, data.Length);
    using (MemoryStream ms = new MemoryStream())
    {
      ms.Write(data, 0, data.Length);
      var newfile = new FileCreationInformation();
      newfile.Content = ms.ToArray();
      newfile.Url = targetUrl;
      newfile.Overwrite = true;

      List docs = ctx.Web.Lists.GetByTitle(targetListTitle);
      Microsoft.SharePoint.Client.File uploadedFile = docs.RootFolder.Files.Add(newfile);
      uploadedFile.CheckOut();
      uploadedFile.CheckIn("Data storage model", CheckinType.MajorCheckIn);
      uploadedFile.Publish("Data storage model layout.");

      ctx.Load(uploadedFile);
      ctx.ExecuteQuery();
    }
  }
}

Créer une page de publication et définir sa mise en page

public static void CreatePublishingPage(ClientContext clientContext, string pageName, string pagelayoutname, string url, string queryurl)
{
    var publishingPageName = pageName + ".aspx";

    Web web = clientContext.Web;
    clientContext.Load(web);

    List pages = web.Lists.GetByTitle("Pages");
    clientContext.Load(pages.RootFolder, f => f.ServerRelativeUrl);
    clientContext.ExecuteQuery();

    Microsoft.SharePoint.Client.File file =
        web.GetFileByServerRelativeUrl(pages.RootFolder.ServerRelativeUrl + "/" + pageName + ".aspx");
    clientContext.Load(file, f => f.Exists);
    clientContext.ExecuteQuery();
    if(file.Exists)
    {
      file.DeleteObject();
      clientContext.ExecuteQuery();
    }
    PublishingWeb publishingWeb = PublishingWeb.GetPublishingWeb(clientContext, web);
    clientContext.Load(publishingWeb);

    if (publishingWeb != null)
    {
      List publishingLayouts = clientContext.Site.RootWeb.Lists.GetByTitle("Master Page Gallery");

      ListItemCollection allItems = publishingLayouts.GetItems(CamlQuery.CreateAllItemsQuery());
      clientContext.Load(allItems, items => items.Include(item => item.DisplayName).Where(obj => obj.DisplayName == pagelayoutname));
      clientContext.ExecuteQuery();

      ListItem layout = allItems.Where(x => x.DisplayName == pagelayoutname).FirstOrDefault();
      clientContext.Load(layout);

      PublishingPageInformation publishingpageInfo = new PublishingPageInformation()
      {
        Name = publishingPageName,
        PageLayoutListItem = layout,
      };

      PublishingPage publishingPage = publishingWeb.AddPublishingPage(publishingpageInfo);
      publishingPage.ListItem.File.CheckIn(string.Empty, CheckinType.MajorCheckIn);
      publishingPage.ListItem.File.Publish(string.Empty);
      clientContext.ExecuteQuery();
    }
    SetSupportCaseContent(clientContext, "SupportCasesPage", url, queryurl);
}

Créer des éléments de liste

public static void AddDemoDataToSupportCasesList(ClientContext ctx, List list, string title,
                                                    string status, string csr, string customerID)
{
  ListItemCreationInformation itemCreateInfo = new ListItemCreationInformation();
  ListItem newItem = list.AddItem(itemCreateInfo);
  newItem["Title"] = title;
  newItem["FTCAM_Status"] = status;
  newItem["FTCAM_CSR"] = csr;
  newItem["FTCAM_CustomerID"] = customerID;
  newItem.Update();
  ctx.ExecuteQuery();
}

Approvisionner du contenu dans une page de publication (composant WebPart Contenu par recherche, composant WebPart Éditeur de script, composant Complément) et publier la page

public static void SetSupportCaseContent(ClientContext ctx, string pageName, string url, string queryurl)
{
  List pages = ctx.Web.Lists.GetByTitle("Pages");
  ctx.Load(pages.RootFolder, f => f.ServerRelativeUrl);
  ctx.ExecuteQuery();

  Microsoft.SharePoint.Client.File file =
      ctx.Web.GetFileByServerRelativeUrl(pages.RootFolder.ServerRelativeUrl + "/" + pageName + ".aspx");
  ctx.Load(file);
  ctx.ExecuteQuery();

  file.CheckOut();

  LimitedWebPartManager limitedWebPartManager = file.GetLimitedWebPartManager(PersonalizationScope.Shared);

  string quicklaunchmenuFormat =
      @"<div><a href='{0}/{1}'>Sample Home Page</a></div>
      <br />
      <div style='font-weight:bold'>CSR Dashboard</div>
      <div class='cdsm_mainmenu'>
          <ul>
              <li><a href='{0}/CSRInfo/{1}'>My CSR Info</a></li>
              <li><a href='{0}/CallQueue/{1}'>Call Queue</a></li>
              <li>
                  <span class='collapse_arrow'></span>
                  <span><a href='{0}/CustomerDashboard/{1}'>Customer Dashboard</a></span>
                  <ul>
                      <li><a href='{0}/CustomerDashboard/Orders{1}'>Recent Orders</a></li>
                      <li><a class='current' href='#'>Support Cases</a></li>
                      <li><a href='{0}/CustomerDashboard/Notes{1}'>Notes</a></li>
                  </ul>
              </li>
          </ul>
      </div>
      <div class='cdsm_submenu'>
      </div>";

  string quicklaunchmenu = string.Format(quicklaunchmenuFormat, url, queryurl);

  string qlwebPartXml = "<?xml version=\"1.0\" encoding=\"utf-8\"?><webParts><webPart xmlns=\"http://schemas.microsoft.com/WebPart/v3\"><metaData><type name=\"Microsoft.SharePoint.WebPartPages.ScriptEditorWebPart, Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c\" /><importErrorMessage>Cannot import this web part.</importErrorMessage></metaData><data><properties><property name=\"Content\" type=\"string\"><![CDATA[" + quicklaunchmenu + "​​​]]></property><property name=\"ChromeType\" type=\"chrometype\">None</property></properties></data></webPart></webParts>";
  WebPartDefinition qlWpd = limitedWebPartManager.ImportWebPart(qlwebPartXml);
  WebPartDefinition qlWpdNew = limitedWebPartManager.AddWebPart(qlWpd.WebPart, "SupportCasesZoneLeft", 0);
  ctx.Load(qlWpdNew);

  //Customer Dropdown List Script web part
  string dpwebPartXml = System.IO.File.ReadAllText(System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath + "Assets/CustomerDropDownlist.webpart");
  WebPartDefinition dpWpd = limitedWebPartManager.ImportWebPart(dpwebPartXml);
  WebPartDefinition dpWpdNew = limitedWebPartManager.AddWebPart(dpWpd.WebPart, "SupportCasesZoneTop", 0);
  ctx.Load(dpWpdNew);

  //Support Case CBS Info web part
  string cbsInfoWebPartXml = System.IO.File.ReadAllText(System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath + "Assets/SupportCaseCBSWebPartInfo.webpart");
  WebPartDefinition cbsInfoWpd = limitedWebPartManager.ImportWebPart(cbsInfoWebPartXml);
  WebPartDefinition cbsInfoWpdNew = limitedWebPartManager.AddWebPart(cbsInfoWpd.WebPart, "SupportCasesZoneMiddle", 0);
  ctx.Load(cbsInfoWpdNew);

  //Support Case Content By Search web part
  string cbswebPartXml = System.IO.File.ReadAllText(System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath + "Assets/SupportCase CBS Webpart/SupportCaseCBS.webpart");
  WebPartDefinition cbsWpd = limitedWebPartManager.ImportWebPart(cbswebPartXml);
  WebPartDefinition cbsWpdNew = limitedWebPartManager.AddWebPart(cbsWpd.WebPart, "SupportCasesZoneMiddle", 1);
  ctx.Load(cbsWpdNew);

  //Support Cases App Part
  string appPartXml = System.IO.File.ReadAllText(System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath + "Assets/SupportCaseAppPart.webpart");
  WebPartDefinition appPartWpd = limitedWebPartManager.ImportWebPart(appPartXml);
  WebPartDefinition appPartdNew = limitedWebPartManager.AddWebPart(appPartWpd.WebPart, "SupportCasesZoneBottom", 0);
  ctx.Load(appPartdNew);

  //Get Host Web Query String and show support case list web part
  string querywebPartXml = System.IO.File.ReadAllText(System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath + "Assets/GetHostWebQueryStringAndShowList.webpart");
  WebPartDefinition queryWpd = limitedWebPartManager.ImportWebPart(querywebPartXml);
  WebPartDefinition queryWpdNew = limitedWebPartManager.AddWebPart(queryWpd.WebPart, "SupportCasesZoneBottom", 1);
  ctx.Load(queryWpdNew);


  file.CheckIn("Data storage model", CheckinType.MajorCheckIn);
  file.Publish("Data storage model");
  ctx.Load(file);
  ctx.ExecuteQuery();
}
  • Pour plus d’informations sur le FillHostWebSupportCasesToThreshold déploiement d’éléments de liste sur le site web hôte et sur le site web de complément, consultez les méthodes et FillAppWebNotesListToThreshold dans la classe SharePointService.cs .

Importante

Les mêmes approches de site web hôte et de site web de complément présentées dans cet exemple peuvent être appliquées à n’importe quel type d’artefact pour les déployer à l’emplacement approprié.

Ajouter des éléments de liste à une liste dans le site web hôte

public string FillHostWebSupportCasesToThreshold()
{
  using (var clientContext = SharePointContext.CreateUserClientContextForSPHost())
  {
    List supportCasesList = clientContext.Web.Lists.GetByTitle("Support Cases");
    ListItemCreationInformation itemCreateInfo = new ListItemCreationInformation();
    for (int i = 0; i < 500; i++)
    {
      ListItem newItem = supportCasesList.AddItem(itemCreateInfo);
      newItem["Title"] = "Wrong product received." + i.ToString();
      newItem["FTCAM_Status"] = "Open";
      newItem["FTCAM_CSR"] = "bjones";
      newItem["FTCAM_CustomerID"] = "thresholds test";
      newItem.Update();
      if (i % 100 == 0)
        clientContext.ExecuteQuery();
    }
    clientContext.ExecuteQuery();


    clientContext.Load(supportCasesList, l => l.ItemCount);
    clientContext.ExecuteQuery();

    if(supportCasesList.ItemCount>=5000)
      return "The Host Web Support Cases List has " + supportCasesList.ItemCount + " items, and exceeds the threshold.";
    else
      return 500 + " items have been added to the Host Web Support Cases List. " +
        "There are " + (5000 - supportCasesList.ItemCount) + " items left to add.";
  }
}

Ajouter des éléments de liste à une liste dans le site web de complément

public string FillAppWebNotesListToThreshold()
{
  using (var clientContext = SharePointContext.CreateUserClientContextForSPAppWeb())
  {
    List notesList = clientContext.Web.Lists.GetByTitle("Notes");

    var itemCreateInfo = new ListItemCreationInformation();
    for (int i = 0; i < 500; i++)
    {
      ListIgit pushientContext.ExecuteQuery();
    }
    clientContext.ExecuteQuery();

    clientContext.Load(notesList, l => l.ItemCount);
    clientContext.ExecuteQuery();

    if (notesList.ItemCount >= 5000)
      return "The Add-in Web Notes List has " + notesList.ItemCount + " items, and exceeds the threshold.";
    else
      return 500 + " items have been added to the Add-in Web Notes List. " +
                        "There are " + (5000-notesList.ItemCount) + " items left to add.";
  }
}

Exemples PnP

S’applique à

  • Microsoft 365 Multi-locataire (MT)
  • Microsoft 365 Dedicated (D) en partie
  • SharePoint 2013 en local : partiellement

Les modèles pour les versions dédiées et en local sont identiques au complément SharePoint technique du modèle, mais il existe des différences sur les technologies qui peuvent être utilisées.