Substituir listas do SharePoint criadas a partir de definições de lista em soluções farm
Se você usou definições de lista para criar listas em sua solução farm, saiba como transformá-las em novas soluções que fornecem funcionalidade semelhante usando o CSOM (modelo de objeto cliente).
Importante
As soluções farm não podem ser migradas para o SharePoint Online. Aplicando as técnicas e o código descritos neste artigo, você pode criar uma nova solução com funcionalidades semelhantes que suas soluções de farm fornecem, que podem ser implantadas no SharePoint Online. Se você estiver usando uma abordagem de transformação local, talvez seja necessário implantar a nova solução no SharePoint Online. Se você estiver usando a abordagem de migração de conteúdo ou Swing, as ferramentas de terceiros poderão criar as listas para você. Para obter mais informações, confira Abordagens de transformação para implantar seu novo Suplemento do SharePoint.
O código neste artigo requer código adicional para fornecer uma solução totalmente funcional. Por exemplo, este artigo não discute como autenticar a Office 365, como implementar o tratamento de exceção necessário e assim por diante. Para obter exemplos de código adicionais, consulte o projeto padrões e práticas do desenvolvedor Office 365.
Observação
The code in this article is provided as-is, without warranty of any kind, either express or implied, including any implied warranties of fitness for a particular purpose, merchantability, or non-infringement.
Dica
Use as técnicas descritas neste artigo para atualizar apenas algumas listas por vez. Além disso, ao encontrar listas para atualizar, você não deve filtrar as listas por tipo de lista.
Para substituir listas criadas a partir de definições de lista usando o CSOM:
Encontre listas que foram criadas usando um modelo base específico.
Crie a nova lista usando a definição de lista fora da caixa.
Configurar configurações de lista.
Defina tipos de conteúdo na nova lista com base nos tipos de conteúdo que foram definidos na lista original.
Adicionar ou remover exibições (opcional).
Migre conteúdo da lista original para a nova lista.
Antes de começar
Idealmente, você deve examinar suas soluções farm existentes, aprender sobre as técnicas descritas neste artigo e planejar como aplicar essas técnicas às suas soluções farm existentes. Se você não está familiarizado com soluções farm ou não tem uma solução farm existente para trabalhar, pode ser útil para você:
Examine a substituição de listas criadas a partir de modelos personalizados para obter uma compreensão rápida de como as listas foram criadas declarativamente usando definições de lista.
Observação
Em Contoso.Intranet, no arquivo elements.xml para SP\ListTemplate\LTContosoLibrary, a ID do modelo de lista personalizada é 10003. Você usará isso para identificar o modelo usado para criar a lista. Examine também as configurações e as exibições definidas em sua lista.
Saiba mais sobre soluções de farm. Para obter mais informações, consulte Criar soluções de farm no SharePoint.
Localizar listas que foram criadas usando um modelo base específico
No código a seguir, o método mostra como encontrar listas que foram criadas usando um modelo base específico. Este método:
Usa o ClientContext para obter todas as listas na Web atual usando Web.Lists. A instrução Include é usada na expressão lambda para retornar uma coleção de listas. Todas as listas retornadas devem ter valores de propriedade especificados para BaseTemplate, BaseType e Title.
Para cada lista na coleção de listas retornadas, se o List.BaseTemplate for igual a 10003, adicionará a lista a uma coleção de listas a serem substituídas, chamada listsToReplace. Lembre-se de que 10003 foi o identificador do modelo de lista personalizado que revisamos no exemplo Contoso.Intranet.
static void Main(string[] args) { using (var clientContext = new ClientContext("http://w15-sp/sites/ftclab")) { Web web = clientContext.Web; ListCollection listCollection = web.Lists; clientContext.Load(listCollection, l => l.Include(list => list.BaseTemplate, list => list.BaseType, list => list.Title)); clientContext.ExecuteQuery(); var listsToReplace = new List<List>(); foreach (List list in listCollection) { // 10003 is the custom list template ID of the list template you're replacing. if (list.BaseTemplate == 10003) { listsToReplace.Add(list); } } foreach (List list in listsToReplace) { ReplaceList(clientContext, listCollection, list); } } }
Importante
No código anterior, primeiro você itera sobre o ListCollection para selecionar quais listas precisam ser modificadas e, em seguida, chame ReplaceList, que começa a modificar as listas. Esse padrão é necessário porque modificar o conteúdo de uma coleção durante a iteração sobre a coleção gera uma exceção.
Depois de identificar uma lista que deve ser substituída, ReplaceList mostra a ordem das operações a serem executadas para substituir a lista.
private static void ReplaceList(ClientContext clientContext, ListCollection listCollection, List listToBeReplaced) { var newList = CreateReplacementList(clientContext, listCollection, listToBeReplaced); SetListSettings(clientContext, listToBeReplaced, newList); SetContentTypes(clientContext, listToBeReplaced, newList); AddViews(clientContext, listToBeReplaced, newList); RemoveViews(clientContext, listToBeReplaced, newList); MigrateContent(clientContext, listToBeReplaced, newList); }
Crie uma nova lista
Para criar uma nova lista, CreateReplacementList usa ListCreationInformation.
O título da nova lista é definido como o título da lista existente, com Suplemento acrescentado a ela. A enumeração ListTemplateType é usada para definir o tipo de modelo da lista como uma biblioteca de documentos. Se você estiver criando uma lista com base em um tipo de modelo diferente, use o tipo de modelo correto. Por exemplo, se você estiver criando uma lista de calendários, use ListTemplateType.Events em vez de ListTemplateType.DocumentLibrary.
private static List CreateReplacementList(ClientContext clientContext, ListCollection lists,List listToBeReplaced)
{
var creationInformation = new ListCreationInformation
{
Title = listToBeReplaced.Title + "add-in",
TemplateType = (int) ListTemplateType.DocumentLibrary,
};
List newList = lists.Add(creationInformation);
clientContext.ExecuteQuery();
return newList;
}
Configurar configurações de lista
SetListSettings aplica as configurações de lista originais à nova lista por:
Obtendo várias configurações de lista da lista original.
Aplicando a configuração de lista da lista original à nova lista.
private static void SetListSettings(ClientContext clientContext, List listToBeReplaced, List newList)
{
clientContext.Load(listToBeReplaced,
l => l.EnableVersioning,
l => l.EnableModeration,
l => l.EnableMinorVersions,
l => l.DraftVersionVisibility );
clientContext.ExecuteQuery();
newList.EnableVersioning = listToBeReplaced.EnableVersioning;
newList.EnableModeration = listToBeReplaced.EnableModeration;
newList.EnableMinorVersions= listToBeReplaced.EnableMinorVersions;
newList.DraftVersionVisibility = listToBeReplaced.DraftVersionVisibility;
newList.Update();
clientContext.ExecuteQuery();
}
Observação
Com base em seus requisitos, as configurações de lista de suas listas originais podem ser diferentes. Examine suas configurações de lista e altere SetListSettings para garantir que suas configurações de lista originais sejam aplicadas às suas novas listas.
Definir tipos de conteúdo na nova lista
SetContentTypes define os tipos de conteúdo na nova lista por:
Obtendo informações de tipo de conteúdo da lista original.
Obtendo informações de tipo de conteúdo da nova lista.
Determinando se a lista original habilita tipos de conteúdo. Se a lista original não habilitar tipos de conteúdo, SetContentTypes sairá. Se a lista original habilitar tipos de conteúdo, SetContentTypes habilita os tipos de conteúdo na nova lista usando newList.ContentTypesEnabled = true.
Para cada tipo de conteúdo na lista original, pesquise os tipos de conteúdo na nova lista para encontrar um tipo de conteúdo correspondente com base no nome do tipo de conteúdo usando newList.ContentTypes.Any(ct => ct. Nome == contentType.Name). Se o tipo de conteúdo não estiver na nova lista, ele será adicionado à lista.
Carregar newList uma segunda vez porque AddExistingContentType pode ter alterado os tipos de conteúdo.
Para cada tipo de conteúdo em newList, determinando se o tipo de conteúdo corresponde a um tipo de conteúdo na lista original com base em ContentType.Name usando listToBeReplaced.ContentTypes.Any(ct => ct). Nome == contentType.Name). Se uma correspondência não for encontrada, o tipo de conteúdo será adicionado ao contentTypesToDelete para ser excluído da nova lista.
Excluindo o tipo de conteúdo chamando ContentType.DeleteObject.
Observação
Se você estiver usando uma abordagem de transformação no local e seus tipos de conteúdo forem implantados declarativamente usando a Estrutura de Recursos, você precisará:
- Crie novos tipos de conteúdo.
- Defina o tipo de conteúdo nos itens de lista ao migrar o conteúdo da lista original para a nova lista em MigrarContent.
private static void SetContentTypes(ClientContext clientContext, List listToBeReplaced, List newList)
{
clientContext.Load(listToBeReplaced,
l => l.ContentTypesEnabled,
l => l.ContentTypes);
clientContext.Load(newList,
l => l.ContentTypesEnabled,
l => l.ContentTypes);
clientContext.ExecuteQuery();
// If the original list doesn't use content types, do not proceed any further.
if (!listToBeReplaced.ContentTypesEnabled) return;
newList.ContentTypesEnabled = true;
newList.Update();
clientContext.ExecuteQuery();
foreach (var contentType in listToBeReplaced.ContentTypes)
{
if (!newList.ContentTypes.Any(ct => ct.Name == contentType.Name))
{
// Current content type needs to be added to the new list. Note that the content type is added to the list, not the site.
newList.ContentTypes.AddExistingContentType(contentType.Parent);
newList.Update();
clientContext.ExecuteQuery();
}
}
// Reload the content types on newList because they might have changed when AddExistingContentType was called.
clientContext.Load(newList, l => l.ContentTypes);
clientContext.ExecuteQuery();
// Remove any content types that are not needed.
var contentTypesToDelete = new List<ContentType>();
foreach (var contentType in newList.ContentTypes)
{
if (!listToBeReplaced.ContentTypes.Any(ct => ct.Name == contentType.Name))
{
// Current content type needs to be removed from new list.
contentTypesToDelete.Add(contentType);
}
}
foreach (var contentType in contentTypesToDelete)
{
contentType.DeleteObject();
}
newList.Update();
clientContext.ExecuteQuery();
}
Observação
Neste ponto, a nova lista pode aceitar conteúdo da lista original. Opcionalmente, você também pode adicionar e remover exibições.
Adicionar ou remover exibições (opcional)
Os usuários podem adicionar ou remover exibições definidas em uma lista para atender às necessidades de negócios. Por esse motivo, talvez seja necessário adicionar ou remover exibições na nova lista.
Adicionar exibições à nova lista
AddViews adiciona exibições da lista original à nova lista por:
Usando List.Views para obter todas as exibições na lista original.
Usando a expressão lambda para carregar várias propriedades de exibição na coleção de exibições .
Para cada exibição na lista original, criando uma exibição usando ViewCreationInformation.
Várias propriedades são definidas na nova exibição com base nas propriedades de exibição do modo de exibição original. O método auxiliar GetViewType é chamado para determinar o ViewType da exibição. A nova exibição é então adicionada à lista de exibições chamada viewsToCreate.
Adicionando as exibições à coleção List.Views usando o método Adicionar na coleção Views da lista.
private static void AddViews(ClientContext clientContext, List listToBeReplaced, List newList) { ViewCollection views = listToBeReplaced.Views; clientContext.Load(views, v => v.Include(view => view.Paged, view => view.PersonalView, view => view.ViewQuery, view => view.Title, view => view.RowLimit, view => view.DefaultView, view => view.ViewFields, view => view.ViewType)); clientContext.ExecuteQuery(); // Build a list of views which exist on the original list only. var viewsToCreate = new List<ViewCreationInformation>(); foreach (View view in listToBeReplaced.Views) { var createInfo = new ViewCreationInformation { Paged = view.Paged, PersonalView = view.PersonalView, Query = view.ViewQuery, Title = view.Title, RowLimit = view.RowLimit, SetAsDefaultView = view.DefaultView, ViewFields = view.ViewFields.ToArray(), ViewTypeKind = GetViewType(view.ViewType), }; viewsToCreate.Add(createInfo); } foreach (ViewCreationInformation newView in viewsToCreate) { newList.Views.Add(newView); } newList.Update(); } private static ViewType GetViewType(string viewType) { switch (viewType) { case "HTML": return ViewType.Html; case "GRID": return ViewType.Grid; case "CALENDAR": return ViewType.Calendar; case "RECURRENCE": return ViewType.Recurrence; case "CHART": return ViewType.Chart; case "GANTT": return ViewType.Gantt; default: return ViewType.None; } }
Remover exibições da nova lista
No código a seguir, RemoveViews remove exibições da nova lista por:
Obter as exibições da lista na nova lista usando a propriedade List.Views .
Para cada exibição na nova lista, determinando se essa exibição não existe na lista original, correspondendo ao título da exibição usando o modo de exibição !listToBeReplaced.Views.Any(v => v.Title == view). Título. Se uma exibição na nova lista não tiver uma exibição correspondente na lista original, adicionando a exibição a viewsToRemove.
Excluindo todas as exibições em viewsToRemove usando View.DeleteObject.
private static void RemoveViews(ClientContext clientContext, List listToBeReplaced, List newList) { // Get the list of views on the new list. clientContext.Load(newList, l => l.Views); clientContext.ExecuteQuery(); var viewsToRemove = new List<View>(); foreach (View view in newList.Views) { if (!listToBeReplaced.Views.Any(v => v.Title == view.Title)) { // If there is no matching view in the source list, add the view to the list of views to be deleted. viewsToRemove.Add(view); } } foreach (View view in viewsToRemove) { view.DeleteObject(); } newList.Update(); clientContext.ExecuteQuery(); }
Migrar conteúdo da lista original para a nova lista
MigrateContent migra o conteúdo da lista original para a nova lista por:
Recuperando o destino para copiar os arquivos ou a pasta raiz da nova lista usando List.RootFolder. A URL relativa ao servidor da pasta de lista de destino é recuperada usando Folder.ServerRelativeUrl.
Recuperando a origem dos arquivos ou a pasta raiz da lista original, usando List.RootFolder. A URL relativa ao servidor da pasta de lista e todos os arquivos na pasta raiz da origem são carregados usando o objeto clientContext .
Para cada arquivo na origem, criando newUrl, que armazena a nova URL do arquivo. newUrl é criado substituindo a pasta raiz de origem pela pasta raiz do destino.
Usando File.CopyTo para copiar o arquivo para a URL da pasta raiz de destino. Como alternativa, você pode optar por usar o método File.MoveTo para mover o arquivo para a URL de destino.
Observação
O código a seguir retorna todos os itens de lista. Em seu ambiente de produção, considere otimizar o código a seguir implementando um loop e usando várias iterações para migrar pequenas quantidades de itens de lista.
private static void MigrateContent(ClientContext clientContext, List listToBeReplaced, List newList)
{
ListItemCollection items = listToBeReplaced.GetItems(CamlQuery.CreateAllItemsQuery());
Folder destination = newList.RootFolder;
Folder source = listToBeReplaced.RootFolder;
clientContext.Load(destination,
d => d.ServerRelativeUrl);
clientContext.Load(source,
s => s.Files,
s => s.ServerRelativeUrl);
clientContext.Load(items,
i => i.IncludeWithDefaultProperties(item => item.File));
clientContext.ExecuteQuery();
foreach (File file in source.Files)
{
string newUrl = file.ServerRelativeUrl.Replace(source.ServerRelativeUrl, destination.ServerRelativeUrl);
file.CopyTo(newUrl, true);
//file.MoveTo(newUrl, MoveOperations.Overwrite);
}
clientContext.ExecuteQuery();
}
Observação
O código anterior mostra como migrar arquivos armazenados na pasta raiz de uma lista. Se sua lista tiver subpastas, você deverá adicionar código adicional para migrar as subpastas e o conteúdo delas. Se sua lista usar fluxos de trabalho, o código adicional será necessário para associar o fluxo de trabalho à nova lista.