SharePoint Tip #12: Forms InfoPath em Workflows criados com Visual Studio

Criar forms InfoPath para usar com Workflows criados no Visual Studio para o SharePoint é, à partida, mais simples do que criar páginas ASPX. No entanto, apesar de existir um walk-through no SDK do MOSS 2007 (http://msdn2.microsoft.com/en-us/library/ms564355.aspx) que descreve todos os passos para criar um workflow utilizando Visual Studio e InfoPath, a parte do deployment é remetida para o SDK do WSS 3.0 (http://msdn2.microsoft.com/en-us/library/ms461324.aspx).

Seguindo todos os passos, em ambos os SDK, é possível criar com sucesso um Workflow com forms InfoPath e instalá-lo no MOSS. Mas quando chegar a altura de o associar a uma lista, o mais provável é que que o Forms Services mostre o erro Form Not Found. O problema está exactamente no deployment que não foi bem executado já que os forms InfoPath requerem um passo que não está presente em nenhum dos tutoriais.

No ficheiro de configuração da feature (feature.xml) é necessário indicar um Receiver Assembly (ou seja, um event handler que trata os eventos de instalação, activação, desactivação e desinstalação da feature) pertencente ao Office SharePoint Server, como indicado abaixo.

<Feature
 
Id="C2D16482-0891-4303-A097-60D7DA1AE41E"
 
Title=" Workflow Sample"
 
Description="Workflow sample description."
 
Version="12.0.0.0"
 
Scope="Site"
 
ReceiverAssembly = "Microsoft.Office.Workflow.Feature, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"
 
ReceiverClass = "Microsoft.Office.Workflow.Feature.WorkflowFeatureReceiver"
 
xmlns="http://schemas.microsoft.com/sharepoint/">
 
<ElementManifests>
   
<ElementManifest Location="Workflow.xml" />
 
</ElementManifests>
 
<Properties>
   
<Property Key="GloballyAvailable" Value="true" />
   
<Property Key="RegisterForms" Value="*.xsn" />
 
</Properties>
</Feature>

O Assembly indicado é instalado com o MOSS (e não com o WSS) e é responsável pelo deployment dos forms InfoPath no Office SharePoint Server. Podemos ver o resultado desse deployment acedendo à Central Administration, secção Application Management, opção Manage Form Templates. Na lista de forms instalados constam todos os que são instalados através do dito Receiver Assembly ou através da opção Upload. No entanto, a opção Upload não permite a utilização do form em Workflows.

A terceira linha assinalada no exemplo acima serve para que o Receiver Assembly saiba onde encontrar os ficheiros .XSN na pasta da feature.

Criar uma Solution para WSS 3.0

O WSS 3.0 inclui uma nova forma de empacotar componentes criados por developers num único ficheiro, designado solution file. Trata-se de um ficheiro com extensão .WSP que não é mais que um ficheiro CAB. Neste pacote podemos colocar features, assemblies, site definitions, list definitions, web parts e outros ficheiros necessários ao funcionamento do componente, tornando-o reutilizável e permitindo que seja o próprio WSS a colocar tudo no lugar adequado.

Principais Vantagens

  • Instalação e desinstalação do componente de forma simples, já que o SharePoint é que coloca os ficheiros nos locais correctos.
  • Pacote reutilizável, com tudo o que é necessário num único ficheiro.
  • Numa farm multi-servidor, permite a instalação automática em todos os servidores a partir de um único ponto.
  • Permite localização, ou seja, criação de componentes multi-língua.

Como se cria uma Solution?

Criar uma solution implica três passos:

  1. Criar o manifest.xml
  2. Estruturar as pastas e os ficheiros que compõem a solution
  3. Transformar a estrutura de pastas e ficheiros num único ficheiro com extensão .WSP

Criar o manifest.xml

O centro da solution é o ficheiro manifest.xml que deve ter obrigatoriamente esse nome e estar localizado na raíz da estrutura de pastas. Este ficheiro refere todos os ficheiros que fazem parte da solution bem como o local onde devem ser instalados. Qualquer ficheiro que não esteja referido no manifest.xml não será instalado.

Um exemplo de um ficheiro manifest.xml seria

<?xml version="1.0" encoding="utf-8" ?>
<Solution
  xmlns=http://schemas.microsoft.com/sharepoint/
  SolutionId
="42CEA020-72FC-4eea-8AD2-D2176BCB00B6"
 
ResetWebServer="TRUE">
  <Assemblies>
   
<Assembly DeploymentTarget="WebApplication" Location="MyLocalAssembly.dll" />
   
<Assembly DeploymentTarget="GlobalAssemblyCache" Location="MyGlobalAssembly.dll">
     
<SafeControls>
        <SafeControl
         
Assembly="MyGlobalAssembly.dll"
         
Namespace="MyNamespace"
         
TypeName="MyClass"
         
Safe="TRUE" />
      
</SafeControls>
   
</Assembly>
  
</Assemblies>
 
<FeatureManifests>
   
<FeatureManifest Location="MyFeatureName\Feature.xml"/>
 
</FeatureManifests>
 
<TemplateFiles>
   
<TemplateFile Location="Images\MyIcon.gif"/>
   
<TemplateFile Location="Layouts\MyCustomPage\MyPage.aspx"/>
 
</TemplateFiles>
</Solution>

A secção <Assemblies> define que assemblies instalar nos servidores e onde. Cada elemento <Assembly> descreve um assembly e o seu atributo DeploymentTarget indica se este deve ser instalado na GAC (se tiver o valor GlobalAssemblyCache) ou na pasta BIN da web application (se tiver o valor WebApplication). O atributo Location indica o local do assembly na origem (estrutura de ficheiros do pacote WSP) e no destino (na estrutura de ficheiros do servidor). Isto é particularmente importante no caso dos assemblies que devem ser instalados localmente, na pasta BIN da web application. Isto porque se o assembly não estiver na raíz do pacote a estrutura de pastas será replicada dentro da pasta BIN.

Quando um assembly representa uma web part ou um user web control, é necessário colocar uma entrada no web.config do SharePoint na secção SafeControls. Para o fazer automaticamente basta colocar o elemento <SafeControls> dentro do elemento <Assembly> em causa (ver exemplo acima).

A secção <FeatureManifests> indica que features devem ser instaladas no servidor, sendo cada uma representada pelo elemento <FeatureManifest>. Mais uma vez, o atributo Location indica o local do assembly na origem (estrutura de ficheiros do pacote WSP) e no destino (interior da pasta …\12\TEMPLATE\FEATURES) portanto, na estrutura de ficheiros do pacote WSP, as features têm que estar cada uma na sua pasta (com o nome da feature) que, por sua vez, tem que estar na raíz da estrutura de ficheiros. Dentro dessa pasta, como é exigido para todas as features, tem que existir um ficheiro Feature.xml que descreve a feature e respectivos elementos.

Todos os ficheiros referidos no Feature.xml ou nos ficheiros dos seus elementos são automaticamente processados pelo SharePoint no âmbito da solution, portanto não é necessário referi-los no manifest.xml. Esta é a excepção à regra de que apenas os ficheiros referidos no manifest.xml serão processados pelo SharePoint.

A secção <TemplateFiles> indica que ficheiros devem ser copiados para os servidores, para a pasta …\12\TEMPLATE. Cada elemento <TemplateFile> indica um ficheiro e o seu atributo Location, como descrito para outros elementos acima, indica o local do ficheiro na origem (estrutura de ficheiros do pacote WSP) e no destino (interior da pasta …\12\TEMPLATE). No exemplo acima, serão copiados dois ficheiros para a estrutura de ficheiros do SharePoint:

  • O ficheiro MyIcon.gif, cujo local no WSP é \Images\MyIcon.gif, será copiado para
    …\12\TEMPLATE\Images\MyIcon.gif
  • O ficheiro MyPage.aspx, cujo local no WSP é \Layouts\MyCustomPage\MyPage.aspx, será copiado para
    …\12\TEMPLATE\LAYOUTS\MyCustomPage\MyPage.aspx

Qualquer uma destas secções é opcional numa solution, foram usadas aqui a título de exemplo por serem também as mais comuns. Existem outras secções úteis para o deployment de ficheiros que podem ser consultadas no SDK do WSS 3.0.

Estruturar as pastas e os ficheiros

A estrutura de ficheiros da solution tem que estar de acordo com o que foi especificado no manifest.xml. No caso do exemplo acima e assumindo que a feature tem um elemento descrito num ficheiro Element.xml, a estrutura deve ser a seguinte:

manifest.xml
MyLocalAssembly.dll
MyGlobalAssembly.dll
MyFeatureName\Feature.xml
MyFeatureName\Element.xml
Images\MyIcon.gif
Layouts\MyCustomPage\MyPage.aspx

Criar o pacote WSP

O pacote WSP é um ficheiro CAB e, como tal, a sua estrutura assenta num ficheiro .DDF (Diamond Definition File) que é depois passado como parâmetro para a ferramenta makecab.exe criar o pacote. O ficheiro .DDF tem uma sintaxe semelhante à de um ficheiro .INF. Para o exemplo acima, o conteúdo deste ficheiro deve ser o seguinte:

; HEADER
.OPTION EXPLICIT
.Set CabinetNameTemplate=MyPackage.wsp
.Set DiskDirectoryTemplate=CDROM
.Set CompressionType=MSZIP
.Set UniqueFiles=Off
.Set Cabinet=On

; ROOT FOLDER
manifest.xml manifest.xml
MyLocalAssembly.dll MyLocalAssembly.dll
MyGlobalAssembly.dll MyGlobalAssembly.dll

; FEATURE FOLDER
.Set DestinationDir=MyFeatureName
MyFeatureName\Feature.xml Feature.xml
MyFeatureName\Element.xml Element.xml

; IMAGE
.Set DestinationDir=Images
Images\MyIcon.gif MyIcon.gif

; PAGE
.Set DestinationDir=Layouts\MyCustomPage
Layouts\MyCustomPage\MyPage.aspx MyPage.aspx

O caracter ponto-e-vírgula indica se trata de um comentário. A zona do cabeçalho é constante para todos os ficheiros deste tipo, com excepção da variável CabinetNameTemplate que deve ter o nome que se pretende dar ao pacote WSP. As restantes linhas listam os ficheiros que devem ser incluídos no pacote indicado em cada uma a localização do ficheiro (pathname completo incluíndo nome do ficheiro) seguida de um espaço e do nome do ficheiro. Quando se pretende especificar uma pasta de destino dentro do pacote, usa-se a variável DestinationDir atribuindo-lhe o caminho desejado.

No exemplo acima, os ficheiros manifest.xml e os dois assemblies são colocados na raíz (não foi especificada nenhuma pasta de destino). De seguida é especificada a pasta de destino /MyFeatureName e dentro desta serão colocados os ficheiros Feature.xml e Element.xml. É ainda colocada uma imagem em /Images e uma página aspx em /Layouts/MyCustomPage.

Para criar o ficheiro WSP (e assumindo que o ficheiro DDF se chama MyPackage.ddf) basta executar: makecab.exe /f MyPackage.ddf.

Nota: o meu colega Raúl Ribeiro colocou no seu blog uma forma de automatizar esta última fase do processo, através de um template de projecto para o Visual Studio 2005. Vejam aqui.