BCS no Sharepoint 2010: Problema Double Hop e Funcões Básicas

UPDATE: Adicionado o código fonte do Web Service de exemplo com os dados para facilitar a vida
Nome do arquivo: webServiceExemplo.zip

http://code.msdn.microsoft.com/matchboxtech

Em minha nova empreitada, fui encarregado de desenvolver uma POC(Prova de Conceito) com o objetivo de integrar o Sharepoint 2010 com um sistema de BI legado (digo legado pois foi desenvolvido inHouse). O cliente gostaria de ter a opção de também adicionar mais uma feature em seu software : Integração com  Sharepoint.

E partindo do princípio, o que é BCS?

BCS ou Business Connectivity Services é um novo serviço disponível no Sharepoint 2010 que veio dar um upgrade no antigo BDC do  2007. Com ele, é possível conectar-se a dados externos (Banco de Dados e/ou Web Services)  representa-los dentro do Sharepoint através de uma EXTERNAL LIST e o melhor, ter a possibilidade de usar as funcionalidade de  CRUD (Create, Update and Delete) nos itens externos. Ou seja, não apenas consultamos os dados mas também disponibilizamos ao usuário uma interface de atualização desses dados EXTERNOS através do Sharepoint. Sexy não?

Para um overwview completo da solução. Recomendo o estudo do seguinte diagrama:

Business Connectivity Services Model

Visio (http://go.microsoft.com/fwlink/?LinkId=165565)
PDF (http://go.microsoft.com/fwlink/?LinkID=165566)
XPS (http://go.microsoft.com/fwlink/?LinkId=165571)

Parece complexo, mas olhando por blocos, fica bem fácil o entendimento.

Voltando ao assunto da POC, no meu caso, foi necessário criar um WebService (preferível WCF) que buscasse os dados no legado (banco de dados SQL Server )e o deixassem disponíveis para utilização. Com esse serviço pronto, foram criados dois web métodos:

getList(string user) – Método que retornava os dados sem nenhuma espécie de filtro (Select * from tabela, por exemplo)

getItem(string user, int id) – Método que retornava o dado filtrado através de um click em algum dos itens retornados do método acima. Recebia um ID como parâmetro

Advertência: Double Hop

Antes de mais nada, aqui existe uma ótima explicação sobre o doube Hop

http://blogs.msdn.com/b/knowledgecast/archive/2007/01/31/the-double-hop-problem.aspx

Existe um terror que cerca as pessoas que trabalham com BCS. O problema Double Hop. Resumindo e deixando de forma bem clara, tudo ocorre quando estamos trabalhando consumindo informações de diferentes máquinas e onde é necessário saber qual é o usuário que está acessando o contexto.  Esse problema ocorre em redes onde a autenticação é NTLM. Se fosse Kerberus, não ocorria

Infelizmente praticamente 90% dos clientes que já visitei utilizam o NTLM.  Na prática, você hospeda o serviço que você desenvolveu acima em um Application Pool que não aceita conexões anônimas e espera que a autenticação Windows integrated funcione. Bem, não vai rolar.

Então você me pergunta: Ué? Deixa acesso anônimo e pega os dados. Foi a primeira coisa que sugeri. Mas ai vem o cliente e diz: Eu preciso saber qual está acessando o web service para eu retornar os dados permissionados, pois nossa aplicação permissiona os dados de acordo com o contexto do cliente. Perdeu playboy. Smiley triste

Dai veio a solução. Passar o usuário que está acessando o serviço como parâmetro. Mais abaixo mostro como fazer isso

Vamos lá:

1)SPD2010: Criar o External Content Type

a) Abra o Sharepoint Designer 2010 e acesse o site desejado

b) Vamos criar um novo External Content Type

image

c) Clique no botão

image

d) Clique em Name  e de o nome de “MatchBoxContentType”

e) Clique em External System e você terá a seguintes opções abaixo. Escolha a WCF Service.

image 

f) Agora você irá precisar indicar qual a url do seu serviço. Confira a configuração abaixo. Observe que no Service Metadada URL minha URL possui ?wsdl no final e no Service Endpoint URL somente o endereço terminando com .svc

image

O resto, deixe como está. Clique em OK.

g) Acessando o serviço recém criado, você precisa mapear agora qual método irá retornar os dados (ReadList) e qual método irá retornar os dados quando ocorrer um clique na external list criada.(ReadItem)

image

h) Clique com o botão direito em cima do método GetList e seleciona a opção New Read List Operation

i) Primeira tela do Wizard. deixe como está: NEXT

j) Segunda tela do Wizard. AI vem o segredo, vamos recordar o que falamos acima do Double Hop

– Falamos que para solucionar o Double Hop, deveríamos passar o login do usuário para o serviço. Mas como faço isso somente configurando os dados. Aqui vai a solução:

Na segunda tela do Wizard, selecione o parametro USER e clique em FILTER. Utilize a seleção abaixo:

image

O filtro USER CONTEXT é responsável por pegar o loginname do usuário que está acessando o serviço e o passa como parametro para nosso método. De posse desse usuário, você pode fazer o permissionamento dos dados e retornar ao Sharepoint. Fácil Não?

– Indo para a Tela 3, Você tem que selecionar quem é o identificador do seu objeto de retorno. No meu caso, é o nome. Selecione, marque a opção MAP TO IDENTIFIER e clique em FINISH

image

k) vamos agorar selecionar quem é nosso método ReadItem. Clique com o botão direito em cima do método GetItem e selecione a opção “New Read Item Operation”

image

O Wizard é muito parecido com o ReadList que acabamos de executar acima. Começaremos dando NEXT na primeira tela.

– Na segunda tela do Wizard temos um passo a mais. Primeiro, iremos mandar como filtro o usuário do Contexto (userContext) como fizemos agora a pouco e no parametro Username nós marcaremos como Identifier

image

Sobre o Map to Identifier: A idéa desse campo é bem interessante. Primeiro que ele deve ser um campo que será um filtro na própria lista de dados. Exemplo, temo uma ReadList que retornar muitos dados de um cadastro. Quando eu CLICAR na external list , lá no Sharepoint, o meu BCS irá chamar esse método GetItem e passará como parâmetro o campo que eu marquei como identificador. O resultado desse filtro será mostrado na tela.

– Enfim, na última tela , marquei o campo nome como Identifier e cliquei em Finish.

image

Para finalizar, clique no ícone de salvar.

Vamos agora criar nossa lista externa, que foi o fruto desse post. Para isso clique no botão image e informe um nome para sua lista. Finalizando, clique em OK.

image

Na teoria, tudo funcionou. Quando você tentar acessar sua recém criada lista, você poderá dar de cara com a seguinte mensagem BROXANTE:

image

Mesmo sendo o administrador dessa bagaça. Eu não consigo ver os dados. Não tem problema, hora de dar permissões no Central Administration:

a) Acesse o Central Administration do seu Sharepoint e navegue nas opções para selecionar o item “Manage Service Applications”

image

b) Selecione Business Data Connectivity Services

c) Verifique que nessa tela, existe um DropDown lá em cima onde lista algumas opções:

image

c) Teremos que nos dar permissão no External Systems e External Content Types. Selecione External Content Types e selecione o nosso abaixo. Botão direto e selecione set Permissions

image

d) Como eu sou o Administrator dessa parada, resolvi me dar Controle Total:

image

e) Clique em OK e agora vamos nos dar permissão no External System. Procure a URL do serviço desenvolvido. Aplique as permissões como feito acima

image

f) Agora que finalizamos. Vamos voltar a External List que nos deu a mensagem de acesso negado.

image

Eis nossa lista criada Baby! Finalizamos. Agora temos algumas considerações.

  1. O conteúdo que retornei no meu web service foi um List (ou uma coleção) de um objeto que criei chamado entidade, o qual possuia as propriedades Nome, Idade, Endereço. Pelo que já passei, foi a melhor forma de retorno que encontrei. Tentei retornar um DataTable mas não deu certo.
  2. Esse trabalho de criar métodos para o ReadList e ReadItem só foi necessário porque estou trabalhando com um serviço. Se fosse apontado direto para um Banco de Dados Sql Server, esses métodos seriam criados automaticamente.
  3. Caso quisessemos usar métodos para UPDATE e DELETE, teríamos que desenvolve-los e aponta-los no Sharepoint Designer como fizemos para o ReadList e ReadItem. Mais uma vez, se fosse conexão direta com o banco, não seria necessário.Esses métodos seriam criados automaticamente
  4. Se você for ver o código do ReadItem, ele está retornando a lista completa. Não está filtrando nada. É apenas um exemplo, mas fica como dever de casa usar um LINQ para pegar o nome que vai chegar no parâmetro e retornar o resultado Alegre
  5. Existe duas outras formas de conexão: a NET Assembly e a Custom Connector. EU não quis explorar porque são muito trabalhosas, mas, caso tenha interesse, comece entendendo a diferença entre elas:
    http://msdn.microsoft.com/en-us/library/ee554911.aspx