Как загрузить данные BDC с URL-адреса BDC? - PullRequest
0 голосов
/ 29 сентября 2010

Я делаю это в SharePoint 2010, но не удивлюсь, если проблема существует в SharePoint 2007 и имеет такое же решение.

У меня есть триммер безопасности на моих данных BDC. Я ожидал, что триммер безопасности выдаст мне URL-адреса на основе URL-адреса профиля «по умолчанию», определенного в модели. К сожалению, это не так. Это дает мне URL-адрес, как: bdc3: // amms_amms / default / 00000000% 252d0000% 252d0000% 252d0000% 252d000000000000 / 1971 / amms / 1973? s_id = ibqaaaaaaaaa = & s_ce = 07nk0004080g10003o03vvf

Мне нужно получить свойства этого объекта (на самом деле просто значение первичного ключа). Любая идея, как я делаю это с объектной моделью BDC? Следующая ссылка, кажется, предоставляет некоторую помощь, но я не видел ничего, что использует URL выше.

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


Обновление: я вижу, что в SharePoint 2007 есть AccessChecker (http://msdn.microsoft.com/en-us/library/aa981124.aspx) и, вероятно, тоже есть в 2010 году (не могу найти хорошую документацию на 2010 год). Мы не можем легко иметь дескрипторы безопасности в базе данных, но метод AccessChecker может быть достаточно.

Копая немного дальше, я вижу, что Microsoft.Office.Server.Search.Connector.BDC.BdcSecurityTrimmer - это то, что, вероятно, используется AccessChecker в SharePoint 2010. Похоже, что это делает запрос к БД по URL-адресу. Кажется неэффективным, даже если он делает это в нескольких потоках (что утверждается в документации 2007 года). Я думаю, что предпочел бы объединить информацию в один вызов веб-службы, но я на грани ...

Ответы [ 2 ]

1 голос
/ 29 сентября 2010

ОК, вот упрощение моего предыдущего ответа. Похоже, что вы можете полностью избежать отражения:

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;
}

Обратите внимание, что я пытался избежать использования UriParser из Microsoft.Office.Server.Search.Connector, используя такой код:

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

К сожалению, это работало для одних идентификаторов, а не для других. Я решил не расследовать дальше, а просто использовать специальный UriParser. В одном примере идентификаторы, которые я искал, были «5,20,21,7,8,6,14,19,17,18,4», но этот второй подход дал мне «5,20,21,24581,8, 24580,24588,24593,17,24592,4" . Это напутало меня на несколько минут, так как первые три были правильными.

0 голосов
/ 29 сентября 2010

Я не уверен, что это лучший подход, но я заставил его работать, используя Reflector для обратного инжиниринга Microsoft.Office.Server.Search.Connector.BDC.BdcSecurityTrimmer.Мне нужно было только значение идентификатора, чтобы это немного упростило.

Ниже приведен мой код, который принимает массив documentCrawlUrls, предоставленный триммеру безопасности, и преобразует их в массив первичных ключей, как определено в моем файле модели BDC.,После того, как я получу их, я могу определить усечение безопасности, используя более специальный код .NET.

В CheckAccess () моего триммера безопасности (ISecurityTrimmer2) у меня есть:

String[] ids = GetIds(documentCrawlUrls);

Тогда у меня естьследующий приватный метод:

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;
}

Я не хотел переписывать класс SPBdcUri, и он был внутренним, поэтому я обманываю с отражением.В настоящее время я использую только один из параметров, чтобы повысить эффективность.Я могу переписать те части SPBdcUri, которые мне нужны, вместо того, чтобы прибегать к рефлексии.

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;
}

О, вот мои утверждения "using":

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;
...