显示带有标签的帖子 功能接收器. 显示所有帖子
显示带有标签的帖子 功能接收器. 显示所有帖子

2007年12月,星期日

网站定义-网站创建过程中的自定义代码

这是三篇文章系列中的第二篇,我的目的是展示如何使用您自己的API代码自定义网站创建过程(称为网站配置)。完整的介绍和系列内容可以在以下位置找到: http://sharepointnutsandbolts.blogspot.com/2007/07/article-series-custom-permissions-with.html。我正在使用的示例自定义如下: any 使用定义创建的网站 应该使用一组特定的权限,而不是简单地遵循继承父网站权限的默认行为。由于无法使用标准的网站定义来完成此操作(就像您可能要执行的许多其他操作一样),因此需要使用API​​。

但是,今天 重点不是我的示例的权限细节,而是更多 how generally to 添加您自己的代码,该代码将在网站配置过程中运行。最好的是,如果您了解SharePoint功能,则实际上非常简单。

有许多原因可能导致您有理由在网站配置过程中使用API​​。本质上,如果你 在onet.xml文件中找不到使用CAML模式进行操作的方法,可能是您不得不 write code. Hence, 想想你几乎容易 能够 在onet.xml文件中执行 and reverse the list in order to work out scenarios which require code, but some examples which spring to mind 任何how are:

  • 更改网站的自定义母版页
  • 创建一个站点列以从列表中获取数据(请参阅我的功能接收器上的文章,该文章位于 在Codeplex上创建查找字段的功能)
  • 向网站添加定制的唯一权限(本系列文章中的示例)
  • 设置网站属性 from 任何 kind of dynamic lookup

简而言之,有很多方案。


使用VSeWSS创建网站定义

如果您曾经用以下方法创建网站定义 Windows 的SharePoint Services的Visual Studio扩展,您会注意到它给您的VS项目包含一个名为SiteProvisioning.cs的文件。内部是一个事件处理程序方法,您可以在其中添加自定义代码,该代码将在根据定义创建站点时执行。该类如下所示:

命名空间 COB.Demos.SiteDefinition

{

    上市 部分的 ProjectXSiteDefinition

    {

        /// <summary>

        ///  在此处定义您自己的功能激活操作代码

        /// </summary>

        上市 虚空 激活(SPFeatureReceiverProperties 属性)

        {

            //我的代码在这里。

        }

    }

}

 

所有这些背后的管道都很有趣。乍一看,方法签名看起来像功能接收者,但实际上不是。但是,检查VS项目(您至少需要用F5生成一个项目才能生成文件)表明,VSeWSS实际上已经在后台创建了一些功能。这些文件可以在VS项目的bin \ Debug \ solution文件夹下找到(默认情况下是隐藏的-您需要在Visual Studio Solution Explorer中执行“显示所​​有文件”)。如果您进一步研究以确切了解VSeWSS的功能,则会发现以下内容:

  • 2 已创建功能-1部署了'default.aspx'文件,另一个没有'elements'文件,但已连接到功能接收器-这是 与VS项目相同的程序集中的类。如果您检查GAC,您的确会在此找到该程序集。
  • 在“ WebFeatures”元素下的onet.xml文件中添加了类似于以下内容的行:

    <特征 ID ="67b2507c-8822-41dc-b939-3d8f34b5ad13" />


    值得注意的是,这是连接到功能接收者的功能的ID。
  • 在包含功能接收器的程序集上使用Reflector显示,主事件处理程序方法执行了一些处理,然后调用 激活 上面显示的方法,即VSeWSS为您提供的位置,以添加您自己的代码以在创建网站时执行。该代码实际上包含在VS项目中的SiteProvisioning.Internal.cs文件中。 (如果您对这里的所有代码到底在做什么感到好奇,就我所知,答案是,当使用VSeWSS项目模板创建网站定义时,没有任何答案。但是,在Solution Generator中也可以找到此代码用于提取网站定义-在这种情况下,需要完成一些修正,这就是所使用的代码。)

因此,总而言之,VSeWSS将创建一个隐藏的功能添加到onet.xml的“ WebFeatures”部分,以便在 定义用于创建网站*。 Feature连接到Feature接收器,该接收器调用您的自定义代码所在的OnActivated方法。

*(注意 如果该定义用于创建网站定义, 根网站也被创建 自动执行,因此功能也会 然后被激活。另请注意,该功能必须已经 已安装 在服务器场中以这种方式激活它)。

我们可以从中得出的结论是,在站点供应过程中没有“特殊位置”可注入自定义代码,但这可以通过使用功能接收器来完成。因此,如果您不想使用VSeWSS创建网站定义,则可以使用这种技术将自定义代码添加到网站创建过程中。

就该代码的外观而言,“ Hello World”示例可能是:

上市 虚空 激活(SPFeatureReceiverProperties 属性)

{

     网页 currentWeb = 空值 ;

     网站 currentSite = 空值 ;

     目的 oParent = properties.Feature.Parent;

 

     如果 (properties.Feature.Parent 网页 )

     {

         currentWeb = ( 网页 家长

        currentSite = currentWeb.Site;

     }

     其他

     {

         currentSite = (网站 家长

        currentWeb = currentSite.RootWeb;

     }

 

     currentWeb.Title = “在以下位置设置供应代码” +  DateTime.Now.ToString();

    currentWeb.Update();

}


希望这可以说明编写在定义中创建的站点上设置属性的代码非常简单。一般而言 网页 目的 是 the entry point, and 任何 property which 能够 be modified 能够 be modified using the API. So, 这个 是 a pretty powerful technique which 能够 be used in many scenarios.

如果您有这种要求,我绝对建议您使用VSeWSS简化流程。当然,也可以手动将所有内容打包并打包到解决方案中,但是该工具确实节省了大量麻烦。但是,与VSeWSS一样, 这个价格是有一定灵活性的。作为我的示例代码 the final 文章将显示,有时将数据传递到 Features by using 功能属性,很遗憾,VSeWSS不支持此功能。因此,在有用的情况下,以下链接提供了一个zip文件,其中包含使用上述技术的解决方案/功能, 没有 使用VSeWSS:

http://sharepointchris.googlepages.com/customcodewithsitedefinitions

在下一篇也是最后一篇文章中,我将介绍在创建网站时使用API​​修改网站权限的细节。希望明确的是,这是 结合此处详细介绍的技术,最终结果是可以根据功能自动激活特定功能,从而自动设置特定权限 创建网站时。

2007年4月20日,星期五

在Codeplex上创建查找字段的功能

在一个 最近贴文 我为功能接收器发布了一些示例代码,该功能接收器将创建查找字段(从列表中获取其数据的站点列)。几个人发表评论,要求提供完整的文件。

我把它们放在Codeplex上 http://www.codeplex.com/SP2007LookupFields.

一些注意事项:-

  • 我已经增强了解决方案的通用性,并且可以在一个功能中创建多个查找字段。现在,列表的名称可以包含在CAML中,功能接收器将对此进行解析,查找列表并使用API​​通过列表GUID修复引用。请注意,当前列表必须位于根网站中,尽管扩展该列表很简单。
  • 所有硬编码值均已删除,例如包含CAML定义的文件的路径现在作为功能属性传递。
  • 我在之前的文章中提到过,您可能具有从属功能,以便包含功能接收器的程序集也可以在激活功能时自动部署。因为程序集只能使用SharePoint进行部署,所以这不太有意义。 解决方案 特征。 因此,我将功能包装在部署程序集和功能的SharePoint解决方案中。激活功能后,程序集已经在GAC中,并且功能接收器运行良好。请注意,增强解决方案也很简单,以便使用适用于高度受控环境的CAS策略将程序集部署到站点容器中。
  • 我还包括一个STSADM脚本,用于部署解决方案-您需要编辑此文件中的URL以指向您的SharePoint网站。

希望这是有用的,如果您有反馈意见,请告诉我。

2007年4月15日,星期日

示例代码-创建查找列作为功能

我答应了 较早的帖子 发布用于创建查找列的功能的代码。这里的基本思想是尽可能使用CAML定义网站栏,但使用代码注入该栏所引用的列表ID(在功能设计时未知,因为SharePoint为列表确定了GUID)。下面提取的是功能接收器的代码。

几个要点:

  • 假定文件D:\ COB.Demo.ListBasedSiteColumns.Fields.xml中存在以下内容(注意,“ List”属性为空):-
    <?xml version="1.0" encoding="utf-8"?>
    <elements xmlns="http://schemas.microsoft.com/sharepoint/">
    <!-- _filecategory="ContentType" _filetype="File" _filename="fields.xml" _uniqueid="c0188da6-e320-44c0-b50c-cb6eaecec512" -->
    <Field
    Type="Lookup"
    Displayname="Locations"
    Required="FALSE"
    List=""
    ShowField="LinkTitleNoMenu"
    UnlimitedLengthInDocumentlibrary="FALSE"
    Group="COBDemo"
    ID ="{ae8e6ab8-b151-4fa4-8694-3cd24ad3b1bc}"
    SourceId="{8c066b26-5a3e-4e1b-85ec-7e584cf178d7}"
    StaticName="Locations"
    Name="Locations">
    </elements>

  • 由于大多数列定义都在CAML中,因此您可以指定列的ID。稍后在我们部署需要通过ID引用此网站列的内容类型或列表时,这将很有用。
  • 网站列在使用时(即在内容类型或列表中使用)无法删除。我更喜欢尝试删除有关停用或重新激活功能的列,但忽略错误处理,以便SharePoint引发异常。这使我很清楚为什么无法禁用该功能。有关更多信息,请参见代码中的注释。
  • 请注意,激活此功能后,包含以下代码的程序集必须可用(在GAC或具有适当CAS策略的站点bin目录中)。您还必须在feature.xml文件中指定FeatureAssembly和FeatureReceiver属性,以注册功能接收者。
  • 关于部署程序集,请注意,尽管您当然可以使用功能框架将程序集部署到GAC或站点bin,但您不能在 这个 特征。尽管事件处理程序的名称为“ 特征Activated”,但在执行代码时,仍未处理CAML。因此,您的程序集尚未被复制,并且在尝试加载该程序集时会收到FileNotFoundException。一个好的解决方案是使用功能依赖项。在这里,您可以创建第二个功能来部署程序集,并将主要功能设置为依赖此功能。另外,您可以将程序集部署功能标记为隐藏,从而使实现更简洁。如果查看我使用过的整个文件集有用,请给我留言,然后将它们放在某个地方。
抱歉,我会在有空的时候尝试做一些事情:-


上市 类 特征Receiver : SPFeatureReceiver
{
private readonly string f_csSITE_COLS_DEFINITION_PATH = @"D:\COB.Demo.ListBasedSiteColumns.Fields.xml";

上市 override 虚空 特征Activated(SPFeatureReceiverProperties 属性)
{
//功能位于Site范围内,因此父级的类型为SPSite而不是SPWeb。
使用(SPSite网站= properties.Feature.Parent作为SPSite)
{
网页 currentWeb = 空值 ;
Guid gRootWebId = Guid.Empty;
如果(网站!=空)
{
currentWeb = site.RootWeb;
gRootWebId = currentWeb.ID;
}
其他
{
currentWeb = properties.Feature.Parent作为SPWeb;
gRootWebId = currentWeb.Site.RootWeb.ID;
}





using (currentWeb)
{
// get reference to the list..
SPList referencedList = currentWeb.Site.RootWeb.Lists["LocationsList"];
string sFieldElement = 空值 ;
XmlTextReader xReader = new XmlTextReader(f_csSITE_COLS_DEFINITION_PATH);
while (xReader.Read())
{
如果 (xReader.LocalName == "Field")
{
sFieldElement = xReader.ReadOuterXml();
break;
}
}


string sFinalCaml = replaceListGuidString(sFieldElement, referencedList);
createLookupColumn(currentWeb, sFinalCaml, "Locations");
currentWeb.Update();
}
}
}


private string replaceListGuidString(string sFieldElement, SPList referencedList)
{
string sPopulatedGuid = string.Format("List=\"{0}\"", referencedList.ID);
return sFieldElement.Replace("List=\"\"", sPopulatedGuid);
}

/// <summary>
/// Attempt to delete the column. Note that 这个 will fail 如果 the column 是 inuse,
/// i.e. it 是 used in a content type or list. I prefer to 不 catch the exception
/// (though it may be useful to add extra logging), hence feature deactivation/re- /// activation will fail. This effectively means 这个 feature 能够 not be deactivated whilst the column 是 in use.
/// </summary>
/// <param name="column">Column to delete.</param>

private 虚空 在 temptColumnDelete(SPFieldLookup column)
{
try
{
column.Delete();
}
catch (SPException e)
{
// consider logging full explanation..
throw;
}
}






private 虚空 createLookupColumn(SPWeb web, string sColumnDefinitionXml, string sColumnName)
{
// delete the column 如果 it exists already and 是 不 yet in use..
SPFieldLookup lookupColumn = 空值 ;
lookupColumn = web.Fields[sColumnName] as SPFieldLookup;
如果(lookupColumn!= 空值 )
{
tryColumnDelete(lookupColumn);
}

// now create the column from the CAML definition..
string sCreatedColName = web.Fields.AddFieldAsXml(sColumnDefinitionXml);

// also set LookupWebId so column 能够 be used in webs other than web which hosts list..
lookupColumn = web.Fields[sCreatedColName] as SPFieldLookup;
lookupColumn.LookupWebId = web.Site.RootWeb.ID;
lookupColumn.Update();
}


上市 override 虚空 特征Deactivating(SPFeatureReceiverProperties 属性)
{
// delete the column 如果 it exists already and 是 不 yet in use..



//功能位于Site范围内,因此父级的类型为SPSite而不是SPWeb。
使用(SPSite网站= properties.Feature.Parent作为SPSite)
{
网页 currentWeb = 空值 ;
Guid gRootWebId = Guid.Empty;
如果(网站!=空)
{
currentWeb = site.RootWeb;
gRootWebId = currentWeb.ID;
}
其他
{
currentWeb = properties.Feature.Parent作为SPWeb;
gRootWebId = currentWeb.Site.RootWeb.ID;
}

SPFieldLookup lookupColumn = 空值 ;
lookupColumn = currentWeb.Fields [“ LocationsList”] as SPFieldLookup;

如果(lookupColumn!= 空值 )
{
tryColumnDelete(lookupColumn);
}
}
}



上市 override 虚空 特征Installed(SPFeatureReceiverProperties 属性)
{
}


上市 override 虚空 特征Uninstalling(SPFeatureReceiverProperties 属性)
{
}
}


如果具有说明这两个功能的完整文件集很有用(特别是因为上面的内容不太可读!),请给我评论,然后将它们放在某个地方。

[更新-这些现已上传到Codeplex,请参见 http://sharepointnutsandbolts.blogspot.com/2007/04/feature-to-create-lookup-fields-on.html]

2007年3月20日,星期二

如何调试SharePoint功能接收器

如果有人发现有用,请快速详细地说明如何完成此操作。对于仍在使用SharePoint功能的用户,功能接收器是一个类,其中包含您编写的一些在激活功能时执行的代码。或停用,安装或卸载。

要注意的关键是它只是标准的ASP.Net调试。该过程是:-

  • 将程序集部署到运行时位置(GAC或站点bin目录)。请注意,如果它是bin目录,则您的功能也将需要适当的CAS策略来授予代码所需的权限。
  • 将.pdb文件部署到同一位置。如果这是GAC,则可以执行以下操作:

    -将驱动器映射到GAC文件夹,即C:\ WINDOWS \ assembly 但是使用UNC路径 例如[MachineName] \ C $ \ WINDOWS \ assembly。这使您可以浏览GAC,而无需框架放在文件夹中的外壳,从而可以查看磁盘上文件的实际结构。
    -找到GAC_MSIL子文件夹。在这里,您将看到当前存储在GAC中的每个程序集的目录。找到您的程序集的目录,然后添加.pdb文件,使其位于dll旁边。


  • 在Visual Studio中,将调试器附加到w3wp.exe进程。请注意,有时会有两个这样的过程(例如,当该过程被回收时),并且有可能附加到错误的过程中。 Either do an IISReset可以将它们都停止,以便只有1个随着下一个Web请求启动,或者在命令提示符下键入“ iisapp”以获取正在运行的w3wp.exe进程的进程ID。然后,可以将正确的匹配到“附加调试器”对话框中显示的列表。
  • 通过Web UI激活功能(网站设置> Site Collection 特征/Site 特征). The debugger will now stop on 任何 breakpoints you set.

请记住,程序集必须以调试模式构建,以便创建符号。