题
我在 SharePoint 2010 中执行此操作,但如果该问题存在于 SharePoint 2007 中并且具有相同的解决方案,我也不会感到惊讶。
我的 BDC 数据有一个运行时安全修剪器。我期望安全修剪器根据模型中定义的“默认”配置文件 URL 为我提供 URL。不幸的是,事实并非如此。它给了我一个如下的 URL:bdc3:// amms_amms/default/00000000%252D0000%252D0000%252D0000%252D00000000000000000000000000000000000000000000000000000000000000%/1971/AMMS/1973?
我需要获取该对象的属性(实际上只是主键值)。知道如何使用 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 很可能是 SharePoint 2010 中的 AccessChecker 使用的内容。看来这会根据 URL 对数据库进行查询。即使它确实在多个线程上执行(2007 年文档声称是这样做的),似乎效率也很低。我想我更愿意将信息批量处理到单个 Web 服务调用中,但我持观望态度......
解决方案
好的,这是我之前答案的简化。看来你可以完全避免反射:
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;
}
请注意,我尝试避免使用 Microsoft.Office.Server.Search.Connector 中的 UriParser,使用如下代码:
string id = HttpUtility.ParseQueryString(new Uri(url).Query)["s_id"];
ids[i] = Identity.Deserialize(id.ToUpper()).GetIdentifierValues()[0].ToString();
不幸的是,这对某些 ID 有效,而对其他 ID 无效。我决定不再进一步调查,只使用特殊的 UriParser。在一个例子中,我正在寻找的 ids 是“5,20,21,7,8,6,14,19,17,18,4”,但第二种方法给了我“5,20,21,24581,8, 24580、24588、24593、17、24592、4"。这让我困惑了几分钟,因为前 3 个都是正确的。
其他提示
我不知道这是最好的办法,但我通过使用反射进行逆向工程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 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;