Wenn man EventReceiver für Listen über ein Feature mit Scope Site für eine bestimmte Liste bereitstellen möchte, werden diese an alle Listen gebunden. Das Beste daran ist aber, daß diese EventReceiver über das SharePoint-Objektmodell nicht zugänglich sind. Sie werden also von Tools wie dem SharePoint Manager nicht angezeigt. Dieses Problem hat bei uns im Kollegenkreis für sehr viel Verwirrung und einige graue Haare gesorgt.
Features mit Scope Site werden normalerweise verwendet um Websitespalten, Inhaltstypen, Webparts, Masterpages und ähnliches bereitzustellen. Also für Dinge, die in der gesamten Websitesammlung nutzbar sein sollen. Manchmal ist es aber nützlich, darüber auch Listeninstanzen und zugehörige EventReceiver bereitzustellen, damit diese bei Aktivierung im Rootweb der Websitesammlung erscheinen. Laut MSDN: Elements by Scope sollte das problemlos möglich sein, führt aber zum genannten Fehler. Exakt derselbe Code funktioniert bei einem Feature mit Scope Web reibungslos.
Vorgehensweise:
Man erstellt eine eigene Listendefinition
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<ListTemplate Name="MyList"
Type="10001"
BaseType="0"
SecurityBits="11"
Sequence="410"
DisplayName="My List"
Description="My List Definition"/>
</Elements>
und die zugehörige schema.xml, die sich in einem Ordner MyList befinden muß, d.h. der Ordnername muß dem Name-Attribut entsprechen. Zu beachten ist auch das Type-Attribut, das hier mit 10001 belegt wurde, um die eigene Vorlage eindeutig zu identifizieren.
Eine Instanz dieser Liste kann man dann so bereitstellen:
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<ListInstance Title="My List Instance"
OnQuickLaunch="TRUE"
TemplateType="10001"
Url="Lists/MyList"
Description="My List Instance">
</ListInstance>
</Elements>
Möchte man an diese Instanz einen EventReceiver binden, geht man normalerweise so vor (wie gesagt, bei einem Site-Scoped Feature geht das nicht):
<Receivers ListTemplateId="10001">
<Receiver>
<Name>MyAddingEventReceiverg</Name>
<Type>ItemAdding</Type>
<Assembly>$SharePoint.Project.AssemblyFullName$</Assembly>
<Class>MyNamespace.EventReceiver</Class>
<SequenceNumber>10000</SequenceNumber>
</Receiver>
</Receivers>
Man beachte auch hier wieder das Attribut ListTemplateId, mit dem der EventReceiver an eine ganz bestimmte Liste gebunden werden soll. Leider wird das bei Site-Scoped Features komplett ignoriert und der EventReceiver hängt dann an ausnahmslos allen Listen und Bibliotheken. Auch die anderen Attribute des Receivers-Elements (Beschreibung) ändern daran nichts.
Lösungen:
Man kann die EventReceiver in ein Feature mit Scope Web aufnehmen. Wenn man dieses Web-Feature vom Site-Feature, das die Inhaltstypen und Listendefinitionen bereitstellt, abhängig macht, dann spielen die einzelnen Bestandteile auch reibungslos zusammen. Nachteil für den Benutzer ist aber, daß er jetzt zwei Features aktivieren muß. Außerdem kann das Web-Feature auch in beliebigen Subwebs aktiviert werden, was u.U. nicht gewünscht ist.
Die bessere Lösung ist in diesem Fall, den EventReceiver an einen Inhaltstyp zu binden. Für die eigene Listendefinition verwendet man dann auch einen eigenen Inhaltstyp (was ohnehin Best Practice entspricht) und bindet den EventReceiver einfach daran. Dieses Vorgehen funktioniert auch bei Site-Features wunderbar.
Und so wird ein EventReceiver an einen Inhaltstyp gebunden:
<ContentType ID="0x01005CFD4072A1BD472AADB25F383E4E888A"
Name="My ContentType"
Group="My ContentTypes">
<FieldRefs>
…
</FieldRefs>
<XmlDocuments>
<XmlDocument NamespaceURI="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms">
<Receivers ListTemplateId="12004">
<Receiver>
<Name>MyAddingEventReceiverg</Name>
<Type>ItemAdding</Type>
<Assembly>$SharePoint.Project.AssemblyFullName$</Assembly>
<Class>MyNamespace.EventReceiver</Class>
<SequenceNumber>10000</SequenceNumber>
</Receiver>
</Receivers>
</XmlDocument>
</XmlDocuments>
</ContentType>
Das selbe Problem hatte ich auch vor kurzen. Das Problem beim ContentType ist aber wenn du von diesem ContentType ableitest wird zu jedem ContentType der EventReceiver an die Liste (nicht CT) gebunden. So wird dieser mehrmals aufgerufen. Was mich dabei gewundert hatte ist das der Name mehrmals vorhanden sein kann.
Ich habe es so gelöst das der EventReceiver über Scope Web (Hidden) bereitgestellt wird und ich diesen dann beim aktivieren des Site Feature aktiviere und beim deaktivieren ebenfalls deaktiviere.
I came, I read this article, I conquered.