我有以下代码来迭代sharepoint站点的子站点。 如果我逐行调试它,它永远不会被我的捕获。
然而在uls日志中我有这个例外,我不知道这意味着什么或者我是否应该担心
53b416d1-1497-4b40-beb5-cd261180ece8 Stack trace:
at Microsoft.SharePoint.SPWeb.get_Created()
at xx.SP.DMS.WebParts.WebParts.LastCreatedJobs.LastCreatedJobs.<>c__DisplayClass8.<LoadGridData>b__7(SPWeb d)
at System.Linq.EnumerableSorter`2.ComputeKeys(TElement[] elements, Int32 count)
at System.Linq.EnumerableSorter`1.Sort(TElement[] elements, Int32 count)
at System.Linq.OrderedEnumerable`1.<GetEnumerator>d__0.MoveNext()
at System.Linq.Enumerable.<TakeIterator>d__3a`1.MoveNext()
at xx.SP.DMS.WebParts.WebParts.LastCreatedJobs.LastCreatedJobs.<>c__DisplayClass8.<LoadGridData>b__5()
at Microsoft.SharePoint.SPSecurity.<>c__DisplayClass5.<RunWithElevatedPrivileges>b__3()
at Microsoft.SharePoint.Utilities.SecurityContext.RunAsProcess(CodeToRunElevated secureCode)
at Microsoft.SharePoint.SPSecurity.RunWithElevatedPrivileges(WaitCallback secureCode, Object param)
at Microsoft.SharePoint.SPSecurity.RunWithElevatedPrivileges(CodeToRunElevated secureCode)
at xx.SP.DMS.WebParts.WebParts.LastCreatedJobs.LastCreatedJobs.LoadGridData()
at xx.SP.DMS.WebParts.WebParts.LastCreatedJobs.LastCreatedJobs.OnPreRender(EventArgs e)
at System.Web.UI.Control.PreRenderRecursiveInternal()
at System.Web.UI.Control.PreRenderRecursiveInternal()
at System.Web.UI.Control.PreRenderRecursiveInternal()
at System.Web.UI.Control.PreRenderRecursiveInternal()
at System.Web.UI.Control.PreRenderRecursiveInternal()
at System.Web.UI.Control.PreRenderRecursiveInternal()
at System.Web.UI.Control.PreRenderRecursiveInternal()
at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
at System.Web.UI.Page.ProcessRequest(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
at System.Web.UI.Page.ProcessRequest()
at System.Web.UI.Page.ProcessRequest(HttpContext context)
at Microsoft.SharePoint.Publishing.TemplateRedirectionPage.ProcessRequest(HttpContext context)
at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)
at System.Web.HttpApplication.PipelineStepManager.ResumeSteps(Exception error)
at System.Web.HttpApplication.BeginProcessRequestNotification(HttpContext context, AsyncCallback cb)
at System.Web.HttpRuntime.ProcessRequestNotificationPrivate(IIS7WorkerRequest wr, HttpContext context)
at System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper(IntPtr rootedObjectsPointer, IntPtr nativeRequestContext, IntPtr moduleData, Int32 flags)
at System.Web.Hosting.PipelineRuntime.ProcessRequestNotification(IntPtr rootedObjectsPointer, IntPtr nativeRequestContext, IntPtr moduleData, Int32 flags)
at System.Web.Hosting.UnsafeIISMethods.MgdIndicateCompletion(IntPtr pHandler, RequestNotificationStatus& notificationStatus)
at System.Web.Hosting.UnsafeIISMethods.MgdIndicateCompletion(IntPtr pHandler, RequestNotificationStatus& notificationStatus)
at System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper(IntPtr rootedObjectsPointer, IntPtr nativeRequestContext, IntPtr moduleData, Int32 flags)
at System.Web.Hosting.PipelineRuntime.ProcessRequestNotification(IntPtr rootedObjectsPointer, IntPtr nativeRequestContext, IntPtr moduleData, Int32 flags)
我的代码如下
private void LoadGridData()
{
try
{
String currentUrl = SPContext.Current.Site.Url;
var jobInfoList = new List<JobInfo>();
SPSecurity.RunWithElevatedPrivileges(delegate
{
using (var clientSiteCollection = new SPSite(currentUrl))
{
foreach (
SPWeb web in
clientSiteCollection.AllWebs.AsSafeEnumerable().Where(
c =>
c.AllProperties[Constants.WebProperties.General.WebTemplate] != null &&
c.AllProperties[Constants.WebProperties.General.WebTemplate].ToString() ==
Constants.WebTemplates.JobWebPropertyName).OrderByDescending(d => d.Created).Take(5)
)
{
if (web.DoesUserHavePermissions(SPContext.Current.Web.CurrentUser.LoginName,
SPBasePermissions.Open))
{
SPList jobInfoListSp = web.Lists.TryGetList(Constants.Lists.JobInfoName);
if (jobInfoListSp != null)
{
if (jobInfoListSp.Items.Count > 0)
{
var value =
new SPFieldUrlValue(
jobInfoListSp.Items[0][Constants.FieldNames.Job.iPowerLink].ToString());
jobInfoList.Add(new JobInfo
{
JobName =
jobInfoListSp.Items[0][Constants.FieldNames.Job.JobName].ToString(),
JobCode =
jobInfoListSp.Items[0][Constants.FieldNames.Job.JobCode].ToString(),
IPowerLink = value.Url,
JobWebsite = web.Url,
IsConfidential =
HelperFunctions.ConvertToBoolean(
jobInfoListSp.Items[0][Constants.FieldNames.Job.Confidential]
.ToString())
});
}
}
}
web.Dispose();
}
}
});
_lastCreatedJobsGrid.DataSource = jobInfoList;
_lastCreatedJobsGrid.DataBind();
}
catch (Exception ex)
{
LoggingService.LogError(LoggingCategory.Job, ex);
}
}
public static class SPWebCollectionExtensions
{
public static IEnumerable<SPWeb> AsSafeEnumerable(this SPWebCollection webs)
{
foreach (SPWeb web in webs)
{
try
{
yield return web;
}
finally
{
web.Dispose();
}
}
}
}
如果需要,任何想法可能是什么原因和解决方案?
更新
我首先对变量进行了查询,然后是foreach,我还删除了AsSafeEnumerable 我想知道这次改变是否会有记忆漏洞?
更新2:当尝试在第一个答案中使用令人印象深刻的代码时,我仍然处理问题。
一个
SPRequest object was not disposed before the end of this thread. To avoid wasting system resources, dispose of this object or its parent (such as an SPSite or SPWeb) as soon as you are done using it. This object will now be disposed. Allocation Id: {96F3F1CB-DBD1-4514-AB9A-D49424AB0B6A} This SPRequest was allocated
at
at Microsoft.SharePoint.Library.SPRequest..ctor()
at Microsoft.SharePoint.SPGlobal.CreateSPRequestAndSetIdentity(SPSite site, String name, Boolean bNotGlobalAdminCode, String strUrl, Boolean bNotAddToContext, Byte[] UserToken, SPAppPrincipalToken appPrincipalToken, String userName, Boolean bIgnoreTokenTimeout, Boolean bAsAnonymous)
at Microsoft.SharePoint.SPWeb.InitializeSPRequest()
at Microsoft.SharePoint.SPWeb.EnsureSPRequest()
at Microsoft.SharePoint.SPWeb.get_AllProperties()
at xx.SP.DMS.WebParts.WebParts.LastCreatedJobs.LastCreatedJobs.<>c__DisplayClass8.<LoadGridData>b__6(SPWeb c)
at System.Linq.Enumerable.WhereEnumerableIterator`1.MoveNext()
at System.Linq.Buffer`1..ctor(IEnumerable`1 source)
at System.Linq.OrderedEnumerable`1.<GetEnumerator>d__0.MoveNext()
at xx.SP.DMS.WebParts.Extensions.Safe.<SafeTake>d__0`1.MoveNext()
at xx.SP.DMS.WebParts.WebParts.LastCreatedJobs.LastCreatedJobs.<>c__DisplayClass8.<LoadGridData>b__5()
at Microsoft.SharePoint.SPSecurity.<>c__DisplayClass5.<RunWithElevatedPrivileges>b__3()
at Microsoft.SharePoint.Utilities.SecurityContext.RunAsProcess(CodeToRunElevated secureCode)
at Microsoft.SharePoint.SPSecurity.RunWithElevatedPrivileges(WaitCallback secureCode, Object param)
at Microsoft.SharePoint.SPSecurity.RunWithElevatedPrivileges(CodeToRunElevated secureCode)
at xx.SP.DMS.WebParts.WebParts.LastCreatedJobs.LastCreatedJobs.LoadGridData()
at xx.SP.DMS.WebParts.WebParts.LastCreatedJobs.LastCreatedJobs.OnPreRender(EventArgs e)
答案 0 :(得分:2)
我认为问题是SPWeb
在调用Enumerable.OrderByDescending
后被处理掉了。此linq方法不是延迟评估的,因此finally
内的AsSafeEnumerable
块将被触发。
样品:
public class Disposed : IDisposable
{
public bool IsDisposed { get; private set; }
public DateTime? Created { get; set; }
public void Dispose()
{
Console.WriteLine("Disposed");
IsDisposed = true;
}
}
public IEnumerable<Disposed> GetDisposed()
{
Func<Disposed> factory = () => new Disposed { Created = DateTime.Now };
foreach(var f in Enumerable.Repeat(factory, 5))
{
Console.WriteLine("In Enumerable");
var item = f();
try
{
Console.WriteLine("Returning item");
yield return item;
}
finally
{
item.Dispose();
}
Console.WriteLine("Next iteration.");
}
}
用法1:
foreach(var item in GetDisposed().Take(5))
{
Console.WriteLine(item.IsDisposed);
}
In Enumerable
Returning item
False
Disposed
Next iteration.
In Enumerable
Returning item
False
Disposed
Next iteration.
In Enumerable
Returning item
False
Disposed
Next iteration.
In Enumerable
Returning item
False
Disposed
Next iteration.
In Enumerable
Returning item
False
Disposed
用法2:
foreach(var item in GetDisposed().OrderByDescending(x => x.Created).Take(5))
{
Console.WriteLine(item.IsDisposed);
}
日志:
In Enumerable
Returning item
Disposed
Next iteration.
In Enumerable
Returning item
Disposed
Next iteration.
In Enumerable
Returning item
Disposed
Next iteration.
In Enumerable
Returning item
Disposed
Next iteration.
In Enumerable
Returning item
Disposed
Next iteration.
True
True
True
True
True
编辑:
这是一种安全处理未采取对象的扩展方法:
public static IEnumerable<TSource> SafeTake<TSource>(
this IEnumerable<TSource> source,
int count
) where TSource : IDisposable
{
foreach(var item in source)
{
if(--count >= 0)
{
yield return item;
}
else if (item != null)
{
item.Dispose();
}
}
}
public static IEnumerable<TSource> SafeWhere<TSource>(
this IEnumerable<TSource> source,
Func<TSource, bool> predicate
) where TSource: IDisposable
{
return source.SelectMany(x => {
var result = predicate(x);
if(!result && x != null) x.Dispose();
return Enumerable.Repeat(x, result ? 1 : 0);
});
}
用法:
foreach (
SPWeb web in
clientSiteCollection.AllWebs.SafeWhere(
c =>
c.AllProperties[Constants.WebProperties.General.WebTemplate] != null &&
c.AllProperties[Constants.WebProperties.General.WebTemplate].ToString() ==
Constants.WebTemplates.JobWebPropertyName).OrderByDescending(d => d.Created).SafeTake(5)
)
{
try
{
if (!web.DoesUserHavePermissions(SPContext.Current.Web.CurrentUser.LoginName, SPBasePermissions.Open)) continue;
SPList jobInfoListSp = web.Lists.TryGetList(Constants.Lists.JobInfoName);
if (jobInfoListSp == null) continue;
if (0 >= jobInfoListSp.Items.Count) continue;
var value =
new SPFieldUrlValue(
jobInfoListSp.Items[0][Constants.FieldNames.Job.iPowerLink].ToString());
jobInfoList.Add(new JobInfo
{
JobName =
jobInfoListSp.Items[0][Constants.FieldNames.Job.JobName].ToString(),
JobCode =
jobInfoListSp.Items[0][Constants.FieldNames.Job.JobCode].ToString(),
IPowerLink = value.Url,
JobWebsite = web.Url,
IsConfidential =
HelperFunctions.ConvertToBoolean(
jobInfoListSp.Items[0][Constants.FieldNames.Job.Confidential]
.ToString())
});
}
finally
{
web.Dispose();
}
}