Pergunta

Estou fazendo isso no SharePoint 2010, mas não ficaria surpreso se o problema existir no SharePoint 2007 e tiver a mesma solução.

Eu tenho um aparador de segurança de tempo de execução nos meus dados do BDC. Eu esperava que o aparador de segurança me desse URLs com base no URL do perfil "padrão" definido no modelo. Infelizmente, este não é o caso. Ele me dá um URL como: BDC3: // AMMS_AMMS/PADRÃO/00000000%252d0000%252d0000%252d0000%252d000000000000/1971/amms/1973?

Preciso obter as propriedades desse objeto (realmente apenas o valor principal da chave). Alguma ideia de como eu faço isso com o modelo de objeto BDC? O link a seguir parece fornecer alguma ajuda, mas não vi nada que consome o URL acima.

http://msdn.microsoft.com/en-us/library/ee556400.aspx


ATUALIZAÇÃO: Vejo que o SharePoint 2007 possui um AccessChecker (http://msdn.microsoft.com/en-us/library/aa981124.asp) e 2010 provavelmente também tem isso (não consigo encontrar uma boa documentação para 2010 sobre isso) . Não podemos facilmente ter descritores de segurança no banco de dados, mas o método AccessChecker pode ser suficiente.

Cavando um pouco mais, vejo que Microsoft.Office.Server.Search.Connector.BDC.BDCSecurityTrimmer é o que é provável o que é usado pelo AccessChecker no SharePoint 2010. Parece que isso faz uma consulta ao DB por URL. Parece ineficiente, mesmo que o faça em vários threads (que a documentação de 2007 afirma fazer). Eu acho que preferiria fazer parte das informações em uma única chamada de serviço da web, mas estou em cima do muro ...

Foi útil?

Solução

OK, aqui está uma simplificação da minha resposta anterior. Parece que você pode evitar totalmente a reflexão:

using Microsoft.BusinessData.Runtime;
using Microsoft.Office.Server.Search.Connector;
using Microsoft.Office.Server.Search.Query;    

private string[] GetIds(IList<string> documentCrawlUrls)
{
    string[] ids = new String[documentCrawlUrls.Count];
    for (int i = 0; i < documentCrawlUrls.Count; i++)
    {
        try
        {
            string url = documentCrawlUrls[i];
            string id = new Microsoft.Office.Server.Search.Connector.UriParser(new Uri(url)).QueryStringParameters["s_id"];
            ids[i] = Identity.Deserialize(id).GetIdentifierValues()[0].ToString();
        }
        catch (Exception ex)
        {
            System.Diagnostics.Trace.WriteLine("Error: " + ex.Message);
        }
    }

    return ids;
}

Observe que tentei evitar o uso do URiparSser em Microsoft.Office.Server.Search.Connector usando código como:

string id = HttpUtility.ParseQueryString(new Uri(url).Query)["s_id"];
ids[i] = Identity.Deserialize(id.ToUpper()).GetIdentifierValues()[0].ToString();

Infelizmente, isso funcionou para alguns IDs e não para outros. Decidi não investigar mais e apenas usar o Uriparsser especial. Em um exemplo, os IDs que eu estava procurando foram "5,20,21,7,8,6,14,19,17,18,4", mas essa segunda abordagem me deu "5,20,21,24581,8, 24580.24588.24593,17,24592,4 ". Isso me bagunçou por alguns minutos desde que os três primeiros estavam corretos.

Outras dicas

Não tenho certeza se é a melhor abordagem, mas consegui que isso funcione usando o refletor para reverter o engenheiro microsoft.office.server.search.conlector.bdc.bdcsecuritytrimmer. Eu só precisava do valor de identidade para que simplificasse um pouco isso.

Abaixo está o meu código que leva uma matriz de documentclerls fornecidos ao aparador de segurança e os traduz em uma matriz de chaves primárias, conforme definido no meu arquivo de modelo BDC. Depois de ter aqueles, posso determinar o corte de segurança usando mais código .NET personalizado.

No CheckAccess () do meu aparador de segurança (isecurityTrimmer2), eu tenho:

String[] ids = GetIds(documentCrawlUrls);

Então eu tenho o seguinte método privado:

private string[] GetIds(IList<string> documentCrawlUrls)
{
    string[] ids = new String[documentCrawlUrls.Count];
    for (int i = 0; i < documentCrawlUrls.Count; i++)
    {
        try
        {
            string url = documentCrawlUrls[i];

            Identity identity = null;
            IEntity entity = null;
            ILobSystemInstance lsi = null;
            ParseUri(url, out entity, out identity, out lsi);
            if (identity != null)
            {
                object[] values = identity.GetIdentifierValues();
                if (values.Length > 0)
                {
                    ids[i] = values[0].ToString();
                }
            }
        }
        catch (Exception ex)
        {
            System.Diagnostics.Trace.WriteLine("Error: " + ex.Message);
        }
    }

    return ids;
}

Eu não queria reescrever a classe spbdcuri e ela é interna, então trapaceio com a reflexão. Atualmente, uso apenas um dos parâmetros out para melhorar a eficiência. Posso reescrever as partes do spbdcuri que preciso em vez de recorrer à reflexão.

private void ParseUri(string crawlUri, out IEntity entity, out Identity identity, out ILobSystemInstance lsi)
{
    //SPBdcUri uri = new SPBdcUri(new Uri(crawlUri));
    AssemblyName assemblyName = new AssemblyName("Microsoft.Office.Server.Search.Connector, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c");
    Assembly assembly = Assembly.Load(assemblyName);
    Type spBdcUriType = assembly.GetType("Microsoft.Office.Server.Search.Connector.BDC.SPBDC.SPBdcUri");
    object uri = Activator.CreateInstance(spBdcUriType,
        BindingFlags.NonPublic | BindingFlags.Instance,
        null, new object[] { new Uri(crawlUri) }, System.Globalization.CultureInfo.CurrentCulture);

    //uri.DoOverrideBDCThrottlingLimits = false;
    spBdcUriType.InvokeMember("DoOverrideBDCThrottlingLimits",
        BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.SetProperty,
        null, uri, new object[] { false });

    //entity = uri.Entity;
    object entityObj = spBdcUriType.InvokeMember("Entity",
        BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetProperty,
        null, uri, null);
    entity = (IEntity)entityObj;

    //identity = uri.Identity;
    object identityObj = spBdcUriType.InvokeMember("Identity",
        BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetProperty,
        null, uri, null);
    identity = (Identity)identityObj;

    //lsi = uri.LobSystemInstance;
    object lsiObj = spBdcUriType.InvokeMember("LobSystemInstance",
        BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetProperty,
        null, uri, null);
    lsi = (ILobSystemInstance)lsiObj;
}

Oh, aqui estão minhas declarações "usando":

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;

using Microsoft.BusinessData.MetadataModel.Collections;
using Microsoft.BusinessData.MetadataModel;
using Microsoft.BusinessData.Runtime;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;
using Microsoft.SharePoint.BusinessData.SharedService;
using Microsoft.Office.Server.Search.Query;
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top