SharePoint 4 Developers

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

Criando Content Types Programaticamente via XML

Nesse post demonstro como criar Content Types programaticamente via XML (Nota Rápida)

Oi pessoal,

Segue aqui mais uma nota rápida, agora para a criação de content types via XML. Esse tipo de abordagem não é comum, pois exige Reflection para a utilização de métodos de escopo Internal da classe SPContentType do namespace Microsoft.SharePoint.

Podemos criar Content Types utilizando XML se criarmos uma Feature para tal, porém se você possui o XML e não quer utilizar uma Feature, a única saída é utilizar Reflection como solução.

Considere o seguinte XML:

Code Snippet
  1. <Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  2.   <ContentType ID="0x0100BEBD79039D12B646B28237616422B927"
  3.                Name="Team"
  4.                Group="World Cup 2010 ContentTypes"
  5.                Version="1">
  6.     <Folder TargetName="_cts/Team" />
  7.     <XmlDocuments>
  8.       <XmlDocument NamespaceURI="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms">
  9.         <FormTemplates xmlns="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms">
  10.           <Display>ListForm</Display>
  11.           <Edit>ListForm</Edit>
  12.           <New>ListForm</New>
  13.         </FormTemplates>
  14.       </XmlDocument>
  15.     </XmlDocuments>
  16.     <FieldRefs>
  17.       <FieldRef ID="{fa564e0f-0c70-4ab9-b863-0177e6ddd247}" Name="Title" Required="TRUE" />
  18.       <FieldRef ID="{05a571ad-f9d1-4aab-a703-1af3ae393fbf}" Name="Country" Required="TRUE" />
  19.     </FieldRefs>
  20.   </ContentType>
  21.   <ContentType ID="0x0100BEBD79039D12B646B28237616422B92701"
  22.                Name="Team Player"
  23.                Group="World Cup 2010 ContentTypes"
  24.                Version="1">
  25.     <Folder TargetName="_cts/Team Player" />
  26.     <XmlDocuments>
  27.       <XmlDocument NamespaceURI="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms">
  28.         <FormTemplates xmlns="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms">
  29.           <Display>ListForm</Display>
  30.           <Edit>ListForm</Edit>
  31.           <New>ListForm</New>
  32.         </FormTemplates>
  33.       </XmlDocument>
  34.     </XmlDocuments>
  35.     <FieldRefs>
  36.       <FieldRef ID="{fa564e0f-0c70-4ab9-b863-0177e6ddd247}" Name="Title" Required="TRUE" />
  37.       <FieldRef ID="{05a571ad-f9d1-4aab-a703-1af3ae393fbf}" Name="Country" Required="TRUE" />
  38.       <FieldRef ID="{04555083-ec04-4c20-a609-42a283428374}" Name="PlayerName" Required="TRUE" />
  39.       <FieldRef ID="{2f2abeb9-ed3d-41d9-bbde-03d1150396a1}" Name="PlayerAge" Required="FALSE" />
  40.       <FieldRef ID="{ea4b814a-a18b-403a-a33a-8ea5436cb540}" Name="Position" Required="TRUE" />
  41.     </FieldRefs>
  42.   </ContentType>
  43.   <ContentType ID="0x0100BEBD79039D12B646B28237616422B92702"
  44.                Name="Team Venue"
  45.                Group="World Cup 2010 ContentTypes"
  46.                Version="1">
  47.     <Folder TargetName="_cts/Team Venue" />
  48.     <XmlDocuments>
  49.       <XmlDocument NamespaceURI="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms">
  50.         <FormTemplates xmlns="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms">
  51.           <Display>ListForm</Display>
  52.           <Edit>ListForm</Edit>
  53.           <New>ListForm</New>
  54.         </FormTemplates>
  55.       </XmlDocument>
  56.     </XmlDocuments>
  57.     <FieldRefs>
  58.       <FieldRef ID="{fa564e0f-0c70-4ab9-b863-0177e6ddd247}" Name="Title" Required="TRUE" />
  59.       <FieldRef ID="{05a571ad-f9d1-4aab-a703-1af3ae393fbf}" Name="Country" Required="TRUE" />
  60.       <FieldRef ID="{af008077-3a7e-41d9-aaca-2b0997bb5e25}" Name="HostCity" Required="TRUE" />
  61.       <FieldRef ID="{9910fa0d-c7e8-464a-9607-caba1502b7dc}" Name="Arrival" Required="FALSE" />
  62.     </FieldRefs>
  63.   </ContentType>
  64. </ Elements >

 

Para adicionar os Content Types acima podemos utilizar o seguinte trecho de código:

Code Snippet
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Xml;
  6. using System.IO;
  7. using Microsoft.SharePoint;
  8. using CommonLibrary;
  9.  
  10. namespace ContentTypes
  11. {
  12.     class Program
  13.     {
  14.         static void Main(string[] args)
  15.         {
  16.             using (SPSite site = new SPSite("http://localhost"))
  17.             {
  18.                 using (SPWeb web = site.RootWeb)
  19.                 {
  20.                     XmlDocument xmlDoc = new XmlDocument();
  21.  
  22.                     xmlDoc.Load(Path.GetFullPath("ContentTypes.xml"));
  23.  
  24.                     foreach (XmlElement fieldNode in xmlDoc.DocumentElement.ChildNodes)
  25.                     {
  26.                         SPContentType ct = ContentTypesHelper.CreateEmptyContentType();
  27.  
  28.                         XmlTextReader xmlReader = new XmlTextReader(fieldNode.OuterXml, XmlNodeType.Element, new XmlParserContext(xmlDoc.NameTable, null, "en", XmlSpace.Default));
  29.  
  30.                         ContentTypesHelper.LoadContentTypeFromXml(ct, xmlReader);
  31.  
  32.                         ContentTypesHelper.SetContentTypeScope(ct, web);
  33.  
  34.                         site.RootWeb.ContentTypes.Add(ct);
  35.  
  36.                         site.RootWeb.Update();
  37.                     }
  38.                 }
  39.             }
  40.         }
  41.     }
  42. }

 

Analisando o código acima, podemos perceber que os métodos CreateEmptyContentType, LoadContentTypeFromXml e SetContentTypeScope são responsáveis pela criação dos Content Types e estão contidos na classe utilitária ContentTypesHelper. Esses métodos utilizam Reflection e foram criados por Robert Fridén em seu blog há anos atrás e resolvi reutilizá-los.

Se analisarmos a classe Microsoft.SharePoint.SPContentType pelo .NET Reflector conseguiremos ver seus métodos de escopo Internal, conforme Figura abaixo:

reflector
Figura 1 - Classe SPContentType visualizada pelo .NET Reflector


Vejamos então o código da classe utilitária ContentTypesHelper:

Code Snippet
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Reflection;
  6. using System.Xml;
  7. using Microsoft.SharePoint;
  8.  
  9. namespace CommonLibrary
  10. {
  11.     public class ContentTypesHelper
  12.     {
  13.         /// <summary>
  14.         /// Creates an Empty Content Type
  15.         /// </summary>
  16.         public static SPContentType CreateEmptyContentType()
  17.         {
  18.             ConstructorInfo constructor = (typeof(SPContentType)).GetConstructor(
  19.                 BindingFlags.NonPublic | BindingFlags.Instance,
  20.                 null,
  21.                 Type.EmptyTypes,
  22.                 null);
  23.  
  24.             SPContentType ctype = (SPContentType)constructor.Invoke(new object[0]);
  25.  
  26.             return ctype;
  27.         }
  28.  
  29.         /// <summary>
  30.         /// Loads Content Type from XML
  31.         /// </summary>
  32.         public static void LoadContentTypeFromXml(SPContentType ctype, XmlTextReader xmlReader)
  33.         {
  34.             MethodInfo loadMethod = ctype.GetType().GetMethod("Load",
  35.                 BindingFlags.NonPublic | BindingFlags.Instance,
  36.                 null,
  37.                 new Type[] { typeof(XmlReader) },
  38.                 null);
  39.  
  40.             loadMethod.Invoke(ctype, new object[] { xmlReader });
  41.         }
  42.  
  43.         /// <summary>
  44.         /// Sets Content Type from XML
  45.         /// </summary>
  46.         public static void SetContentTypeScope(SPContentType ctype, SPWeb web)
  47.         {
  48.             string scope = web.ServerRelativeUrl.TrimStart('/');
  49.  
  50.             MethodInfo setCTScopeMethod = ctype.GetType().GetMethod(
  51.               "SetScope",
  52.               BindingFlags.NonPublic | BindingFlags.Instance,
  53.               null,
  54.               new Type[] { typeof(string) },
  55.               null);
  56.  
  57.             setCTScopeMethod.Invoke(ctype, new object[] { scope });
  58.  
  59.             PropertyInfo fieldLinksScopeProperty = ctype.FieldLinks.GetType().GetProperty(
  60.               "Scope",
  61.               BindingFlags.NonPublic | BindingFlags.Instance,
  62.               null,
  63.               typeof(string),
  64.               Type.EmptyTypes,
  65.               null);
  66.  
  67.             fieldLinksScopeProperty.SetValue(ctype.FieldLinks, scope, new object[0]);
  68.  
  69.             PropertyInfo contentTypeWebProperty = ctype.GetType().GetProperty(
  70.               "Web",
  71.               BindingFlags.NonPublic | BindingFlags.Instance,
  72.               null,
  73.               typeof(SPWeb),
  74.               Type.EmptyTypes,
  75.               null);
  76.  
  77.             contentTypeWebProperty.SetValue(ctype, web, new object[0]);
  78.         }
  79.     }
  80. }

 

No final os Content Types serão criados conforme a Figura abaixo:

cttypes
Figura 2 – Criação dos Content Types


Baixe a solução aqui.

Considerações

  • Os Site Columns não são herdados automaticamente ao utilizarmos essa abordagem. Observem que os Content Types do XML estão listando todas as colunas, o que não seria necessário se a herança funcionasse corretamente.
  • A adição da propriedade Inherits=TRUE não modifica esse comportamento.

Referências:
http://msdn.microsoft.com/en-us/library/system.reflection.bindingflags.aspx
http://www.15seconds.com/issue/050602.htm
http://vspug.com/bobsbonanza/2007/12/17/deploying-site-columns-and-content-types-to-sharepoint-webs
http://www.red-gate.com/products/reflector


[]’s

Marcel Medina

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

Criando Site Columns Programaticamente via XML

Nesse post demonstro como criar Site Columns programaticamente via XML (Nota R&#225;pida)

Oi pessoal,

De agora em diante também postarei algumas notas rápidas com dicas de desenvolvimento. Acredito que serão bastante úteis no dia-a-dia de cada um.

Nesse post demonstro como criar Site Columns programaticamente via XML.

Considere o seguinte XML de Site Columns:

Code Snippet
  1. <Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  2.   <Field Type="Choice" Description="List of countries" Required="TRUE" Format="Dropdown" FillInChoice="FALSE" Group="World Cup 2010 Columns" ID="{05A571AD-F9D1-4aab-A703-1AF3AE393FBF}" StaticName="Country" Name="Country" DisplayName="Country" Version="1">
  3.     <CHOICES>
  4.       <CHOICE>Algeria</CHOICE>
  5.       <CHOICE>Argentina</CHOICE>
  6.       <CHOICE>Australia</CHOICE>
  7.       <CHOICE>Brazil</CHOICE>
  8.       <CHOICE>Cameroon</CHOICE>
  9.       <CHOICE>Chile</CHOICE>
  10.       <CHOICE>Côte d'Ivoire</CHOICE>
  11.       <CHOICE>Denmark</CHOICE>
  12.       <CHOICE>England</CHOICE>
  13.       <CHOICE>France</CHOICE>
  14.       <CHOICE>Germany</CHOICE>
  15.       <CHOICE>Ghana</CHOICE>
  16.       <CHOICE>Greece</CHOICE>
  17.       <CHOICE>Honduras</CHOICE>
  18.       <CHOICE>Italy</CHOICE>
  19.       <CHOICE>Japan</CHOICE>
  20.       <CHOICE>Korea DPR</CHOICE>
  21.       <CHOICE>Korea Republic</CHOICE>
  22.       <CHOICE>Mexico</CHOICE>
  23.       <CHOICE>Netherlands</CHOICE>
  24.       <CHOICE>New Zealand</CHOICE>
  25.       <CHOICE>Nigeria</CHOICE>
  26.       <CHOICE>Paraguay</CHOICE>
  27.       <CHOICE>Portugal</CHOICE>
  28.       <CHOICE>Serbia</CHOICE>
  29.       <CHOICE>Slovakia</CHOICE>
  30.       <CHOICE>Slovenia</CHOICE>
  31.       <CHOICE>South Africa</CHOICE>
  32.       <CHOICE>Spain</CHOICE>
  33.       <CHOICE>Switzerland</CHOICE>
  34.       <CHOICE>Uruguay</CHOICE>
  35.       <CHOICE>USA</CHOICE>
  36.     </CHOICES>
  37.   </Field>
  38.   <Field Type="Choice" Description="List of host cities" Required="TRUE" Format="Dropdown" FillInChoice="FALSE" Group="World Cup 2010 Columns" ID="{AF008077-3A7E-41d9-AACA-2B0997BB5E25}" StaticName="HostCity" Name="HostCity" DisplayName="City" Version="1">
  39.     <Default>Johannesburg</Default>
  40.     <CHOICES>
  41.       <CHOICE>Cape Town</CHOICE>
  42.       <CHOICE>Durban</CHOICE>
  43.       <CHOICE>Johannesburg</CHOICE>
  44.       <CHOICE>Mangaung/Bloemfontein</CHOICE>
  45.       <CHOICE>Nelson Mandela Bay/Port Elizabeth</CHOICE>
  46.       <CHOICE>Nelspruit</CHOICE>
  47.       <CHOICE>Polokwane</CHOICE>
  48.       <CHOICE>Rustenburg</CHOICE>
  49.       <CHOICE>Tshwane/Pretoria</CHOICE>
  50.     </CHOICES>
  51.   </Field>
  52.   <Field Type="Choice" Description="List of players" Required="TRUE" Format="Dropdown" FillInChoice="FALSE" Group="World Cup 2010 Columns" ID="{EA4B814A-A18B-403a-A33A-8EA5436CB540}" StaticName="Position" Name="Position" DisplayName="Position" Version="1">
  53.     <CHOICES>
  54.       <CHOICE>Defensive Midfielder</CHOICE>
  55.       <CHOICE>Forward</CHOICE>
  56.       <CHOICE>Goalkeeper</CHOICE>
  57.       <CHOICE>Left Back</CHOICE>
  58.       <CHOICE>Left Midfielder</CHOICE>
  59.       <CHOICE>Right Back</CHOICE>
  60.       <CHOICE>Right Midfielder</CHOICE>
  61.       <CHOICE>Stopper</CHOICE>
  62.       <CHOICE>Striker</CHOICE>
  63.       <CHOICE>Sweeper</CHOICE>
  64.     </CHOICES>
  65.   </Field>
  66.   <Field Type="Text" Description="The name of the player" Required="TRUE" MaxLength="255" Group="World Cup 2010 Columns" ID="{04555083-EC04-4c20-A609-42A283428374}" StaticName="PlayerName" Name="PlayerName" DisplayName="Player Name"></Field>
  67.   <Field Type="Number" Description="The age of the player" Required="FALSE" Decimals="0" Group="World Cup 2010 Columns" ID="{2F2ABEB9-ED3D-41d9-BBDE-03D1150396A1}" StaticName="PlayerAge" Name="PlayerAge" DisplayName="Player Age"></Field>
  68.   <Field Type="DateTime" Description="The date of arrival" Required="FALSE" Format="DateOnly" Group="World Cup 2010 Columns" ID="{9910FA0D-C7E8-464a-9607-CABA1502B7DC}" StaticName="Arrival" Name="Arrival" DisplayName="Arrival" />
  69. </Elements>

 

Para adicionar os Site Columns acima podemos utilizar o seguinte trecho de código:

Code Snippet
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Xml;
  6. using System.IO;
  7. using Microsoft.SharePoint;
  8.  
  9. namespace SiteColumns
  10. {
  11.     public class Program
  12.     {
  13.         public static void Main(string[] args)
  14.         {
  15.             using (SPSite site = new SPSite("http://localhost/"))
  16.             {
  17.                 XmlDocument xmlDoc = new XmlDocument();
  18.  
  19.                 xmlDoc.Load(Path.GetFullPath("SiteColumns.xml"));
  20.  
  21.                 foreach (XmlElement fieldNode in xmlDoc.DocumentElement.ChildNodes)
  22.                 {
  23.                     site.RootWeb.Fields.AddFieldAsXml(fieldNode.OuterXml);
  24.                 }
  25.             }
  26.         }
  27.     }
  28. }

 

No final os Site Columns serão criados conforme a Figura abaixo:


Figura 1 – Criação dos Site Columns

Baixe a solução aqui.

[]’s

Marcel Medina

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

Error occurred in deployment step 'Add Solution': Failed to load receiver assembly

Alguns problemas na integra&#231;&#227;o Visual Studio 2010 x SharePoint Foundation 2010 ainda podem ser encontradas: Error occurred in deployment step &#39;Add Solution&#39;: Failed to load receiver assembly Microsoft.Office.SharePoint.ClientExtensions ou Could not load file or assembly Microsoft.Office.Server

Oi pessoal, tudo bem?

A integração Visual Studio 2010 x SharePoint Foundation 2010 no deploy de soluções do tipo BDC Model ainda apresenta problemas. O problema está no deploy pelo Visual Studio, justamente por não encontrar as DLLs necessárias para realizar a operação. Seguem mensagens de erro encontradas:

Problemas:

Error occurred in deployment step 'Add Solution': Failed to load receiver assembly "Microsoft.Office.SharePoint.ClientExtensions, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" for feature "<Sua Feature>: System.IO.FileNotFoundException: Could not load file or assembly 'Microsoft.Office.SharePoint.ClientExtensions, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c' or one of its dependencies. The system cannot find the file specified.
File name: 'Microsoft.Office.SharePoint.ClientExtensions, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c'
   at System.Reflection.Assembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, Assembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection)
   at System.Reflection.Assembly.InternalLoad(AssemblyName assemblyRef, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection)
   at System.Reflection.Assembly.InternalLoad(String assemblyString, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection)
   at System.Reflection.Assembly.Load(String assemblyString)
   at Microsoft.SharePoint.Administration.SPFeatureDefinition.get_ReceiverObject()

Error occurred in deployment step 'Add Solution': Could not load file or assembly 'Microsoft.Office.Server, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c' or one of its dependencies. The system cannot find the file specified.

Solução:

Para eliminar esse problema é necessário a cópia de alguns arquivos do SharePoint Server 2010, encontrados no diretório 14\ISAPI:

  • microsoft.office.sharepoint.clientextensions.dll
  • Microsoft.Office.Sharepoint.ClientExtensions.xml
  • Microsoft.Office.Server.dll
  • Microsoft.Office.Server.xml

Registre as DLLs no GAC para eliminar o problema, simplesmente copiando as DLLs para o diretório C:\Windows\assembly.

Reinicie o Visual Studio 2010 e realize o deploy de sua solução do BDC Model sem problemas!

[]’s

Marcel Medina

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