I made a feature that creates a list with some default data (with a list definition and all required XML)
I observed that when the list already exists, the data will be inserted again in the list... So I tried to make a "FeatureReceiver" to prevent the feature from creating the list if it already exists, but the base class of FeatureReceiver is an abstract class, so even if the list doesn't exists, I can't "call" the base function to continue the normal process...
Is there an easy way to do this or will I have to create the list through the FeatureReceiver by calling the XML file?
I would suggest that you create the lists and all the other stuff you have to do (add/remove fields, contenttypes etc) all through code. I usually never create any lists through xml. This might give you some guidance:
http://johanleino.wordpress.com/2009/08/12/howto-add-splist-based-on-a-custom-template/
Related
I have an odd issue.
I have client that wants a sharepoint list what is populated from a WCFService. That part is working quite well.
I have a bdcmodel that is mapping the WCF data and I can create an external list from the bdcmodel as well so that is working fine.
The issue I have is that one of the properties in the model is actually a collection of entities called Attributes. The objects in this collection simply have 2 properties Name and Value so really they are just a key value pair.
The client wants to see the list of attributes of the parent entity in the external list. So there would be an Attributes column and within that column would be the list of attributes for each parent object.
Is there even a way to do this? I am looking into Custom Field Types, but it seems like these are really intended to be singular values.
How would I create a list within and external list?
Any help anyone can give would be great even if its just to tell me that there really isn't a stable way to do this so I can go back to the client and tell them we will need to build a custom list to support this because the OOB external list and custom fields and custom field types won't support this kind of nested listing.
I decided to set up the custom field as a string and when I get my collection in from the BdcModel I am serializing it to JSON and then passing it to the field. When the field is viewed in display, edit or new I have overridden the FieldRenderingControl and I am tiling the collection out that way.
I'm curious how others address this issue. Using VSEWSS 1.3, I have created a site content type, a list definition (w event receivers), and a list instance. All of them are in the same WSP solution and each is activated individually via features.
Now let's assume that all the features have been activated for some time, and the list instance contains a number of items (that can't be deleted). Now suppose I need to make a change to the schema.xml (inject some javascript, modify views, whatever) of the list.
Is it even possible to "upgrade" the schema of the existing list instance? Otherwise I would think I'm stuck creating a new instance and copying items over.
In my experience, the schema of the list instance will be upgraded most of the time. But if you have made manual customizations to the content type instance or to the list instance's fields, that can break inheritance to the site content type and the list definition resulting in the schema changes not being passed to the list instance. However, even in this latter case, changes to the event receiver will still be picked up by the list instance.
When beginning to develop against SharePoint I did not fully understand all the ins and outs initially. I created a list definition (for a document library) and associated various custom actions to it. Unfortunately, I used the following for the list definition itself:
<ListTemplate...
...
Type="101"
...
And to register the CustomActions against the list:
<CustomAction...
...
RegistrationType="List"
RegistrationId="101"
...
Of course, this means that the custom actions are visible for all document libraries where the feature is activated which is undesirable behaviour. Also, there are lots of these document libraries that have been created from the above list definition in production.
What is the best way to fix this problem? My assumption is that I somehow need to change the "Type" attribute of the already existing lists, but I do not know how to do that. Can it be done via some direct SQL manipulation perhaps? Or is there a better way?
Note: I can see that the AllLists table has a column tp_ServerTemplate, is that the right thing to change?
Modifying the SharePoint database is completely unsupported by Microsoft. Please do not do this on production!
Another option is to create a content type and associate the custom action with that. You may need to write a simple console application to iterate through your existing document libraries and add the content type so it is available for use. The existing documents that you'd like the custom action to apply to would need their content types changed as well.
From some quick initial testing it does look like changing the AllLists table does the trick.
So steps to resolve:
1) Change List Definition Type attribute to be a unique value (for example 11000)
2) Change the CustomAction RegistrationId attributes to be the same (11000)
3) Update the tp_servertemplate column in the AllLists table to be the new template Type (11000) for all the relevant lists.
Metadata seems to be used frequently to describe a SharePoint list's structure. That structure allows the storage of data at the list item level.
How can I specify information about the list itself without relying on an additional column?
Ideally I want something like SPList.Properties ["Mykey"] = "MyValue"
PropertiesXml isn't settable but is there any way to alter the data it returns?
There is no property bag on the SPList object itself, however you can use the one on SPList.RootFolder. Its SPFolder object has a Properties property.
As an alternative to Alex' direct answer, you could store the metadata on your lists in a separate dedicated, possibly hidden, list.
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:
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?
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.
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).
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 ).
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