Reemplazar archivos de SharePoint implementados mediante módulos en soluciones de granja de servidores
Si implementó archivos mediante declaración mediante módulos en soluciones de granja de servidores, obtenga información sobre cómo transformarlos en nuevas soluciones que actualicen las referencias a los archivos y proporcionen una funcionalidad similar mediante el modelo de objetos de cliente (CSOM). En el pasado, los módulos se usaban para implementar archivos como páginas maestras y diseños de página.
Importante
Las soluciones de granja no se pueden migrar a SharePoint Online. Al aplicar las técnicas y el código descritos en este artículo, puede crear una nueva solución con una funcionalidad similar a la que proporcionan las soluciones de granja de servidores, actualizar las referencias a los archivos y, a continuación, implementar la nueva solución en SharePoint Online. A continuación, puede deshabilitar la característica y retirar la solución de granja de servidores anterior.
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 describe cómo autenticarse con Office 365, cómo implementar el control de excepciones necesario, 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.
En este artículo se describe cómo usar el proceso de transformación para:
- Carga y actualización de referencias a páginas maestras
- Carga y actualización de referencias a diseños de página
Use este proceso de transformación cuando:
- Las soluciones de granja de servidores existentes usaron módulos para implementar archivos.
- Quiere reemplazar páginas maestras y diseños de página en soluciones de granja de servidores por nuevas páginas maestras y diseños de página para que se puedan migrar a SharePoint Online.
- Ha establecido los tipos de contenido de documento en páginas maestras o diseños de página en la solución de granja de servidores mediante declaración.
Antes de empezar
Lo ideal es revisar las soluciones de granja de servidores existentes, obtener información sobre las técnicas descritas en este artículo y planear cómo aplicar estas técnicas a los escenarios. Si no está familiarizado con las soluciones de granja de servidores o no tiene una solución de granja de servidores existente con la que trabajar, puede resultarle útil obtener información sobre las soluciones de granja de servidores.
Para obtener más información, vea Compilar soluciones de granja de servidores en SharePoint.
Habilitación de las características de publicación en la colección de sitios y el sitio
Antes de ejecutar el ejemplo de código, habilite las características de publicación en la colección de sitios y el sitio con los procedimientos siguientes.
Para habilitar la característica infraestructura de publicación de SharePoint Server en la colección de sitios
Abra el sitio de SharePoint y vaya a Configuración>configuración del sitio.
En Administración de colecciones de sitios, elija Características de la colección de sitios.
En Infraestructura de publicación de SharePoint Server, elija Activar.
Para habilitar la característica de publicación de SharePoint Server en el sitio
Abra el sitio de SharePoint y vaya a Configuración>configuración del sitio.
En Acciones del sitio, elija Administrar características del sitio.
En Publicación de SharePoint Server, elija Activar.
Configuración del proyecto de Visual Studio
Descargue el proyecto de ejemplo. Elija Ver sin procesar para iniciar la descarga del proyecto de ejemplo, extraer los archivos del archivo ZIP y, a continuación, vaya a la carpeta Module9/ModuleReplacement.
Abra ModuleReplacement.sln.
Abra settings.xml. Revise y actualice los siguientes atributos para satisfacer sus requisitos:
Elemento masterPage: usa el atributo file para especificar la nueva página maestra que se va a implementar en la Galería de páginas maestras y el atributo replaces para especificar la página maestra existente en la Galería de páginas maestras.
elemento pageLayout: usa el atributo file para especificar el nuevo archivo de diseño de página, el atributo replaces para especificar el archivo de diseño de página existente y otros atributos para especificar información adicional sobre el diseño de página.
<?xml version="1.0" encoding="utf-8" ?> <branding> <masterPages> <masterPage file="contoso_app.master" replaces="contoso.master"/> </masterPages> <pageLayouts> <pageLayout file="ContosoWelcomeLinksApp.aspx" replaces="ContosoWelcomeLinks.aspx" title="Contoso Welcome Links add-in" associatedContentTypeName="Contoso Web Page" defaultLayout="true" /> </pageLayouts> </branding>
En MasterPageGalleryFiles.cs, las clases MasterPageGalleryFile y LayoutFile definen objetos empresariales que almacenan información sobre las nuevas páginas maestras y diseños de página que se van a cargar en SharePoint.
Carga y actualización de referencias a páginas maestras
Para cargar y actualizar referencias a las nuevas páginas maestras en el sitio de SharePoint:
En Program.cs, agregue la siguiente instrucción using .
using System.Security;
En Program.cs, agregue los métodos siguientes para realizar la autenticación en Office 365.
static SecureString GetPassword()
{
SecureString sStrPwd = new SecureString();
try
{
Console.Write("Password: ");
for (ConsoleKeyInfo keyInfo = Console.ReadKey(true); keyInfo.Key != ConsoleKey.Enter; keyInfo = Console.ReadKey(true))
{
if (keyInfo.Key == ConsoleKey.Backspace)
{
if (sStrPwd.Length > 0)
{
sStrPwd.RemoveAt(sStrPwd.Length - 1);
Console.SetCursorPosition(Console.CursorLeft - 1, Console.CursorTop);
Console.Write(" ");
Console.SetCursorPosition(Console.CursorLeft - 1, Console.CursorTop);
}
}
else if (keyInfo.Key != ConsoleKey.Enter)
{
Console.Write("*");
sStrPwd.AppendChar(keyInfo.KeyChar);
}
}
Console.WriteLine("");
}
catch (Exception e)
{
sStrPwd = null;
Console.WriteLine(e.Message);
}
return sStrPwd;
}
static string GetUserName()
{
string strUserName = string.Empty;
try
{
Console.Write("Username: ");
strUserName = Console.ReadLine();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
strUserName = string.Empty;
}
return strUserName;
}
En Program.cs, agregue el código siguiente al método Main , que realiza las siguientes tareas:
Carga el archivo settings.xml.
Obtiene una referencia a la Galería de páginas maestras mediante GetCatalog (116).
Las páginas maestras se cargan en la Galería de páginas maestras. El identificador de la plantilla de lista de la Galería de páginas maestras es 116. Para obtener más información, vea Elemento ListTemplate (Site). Se cargan otros detalles sobre la Galería de páginas maestras, incluido el uso de List.ContentTypes para obtener los tipos de contenido asociados a la Galería de páginas maestras.
Carga las propiedades del objeto Web, incluidos Web.ContentTypes, Web.MasterUrl y Web.CustomMasterUrl.
Establece parentMasterPageContentTypeId en el identificador de tipo de contenido de las páginas maestras. Para obtener más información, vea Base Content Type Hierarchy.
Obtiene el tipo de contenido de las páginas maestras de la Galería de páginas maestras. Este tipo de contenido se usa para establecer el tipo de contenido de la nueva página maestra más adelante en este artículo.
static void Main(string[] args) { string userName = GetUserName(); SecureString pwd = GetPassword(); // End program if no credentials were entered. if (string.IsNullOrEmpty(userName) || (pwd == null)) return; using (var clientContext = new ClientContext("http://sharepoint.contoso.com")) { clientContext.AuthenticationMode = ClientAuthenticationMode.Default; clientContext.Credentials = new SharePointOnlineCredentials(userName, pwd); XDocument settings = XDocument.Load("settings.xml"); // Get a reference to the Master Page Gallery which will be used to upload new master pages. Web web = clientContext.Web; List gallery = web.GetCatalog(116); Folder folder = gallery.RootFolder; // Load additional Master Page Gallery properties. clientContext.Load(folder); clientContext.Load(gallery, g => g.ContentTypes, g => g.RootFolder.ServerRelativeUrl); // Load the content types and master page information from the web. clientContext.Load(web, w => w.ContentTypes, w => w.MasterUrl, w => w.CustomMasterUrl); clientContext.ExecuteQuery(); // Get the content type for the master page from the Master Page Gallery using the content type ID for masterpages (0x010105). const string parentMasterPageContentTypeId = "0x010105"; ContentType masterPageContentType = gallery.ContentTypes.FirstOrDefault(ct => ct.StringId.StartsWith(parentMasterPageContentTypeId)); UploadAndSetMasterPages(web, folder, clientContext, settings, masterPageContentType.StringId); } }
En Program.cs, agregue el método UploadAndSetMasterPages , que crea una lista de objetos empresariales MasterPageGalleryFile mediante:
Leer todos los elementos masterPage definidos en settings.xml.
Para cada elemento masterPage , que especifica una página maestra que se cargará en SharePoint, cargando los valores de atributo en un objeto empresarial MasterPageGalleryFile .
Para cada objeto de negocio MasterPageGalleryFile de la lista, realiza una llamada a UploadAndSetMasterPage.
private static void UploadAndSetMasterPages(Web web, Folder folder, ClientContext clientContext, XDocument settings, string contentTypeId) { IList<MasterPageGalleryFile> masterPages = (from m in settings.Descendants("masterPage") select new MasterPageGalleryFile { File = (string)m.Attribute("file"), Replaces = (string)m.Attribute("replaces"), ContentTypeId = contentTypeId }).ToList(); foreach (MasterPageGalleryFile masterPage in masterPages) { UploadAndSetMasterPage(web, folder, clientContext, masterPage); } }
En Program.cs, agregue el método UploadAndSetMasterPage , que realiza las tareas siguientes:
Comprueba la página maestra.
Carga el nuevo archivo mediante FileCreationInformation.
Obtiene el elemento de lista asociado al archivo recién cargado.
Establece varias propiedades en el elemento de lista, incluido el establecimiento del identificador de tipo de contenido del elemento de lista en el identificador de tipo de contenido de la página maestra.
Comprueba, publica y aprueba la nueva página maestra.
Si la página maestra del sitio actual o la dirección URL de la página maestra personalizada se establecen en la página maestra anterior, actualiza Web.MasterUrl oWeb.CustomMasterUrl para usar la dirección URL de página maestra recién cargada.
private static void UploadAndSetMasterPage(Web web, Folder folder, ClientContext clientContext, MasterPageGalleryFile masterPage) { using (var fileReadingStream = System.IO.File.OpenRead(masterPage.File)) { // If necessary, ensure that the master page is checked out. PublishingHelper.CheckOutFile(web, masterPage.File, folder.ServerRelativeUrl); // Use the FileCreationInformation class to upload the new file. var fileInfo = new FileCreationInformation(); fileInfo.ContentStream = fileReadingStream; fileInfo.Overwrite = true; fileInfo.Url = masterPage.File; File file = folder.Files.Add(fileInfo); // Get the list item associated with the newly uploaded master page file. ListItem item = file.ListItemAllFields; clientContext.Load(file.ListItemAllFields); clientContext.Load(file, f => f.CheckOutType, f => f.Level, f => f.ServerRelativeUrl); clientContext.ExecuteQuery(); item["ContentTypeId"] = masterPage.ContentTypeId; item["UIVersion"] = Convert.ToString(15); item["MasterPageDescription"] = "Master Page Uploaded using CSOM"; item.Update(); clientContext.ExecuteQuery(); // If necessary, check in, publish, and approve the new master page file. PublishingHelper.CheckInPublishAndApproveFile(file); // On the current site, update the master page references to use the new master page. if (web.MasterUrl.EndsWith("/" + masterPage.Replaces)) { web.MasterUrl = file.ServerRelativeUrl; } if (web.CustomMasterUrl.EndsWith("/" + masterPage.Replaces)) { web.CustomMasterUrl = file.ServerRelativeUrl; } web.Update(); clientContext.ExecuteQuery(); } }
Carga y actualización de referencias a diseños de página
Nota:
Los ejemplos de código de esta sección se basan en los ejemplos de código de la sección anterior de este artículo.
Para reemplazar los diseños de página que se implementaron mediante módulos en soluciones de granja de servidores y para cargar y actualizar referencias para usar los nuevos archivos de diseño de página:
Actualice el método Main con el código siguiente. Este código contiene pasos adicionales para cargar y actualizar referencias a archivos de diseño de página, entre los que se incluyen:
Establecer parentPageLayoutContentTypeId en el identificador de tipo de contenido del diseño de página.
Obtener un tipo de contenido que coincida con parentPageLayoutContentTypeId desde la Galería de páginas maestras.
Llamar a UploadPageLayoutsAndUpdateReferences.
static void Main(string[] args) { string userName = GetUserName(); SecureString pwd = GetPassword(); // End program if no credentials were entered. if (string.IsNullOrEmpty(userName) || (pwd == null)) return; using (var clientContext = new ClientContext("http://sharepoint.contoso.com")) { clientContext.AuthenticationMode = ClientAuthenticationMode.Default; clientContext.Credentials = new SharePointOnlineCredentials(userName, pwd); XDocument settings = XDocument.Load("settings.xml"); // Get a reference to the Master Page Gallery, which will be used to upload new master pages. Web web = clientContext.Web; List gallery = web.GetCatalog(116); Folder folder = gallery.RootFolder; // Load additional Master Page Gallery properties. clientContext.Load(folder); clientContext.Load(gallery, g => g.ContentTypes, g => g.RootFolder.ServerRelativeUrl); // Load the content types and master page information from the web. clientContext.Load(web, w => w.ContentTypes, w => w.MasterUrl, w => w.CustomMasterUrl); clientContext.ExecuteQuery(); // Get the content type for the master page from the Master Page Gallery using the content type ID for masterpages (0x010105). const string parentMasterPageContentTypeId = "0x010105"; ContentType masterPageContentType = gallery.ContentTypes.FirstOrDefault(ct => ct.StringId.StartsWith(parentMasterPageContentTypeId)); UploadAndSetMasterPages(web, folder, clientContext, settings, masterPageContentType.StringId); // Get the content type ID for the page layout, and then update references to the page layouts. const string parentPageLayoutContentTypeId = "0x01010007FF3E057FA8AB4AA42FCB67B453FFC100E214EEE741181F4E9F7ACC43278EE811"; ContentType pageLayoutContentType = gallery.ContentTypes.FirstOrDefault(ct => ct.StringId.StartsWith(parentPageLayoutContentTypeId)); UploadPageLayoutsAndUpdateReferences(web, folder, clientContext, settings, pageLayoutContentType.StringId); } }
En Program.cs, agregue el método UploadPageLayoutsAndUpdateReferences , que realiza los pasos siguientes:
Lee la información de reemplazo de diseño de página leyendo los elementos pagelayout de settings.xml, almacenando la información de reemplazo de diseño de página en objetos empresariales LayoutFile y agregando todos los objetos de negocio a una lista.
Para cada diseño de página que se va a reemplazar:
Consulta los tipos de contenido del sitio mediante Web.ContentTypes para buscar un tipo de contenido coincidente donde el nombre del tipo de contenido del sitio sea igual al associatedContentTypeName especificado en settings.xml para el nuevo diseño de página.
Llama a UploadPageLayout.
Llama a UpdatePages para actualizar las páginas existentes para usar los nuevos diseños de página.
private static void UploadPageLayoutsAndUpdateReferences(Web web, Folder folder, ClientContext clientContext, XDocument settings, string contentTypeId) { // Read the replacement settings stored in pageLayout elements in settings.xml. IList<LayoutFile> pageLayouts = (from m in settings.Descendants("pageLayout") select new LayoutFile { File = (string)m.Attribute("file"), Replaces = (string)m.Attribute("replaces"), Title = (string)m.Attribute("title"), ContentTypeId = contentTypeId, AssociatedContentTypeName = (string)m.Attribute("associatedContentTypeName"), DefaultLayout = m.Attribute("defaultLayout") != null && (bool)m.Attribute("defaultLayout") }).ToList(); // Update the content type association. foreach (LayoutFile pageLayout in pageLayouts) { ContentType associatedContentType = web.ContentTypes.FirstOrDefault(ct => ct.Name == pageLayout.AssociatedContentTypeName); pageLayout.AssociatedContentTypeId = associatedContentType.StringId; UploadPageLayout(web, folder, clientContext, pageLayout); } UpdatePages(web, clientContext, pageLayouts); }
En Program.cs, agregue el método UploadPageLayout , que realiza las tareas siguientes:
Comprueba el archivo de diseño de página.
Carga el nuevo archivo mediante FileCreationInformation.
Obtiene el elemento de lista asociado al archivo recién cargado.
Establece varias propiedades en el elemento de lista, como ContentTypeId y PublishingAssociatedContentType.
Comprueba, publica y aprueba el nuevo archivo de diseño de página.
Para quitar referencias al archivo de diseño de página anterior, llama a PublishingHelper.UpdateAvailablePageLayouts para actualizar el XML almacenado en la propiedad PageLayouts del sitio actual.
Si el valor del atributo defaultLayout del archivo de diseño de página recién cargado de settings.xml se establece en true, usa PublishingHelper.SetDefaultPageLayout para actualizar el XML almacenado en la propiedad DefaultPageLayout en el sitio actual.
private static void UploadPageLayout(Web web, Folder folder, ClientContext clientContext, LayoutFile pageLayout) { using (var fileReadingStream = System.IO.File.OpenRead(pageLayout.File)) { PublishingHelper.CheckOutFile(web, pageLayout.File, folder.ServerRelativeUrl); // Use FileCreationInformation to upload the new page layout file. var fileInfo = new FileCreationInformation(); fileInfo.ContentStream = fileReadingStream; fileInfo.Overwrite = true; fileInfo.Url = pageLayout.File; File file = folder.Files.Add(fileInfo); // Get the list item associated with the newly uploaded file. ListItem item = file.ListItemAllFields; clientContext.Load(file.ListItemAllFields); clientContext.Load(file, f => f.CheckOutType, f => f.Level, f => f.ServerRelativeUrl); clientContext.ExecuteQuery(); item["ContentTypeId"] = pageLayout.ContentTypeId; item["Title"] = pageLayout.Title; item["PublishingAssociatedContentType"] = string.Format(";#{0};#{1};#", pageLayout.AssociatedContentTypeName, pageLayout.AssociatedContentTypeId); item.Update(); clientContext.ExecuteQuery(); PublishingHelper.CheckInPublishAndApproveFile(file); PublishingHelper.UpdateAvailablePageLayouts(web, clientContext, pageLayout, file); if (pageLayout.DefaultLayout) { PublishingHelper.SetDefaultPageLayout(web, clientContext, file); } } }
En Program.cs, agregue el método UpdatePages , que realiza las tareas siguientes:
Obtiene la biblioteca Pages y, a continuación, obtiene todos los elementos de lista de la biblioteca pages .
Para cada elemento de lista, usa el campo PublishingPageLayout del elemento de lista para buscar un diseño de página coincidente para actualizar, que se especificó en settings.xml y ahora se almacena en pagelayouts . Si el campo PublishingPageLayout del elemento de lista debe actualizarse para hacer referencia al nuevo diseño de página:
Desproteger el archivo del elemento de lista mediante PublishingHelper.CheckOutFile.
Novedades la dirección URL del diseño de página para hacer referencia al nuevo archivo de diseño de página y, a continuación, actualiza el campo PublishingPageLayout del elemento de lista.
Comprueba, publica y aprueba el archivo al que hace referencia el elemento de lista.
private static void UpdatePages(Web web, ClientContext clientContext, IList<LayoutFile> pageLayouts) { // Get the Pages Library, and then get all the list items in it. List pagesList = web.Lists.GetByTitle("Pages"); var allItemsQuery = CamlQuery.CreateAllItemsQuery(); ListItemCollection items = pagesList.GetItems(allItemsQuery); clientContext.Load(items); clientContext.ExecuteQuery(); foreach (ListItem item in items) { // Only update those pages that are using a page layout which is being replaced. var pageLayout = item["PublishingPageLayout"] as FieldUrlValue; if (pageLayout != null) { LayoutFile matchingLayout = pageLayouts.FirstOrDefault(p => pageLayout.Url.EndsWith("/" + p.Replaces)); if (matchingLayout != null) { // Check out the page so that we can update the page layout. PublishingHelper.CheckOutFile(web, item); // Update the pageLayout reference. pageLayout.Url = pageLayout.Url.Replace(matchingLayout.Replaces, matchingLayout.File); item["PublishingPageLayout"] = pageLayout; item.Update(); File file = item.File; // Get the file and other attributes so that you can check in the file. clientContext.Load(file, f => f.Level, f => f.CheckOutType); clientContext.ExecuteQuery(); PublishingHelper.CheckInPublishAndApproveFile(file); } } } }