使用 STA 线程修改 SharePoint 页面时检测到 DisconnectedContext
DisconnectedContext detected when using STA thread to modify SharePoint page
背景信息:我在 SharePoint 2010 中使用 ItemCheckedIn 接收器,目标是 .NET 3.5 Framework。接收者的目标是:
- 确保页面的属性(列)与页面上内容编辑器 Web 部件中的数据相匹配,以便可以在使用筛选器 Web 部件的搜索中找到该页面。这些页面是自动生成的,因此除非有任何错误,否则它们保证符合预期的格式。
- 如果不匹配,请签出页面,修复属性,然后重新签入。
我一直在防止接收器陷入无限 check-in/check-out 循环,尽管现在我正在努力解决这个问题,但它非常笨拙。但是,现在我无法处理它,因为每当我点击 UpdatePage 函数时都会收到 DisconnectedContext 错误:
public override void ItemCheckedIn(SPItemEventProperties properties)
{
// If the main page or machine information is being checked in, do nothing
if (properties.AfterUrl.Contains("home") || properties.AfterUrl.Contains("machines")) return;
// Otherwise make sure that the page properties reflect any changes that may have been made
using (SPSite site = new SPSite("http://san1web.net.jbtc.com/sites/depts/VPC/"))
using (SPWeb web = site.OpenWeb())
{
SPFile page = web.GetFile(properties.AfterUrl);
// Make sure the event receiver doesn't get called infinitely by checking version history
...
UpdatePage(page);
}
}
private static void UpdatePage(SPFile page)
{
bool checkOut = false;
var th = new Thread(() =>
{
using (WebBrowser wb = new WebBrowser())
using (SPLimitedWebPartManager manager = page.GetLimitedWebPartManager(PersonalizationScope.Shared))
{
// Get web part's contents into HtmlDocument
ContentEditorWebPart cewp = (ContentEditorWebPart)manager.WebParts[0];
HtmlDocument htmlDoc;
wb.Navigate("about:blank");
htmlDoc = wb.Document;
htmlDoc.OpenNew(true);
htmlDoc.Write(cewp.Content.InnerText);
foreach (var prop in props)
{
// Check that each property matches the information on the page
string element;
try
{
element = htmlDoc.GetElementById(prop).InnerText;
}
catch (NullReferenceException)
{
break;
}
if (!element.Equals(page.GetProperty(prop).ToString()))
{
if (!prop.Contains("Request"))
{
checkOut = true;
break;
}
else if (!element.Equals(page.GetProperty(prop).ToString().Split(' ')[0]))
{
checkOut = true;
break;
}
}
}
if (!checkOut) return;
// If there was a mismatch, check the page out and fix the properties
page.CheckOut();
foreach (var prop in props)
{
page.SetProperty(prop, htmlDoc.GetElementById(prop).InnerText);
page.Item[prop] = htmlDoc.GetElementById(prop).InnerText;
try
{
page.Update();
}
catch
{
page.SetProperty(prop, Convert.ToDateTime(htmlDoc.GetElementById(prop).InnerText).AddDays(1));
page.Item[prop] = Convert.ToDateTime(htmlDoc.GetElementById(prop).InnerText).AddDays(1);
page.Update();
}
}
page.CheckIn("");
}
});
th.SetApartmentState(ApartmentState.STA);
th.Start();
}
据我所知,使用 WebBrowser 是在此版本的 .NET 中填充 HtmlDocument 的唯一方法,因此这就是我必须使用此线程的原因。
此外,我已经阅读了一些资料,看起来 DisconnectedContext 错误与线程和 COM 有关,我对这些主题几乎一无所知。我该如何处理 prevent/fix 这个错误?
编辑
正如@Yevgeniy.Chernobrivets 在评论中指出的那样,我可以插入一个绑定到页面列的 editable 字段,而不用担心解析任何 html,但是因为当前页面布局在内容编辑器 WebPart 中使用 HTML table,这种字段无法正常工作,我需要制作新的页面布局并从下到上重建我的解决方案,我真的宁愿避免。
我还想避免下载任何东西,因为我工作的公司通常不允许使用未经批准的软件。
您不应该使用 WebBrowser class 进行 html 解析,它是 Windows Forms 的一部分,不适合网络以及纯 html 解析.尝试使用一些 html 解析器,例如 HtmlAgilityPack。
背景信息:我在 SharePoint 2010 中使用 ItemCheckedIn 接收器,目标是 .NET 3.5 Framework。接收者的目标是:
- 确保页面的属性(列)与页面上内容编辑器 Web 部件中的数据相匹配,以便可以在使用筛选器 Web 部件的搜索中找到该页面。这些页面是自动生成的,因此除非有任何错误,否则它们保证符合预期的格式。
- 如果不匹配,请签出页面,修复属性,然后重新签入。
我一直在防止接收器陷入无限 check-in/check-out 循环,尽管现在我正在努力解决这个问题,但它非常笨拙。但是,现在我无法处理它,因为每当我点击 UpdatePage 函数时都会收到 DisconnectedContext 错误:
public override void ItemCheckedIn(SPItemEventProperties properties)
{
// If the main page or machine information is being checked in, do nothing
if (properties.AfterUrl.Contains("home") || properties.AfterUrl.Contains("machines")) return;
// Otherwise make sure that the page properties reflect any changes that may have been made
using (SPSite site = new SPSite("http://san1web.net.jbtc.com/sites/depts/VPC/"))
using (SPWeb web = site.OpenWeb())
{
SPFile page = web.GetFile(properties.AfterUrl);
// Make sure the event receiver doesn't get called infinitely by checking version history
...
UpdatePage(page);
}
}
private static void UpdatePage(SPFile page)
{
bool checkOut = false;
var th = new Thread(() =>
{
using (WebBrowser wb = new WebBrowser())
using (SPLimitedWebPartManager manager = page.GetLimitedWebPartManager(PersonalizationScope.Shared))
{
// Get web part's contents into HtmlDocument
ContentEditorWebPart cewp = (ContentEditorWebPart)manager.WebParts[0];
HtmlDocument htmlDoc;
wb.Navigate("about:blank");
htmlDoc = wb.Document;
htmlDoc.OpenNew(true);
htmlDoc.Write(cewp.Content.InnerText);
foreach (var prop in props)
{
// Check that each property matches the information on the page
string element;
try
{
element = htmlDoc.GetElementById(prop).InnerText;
}
catch (NullReferenceException)
{
break;
}
if (!element.Equals(page.GetProperty(prop).ToString()))
{
if (!prop.Contains("Request"))
{
checkOut = true;
break;
}
else if (!element.Equals(page.GetProperty(prop).ToString().Split(' ')[0]))
{
checkOut = true;
break;
}
}
}
if (!checkOut) return;
// If there was a mismatch, check the page out and fix the properties
page.CheckOut();
foreach (var prop in props)
{
page.SetProperty(prop, htmlDoc.GetElementById(prop).InnerText);
page.Item[prop] = htmlDoc.GetElementById(prop).InnerText;
try
{
page.Update();
}
catch
{
page.SetProperty(prop, Convert.ToDateTime(htmlDoc.GetElementById(prop).InnerText).AddDays(1));
page.Item[prop] = Convert.ToDateTime(htmlDoc.GetElementById(prop).InnerText).AddDays(1);
page.Update();
}
}
page.CheckIn("");
}
});
th.SetApartmentState(ApartmentState.STA);
th.Start();
}
据我所知,使用 WebBrowser 是在此版本的 .NET 中填充 HtmlDocument 的唯一方法,因此这就是我必须使用此线程的原因。
此外,我已经阅读了一些资料,看起来 DisconnectedContext 错误与线程和 COM 有关,我对这些主题几乎一无所知。我该如何处理 prevent/fix 这个错误?
编辑
正如@Yevgeniy.Chernobrivets 在评论中指出的那样,我可以插入一个绑定到页面列的 editable 字段,而不用担心解析任何 html,但是因为当前页面布局在内容编辑器 WebPart 中使用 HTML table,这种字段无法正常工作,我需要制作新的页面布局并从下到上重建我的解决方案,我真的宁愿避免。
我还想避免下载任何东西,因为我工作的公司通常不允许使用未经批准的软件。
您不应该使用 WebBrowser class 进行 html 解析,它是 Windows Forms 的一部分,不适合网络以及纯 html 解析.尝试使用一些 html 解析器,例如 HtmlAgilityPack。