更新已部署的 SharePoint 内容类型以处理其他项目事件

发布于 2024-07-25 23:38:26 字数 1489 浏览 2 评论 0原文

我有一个网站内容类型,用于整个网站集中的少数列表。 在该内容类型中,我描述了一个事件接收器来处理 ItemAdding 事件。 这很好用。 现在我需要更新内容类型,以便也处理 ItemUpdating。 我突然尝试简单地修改我的内容类型的 xml,因为这似乎可以轻松进行版本跟踪。 这是有效的,因为我的更新已应用于网站内容类型,但不适用于一直使用此内容类型的列表。 这是预料之中的。 然后我注意到 SharePoint SDK 对此采取了严峻的观点

在任何情况下您都不应该 更新内容类型定义 获得内容类型后的文件 安装并激活该内容 类型。 Windows SharePoint Services 确实 不跟踪对内容所做的更改 类型定义文件。 因此,你 没有办法推倒 对网站内容类型所做的更改 子内容类型。

然后,SDK 指出了几个部分,这些部分描述了如何使用 UI 或代码来推送更改。 由于 UI 不提供事件接收器的挂钩,我想我将选择代码路径。

我以为我可以做这样的事情,只需将一个新的事件接收器添加到内容类型的列表副本中:

SPList list = web.Lists["My list"];
SPContentType ctype = list.ContentTypes["My content type"];
// Doesn't work -- EventReceivers is null below.
ctype.EventReceivers.Add(SPEventReceiverType.ItemUpdating, 
                         "My assembly name", "My class name");

但问题是 ctype.EventReceivers 在这里为 null,即使我已经将 ItemAdding 连接到此列表。 看来它已被移至列表本身。 因此,该列表具有有效的 EventReceivers 集合。

SPList list = web.Lists["My list"];
list.EventReceivers.Add(SPEventReceiverType.ItemUpdating, 
                        "My assembly name", "My class name");

所以,我有几个问题:

  1. 正确的方法是将任何新的事件接收器直接添加到列表中,而完全忘记我的内容类型吗?
  2. 为了完成此更改,在配置管理方面处理此问题的最佳方法是什么? 我应该创建一个简单的控制台应用程序来查找所有适当的列表并修改每个列表吗? 或者以某种方式创建功能是更好的选择吗? 无论哪种方式,这种变化似乎都会自行消失,并且很难被未来可能需要使用这种内容类型的开发人员发现。

I have a site content type that was used for a handful of lists throughout my site collection. In that content type, I describe an event receiver to handle the ItemAdding event. This works fine. Now I need to update the content type so that ItemUpdating is also handled. Off the top of my head, I tried simply modifying the xml for my content type, since this seemed to allow for easy version tracking. This worked in the sense that my updates were applied to the site content type, but not to my lists that had been using this content type. This much was expected. Then I noticed that the SharePoint SDK takes a grim view of that:

Under no circumstances should you
update the content type definition
file for a content type after you have
installed and activated that content
type. Windows SharePoint Services does
not track changes made to the content
type definition file. Therefore, you
have no method for pushing down
changes made to site content types to
the child content types.

The SDK then points to a couple sections which describe how to use the UI or code to push changes. Since the UI offers no hook into event receivers, I guess I will be choosing the code path.

I thought I'd be able to do something like this and just add a new event receiver to the list's copy of the content type:

SPList list = web.Lists["My list"];
SPContentType ctype = list.ContentTypes["My content type"];
// Doesn't work -- EventReceivers is null below.
ctype.EventReceivers.Add(SPEventReceiverType.ItemUpdating, 
                         "My assembly name", "My class name");

But the catch is that ctype.EventReceivers is null here, even though I have ItemAdding already hooked up to this list. It appears that it was moved to the list itself. So, the list has a valid EventReceivers collection.

SPList list = web.Lists["My list"];
list.EventReceivers.Add(SPEventReceiverType.ItemUpdating, 
                        "My assembly name", "My class name");

So, I have a couple questions:

  1. Is the correct way to do this just to add any new event receivers directly to the list and just forget about my content type altogether?
  2. To accomplish this change, what's the best way to handle this in terms of configuration management? Should I create a simple console app to find all the appropriate lists and modify each of them? Or is somehow creating a Feature a better option? Either way, it seems like this change is going to be off on its own and difficult to discover by future devs who might need to work with this content type.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

温柔戏命师 2024-08-01 23:38:26

添加EventReceiver后是否调用了ctype.Update(true)? 如果不这样做,它就不会被坚持下去。
并且不要使用 List 内容类型,而应使用 SPWeb.ContentTypes。

此代码对我有用:

var docCt = web.ContentTypes[new SPContentTypeId("0x0101003A3AF5E5C6B4479191B58E78A333B28D")];
//while(docCt.EventReceivers.Count > 0)
//  docCt.EventReceivers[docCt.EventReceivers.Count - 1].Delete();
docCt.EventReceivers.Add(SPEventReceiverType.ItemUpdated, "ASSEMBLYNAME, Version=1.0.0.0, Culture=neutral, PublicKeyToken=c5b857a999fb347e", "CLASSNAME");

docCt.Update(true);

true 参数意味着它也会被下推到所有子 ContentType。 (即使用内容类型的所有列表)。

Did you call ctype.Update(true) after adding the EventReceiver? If you don't it won't be persisted .
And don't use the List content type, use SPWeb.ContentTypes instead.

This code works for me:

var docCt = web.ContentTypes[new SPContentTypeId("0x0101003A3AF5E5C6B4479191B58E78A333B28D")];
//while(docCt.EventReceivers.Count > 0)
//  docCt.EventReceivers[docCt.EventReceivers.Count - 1].Delete();
docCt.EventReceivers.Add(SPEventReceiverType.ItemUpdated, "ASSEMBLYNAME, Version=1.0.0.0, Culture=neutral, PublicKeyToken=c5b857a999fb347e", "CLASSNAME");

docCt.Update(true);

The true parameter means it gets pushed down to all child ContentTypes as well. (i.e. to all lists using the content type).

二货你真萌 2024-08-01 23:38:26

要回答问题的第二部分,这是一件棘手的事情,因为对网站集上的内容类型的更改不会被推送到使用它的列表中。 “副本”本质上是由网站集中的字段组成的,在将内容类型添加到列表后,它们之间不再有链接。 我认为这是因为您应该对列表进行更改而不影响网站集。 无论如何,我对这个“问题”的贡献以及我如何解决它,涉及使xml成为“主”,并且在featurereceiver中,我拉出xml并找到使用内容类型的所有位置,并从那里更新内容类型(实际上列表级别的 fieldrefs) 以匹配 xml 中的字段。 代码如下:

var elementdefinitions = properties.Feature.Definition.GetElementDefinitions();

foreach (SPElementDefinition elementDefinition in elementdefinitions)
{
   if (elementDefinition.ElementType == "ContentType")
   {
     XmlNode ElementXML = elementDefinition.XmlDefinition;

     // get all fieldrefs nodes in xml
     XmlNodeList FieldRefs = ElementXML.ChildNodes[0].ChildNodes;

     // get reference to contenttype
     string ContentTypeID = ElementXML.Attributes["ID"].Value.ToString();
     SPContentType ContentType = 
         site.ContentTypes[new SPContentTypeId(ContentTypeID)];

     // Get all all places where the content type beeing used
     IList<SPContentTypeUsage> ContentTypeUsages = 
        SPContentTypeUsage.GetUsages(ContentType);
   }
}

接下来是将 xml xml 中的 fieldrefs 与列表中的字段进行比较(由 ID 属性完成)并确保它们相等。 不幸的是,我们无法更新 SPFieldLink 类(fieldref)上的所有内容(是的,我知道它不支持),这里我实际上使用反射来更新这些值(fe ShowInEditForm )。

To answer the second part of your question, this a tricky thing because of the fact that changes to contenttypes on the sitecollection won´t be pushed down to the lists where it´s used. A "copy" is essentially made of the fields in the sitecollection and there is no more link between them after you add a contenttype to the list. I think this is due to the fact that you are supposed to make changes to lists without it affecting the sitecollection. Anyhow my contribution to this "problem", and how I have solved it, involves making the xml the "master" and in a featurereceiver I pull up the xml and find all places where the contenttype is used and from there update the contenttypes (really the fieldrefs) on list level to match the one in the xml. The code goes something like:

var elementdefinitions = properties.Feature.Definition.GetElementDefinitions();

foreach (SPElementDefinition elementDefinition in elementdefinitions)
{
   if (elementDefinition.ElementType == "ContentType")
   {
     XmlNode ElementXML = elementDefinition.XmlDefinition;

     // get all fieldrefs nodes in xml
     XmlNodeList FieldRefs = ElementXML.ChildNodes[0].ChildNodes;

     // get reference to contenttype
     string ContentTypeID = ElementXML.Attributes["ID"].Value.ToString();
     SPContentType ContentType = 
         site.ContentTypes[new SPContentTypeId(ContentTypeID)];

     // Get all all places where the content type beeing used
     IList<SPContentTypeUsage> ContentTypeUsages = 
        SPContentTypeUsage.GetUsages(ContentType);
   }
}

The next thing is to compare the fieldrefs in xml xml with the fields on the list (done by the ID attribute) and making sure that they are equal. Unfortunately we can´t update all things on the SPFieldLink class (the fieldref) and (yes I know it´s not supported) here I have actually used reflection to update those values (f.e. ShowInEditForm ).

凹づ凸ル 2024-08-01 23:38:26

至于你问题的第二部分,我想介绍一下我们过去针对类似情况所做的工作。 在我们的情况下,我们需要几个不同的脚本:一个允许我们将内容类型更新传播到所有网站中的所有列表,另一个将母版页/页面布局重置为站点定义(非自定义表单) )。

因此,我们为每个操作创建了一些自定义 stsadm 命令。 这样做很好,因为脚本可以放入源代码管理中,并且它实现了已经存在的 stsadm 接口。

自定义 SharePoint stsadm 命令

As far as the second part of your question, I wanted to pass along what we've done for similar situations in the past. In our situation, we needed a couple of different scrips: One that would allow us to propagate content type updates down to all of the lists in all webs and another that would reset Master Pages/Page Layouts to the site definition (un-customized form).

So, we created some custom stsadm commands for each of these actions. Doing it this way is nice because the scripts can be placed into source control and it implements the already-existing stsadm interface.

Custom SharePoint stsadm Commands

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文