2008年6月22日,星期日

内容部署向导已更新-版本1.0

我今天发布了新版本的内容部署向导,标记为“发布1.0”。此版本仅对beta 2进行了微小的更改,主要目的是为将来的beta版本铺平道路,该版本将包含新功能。但是,我还想交流一下,当前的代码库现在是稳定的,因为我听到一些人的反馈说'beta'标签使一些人感到失望(例如,SharePoint顾问的非技术客户)。

也就是说,已合并了以下较小更新:

  • 修改哪些列表从树视图中过滤出来的功能:

    某些“系统”类型的列表未在树状视图中显示,因为它们通常与导入/导出操作无关,但是有时您可能希望“取消隐藏”某些列表,例如如果您使用变体,则“变体标签”和“关系列表”列出。请参阅readme.txt文件以获取有关如何执行此操作的说明。

  • 小错误修复,例如现在,如果您选择的文件名中包含句点(。),. cmp文件现在可以正确保存,带有扩展名。如果已添加父网站集,请进行验证以防止从树形视图添加子对象

可以从以下位置下载新版本 www.codeplex.com/SPDeploymentWizard.

未来发展

下一版向导的工作正在进行中,主要重点是:

  • 允许对导入/导出操作进行脚本化
  • 允许将操作中使用的设置保存到文件中以方便重用
  • 支持增量部署(希望如此!)

如果您还有其他建议,我不能保证可以在下一个发行版中包括这些建议,但是我一定很想听听。

2008年6月15日,星期日

处置SharePoint对象-它们的作用't tell you

如果您是SharePoint开发人员,并且发现自己定期编写代码以与SPListItem对象一起使用,则此处的一些信息可能会帮助您在某些情况下以更简洁的方式来考虑代码。 有趣的是,在任何关键论文/文章中都没有提到这一点-我可以想到一个很好的理由(我们将要介绍),但是在我看来,这是一种安全的技术。但是,如果您还有其他想法,我很想听听您的意见。

现在,大多数开发人员都精通编写高效SharePoint代码所需的技术(本文结尾列出了关键资源),特别是在处置您代码创建的任何SPSite / SPWeb对象方面。事实是,必须时刻谨记处理这些对象有时会限制我们编写代码的方式-考虑以下简化示例:

public void DoSomething()
{
SPList list = getList();

// do something with list..
foreach (SPListItem item in list.Items)
{
processItem(item);
}

// ** PROBLEM - how do we now dispose of the SPSite/SPWeb objects we created earlier? **
}

private SPList getList()
{
// 能够 't dispose of these objects here if we're returning a list - we'll be 在 tempting to use
// objects which have already been disposed of..
SPSite site = new SPSite("http://cob.blog.dev");
SPWeb web = site.OpenWeb("/MyWeb");
SPList list = web.Lists["MyList"];

return list;
}


这里的问题是,我们以与需要处置它们的方法不同的方式创建了SPSite / SPWeb对象-在编写库代码时,这可能会发生很多。为了扩展此示例,下面是我经常使用的一种模式,以确保以最有效的方式获取对象-使用SPContext(如果存在),但如果没有则实例化它们(即,从事件接收器调用代码,控制台应用等):


public void DoSomething()
{
bool bDisposalsRequired = false;

// get list from SPContext if we have one..
SPList list = getListFromContext();
if (list == null)
{
// otherwise get list from objects we create..
list = getInstantiatedList();
bDisposalsRequired = true;
}

// do something with list..
foreach (SPListItem item in list.Items)
{
processItem(item);
}

if (bDisposalsRequired)
{
// ** PROBLEM - how do we now dispose of the SPSite/SPWeb objects we created earlier? **
}
}

private SPList getInstantiatedList()
{
// 能够 't dispose of these objects here if we're returning a list - we'll be 在 tempting to use
// objects which have already been disposed of..
SPSite site = new SPSite("http://cob.blog.dev");
SPWeb web = site.OpenWeb("/MyWeb");
SPList list = web.Lists["MyList"];

return list;
}

private SPList getListFromContext()
{
SPContext currentContext = SPContext.Current;
SPList list = null;

if (currentContext != null)
{
list = currentContext.Site.AllWebs["MyWeb"].Lists["MyList"];
}

return list;
}


当代码开始变得像这样复杂时,我们开始 想要一种简单的方式来处理我们在其他地方创建的对象。我可能会对此提出警告,但是如果您不仅使用另一种方法创建了SPSite / SPWeb对象,还会发生什么呢? ?突然正确地布置对象比白皮书中给出的示例要复杂得多。 

现在,精明的SharePoint开发人员可能会认为"等等,SPList有一个ParentWeb对象(而SPListItem有一个ParentList对象!),如果我按层次结构进行这种处理会怎样?"-此代码如下所示:


if (bDisposalsRequired)
{
list.ParentWeb.Dispose();
list.ParentWeb.Site.Dispose();
}


现在我们如何知道正确的物体已被处置?这些对象与我们之前使用的对象相同吗?或者SharePoint已使用以下引用填充了这些属性: 不同 对象,这意味着我们已经将原始对象保留下来并且可能会遇到可扩展性问题?

好吧,好消息是这些是相同的对象,因此以这种方式处理 处理您创建的对象。我们可以通过使用System.Object的GetHashCode()方法比较对象来告诉我们:


private void compareObjects()
{
SPSite site = new SPSite("http://cob.blog.dev");
SPWeb web = site.OpenWeb("/MyWeb");
SPList list = web.Lists["MyList"];

SPWeb parentWeb = list.ParentWeb;



// no message displayed..
Debug.Assert(parentWeb.GetHashCode() != web.GetHashCode(), "Objects are not same!");


// create a *new* SPWeb object and compare it to our other reference..
web = site.OpenWeb("/MyWeb");

// message IS displayed..
Debug.Assert(parentWeb.GetHashCode() != web.GetHashCode(), "Objects are not same!");
}


从中我们看到的是,存储在list.ParentWeb属性中的SPWeb对象与我们创建的原始SPWeb对象具有相同的哈希码,但是如果我们创建同一网站的新实例,则其具有不同的哈希码。这表明第一个比较中的对象是相同的-因此,通过ParentWeb引用处理它们确实会处理我们创建的对象。开心的日子-我们找到了 能够 以一种可能更具逻辑性和可读性的方式来分解我们的代码。


注意事项

那么,为什么在任何已发布的指南中都没有提及呢?很好,在整个代码中使用这种技术之前,您应该考虑到以这种方式编写代码时,我们实际上是依靠当前SharePoint API的内部实现细节。如果Microsoft要在Service Pack(或SharePoint的下一版本)中对此进行更改,则我们的代码可能不再能正确处理对象。我建议您自己考虑一下(尤其是因为您可能对我的结论有所不同),但是我建议这种更改不太可能。原因是SharePoint团队本身需要消除任何不必要的SPSite / SPWeb对象,因此 当然 有道理,用于获取SPList的相同SPWeb实例用于填充ParentWeb变量。创建一个额外的实例将使API 高效。在此基础上,我个人很高兴以这种方式编写代码。如果您认为我错了(我不能保证我没有错),那么我当然希望收到您的来信。

在下一篇文章中,我还将讨论超越MSDN示例的想法,并尝试以更“企业”或“模式”的方式编写SharePoint数据访问代码。敬请期待更多。


处置SharePoint对象-必读

2008年6月1日,星期日

常见SharePoint开发任务的代码/功能示例

有很多工具可以帮助开发人员,但是我一直认为最有用的事情实际上是 看到一个很好的例子 我正在尝试开发的东西。这就是为什么SharePoint博客如此受欢迎吧?除了查看我最喜欢的博客或过去的文章,我 总是 回到以前的工作-也许看看我在某个SharePoint文件中使用了什么值,或者获取了我编写的代码块,可以对其进行修改以满足我的当前要求。因此,今天我想向您指出一些有用的示例,如果您是SharePoint开发人员,这些示例可能是很好的参考资料-实际上,我在这里并没有发布任何新内容,而是强调我最近 “配置存储”解决方案 提供了一个伟大的"one-stop shop"几种常见SharePoint开发任务的可下载示例。在解决方案中都可以找到以下开发任务的示例:

  • 将网站列,内容类型部署为功能
  • 部署列表(具有默认列表项)作为功能
  • 使用功能接收器
  • 使用SPWebConfigModification在代码中进行web.config更改/作为功能的一部分
  • 使用SPQuery有效地查找列表中的项目
  • 在没有WSP Builder的情况下构建解决方案包(.wsp)
  • 编写解决方案部署脚本以收回解决方案,停用功能,重新部署解决方案,激活功能等。
  • 使用事件接收器
  • 作为.Net的奖励,如何使用HttpRuntime类与Web上下文外部的ASP.Net缓存一起使用

整套代码/功能文件 可以从Codeplex下载 ,使其成为包含上述所有任务的样本的出色参考项目。如果这对您有用,则下面的列表详细介绍了要打开的文件以查找代码示例以及一些说明,这些说明可以帮助您掌握任务:

将网站列,内容类型部署为功能:

文件

笔记

ConfigStoreElements.xml           

这是通过使用Field / ContentType功能元素来完成的。请注意,这些字段应位于同一元素文件中任何ListTemplate / ListInstance项之前-如果在不同文件中使用两组元素,请确保在manifest.xml中首先列出字段/内容类型文件。



部署列表(具有默认列表项)作为功能:

文件

笔记

ConfigStoreElements.xml           

这是通过使用ListTemplate / ListInstance Feature元素完成的。



功能接收器:

文件

笔记

ConfigStoreFeatureReceiver.cs

就我而言,功能接收器对web.config进行了修改,并以编程方式将列表事件接收器添加到了列表中。



web.config修改

文件

笔记

ConfigStoreFeatureReceiver.cs

这是通过使用SPWebConfigModification类来完成的。我将三个条目添加到web.config中以支持我的解决方案。

 

使用SPQuery查找列表中的项目:

文件

笔记

ConfigStore.cs                                  

我在ConfigStore类中有两个方法以这种方式执行查询(也称为CAML查询)。

 

在没有WSPBuilder的情况下构建解决方案包(.wsp):

文件

笔记

makecab.ddf /                                   
manifest.xml                           

尽管WSPBuilder提供了一种很棒的自动化方式来构建解决方案,但有时还是需要逐步退出该工具以“手动”方式来构建软件包。就我而言,我遇到一个问题,其中WSPBuilder将“错误”顺序的元素添加到生成的manifest.xml文件中,这导致解决方案部署失败。

 

解决方案部署脚本以撤消解决方案,停用功能等:

文件

笔记

COB.SharePoint.Utilities.ConfigStore_Install.bat      

这是我经常用于部署解决方案的脚本。它在每个阶段都有错误检查,因此我可以轻松判断出安装失败的那一点,以进行更简单的问题诊断。

 

使用事件接收器:

文件

笔记

ConfigStoreListEventReceiver.cs

在Config Store解决方案中,当列表内容更改时,我使用列表事件接收器将项目添加到缓存中。此代码使用列表上的ItemAdded和ItemUpdated事件显示。

 

使用HttpRuntime类与ASP.Net外部的ASP.Net缓存一起使用:

文件

笔记

ConfigStoreListEventReceiver.cs

列表事件接收器要记住的一点是,我们实际上无权访问HttpContext.Current或SPContext.Current-两者均为空。如果不是HttpRuntime类,这对我的Config Store代码来说将是一个问题,因为我想从列表事件接收器的缓存中添加/删除项目(即在列表项更改后立即管理缓存)。幸运的是,HttpRuntime允许我们从任何代码位置(例如,控制台应用程序)访问ASP.Net框架。

 

下载所有这些东西的链接位于 http://www.codeplex.com/SPConfigStore。希望您发现样本有用,如果没有任何意义,请随时发表评论。