SharePoint 4 Developers

Guia de referência adicional em desenvolvimento .NET / SharePoint

Artigo publicado na Revista .net Magazine

O artigo mostrará ao leitor uma introdução ao funcionamento de Web Parts e como desenvolver Visual Web Parts para deploy no SharePoint 2010, mostrando as novidades no desenvolvimento com o Visual Studio 2010 e como usufruir os recursos que a ferramenta oferece.
 capaOnline_net80small

Oi pessoal, tudo bem?

Gostaria de informar a todos que na Revista .net Magazine edição 80 meu artigo exclusivo sobre desenvolvimento de WebParts no SharePoint 2010 foi publicado. Seguem mais detalhes:

Do que trata o artigo

O artigo mostrará ao leitor uma introdução ao funcionamento de Web Parts e como desenvolver Visual Web Parts para deploy no SharePoint 2010, mostrando as novidades no desenvolvimento com o Visual Studio 2010 e como usufruir os recursos que a ferramenta oferece.

Para que serve

Uma maneira de customizar sites e portais no SharePoint é através da adição de Web Parts. O Visual Studio 2010 torna-se agora um poderoso aliado no desenvolvimento para o SharePoint 2010 e traz novos templates para desenvolvimento. Visual Web Parts estão entre esses novos templates que facilitam o trabalho do desenvolvedor.

Em que situação o tema é útil

Com o lançamento do SharePoint 2010 muitos desenvolvedores .NET podem iniciar o desenvolvimento nessa plataforma com mais facilidade e sem apuros, ao contrário das versões anteriores que dificultavam o acesso de novos desenvolvedores. Esse artigo traz uma abordagem para desenvolvedores .NET que desejam se beneficiar das novas funcionalidades do Visual Studio 2010 para o desenvolvimento no SharePoint 2010.

Acredito que vocês vão gostar! Já nas bancas!

Link para a revista: http://www.devmedia.com.br/post-18775-Revista--net-Magazine-Edicao-80.html

[]’s

Marcel Medina

Clique aqui para ler o mesmo conteúdo em Inglês.

Customização de Form Templates

Trabalhe com a customização de Form Templates no SharePoint 2010. O autor mostra 3 abordagens para a realização da tarefa.

Oi pessoal, tudo bem?

Tenho encontrado coisas interessantes no SharePoint Server 2010 após o projeto de migração do MOSS 2007 que trabalhei recentemente. Segue uma delas, você consegue identificar a diferença entre as Figuras 1 e 2 abaixo?

DocContentType
Figura 1 – Document Content Type

RepContentType
Figura 2 – Report Content Type

Parece óbvio não? Os botões de Salvar e Cancelar ficam evidentes, mas a principal diferença que afeta os usuários está na seleção do tipo de content type.

No exemplo das Figuras 1 e 2 foram utilizados os content types Document e Report respectivamente. Cada um deles faz referência a um tipo de Form Template.

OBS: Para efeito de comparação excluí as demais colunas que compõe o content type Report da Figura 2.

O que fazer se você precisar disponibilizar o campo Content Type Choice (Figura 1)? Vou mostrar algumas abordagens para mudar esse cenário.

Abordagem 1 - SharePoint Manager 2010

Essa ferramenta é sensacional, pois facilita muito o trabalho. Ajudando na rápida alteração dos objetos do SharePoint. Se você é SharePointer, precisa conhecer!

Utilizando a ferramenta fica muito simples de alterar o Form Template, conforme a Figura 3:

SharePointManager
Figura 3 – Alteração do Form Template

O Form Template chamado RptLibraryForm é responsável por não apresentar o campo para seleção de content types (Figura 2). Conforme Figura 3, a solução seria a alteração dos atributos DisplayFormTemplateName, EditFormTemplateName e NewFormTemplateName para um outro form, ex: DocumentLibraryForm (Esse form é o mesmo exibido na Figura 1).

Os form templates são encontrados nos content types, e eles podem ser alterados em 2 locais: no root do site collection ou em document libraries. Esse tipo de alteração seria recomendada apenas para alteração direta em document libraries, pois não recomendo mudar um objeto base do root do site collection. Qualquer erro nesse nível afetará os seu site e sub-sites!

Nesse ponto é que entra uma solução mais sustentável, com o desenvolvimento de form templates.

Abordagem 2 – Script

O script pode ser criado com um Console Application no Visual Studio ou via PowerShell.

Independente da maneira que isso será executado, o resultado será o mesmo da utilização do SharePoint Manager 2010, porém será realizado através de script.

Segue código abaixo para atualização via Console Application:

Code Snippet
  1. static void Main(string[] args)
  2. {
  3.     using (SPSite site = new SPSite("http://portal.sharepoint4developers.net"))
  4.     {
  5.         using (SPWeb web = site.RootWeb)
  6.         {
  7.             // Get the library
  8.             SPDocumentLibrary library = web.Lists["Sample"] as SPDocumentLibrary;
  9.  
  10.             // Change the form template
  11.             library.ContentTypes["Report"].DisplayFormTemplateName = "CustomLibraryForm";
  12.             library.ContentTypes["Report"].EditFormTemplateName = "CustomLibraryForm";
  13.             library.ContentTypes["Report"].NewFormTemplateName = "CustomLibraryForm";
  14.  
  15.             // Update the content type
  16.             library.ContentTypes["Report"].Update();
  17.         }
  18.     }
  19. }

OBS: O código acima é aplicado na alteração de um content type vinculado a um Document Library.

Esse é o Powershell script equivalente ao Console Application:

Powershell
Figura 4 – Powershell script

Faça o download do script aqui.

Abordagem 3 - Desenvolvimento de Form Templates

Uma solução segura é o desenvolvimento de features no SharePoint, pois os pacotes podem ser facilmente adicionados e ativados. Da mesma forma quando não utilizados, desativados e removidos.

Recomendo sempre abordagens sustentáveis, pois vão funcionar sem problemas e não te trarão dores de cabeça no futuro.

Crie uma nova solução no Visual Studio 2010 e nomeie de CustomLibraryFormSolution, conforme a Figura 5:

EmptySolution1
Figura 5 – Nova Solução

Defina a solução como uma Farm Solution, valide-a e aguarde sua criação pelo Wizard, conforme Figura 6:

EmptySolution2
Figura 6 – Wizard

Após a criação do projeto é necessária a configuração de um User Control e Feature para deploy.

Criação do User Control Custom Library Form

Esse User Control representará o novo form template que criaremos. Para começar faça o mapeamento do diretório 14\TEMPLATE\CONTROLTEMPLATES no seu projeto, conforme Figura 7:

MappedFolder1MappedFolder2
Figura 7 – Mapeamento de diretório do SharePoint

OBS: Esse mapeamento é importante para deploy do User Control no local correto.

Adicione um novo User Control nesse diretório e nomeie de CustomLibraryForm, conforme Figura 8:

UserControl
Figura 8 – User Control para criação do Form Template

OBS: Se você abrir o diretório 14\TEMPLATE\CONTROLTEMPLATES verá que contém diversos User Controls. Os principais form templates utilizados estão concentrados no arquivo DefaultTemplates.ascx.

Apague os arquivos .cs e deixe apenas o ascx disponível. Abra o User Control, delete todo o conteúdo e adicione o código abaixo:

Code Snippet
  1.    <%@ Control Language="C#"AutoEventWireup="false" %>
  2. <%@Assembly Name="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
  3. <%@Register TagPrefix="SharePoint" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" namespace="Microsoft.SharePoint.WebControls"%>
  4. <%@Register TagPrefix="ApplicationPages" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" namespace="Microsoft.SharePoint.ApplicationPages.WebControls"%>
  5. <%@Register TagPrefix="SPHttpUtility" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" namespace="Microsoft.SharePoint.Utilities"%>
  6. <%@ Register TagPrefix="wssuc" TagName="ToolBar" src="~/_controltemplates/ToolBar.ascx" %>
  7. <%@ Register TagPrefix="wssuc" TagName="ToolBarButton" src="~/_controltemplates/ToolBarButton.ascx" %>
  8.  
  9. <SharePoint:RenderingTemplate id="CustomLibraryFormCore" runat="server">
  10.     <Template>
  11.             <table class="ms-formtable" style="margin-top: 8px;" border="0" cellpadding="0" id="formTbl" cellspacing="0" width="100%">
  12.             <SharePoint:ChangeContentType runat="server"/>
  13.             <SharePoint:DocumentLibraryFields runat="server"/>
  14.             <SharePoint:ApprovalStatus runat="server"/>
  15.             </table>
  16.             <SharePoint:WebPartPageMaintenanceMessage runat="server"/>
  17.             <SharePoint:DocumentTransformersInfo runat="server"/>
  18.             <table cellpadding="0" cellspacing="0" width="100%"><tr><td class="ms-formline"><img src="/_layouts/images/blank.gif" width='1' height='1' alt="" /></td></tr></table>
  19.             <table cellpadding="0" cellspacing="0" width="100%" style="padding-top: 7px"><tr><td width="100%">
  20.             <SharePoint:ItemHiddenVersion runat="server"/>
  21.             <SharePoint:InitContentType runat="server"/>
  22.             <wssuc:ToolBar CssClass="ms-formtoolbar" id="toolBarTbl" RightButtonSeparator="&amp;#160;" runat="server">
  23.                 <Template_Buttons>
  24.                     <SharePoint:CreatedModifiedInfo runat="server"/>
  25.                 </Template_Buttons>
  26.                 <Template_RightButtons>
  27.                     <SharePoint:SaveButton runat="server"/>
  28.                     <SharePoint:GoBackButton runat="server"/>
  29.                 </Template_RightButtons>
  30.             </wssuc:ToolBar>
  31.             </td></tr></table>
  32.     </Template>
  33. </SharePoint:RenderingTemplate>
  34.  
  35. <SharePoint:RenderingTemplate id="CustomLibraryForm" runat="server">
  36.     <Template>
  37.             <SharePoint:InformationBar runat="server"/>
  38.             <wssuc:ToolBar CssClass="ms-formtoolbar" id="toolBarTbltop" RightButtonSeparator="&amp;#160;" runat="server">
  39.                 <Template_RightButtons>
  40.                     <SharePoint:SaveButton runat="server"/>
  41.                     <SharePoint:GoBackButton runat="server"/>
  42.                 </Template_RightButtons>
  43.             </wssuc:ToolBar>
  44.             <SharePoint:FormToolBar runat="server"/>
  45.             <SharePoint:FormComponent TemplateName="CustomLibraryFormCore" runat="server"/>
  46.     </Template>
  47. </SharePoint:RenderingTemplate>

OBS: O código acima foi extraído do User Control RptLibTemplate.ascx. A linha 12 foi a única linha adicionada que permite a seleção do Content Type.

Criação da Feature Custom Report

Essa feature será responsável pelo deploy de um Content Type que se utiliza do novo Form Template criado. Adicione um novo item do tipo Content Type e o nomeie de CustomReport, conforme Figura 9:

Feature2
Figura 9 – Novo Item do tipo Content Type

O Wizard será exibido conforme Figura 10, então selecione o content type base do qual o novo content type herdará as configurações.

wizard1
Figura 10 – Wizard

O XML do Content Type será exibido automaticamente após sua criação, modifique-o conforme o código abaixo:

Code Snippet
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  3.   <!-- Parent ContentType: Report (0x01010058DDEB47312E4967BFC1576B96E8C3D4) -->
  4.   <ContentType ID="0x01010058DDEB47312E4967BFC1576B96E8C3D4006440fbf80e1849a8bc00166a8703769d"
  5.                Name="Custom Report"
  6.                Group="Business Intelligence"
  7.                Description="References a Custom Form Template"
  8.                Inherits="FALSE"
  9.                Version="0">
  10.     <FieldRefs/>
  11.     <XmlDocuments>
  12.       <XmlDocument NamespaceURI="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms">
  13.         <FormTemplates xmlns="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms">
  14.           <Display>CustomLibraryForm</Display>
  15.           <Edit>CustomLibraryForm</Edit>
  16.           <New>CustomLibraryForm</New>
  17.         </FormTemplates>
  18.       </XmlDocument>
  19.     </XmlDocuments>
  20.   </ContentType>
  21. </Elements>

OBS: Assegure-se de que a linha 8 seja alterada para Inherits=”FALSE”, pois isso impede que o Form Template informado na seção XmlDocuments seja sobrescrito pela herança. O interessante é que mesmo definindo esse atributo como falso, as colunas serão herdadas automaticamente. :)

Uma feature precisa ser criada para deploy do content type. Adicione uma Feature no projeto e defina seus atributos conforme a Figura 11:

Feature2
Figura 11 – Detalhes da Feature Custom Report

Antes de qualquer coisa, check a propriedade Reset Web Server do package para garantir que o User Control seja identificado imediatamente após o deploy, conforme Figura 12:

Package
Figura 12 – Detalhes do package

OBS: Baixe a solução pronta aqui.

Form Template Customizado

Ao final da criação do form, o resultado esperado pode ser visto logo abaixo na Figura 13, que mostra a utilização do CustomLibraryForm:

CustomRepContentType
Figura 13 – Custom Form Template

OBS: Como podemos ver, trata-se do próprio form RptLibraryForm com a adição do campo Content Type Choice.

As três abordagens utilizadas funcionam muito bem. Conforme já disse, utilize sempre boas práticas e crie soluções sustentáveis.

Ao contrário da utilização de features, com scripts a solução é rápida, porém nesse caso temporária. Digo isso pois no futuro alguma coisa pode “quebrar” em função do script executado (com ou sem documentação).

Espero que esse post venha a te ajudar.

Referências:
http://msdn.microsoft.com/en-us/library/aa544142.aspx
http://msdn.microsoft.com/en-us/library/ms468437.aspx
http://msdn.microsoft.com/en-us/library/aa544154.aspx

[]’s

Marcel Medina

Clique aqui para ler o mesmo conteúdo em Inglês.

Configurando Taxonomy Field Values Programaticamente

A configura&#231;&#227;o de Taxonomy Field values pode ser comlicada, principalmente pela falta de documenta&#231;&#227;o. Nesse post eu mostro um exemplo de como se trabalhar com o novo modelo de objetos para a migra&#231;&#227;o de field values (Lookup fields X Taxonomy fields).

Oi pessoal,

Essa semana realizei a migração de Lookup Lists e Lookup fields. Fiquei impressionado pela falta de documentação e exemplos de como trabalhar com Taxonomy field values.

Nessa nota rápida vou mostrar a vocês um exemplo de como se trabalhar com o novo modelo de objetos para a migração de field values (Lookup fields X Taxonomy fields).

Premissa

Considere a seguinte Lookup List e Term Store nesse exemplo, que contém os jogadores da seleção da Copa de 2010, conforme Figura 1:

vs680 Figura 1 – Lookup List vs Taxonomy Term Store

OBS: Como você pode perceber, a decisão em migrar Lookup fields para Taxonomy fields é uma batalha. Será que vale a pena? No meu caso como estou criando um Content Type Hub, todos os Site Columns não podem possuir dependencias, então uma solução é se livrar dos Lookup fields.

Lookup fields X Taxonomy fields

Imagine uma Lista que contenha ambos os campos (fields), o primeiro mapeia a Lookup List e o segundo o Term Store. Nesse cenário o Lookup field contém valores, porém o Taxonomy field não, pois foi recentemente criado e precisa ser populado.

Como uma solução para isso, o código abaixo mapeia os Lookup field values para Taxonomy field values, também conhecido como Managed Metadata field values.

Code Snippet
  1. static void Main(string[] args)
  2. {
  3.     var url = ConfigurationManager.AppSettings["Url"].ToString();
  4.     var library = ConfigurationManager.AppSettings["Library"].ToString();
  5.  
  6.     // Leitura de XML, considere
  7.     // (key => lookup field,value => taxonomy field)
  8.     Dictionary<string, string> mappingFields = XMLHelper.ReadDictionaryXML("MappingFields.xml");
  9.  
  10.     using (SPSite site = new SPSite(url))
  11.     {
  12.         using (SPWeb web = site.RootWeb)
  13.         {
  14.             // Obtem a lista/library
  15.             SPList list = web.Lists[library];
  16.  
  17.             foreach (SPListItem item in list.Items)
  18.             {
  19.                 // Itera em todos os mapped fields
  20.                 foreach (var mappedField in mappingFields)
  21.                 {
  22.                     if (item.Fields.ContainsField(mappedField.Key))
  23.                     {
  24.                         // Atualiza sem deixar rastros
  25.                         web.Site.AllowUnsafeUpdates = true;
  26.  
  27.                         // Obtem a instancia do lookup field
  28.                         var lookupValueList = (item[mappedField.Key] as SPFieldLookupValueCollection).ToList();
  29.  
  30.                         // Obtem a instancia do taxonomy field
  31.                         TaxonomyField managedField = item[mappedField.Value] as TaxonomyField;
  32.  
  33.                         // Obtem a taxonomy session atual
  34.                         TaxonomySession session = new TaxonomySession(web.Site, false);
  35.  
  36.                         // Obtem o term store (pelo SspId)
  37.                         var termStoreCol = session.TermStores[managedField.SspId];
  38.  
  39.                         // Obtem os termos de um especifico term set (pelo TermSetId)
  40.                         var termCol = termStoreCol.GetTermSet(managedField.TermSetId).Terms;
  41.  
  42.                         var listTerms = new List<Term>();
  43.  
  44.                         // Itera em todos os lookup values
  45.                         foreach (var itemValue in lookupValueList)
  46.                         {
  47.                             string value = itemValue.LookupValue;
  48.  
  49.                             // Obtem o termo que corresponde a cada valor
  50.                             // encontrado na lista de lookup values
  51.                             var termToSet = termCol[value];
  52.  
  53.                             listTerms.Add(termToSet);
  54.                         }
  55.  
  56.                         // Define o field value utilisando a lista de termos
  57.                         managedField.SetFieldValue(item, listTerms);
  58.  
  59.                         // Salva o item
  60.                         item.SystemUpdate();
  61.  
  62.                         // Cancela unsafe updates
  63.                         web.Site.AllowUnsafeUpdates = false;
  64.                     }
  65.                 }
  66.             }
  67.         }
  68.     }
  69. }

OBS: O código acima está bem comentado, o que dispensa comentários.

Espero que essa nota rápida ajude.

Referência:
http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.taxonomy.taxonomyfield.aspx

[]’s,

Marcel Medina

Clique aqui para ler o mesmo conteúdo em Inglês.