SharePoint 4 Developers

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

Configurando Formatação Condicional Programaticamente

Aprenda a como aplicar a formatação condicional em List Views manualmente e programaticamente usando o SharePoint Designer 2010 e Visual Studio 2010 respectivamente.

Oi pessoal,

Hoje quero falar um pouco sobre formatação condicional, que permite aplicarmos estilos HTML em views dependendo de critérios especificados. Isso não é algo novo no SharePoint, pois desde o MOSS 2007 isso já existia.

Nesse post vou demonstrar como aplicar formatação condicional de forma manual e programática. Fiquem ligados!

Formatação condicional no SharePoint Designer 2010

Tomemos como exemplo a lista de Grades (Notas) abaixo. Basicamente a idéia é implementar uma seleção de cores na coluna Grade para diferenciar as notas. Com base nessas notas as cores irão variar.

1_6804
Figura 1 – Lista de Grades (Notas)

Ao utilizar o SharePoint Designer 2010, essa customização fica fácil. Vá até a Lista de Grades no SharePoint Designer 2010 e abra a view chamada “All Items”, conforme Figura 2:

2_6804
Figura 2 – All Items view

O interessante é que a view pode ser visualizada de 2 maneiras (Design e Code), o que facilita nosso trabalho. Siga os passos conforme demonstrado na Figura 3 e a formatação condicional será aplicada na coluna Grade.

3_6804
Figura 3 – Formatação Condicional no SharePoint 2010

Logo após o passo 3 acima, um popup solicitará que você especifique um critério para sua condição, em outras palavras uma regra, que definirá quando aplicar as cores corretas na Lista de Grades (Notas).

44
Figura 4 – Condition Criteria

De acordo com a regr acima, defina a cor de fundo (background colour) para Verde.

OBS: Cores diferentes serão aplicadas a diferentes regras criadas.

54
Figura 5 – Background colour

Depois de configurar a regra, a formatação condicional pode ser visualizada pelas cores disponíveis, conforme Figura 6:

6_6804
Figura 6 – Cores da Formatação Condicional

A barra da formatação condicional é bastante clara, exibe todas as regras criadas. Isso permite que você configure os estilos a qualquer momento. Bastante útil!

No final obteremos a Lista de Grades desse jeito, conforme Figura 7:

7_6804
Figura 7 – Formatação Condicional aplicada à Lista de Grades (Notas)

Formatação condicional no Visual Studio 2010

Até o momento vimos como definir formatação condicional manualmente. Agora veremos como definí-la programaticamente!

Primeiro de tudo identifique a seção Xsl (da Figura 6), copie todo o conteúdo dessa seção em um arquivo xsl, conforme o código abaixo:

Code Snippet
  1. <xsl:stylesheet xmlns:x="http://www.w3.org/2001/XMLSchema" xmlns:d="http://schemas.microsoft.com/sharepoint/dsp" version="1.0" exclude-result-prefixes="xsl msxsl ddwrt" xmlns:ddwrt="http://schemas.microsoft.com/WebParts/v2/DataView/runtime" xmlns:asp="http://schemas.microsoft.com/ASPNET/20" xmlns:__designer="http://schemas.microsoft.com/WebParts/v2/DataView/designer" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:SharePoint="Microsoft.SharePoint.WebControls" xmlns:ddwrt2="urn:frontpage:internal" xmlns:o="urn:schemas-microsoft-com:office:office">
  2.   <xsl:include href="/_layouts/xsl/main.xsl"/>
  3.   <xsl:include href="/_layouts/xsl/internal.xsl"/>
  4.   <xsl:param name="AllRows" select="/dsQueryResponse/Rows/Row[$EntityName = '' or (position() &gt;= $FirstRow and position() &lt;= $LastRow)]"/>
  5.   <xsl:param name="dvt_apos">&apos;</xsl:param>
  6.   <xsl:template name="FieldRef_printTableCell_EcbAllowed.Grade" match="FieldRef[@Name='Grade']" mode="printTableCellEcbAllowed" ddwrt:dvt_mode="body" ddwrt:ghost="" xmlns:ddwrt2="urn:frontpage:internal">
  7.     <xsl:param name="thisNode" select="."/>
  8.     <xsl:param name="class" />
  9.     <td>
  10.       <xsl:attribute name="style">
  11.         <xsl:if test="normalize-space($thisNode/@Grade) = 'A'" ddwrt:cf_explicit="1" xmlns:ddwrt="http://schemas.microsoft.com/WebParts/v2/DataView/runtime">background-color: #009900;</xsl:if>
  12.         <xsl:if test="normalize-space($thisNode/@Grade) = 'B'" ddwrt:cf_explicit="1" xmlns:ddwrt="http://schemas.microsoft.com/WebParts/v2/DataView/runtime">background-color: #66FF33;</xsl:if>
  13.         <xsl:if test="normalize-space($thisNode/@Grade) = 'C'" ddwrt:cf_explicit="1" xmlns:ddwrt="http://schemas.microsoft.com/WebParts/v2/DataView/runtime">background-color: #FFFF00;</xsl:if>
  14.         <xsl:if test="normalize-space($thisNode/@Grade) = 'D'" ddwrt:cf_explicit="1" xmlns:ddwrt="http://schemas.microsoft.com/WebParts/v2/DataView/runtime">background-color: #FF9900;</xsl:if>
  15.         <xsl:if test="normalize-space($thisNode/@Grade) = 'E'" ddwrt:cf_explicit="1" xmlns:ddwrt="http://schemas.microsoft.com/WebParts/v2/DataView/runtime">background-color: #FF0000;</xsl:if>
  16.       </xsl:attribute>
  17.  
  18.       <xsl:if test="@ClassInfo='Menu' or @ListItemMenu='TRUE'">
  19.         <xsl:attribute name="height">100%</xsl:attribute>
  20.         <xsl:attribute name="onmouseover">OnChildItem(this)</xsl:attribute>
  21.       </xsl:if>
  22.       <xsl:attribute name="class">
  23.         <xsl:call-template name="getTDClassValue">
  24.           <xsl:with-param name="class" select="$class" />
  25.           <xsl:with-param name="Type" select="@Type"/>
  26.           <xsl:with-param name="ClassInfo" select="@ClassInfo"/>
  27.         </xsl:call-template>
  28.       </xsl:attribute>
  29.       <xsl:apply-templates select="." mode="PrintFieldWithECB">
  30.         <xsl:with-param name="thisNode" select="$thisNode"/>
  31.       </xsl:apply-templates>
  32.     </td>
  33.   </xsl:template>
  34. </xsl:stylesheet>

OBS: O SharePoint Designer 2010 cria uma subsection chamada xsl:attribute para armazenar a formatação condicional que você criou (Linhas 10 a 16).

Nesse exemplo criei uma feature para o deploy da Lista de Grades. Observe a estrutura da solução para você ter uma idéia do que ela é constituída:

94
Figura 8 – Solução da Formatação Condicional

OBS: Os arquivos xsl no SharePoint 2010 precisam ser disponibilizados no diretório Layouts\Xsl.

Para fazer o deploy da Lista de Grades, codifiquei o método FeatureActivated (disponível no Event Receiver da feature):

Code Snippet
  1. public override void FeatureActivated(SPFeatureReceiverProperties properties)
  2. {
  3.     SPWeb web = (SPWeb)properties.Feature.Parent;
  4.  
  5.     string grades = "Grades";
  6.  
  7.     if (web.Lists.TryGetList(grades) == null)
  8.     {
  9.         // Creating list
  10.         Guid listGuid = web.Lists.Add(grades, "", SPListTemplateType.GenericList);
  11.         SPList list = web.Lists[listGuid];
  12.         list.OnQuickLaunch = true;
  13.  
  14.         // Configuring fields
  15.         SPField title = list.Fields["Title"];
  16.         title.Title = "Name";
  17.         title.Update(true);
  18.  
  19.         list.Fields.Add("Grade", SPFieldType.Text, true);
  20.  
  21.         // Updating view
  22.         SPView mainView = list.Views[0];
  23.         mainView.ViewFields.DeleteAll();
  24.         mainView.ViewFields.Add("Attachments");
  25.         mainView.ViewFields.Add("LinkTitle");
  26.         mainView.ViewFields.Add("Grade");
  27.         mainView.XslLink = "ConditionalFormattingXsl/grades.xsl";
  28.         mainView.Update();
  29.  
  30.         // Saving changes
  31.         list.Update();
  32.     }
  33. }

OBS: Preste atenção na linha 27. Ela que faz o serviço! Sensacional.

Uma vez que a solução foi disponibilizada, ative-a e você obterá a Lista de Grades criada com a Formatação Condicional aplicada automaticamente.

8_6804
Figura 9 – Feature criada

Faça o download da solução aqui.

Para facilitar as coisas, sempre utilize o SharePoint Designer para criar formatação condicional em suas views. Então copie a seção Xsl e cole em um arquivo xsl. Evite dores de cabeça.

Espero que isso tenha te ajudado.

Referências:
http://stefan-stanev-sharepoint-blog.blogspot.com/2010/08/xsltlistviewwebpart-several-xslt-tips.html
http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.spview.xsllink.aspx
http://office.microsoft.com/en-us/sharepoint-designer-help/apply-conditional-formatting-to-a-data-view-HA010099624.aspx

[]’s,

Marcel Medina

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

Business Connectivity Services – Parte V

Explore a interface IContextProperty para obter os detalhes de conex&#227;o do BDC. Aprenda como a criar ECTs via Assembly .NET no SharePoint 2010 atrav&#233;s do Business Connectivity Services.

Oi pessoal,

Este é mais um artigo da série sobre o BCS. Aprenda a criar ECTs via Assembly .NET no SharePoint 2010 através do Business Connectivity Services!

Esta abordagem irá tirar proveito da interface IContextProperty para obter os detalhes do BDC Connection definido no BDC Model.

Divirtam-se com a leitura!

Criação de ECTs via Assembly .NET

A criação de ECTs via Assembly .NET necessita apenas o VS2010. O SPD2010 não será usado.

Esta abordagem pode ser aplicada em cenários que:

  • Precisem da criação de regras de negócios, que podem ser desenvolvidas no BDC model;
  • Utilizem databases diferentes do SQL Server, que podem ser implementadas na camada de acesso a dados;
  • Exijam o deploy de pacotes WSP para a ativação de features, que é automaticamente gerado pelo VS2010;

Se você possui alguns destes cenários, esta implementação tem um maior nível de dificuldade pelo nível de detalhes na criação do assembly .NET, que é exibido nas próximas seções do artigo.

Trabalhando com o Visual Studio 2010

O template Business Data Connectivity Model será usado neste artigo. Inicie pela abertura do VS2010 e crie um novo projeto de acordo com a Figura 1:

Solution

Figura 1 – Criação de um novo projeto e solução

Na seqüência um Wizard aparece para ajudar no setup do projeto. A URL precisa ser validada para debugging, e a solução será criada como uma Farm Solution, de acordo com a Figura 2:

1part1

Figura 2 – Wizard

OBS: Uma vez que o projeto for criado, apague as classes Entity1 e Entity1Service. Não se esqueça de apagar a entidaded criada que está disponível no BDC Designer, pois novas classes serão geradas em um novo modelo.

Camada de Acesso a Dados

Pelo fato da feature gerar um pacote WSP, decidi por disponibilizar o modelo de acesso a dados no mesmo projeto. Para a manipulação do database é necessária a adição de alguns objetos, e para propósitos de demonstração usarei o LINQ to SQL pois ser mais simples de implementar.

Adicione o LINQ to SQL ao projeto e nomeie de Dev.dbml, então adicione uma nova conexão pelo Server Explorer que utilize Windows Authentication, abra o database e arraste a tabela Contact (Parte II)de acordo com a Figura 3:

LINQtoSQL

Figura 3 – Adição da tabela Contact

Antes de manipularmos os dados da tabela Contact, uma classe que contenha métodos CRUD precisam ser criados. Crie a classe ContactManager e adicione o código abaixo, que está bem documentado:

Code Snippet
  1. public class ContactManager
  2. {
  3.     /// <summary>
  4.     /// Gets all the Contacts
  5.     /// </summary>
  6.     /// <returns>Contacts Array</returns>
  7.     public Contact[] GetContacts()
  8.     {
  9.         var contacts = new List<Contact>();
  10.  
  11.         using (DevDataContext dev = new DevDataContext())
  12.         {
  13.             contacts = (from cont in dev.Contacts
  14.                         select cont).ToList();
  15.         }
  16.         return contacts.ToArray();
  17.     }
  18.  
  19.     /// <summary>
  20.     /// Gets a specific Contact
  21.     /// </summary>
  22.     /// <param name="contactId">Contact Id</param>
  23.     /// <returns>Returns the Contact</returns>
  24.     public Contact GetContactById(int contactId)
  25.     {
  26.         var contact = new Contact();
  27.  
  28.         using (DevDataContext dev = new DevDataContext())
  29.         {
  30.             contact = (from cont in dev.Contacts
  31.                         where cont.ContactID == contactId
  32.                         select cont).First();
  33.         }
  34.         return contact;
  35.     }
  36.  
  37.     /// <summary>
  38.     /// Updates a specific Contact
  39.     /// </summary>
  40.     /// <param name="contact">Contact to be updated</param>
  41.     public void UpdateContact(Contact contact)
  42.     {
  43.         var contactDB = new Contact();
  44.  
  45.         using (DevDataContext dev = new DevDataContext())
  46.         {
  47.             contactDB = (from cont in dev.Contacts
  48.                             where cont.ContactID == contact.ContactID
  49.                             select cont).First();
  50.  
  51.             // Alters the object
  52.             contactDB.Address = contact.Address;
  53.             contactDB.City = contact.City;
  54.             contactDB.CompanyName = contact.CompanyName;
  55.             contactDB.ContactName = contact.ContactName;
  56.             contactDB.ContactTitle = contact.ContactTitle;
  57.             contactDB.Country = contact.Country;
  58.             contactDB.Email = contact.Email;
  59.             contactDB.Fax = contact.Fax;
  60.             contactDB.Phone = contact.Phone;
  61.             contactDB.PostalCode = contact.PostalCode;
  62.             contactDB.Region = contact.Region;
  63.  
  64.             // Submitting the changes
  65.             dev.Refresh(System.Data.Linq.RefreshMode.KeepChanges, contactDB);
  66.             dev.SubmitChanges();
  67.         }
  68.     }
  69.  
  70.     /// <summary>
  71.     /// Adds a Contact
  72.     /// </summary>
  73.     /// <param name="contact">New Contact</param>
  74.     public void AddContact(Contact contact)
  75.     {
  76.         using (DevDataContext dev = new DevDataContext())
  77.         {
  78.             dev.Contacts.InsertOnSubmit(contact);
  79.             dev.SubmitChanges();
  80.         }
  81.     }
  82.  
  83.     /// <summary>
  84.     /// Deletes a Contacts
  85.     /// </summary>
  86.     /// <param name="contactId">Contact Id</param>
  87.     public void DeleteContact(int contactId)
  88.     {
  89.         using (DevDataContext dev = new DevDataContext())
  90.         {
  91.             var contact = (from cont in dev.Contacts
  92.                             where cont.ContactID == contactId
  93.                             select cont).First();
  94.             dev.Contacts.DeleteOnSubmit(contact);
  95.             dev.SubmitChanges();
  96.         }
  97.     }
  98. }

OBS: Este mesmo código já foi explicado na criação de ECTs via Web Services na parte II, porém por ser importante nessa demo, o mesmo código foi reutilizado.

Crie uma partial class chamada DevDataContext, pelo fato de já termos essa classe gerada automaticamente pelo Visual Studio. Crie um novo construtor, de acordo com o código abaixo:

Code Snippet
  1. public partial class DevDataContext
  2.     {
  3.         public DevDataContext() :
  4.             base(BdcModel1.ContactService.GetConnection(), mappingSource)
  5.         {
  6.             OnCreated();
  7.         }
  8.     }

OBS: O novo construtor contém uma chamada ao método GetConnection(), que pertence à classe ContactService e retorna uma connection string, obtida diretamente pelo BDC Metadata Model (veremos adiante).

BDC Model

O Modelo de Metadados será criado utilizando os novos painéis do BDC no Visual Studio. Será criado com base na Camada de Acesso a Dados, pelo fato de utilizarmos a entidade Contact.

Utilize o painel do BDC Designer, de acordo com a Figura 4:

1and2Figura 4 – Adição da entidade Contact

Após a criação da entidade Contact, adicione um Identificador e nomeie de ContactID, também adicione os seguintes Métodos: GetConnection, ReadItem, ReadList, Delete, Update e Create. O menu de contexto nos ajuda nesse caso, conforme a Figura 5:

2

Figura 5 – Adição de Identificador e Métodos

Para adicionar e configurar métodos, a maneira mais conveniente é a utilização do painel BDC Method Details (pelo fato de gerar XML automaticamente) conforme Figura 6:

3

Figura 6 – Painel BDC Method Details

 

A Tabela 1 abaixo mostra um resumo das configurações iniciadas na Figura 6. Contendo todos os métodos e assinaturas:

Option Method Parameters Direction Type Descriptor
Create Creator Method Create returnContact Return ReturnContact
    newContact In NewContact
Create Deleter Method Delete contactID In ContactID
Create Finder Method ReadList contactList Return ContactList
Create Specific Finder Method ReadItem contact Return Contact
    contactID In ContactID
Create Updater Method Update contact In Contact
Create Blank Method GetConnection parameter Return connection
Tabela 1 – Geração automática dos métodos da entidade Contact

OBS: Por padrão um Blank Method criará um método chamado Method. Renomeie para GetConnection.

Antes de configurar os demais métodos, assegure-se de que o tipo do identificador de ContactID é System.Int32. Inicie pelo método ReadItem para configuração e clique sobre o parâmetro (conhecido como type descriptor) Contact, para a seleção de seu tipo conforme a Figura 7:

bdcmethoddetails

Figura 7 – Tipo do TypeDescriptor

O próximo passo é a adição de novos Type Descriptors ao Type Descriptor Contact através do painel BDC Explorer, que basicamente representa seus atributos. A Figura 10 mostra como adicionar Type Descriptors e a Tabela 2 seus detalhes:

6part1Figura 8 – Adição de Type Descriptors

 

Type Descriptor Tipo
Address System.String
City System.String
CompanyName System.String
ContactID System.Int32
ContactName System.String
ContactTitle System.String
Country System.String
Email System.String
Fax System.String
Phone System.String
PostalCode System.String
Region System.String
Tabela 2 – Tipos de Type Descriptors

Quando criados, os Type Descriptors serão reutilizados automaticamente ao criar outros métodos. O código abaixo exibe o XML gerado automaticamente da entidade Contact (após a configuração de todos os métodos). Extraído do arquivo BdcModel1.bdcm:

Code Snippet
  1. <Entity Name="Contact" Namespace="ContactServices.BdcModel.BdcModel1" Version="1.0.0.64">
  2.   <Properties>
  3.     <Property Name="Class" Type="System.String">ContactServices.BdcModel.BdcModel1.ContactService, BdcModel1</Property>
  4.   </Properties>
  5.   <Identifiers>
  6.     <Identifier Name="ContactID" TypeName="System.Int32" />
  7.   </Identifiers>
  8.   <Methods>
  9.     <Method Name="ReadItem">
  10.       <Parameters>
  11.         <Parameter Name="contact" Direction="Return">
  12.           <TypeDescriptor Name="Contact" TypeName="ContactServices.BdcModel.Contact, BdcModel1" IsCollection="false">
  13.             <TypeDescriptors>
  14.               <TypeDescriptor Name="Address" TypeName="System.String" />
  15.               <TypeDescriptor Name="City" TypeName="System.String" />
  16.               <TypeDescriptor Name="CompanyName" TypeName="System.String" />
  17.               <TypeDescriptor Name="ContactID" TypeName="System.Int32" IsCollection="false" IdentifierEntityName="Contact" IdentifierEntityNamespace="ContactServices.BdcModel.BdcModel1" IdentifierName="ContactID" />
  18.               <TypeDescriptor Name="ContactName" TypeName="System.String" />
  19.               <TypeDescriptor Name="ContactTitle" TypeName="System.String" />
  20.               <TypeDescriptor Name="Country" TypeName="System.String" />
  21.               <TypeDescriptor Name="Email" TypeName="System.String" />
  22.               <TypeDescriptor Name="Fax" TypeName="System.String" />
  23.               <TypeDescriptor Name="Phone" TypeName="System.String" />
  24.               <TypeDescriptor Name="PostalCode" TypeName="System.String" />
  25.               <TypeDescriptor Name="Region" TypeName="System.String" />
  26.             </TypeDescriptors>
  27.           </TypeDescriptor></Parameter>
  28.         <Parameter Name="contactID" Direction="In">
  29.           <TypeDescriptor Name="ContactID" TypeName="System.Int32" IdentifierEntityName="Contact" IdentifierEntityNamespace="ContactServices.BdcModel.BdcModel1" IdentifierName="ContactID" /></Parameter>
  30.       </Parameters>
  31.       <MethodInstances>
  32.         <MethodInstance Name="ReadItem" Type="SpecificFinder" ReturnParameterName="contact" ReturnTypeDescriptorPath="Contact" />
  33.       </MethodInstances></Method>
  34.     <Method Name="ReadList">
  35.       <Parameters>
  36.         <Parameter Name="contactList" Direction="Return">
  37.           <TypeDescriptor Name="ContactList" TypeName="System.Collections.Generic.IEnumerable`1[[ContactServices.BdcModel.Contact, BdcModel1]]" IsCollection="true">
  38.             <TypeDescriptors>
  39.               <TypeDescriptor Name="Contact" IsCollection="false" TypeName="ContactServices.BdcModel.Contact, BdcModel1">
  40.                 <TypeDescriptors>
  41.                   <TypeDescriptor Name="Address" TypeName="System.String" />
  42.                   <TypeDescriptor Name="City" TypeName="System.String" />
  43.                   <TypeDescriptor Name="CompanyName" TypeName="System.String" />
  44.                   <TypeDescriptor Name="ContactID" IdentifierEntityNamespace="ContactServices.BdcModel.BdcModel1" IdentifierEntityName="Contact" IdentifierName="ContactID" IsCollection="false" TypeName="System.Int32" />
  45.                   <TypeDescriptor Name="ContactName" TypeName="System.String" />
  46.                   <TypeDescriptor Name="ContactTitle" TypeName="System.String" />
  47.                   <TypeDescriptor Name="Country" TypeName="System.String" />
  48.                   <TypeDescriptor Name="Email" TypeName="System.String" />
  49.                   <TypeDescriptor Name="Fax" TypeName="System.String" />
  50.                   <TypeDescriptor Name="Phone" TypeName="System.String" />
  51.                   <TypeDescriptor Name="PostalCode" TypeName="System.String" />
  52.                   <TypeDescriptor Name="Region" TypeName="System.String" /></TypeDescriptors></TypeDescriptor></TypeDescriptors></TypeDescriptor></Parameter>
  53.       </Parameters>
  54.       <MethodInstances>
  55.         <MethodInstance Name="ReadList" Type="Finder" ReturnParameterName="contactList" ReturnTypeDescriptorPath="ContactList" />
  56.       </MethodInstances></Method>
  57.     <Method Name="Create">
  58.       <Parameters>
  59.         <Parameter Name="returnContact" Direction="Return">
  60.           <TypeDescriptor Name="ReturnContact" IsCollection="false" TypeName="ContactServices.BdcModel.Contact, BdcModel1">
  61.             <TypeDescriptors>
  62.               <TypeDescriptor Name="Address" TypeName="System.String" />
  63.               <TypeDescriptor Name="City" TypeName="System.String" />
  64.               <TypeDescriptor Name="CompanyName" TypeName="System.String" />
  65.               <TypeDescriptor Name="ContactID" IdentifierEntityNamespace="ContactServices.BdcModel.BdcModel1" IdentifierEntityName="Contact" IdentifierName="ContactID" IsCollection="false" TypeName="System.Int32" />
  66.               <TypeDescriptor Name="ContactName" TypeName="System.String" />
  67.               <TypeDescriptor Name="ContactTitle" TypeName="System.String" />
  68.               <TypeDescriptor Name="Country" TypeName="System.String" />
  69.               <TypeDescriptor Name="Email" TypeName="System.String" />
  70.               <TypeDescriptor Name="Fax" TypeName="System.String" />
  71.               <TypeDescriptor Name="Phone" TypeName="System.String" />
  72.               <TypeDescriptor Name="PostalCode" TypeName="System.String" />
  73.               <TypeDescriptor Name="Region" TypeName="System.String" /></TypeDescriptors></TypeDescriptor></Parameter>
  74.         <Parameter Name="newContact" Direction="In">
  75.           <TypeDescriptor Name="NewContact" IsCollection="false" TypeName="ContactServices.BdcModel.Contact, BdcModel1">
  76.             <TypeDescriptors>
  77.               <TypeDescriptor Name="Address" TypeName="System.String" CreatorField="true" />
  78.               <TypeDescriptor Name="City" TypeName="System.String" CreatorField="true" />
  79.               <TypeDescriptor Name="CompanyName" TypeName="System.String" CreatorField="true" />
  80.               <TypeDescriptor Name="ContactID" IdentifierEntityNamespace="ContactServices.BdcModel.BdcModel1" IdentifierEntityName="Contact" IdentifierName="ContactID" IsCollection="false" TypeName="System.Int32" CreatorField="true" />
  81.               <TypeDescriptor Name="ContactName" TypeName="System.String" CreatorField="true" />
  82.               <TypeDescriptor Name="ContactTitle" TypeName="System.String" CreatorField="true" />
  83.               <TypeDescriptor Name="Country" TypeName="System.String" CreatorField="true" />
  84.               <TypeDescriptor Name="Email" TypeName="System.String" CreatorField="true" />
  85.               <TypeDescriptor Name="Fax" TypeName="System.String" CreatorField="true" />
  86.               <TypeDescriptor Name="Phone" TypeName="System.String" CreatorField="true" />
  87.               <TypeDescriptor Name="PostalCode" TypeName="System.String" CreatorField="true" />
  88.               <TypeDescriptor Name="Region" TypeName="System.String" CreatorField="true" /></TypeDescriptors></TypeDescriptor></Parameter>
  89.       </Parameters>
  90.       <MethodInstances>
  91.         <MethodInstance Name="Create" Type="Creator" ReturnParameterName="returnContact" ReturnTypeDescriptorPath="ReturnContact" />
  92.       </MethodInstances></Method>
  93.     <Method Name="Update">
  94.       <Parameters>
  95.         <Parameter Name="contact" Direction="In">
  96.           <TypeDescriptor Name="Contact" IsCollection="false" TypeName="ContactServices.BdcModel.Contact, BdcModel1">
  97.             <TypeDescriptors>
  98.               <TypeDescriptor Name="Address" TypeName="System.String" UpdaterField="true" />
  99.               <TypeDescriptor Name="City" TypeName="System.String" UpdaterField="true" />
  100.               <TypeDescriptor Name="CompanyName" TypeName="System.String" UpdaterField="true" />
  101.               <TypeDescriptor Name="ContactID" IdentifierEntityNamespace="ContactServices.BdcModel.BdcModel1" IdentifierEntityName="Contact" IdentifierName="ContactID" IsCollection="false" TypeName="System.Int32" UpdaterField="true" />
  102.               <TypeDescriptor Name="ContactName" TypeName="System.String" UpdaterField="true" />
  103.               <TypeDescriptor Name="ContactTitle" TypeName="System.String" UpdaterField="true" />
  104.               <TypeDescriptor Name="Country" TypeName="System.String" UpdaterField="true" />
  105.               <TypeDescriptor Name="Email" TypeName="System.String" UpdaterField="true" />
  106.               <TypeDescriptor Name="Fax" TypeName="System.String" UpdaterField="true" />
  107.               <TypeDescriptor Name="Phone" TypeName="System.String" UpdaterField="true" />
  108.               <TypeDescriptor Name="PostalCode" TypeName="System.String" UpdaterField="true" />
  109.               <TypeDescriptor Name="Region" TypeName="System.String" UpdaterField="true" /></TypeDescriptors></TypeDescriptor></Parameter>
  110.       </Parameters>
  111.       <MethodInstances>
  112.         <MethodInstance Name="Update" Type="Updater" />
  113.       </MethodInstances></Method>
  114.     <Method Name="Delete">
  115.       <Parameters>
  116.         <Parameter Name="contactID" Direction="In">
  117.           <TypeDescriptor Name="ContactID" TypeName="System.Int32" IdentifierEntityName="Contact" IdentifierEntityNamespace="ContactServices.BdcModel.BdcModel1" IdentifierName="ContactID" /></Parameter>
  118.       </Parameters>
  119.       <MethodInstances>
  120.         <MethodInstance Name="Delete" Type="Deleter" />
  121.       </MethodInstances></Method>
  122.     <Method Name="GetConnection">
  123.       <Parameters>
  124.         <Parameter Name="parameter" Direction="Return">
  125.           <TypeDescriptor Name="connection" TypeName="System.String" /></Parameter>
  126.       </Parameters></Method>
  127.   </Methods>
  128.   </Entity>

OBS: O arquivo BdcModel1.bdcm pode ser visualizado em XML diretamente no Visual Studio, utilize o menu de contexto Open With... e então XML (Text) Editor.

BDC Model Connection

Os detalhes de conexão podem ser definidos dentro das propriedades do LobSystemInstance se você utilizar um database ou web service. Como isso se aplica no cenário dessa demo, temos o código abaixo:

Code Snippet
  1. <LobSystemInstance Name="BdcModel1">
  2.   <Properties>
  3.     <Property Name="AuthenticationMode" Type="System.String">PassThrough</Property>
  4.     <!-- AuthenticationMode can be set to PassThrough, RevertToSelf, RdbCredentials, or WindowsCredentials. -->
  5.     <Property Name="DatabaseAccessProvider" Type="System.String">SqlServer</Property>
  6.     <!-- Options:  SQL Server, OleDB, Oracle, or ODBC. -->
  7.     <Property Name="RdbConnection Data Source" Type="System.String">W2008R2Sub1</Property>
  8.     <!-- Type the database server name or the SQL Server instance name in the format SQLServer\Instance. -->
  9.     <Property Name="RdbConnection Initial Catalog" Type="System.String">Dev</Property>
  10.     <!-- Type the database name. -->
  11.     <Property Name="RdbConnection Integrated Security" Type="System.String">SSPI</Property>
  12.     <!-- Type SSPI for Integrated Security. -->
  13.     <Property Name="RdbConnection Pooling" Type="System.String">false</Property>
  14.     <!-- Type true or false for Pooling -->
  15.   </Properties>
  16. </LobSystemInstance>

OBS: Se você quiser saber mais sobre os tipos de autenticação disponíveis através do BCS, verifique a seção Referências. Basicamente o XML acima contém propriedades comumente usadas na criação de connection strings.

Métodos da Entidade do BDC Model

Durante a criação dos métodos através dos painéis do BDC, o Visual Studio ao mesmo tempo foi gerando automaticamente a classe ContactService e seus respectivos métodos. Eles ainda não estão implementados, pois estão gerando a exceção do tipo NotImplementedException.

Antes de codificarmos, você se lembra do código que contém o método GetConnection? Ele precisa retornar a connection string de um database, mas como? Exploraremos as propriedades do LobSystemInstance definidas previamente.

Mas como ler o XML que contém essas propriedades? Fácil! Apenas implemente a interface IContextProperty na classe ContactService e o BDC se encarrega do resto.

OBS: Quando um assembly possui uma classe que implementa IContextProperty, suas propriedades são inicializadas automaticamente no momento que o assembly é executado no BDC. Isso é uma mão na roda!

Adicione a referência ao assembly Microsoft.Business, que está disponível no diretório 14: \ISAPI\Microsoft.BusinessData.dll.

Observe o código abaixo, que exibe a classe ContactService:

Code Snippet
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using ContactServices.BdcModel;
  6. using Microsoft.BusinessData.SystemSpecific;
  7. using Microsoft.BusinessData.MetadataModel;
  8. using Microsoft.BusinessData.Runtime;
  9. using Microsoft.BusinessData.MetadataModel.Collections;
  10.  
  11. namespace ContactServices.BdcModel.BdcModel1
  12. {
  13.     public partial class ContactService : IContextProperty
  14.     {
  15.         private static IMethodInstance methodInstance;
  16.         private static ILobSystemInstance lobSystemInstance;
  17.         private static IExecutionContext executionContext;
  18.  
  19.         #region IContextProperty implementation
  20.  
  21.         public IMethodInstance MethodInstance
  22.         {
  23.             get { return methodInstance; }
  24.             set { methodInstance = value; }
  25.         }
  26.  
  27.         public ILobSystemInstance LobSystemInstance
  28.         {
  29.             get { return lobSystemInstance; }
  30.             set { lobSystemInstance = value; }
  31.         }
  32.  
  33.         public IExecutionContext ExecutionContext
  34.         {
  35.             get { return executionContext; }
  36.             set { executionContext = value; }
  37.         }
  38.  
  39.         #endregion
  40.  
  41.         public static Contact ReadItem(int contactID)
  42.         {
  43.             // Implement your own business rules
  44.             return new ContactManager().GetContactById(contactID);
  45.         }
  46.  
  47.         public static IEnumerable<Contact> ReadList()
  48.         {
  49.             // Implement your own business rules
  50.             return new ContactManager().GetContacts();
  51.         }
  52.  
  53.         public static Contact Create(Contact newContact)
  54.         {
  55.             if (string.IsNullOrEmpty(newContact.ContactName) || string.IsNullOrEmpty(newContact.Email) || string.IsNullOrEmpty(newContact.Phone))
  56.                 throw new ObjectNotFoundException("ContactName, Email and Phone are mandatories.");
  57.  
  58.             var manager = new ContactManager();
  59.             manager.AddContact(newContact);
  60.             return manager.GetContactById(newContact.ContactID);
  61.         }
  62.  
  63.         public static void Update(Contact contact)
  64.         {
  65.             if (string.IsNullOrEmpty(contact.ContactName) || string.IsNullOrEmpty(contact.Email) || string.IsNullOrEmpty(contact.Phone))
  66.                 throw new ObjectNotFoundException("ContactName, Email and Phone are mandatories.");
  67.  
  68.             new ContactManager().UpdateContact(contact);
  69.         }
  70.  
  71.         public static void Delete(int contactID)
  72.         {
  73.             // Implement your own business rules
  74.             new ContactManager().DeleteContact(contactID);
  75.         }
  76.  
  77.         public static string GetConnection()
  78.         {
  79.             INamedPropertyDictionary properties = lobSystemInstance.GetProperties();
  80.  
  81.             string template = "Data Source={0};Initial Catalog={1};Integrated Security={2};";
  82.  
  83.             string dataSource = "RdbConnection Data Source";
  84.             string initialCatalog = "RdbConnection Initial Catalog";
  85.             string integratedSecurity = "RdbConnection Integrated Security";
  86.  
  87.             if (!properties.ContainsKey(dataSource) || !properties.ContainsKey(initialCatalog) || !properties.ContainsKey(integratedSecurity))
  88.                 throw new Exception("LobSystemInstance does not contain a connection string");
  89.  
  90.             return string.Format(template, properties[dataSource].ToString(), properties[initialCatalog].ToString(), properties[integratedSecurity].ToString());
  91.  
  92.         }
  93.     }
  94. }

Em exceçào ao método GetConnection, todos os outros chamam métodos CRUD da classe ContactManager. Ainda, nos métodos Create e Update existe uma validação de campos obrigatórios ContactName, Email e Phone, que não podem ser nulos ou vazios pois geram uma exceção do tipo ObjectNotFoundException.

Como esperado, o método GetConnection obtém as propriedades de LobSystemInstance, que contém os detalhes de conexão do BDC, e retorna a connection string utilizada no construtor da Partial Class DevDataContext.

Criando o Pacote de Deploy

O deploy de pacotes WSP no mundo real é feito ou manualmente ou utilizando scripts, e não diretamente com a intervenção do Visual Studio. Estou apenas explicando isso para propósitos de demonstração e entendimento do STSADM.

Antes de gerar o pacotes WSP, mais algumas configurações são necessárias. Renomeie a feature para BdcModelFeature e adicione a propriedade SiteUrl no arquivo XML BdcModelFeature.Template.xml, de acordo com a Figura 9:

9_680 Figura 9 – Propriedades da Feature

Finalmente gere o pacote WSP ao selecionar Package no menu de contexto do Visual Studio. Pegue o pacote no diretório Bin e utilizando o STSADM faça o deploy utilizando os seguintes comandos:

stsadm -o addsolution -filename "ContactServices.BdcModel.wsp"

stsadm -o deploysolution -name "ContactServices.BdcModel.wsp" -allowGacDeployment –immediate

stsadm -o execadmsvcjobs

stsadm -o installfeature -filename "ContactServices.BdcModel_BdcModelFeature\feature.xml" –force

stsadm -o activatefeature -name "ContactServices.BdcModel_BdcModelFeature"

OBS: Faça o download da solução aqui.

Configurando a External List

Nesse estágio já é possível a criação da External List que proverá uma interface visual para os dados externos no SharePoint 2010. Tanto pelo SharePoint Designer quanto pela interface do SharePoint é possível a criação de External Lists, na Parte II mostrei como utilizar o SharePoint Designer para essa tarefa, e agora vou mostrar como utilizar a interface visual do SharePoint para isso.

Vá até o web site e acesse Site Actions > More Options. A Figura 10 exibe um modal dialog para selecionarmos a External List:

10
Figura 10 – Seleção da External List

Então escolha o External Content Type ContactServices.BdcModel.BdcModel1.Contact e crie a Lista Contacts, conforme exibido na Figura 11:

11_680
Figura 11 – Criação da External List Contacts

Depois disso oteremos a Lista Contacts criada. É só isso? Não, precisamos definir as permissões no BDC Service Application para este Assembly, do contrário obteremos a seguinte tela:

BDC1
Figura 12 – Acesso negado pelo Business Data Connectivity

Definindo as Permissões do BDC

Após o deploy do Assembly .NET, precisamos definir permissões apropriadas no BDC Service Application para que os usuários visualizem os dados externos. Vá ao BDC Service Application em Central Administration e encontre o Assembly .NET:

BDC2_680
Figura 13 – Procurando o .NET Assembly

Então defina os usuários que possuirão permissão para visualizar o conteúdo dos dados externos, conforme a Figura 14:

BDC3_680
Figura 14 – Definindo permissões no BDC

Ao fazer isso, dê um refresh na External List (Figura 12) e você obterá os dados externos. Smile

Esse artigo foi de um nível mais avançado pessoal, daqui para frente vocês estarão aptos a criarem seus próprios ECTs via Assemblies .NET.

A série sobre o BDC ainda nào está finalizada, da próxima vez falarei sobre como interfacear ECTs com Client Applications. Até a próxima!

Referências:
http://msdn.microsoft.com/en-us/library/ee556826(v=office.14).aspx
http://msdn.microsoft.com/en-us/library/microsoft.businessdata.systemspecific.icontextproperty(office.14).aspx

[]'s

Marcel Medina

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

Feature CopyToClipboard - Codeplex

Esta &#233; uma Feature do SharePoint 2010 que adiciona um bot&#227;o ao Ribbon, permitindo que usu&#225;rios copiem links (urls) de documentos ao clipboard.

Oi pessoal, tudo bem?

Resolvi dar uma contribuição ao mundo Open Source, pela criação de uma Feature no SharePoint 2010.

Essa feature foi criada pela necessidade dos usuários em copiar diversos links de documentos e colar em e-mails e documentos. Trata-se da Feature chamada CopyToClipboard, que possibilita que essa ação seja realizada pelo usuário sem apuros.

Basicamente a Feature contém uma Custom Action que adiciona um botão no Ribbon. A solução é composta de arquivos xml de configuração + ECMAScript (Client Object Model) + JQuery.

Gostaria de divulgar a Feature a todos. Com relação à abordagem técnica, com certeza merece um artigo exclusivo, que logo mais disponibilizarei.

Faça o deploy em seu ambiente e divulgue aos usuários. O projeto para download e mais detalhes estão disponíveis no link: http://copytoclipboard.codeplex.com/

logo-home

[]’s

Marcel Medina

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