SPActiveDirectoryClaimProvider 中的内存泄漏?
-
10-12-2019 - |
题
在与自定义声明提供商合作时,我发现了有趣的事情 SPActiveDirectoryClaimProvider
. 。如果您使用任何 .net 程序集浏览器\反编译器(.NET Reflector 或 ILSpy)调查代码,您会发现内存泄漏 SPWeb
方法中的对象 FillResolve
. 。仔细看看代码:
// Microsoft.SharePoint.Administration.Claims.SPActiveDirectoryClaimProvider
private void FillResolve(Uri context, string[] entityTypes, bool inputIsEmailOnly, string resolveInput, List<PickerEntity> resolved)
{
SPWeb sPWeb = null;
SPSite sPSite = null;
if (!SPThreadContext.Items.Contains("SPActiveDirectoryClaimProviderIgnoreContext"))
{
bool catchAccessDeniedException = SPSecurity.CatchAccessDeniedException;
try
{
SPSecurity.CatchAccessDeniedException = false;
sPSite = new SPSite(context.AbsoluteUri);
if (sPSite != null)
{
sPWeb = sPSite.OpenWeb();
}
if (!sPWeb.Exists)
{
sPWeb = null;
}
}
catch
{
if (sPSite != null)
{
sPSite.Dispose();
sPWeb = null;
}
}
finally
{
SPSecurity.CatchAccessDeniedException = catchAccessDeniedException;
}
}
try
{
SPWebApplication webApp = SPWebApplication.Lookup(context);
SPPrincipalType scopes = SPActiveDirectoryClaimProvider.ConvertEntityTypeToPrincipalTypes(entityTypes);
SPPrincipalInfo sPPrincipalInfo = SPUtility.ResolveWindowsPrincipal(sPWeb, webApp, resolveInput, scopes, inputIsEmailOnly);
if (sPPrincipalInfo != null)
{
if (inputIsEmailOnly && MatchType.EmailAddress == sPPrincipalInfo.MatchType && SPActiveDirectoryClaimProvider.DisableEmailResolve())
{
ULS.SendTraceTag(2466693u, ULSCat.msoulscat_WSS_ClaimsAuthentication, ULSTraceLevel.VerboseEx, "Dicarding match '{0}' for input '{1}' because it is email match and feature is disabled.", new object[]
{
sPPrincipalInfo.LoginName,
resolveInput
});
}
else
{
PickerEntity pickerEntity = this.CreatePickerEntity(sPPrincipalInfo);
if (pickerEntity != null)
{
resolved.Add(pickerEntity);
ULS.SendTraceTag(1634481712u, ULSCat.msoulscat_WSS_ClaimsAuthentication, ULSTraceLevel.VerboseEx, string.Format(CultureInfo.InvariantCulture, "Returning AD resolve match '{0}' for input '{1}'.", new object[]
{
pickerEntity.Key,
resolveInput
}));
}
}
}
else
{
if (!inputIsEmailOnly)
{
int maxCount = 10;
bool flag = false;
IList<SPPrincipalInfo> list;
if (sPWeb != null)
{
list = SPUtility.SearchPrincipals(sPWeb, resolveInput, scopes, SPPrincipalSource.Windows, null, maxCount, out flag);
}
else
{
list = SPUtility.SearchWindowsPrincipals(webApp, resolveInput, scopes, maxCount, out flag);
}
List<PickerEntity> list2 = new List<PickerEntity>();
foreach (SPPrincipalInfo current in list)
{
if (inputIsEmailOnly && MatchType.EmailAddress == current.MatchType && SPActiveDirectoryClaimProvider.DisableEmailResolve())
{
ULS.SendTraceTag(2466694u, ULSCat.msoulscat_WSS_ClaimsAuthentication, ULSTraceLevel.VerboseEx, "Dicarding match '{0}' for input '{1}' because it is email match and feature is disabled.", new object[]
{
current.LoginName,
resolveInput
});
}
else
{
PickerEntity pickerEntity2 = this.CreatePickerEntity(current);
if (pickerEntity2 != null)
{
list2.Add(pickerEntity2);
ULS.SendTraceTag(1634481713u, ULSCat.msoulscat_WSS_ClaimsAuthentication, ULSTraceLevel.VerboseEx, string.Format(CultureInfo.InvariantCulture, "Returning AD resolve search match '{0}' for input '{1}'.", new object[]
{
pickerEntity2.Key,
resolveInput
}));
}
}
}
if (list2.Count == 1 && list2[0].Claim != null && SPClaim.EqualClaimValues(list2[0].Claim.Value, resolveInput))
{
resolved.Add(list2[0]);
}
else
{
if (list2.Count > 0)
{
PickerEntity pickerEntity = base.CreatePickerEntity();
pickerEntity.IsResolved = false;
pickerEntity.DisplayText = resolveInput;
pickerEntity.MultipleMatches.AddRange(list2);
resolved.Add(pickerEntity);
}
}
}
}
}
catch
{
throw;
}
finally
{
if (sPSite != null)
{
sPSite.Dispose();
}
}
}
根据最佳实践(http://msdn.microsoft.com/en-us/library/office/ee557362%28v=office.14%29.aspx)我们应该处置 SPWeb
使用创建的对象 OpenWeb
方法。但 sPWeb
对象未在该方法的任何部分中释放。这意味着,每次我们在人员选择器中执行搜索和解析时,都会有一个 SPWeb
对象将会被泄露。我没有 msdn 订阅,无法联系 Microsoft 解决此问题。对于 SharePoint 2010 (SP2) 和 SharePoint 2013 (SP1) 来说,存在此问题。
我相信社区可以确认内存泄漏并联系微软来解决这个问题。
解决方案
在使用 OpenWeb 方法的 SPSite 上调用 Dispose() 将自动释放它打开的 SPWeb。只要 SPSite 被处置,您就不会遇到问题,除非您打开大量 SPWeb 并且没有明确处置它们。
查看该代码,它似乎正在处理 SPSite,因此应该没问题。
编辑
作为参考,以下是 .Dispose() 方法调用的 SPSite 类中的 .Close() 方法。正如您所看到的,它在处置自身之前处置了它打开的所有 SPWeb:
public void Close()
{
SPEventManager.WaitForPostEvents();
if (this.m_openedWebs != null)
{
SPWeakObjectHandleList<SPWeb> list = new SPWeakObjectHandleList<SPWeb>(this.m_openedWebs);
foreach (SPWeb web in list)
{
web.Close();
}
list.Dispose();
this.m_openedWebs.Dispose();
}
this.m_rootWebCreated = false;
SPRequestContext.UnregisterSite(this);
this.InvalidateSite();
}