avoid deactivating feature if content type is used
-
Wednesday, August 22, 2012 11:15 AM
Hello,
I added content types to a web using C#. If I want to deactivate the feature that deploys the content types I want to delete them. There is a nice method that gets the usage of a content type (don't know which library it was). My question is: Does I have to handle this scenario or does SharePoint recognizes this and stops deactivating the feature without deleting the content types?
best regards
All Replies
-
Wednesday, August 22, 2012 11:38 AM
Hi,
SharePoint warns you when you deactivate any feature. It may give exception if you are going to delete content type that is in use, but I didn't come across it yet.
Library you were looking for check usage of content type, you can refer below link.
http://msdn.microsoft.com/en-us/library/ms453791.aspx
Thanks and Regards, Shailesh B. Davara
-
Wednesday, August 22, 2012 11:45 AM
Hi,
yeah I know this library. I just forgot it in that moment :)
Of course SharePoint warns me, but does this also work for programmatically added content types like this:
SPContentType contentType = web.ContentTypes.Cast<SPContentType>().FirstOrDefault(ct => ct.Name.Equals("MyContentType")); // Remove if available if (contentType != null) { contentType.Delete(); } contentType = new SPContentType(web.ContentTypes["Document"], web.ContentTypes, "MyContentType") { Description = "MyContentType", Group = "Custom", }; web.ContentTypes.Add(contentType); contentType.Update();I want to remove them here:
SPContentType contentType = web.ContentTypes["MyContentType"]; if (contentType != null) { var usages = SPContentTypeUsage.GetUsages(contentType); if (usages.Count > 0) { // Do not deactivate feature then return false; } else { web.ContentTypes.Delete(contentType.Id); return true; } }Can I tell SharePoint to stop deactivation if it is in use?
-
Wednesday, August 22, 2012 12:01 PM
May be you can try to throw an exception explicitly when your condition is not met, something like
public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
{//If conditions are not met....
throw new Exception("Deactivation should stop!!!");
}"T" | My blog updates | My Twitter | Our Products | Mail Me | LinkedIn | My Virtual Business Card
-
Monday, October 01, 2012 9:10 AM
The preassigned answer is not completly right. I am checking for ContentTypeUsage.
SPContentTypeUsage.GetUsages(contentType)
If the CT is in use i find it. So I am checking everyone and remove everyone if none is used. Unfortunatly if I used a CT in a list and remove the list (also from recycle bin) the GetUsage method finds no usage (correct I guess), but when I remove the CT then an exception occurs, that the CT is in use.
Why? And what is the solution?
-
Monday, October 01, 2012 9:20 AM
hi
do you updated web after deleting lists and before deleting content type?
yaşamak bir eylemdir
-
Monday, October 01, 2012 9:35 AM
Why do I have to do that? I am deleting the list in SharePoint and not by code.
I am doing the following:
public override void FeatureDeactivating(SPFeatureReceiverProperties properties) { SPWeb web = null; if (properties.Feature.Parent is SPWeb) { web = properties.Feature.Parent as SPWeb; } else if (properties.Feature.Parent is SPSite) { web = ((SPSite)properties.Feature.Parent).RootWeb; } if (web != null) { this.RemoveContentTypes(web, "InQuDocument", "InQuVersion"); web.Update(); web.Dispose(); } else { throw new NullReferenceException("Could not deactivate feature because no SPWeb found"); } } private bool CheckForUsageOfContentType(SPWeb web, string contentTypeName) { if (string.IsNullOrEmpty(contentTypeName)) { return false; } SPContentType contentType = web.ContentTypes[ResourceHelper.GetContentTypeName(contentTypeName, ResourceFiles.Common, web.Language)]; if (contentType != null) { var usages = SPContentTypeUsage.GetUsages(contentType); if (usages.Count > 0) { // Do not deactivate feature then return true; } } return false; } private void RemoveContentTypes(SPWeb web, params string[] contentTypeNames) { foreach (string contentType in contentTypeNames) { if (this.CheckForUsageOfContentType(web, contentType)) { throw new NotSupportedException(string.Format("Could not remove ContentType {0} because it is in usage.", contentType)); } } foreach (string contentType in contentTypeNames) { this.RemoveContentType(contentType, web); } } private bool RemoveContentType(string keyName, SPWeb web) { if (string.IsNullOrEmpty(keyName)) { return false; } SPContentType contentType = web.ContentTypes[ResourceHelper.GetContentTypeName(keyName, ResourceFiles.Common, web.Language)]; if (contentType != null) { contentType.Delete(); return true; } return false; }And here "contentType.Delete()" it fails with SPException "ContentType is in use".
-
Monday, October 01, 2012 11:18 AM
Hi,
did you able to debug and check inner exception? I guess if you go and check inside of inner exception and details, it will surely leads to some solution.
Thanks and Regards, Shailesh B. Davara
-
Monday, October 01, 2012 11:47 AM
Die inner exception is null.
The stack trace looks like this:
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code. Exception Details: Microsoft.SharePoint.SPException: The content type is in use. Source Error: An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below. Stack Trace: [SPException: The content type is in use.] Microsoft.SharePoint.SPContentTypeCollection.DeleteFromWeb(SPContentTypeId id, String strName) +648 Microsoft.SharePoint.SPContentTypeCollection.Delete(SPContentTypeId id) +26781284 Microsoft.SharePoint.SPContentType.Delete() +85 SP2010.Common.Features.InQuBase.InQuBaseEventReceiver.RemoveContentType(String keyName, SPWeb web) +298 SP2010.Common.Features.InQuBase.InQuBaseEventReceiver.RemoveContentTypes(SPWeb web, String[] contentTypeNames) +481 SP2010.Common.Features.InQuBase.InQuBaseEventReceiver.FeatureDeactivating(SPFeatureReceiverProperties properties) +710 Microsoft.SharePoint.SPFeature.DoActivationCallout(Boolean fActivate, Boolean fForce) +26245030 Microsoft.SharePoint.SPFeature.Deactivate(SPSite siteParent, SPWeb webParent, Boolean fForce) +26239199 Microsoft.SharePoint.SPFeatureCollection.Remove(Guid featureId, Boolean force) +28035674 Microsoft.SharePoint.ApplicationPages.DeactivateFeaturePage.LnkbtnDeactivateFeature_Click(Object objSender, EventArgs evtargs) +142 System.Web.UI.WebControls.LinkButton.OnClick(EventArgs e) +101 System.Web.UI.WebControls.LinkButton.RaisePostBackEvent(String eventArgument) +100 System.Web.UI.Page.RaisePostBackEvent(IPostBackEventHandler sourceControl, String eventArgument) +29 System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +2981
-
Tuesday, October 02, 2012 3:26 AM
When you delete a list then did you first remove the association of that list with content type by going to the list settings and then deleting the content type attached there? If you have not done that, then though the list is deleted but the association of that list with content type prevails in the database due to which inspite of the fact that the list has been deleted you are facing the content type usage issue.
I have written a blog about this which you can check at
http://community.zevenseas.com/Blogs/Geetanjali/Lists/Posts/Post.aspx?ID=4
Here I have explained which table stores the mapping between the list and content type.
P.S. It is not recommended to make modifications to the content database. This article is to explain behind the scene what is actually happening.
Hope it will give you some idea as to why you faced this error even on deleting the list.
Geetanjali Arora | My blogs |
- Proposed As Answer by Nauzad KapadiaMVP Tuesday, October 02, 2012 6:04 AM
- Unproposed As Answer by Gozar15 Tuesday, October 02, 2012 1:31 PM
-
Tuesday, October 02, 2012 5:37 AM
Thanks for explaining. I did not remove the association. I thought the GetUsages-Method recognizes such problems. In fact it does not.
So I guess there is no real chance to remove a used content type by feature?! If I have to update it by wsp an error occurs always?!
-
Tuesday, October 02, 2012 1:32 PMSo there is no reason to add a content type by feature? Am I correct?
-
Tuesday, October 02, 2012 4:55 PM
If you have to deploy some content types to your site collection, you can do them using features. The thing which is very tricky when it comes to content types is deleting the content types which are already in use.
In case you have accidentally deleted a list which has the content type attached to it from UI without removing the association of content type from it then you get stuck with orphanded content type association in the content database and as a result deactivation will not help you. However, if while deleting the list from UI if the proper best practice is followed then you will not face this issue in deactivation. In case you delete list programmatically then you can programmatically delete the association and then delete the list.
Geetanjali Arora | My blogs |
-
Tuesday, October 02, 2012 9:26 PM
Content types deployed with code vs content types that are deployed with xml behave differently from one another in sharepoint.
Content deployed through schema code isn't immeditaley stored in the content database. It exists only out in the 14 hive's feature folder. I call this Schema mode. Once a content type is used from that feature it get's logged in the content database, but is still based on the schema in the 14 hive.
Deactivating the feature will happen, but it will not retract your content types if they are in use. You must remove the content type from usage before deactivating the feature to get it to retract, again this is because it's still schema based.
However, if someone edits that content type in the browser it breaks it's dependency on the schema and becomes persistent on the change in the content database and no longer based on the schema. However it is still associated with the feature so you can't delete it "this content type is part of a feature". In my experience we tell our designers and admins not to touch wsp deployed content types in the browser and instead make a code change. Because we've had experiences where content types that were deployed via xml will not retract if edited in the browser in use or not. Or they get stuck as being in use when their not.
To get around that you can deploy via code,
But it still doesn't solve your question. You can block the feature from being deactivated via the feature deactiving event, you msut add a feature event receiver to do it.
After calling
SPContentTypeUsage.GetUsages(contentType)
Throw an exception "Cannot deactivate this feature, content types in use."
BUt it's cosmetic, after removing the usage of your content type you can reactivate the feature and deactivate it again to get it to retract them.
My Blog: http://www.thesug.org/Blogs/ryan_mann1/default.aspx Website: Under Construction
-
Thursday, October 04, 2012 5:39 AM
But it still doesn't solve your question. You can block the feature from being deactivated via the feature deactiving event, you msut add a feature event receiver to do it.
I am doing that "workaround" but it is not working. As you can see in my code (previous post) I am searching for using of every content type and if anyone is in use I stop deactivation. The problem is when I used a CT and removed the list (also from recycle bin) the GetUsages method returns 0 but nevertheless I cannot remove the ct because an SPException is thrown (CT is in use...).After calling
SPContentTypeUsage.GetUsages(contentType)
Throw an exception "Cannot deactivate this feature, content types in use."
-
Thursday, October 04, 2012 2:47 PM
There are two level's to the recycle bin, one at the user level I think, and another at the site level. When you go to recycle bin and delete the items there should be a link at the top somewhere to trill into the next level of the recycle bin where you have to delete them again.
Also, when deploying content types and lists with xml based entities, if they are edited bysomeone in the browser, they get stuck, and they will say they are in use when they are actually not. I'm not exactly sure what the trigger scenarios are for introducing this bug, but I've seen it countless times. Which is why I make my content types read only and tell people if they want to edit it to create a new CT that inherits it, or edit it in the context of a lsit and not to modify the site collection level content type.
When it gets edited in the browser it breaks it's schema dependancy and it becomes committed to the sites content database. When it's in use it gets entered in a table containing it's ID and the id of what's using it etc. The CT in the database also gets a flag wit a name of something like "IsFeatureCT".
(The following is not recommended and not support from Microsoft to the best of my knowledge, but it works)
You can run a sql select query to see if your CT is infact hosed up,
SELECT SiteId, sys.fn_varbintohexstr(ContentTypeId) AS ID, WebId, ListId, IsFieldId, Class
FROM ContentTypeUsage
WHERE (sys.fn_varbintohexstr(ContentTypeId) LIKE ‘ID%’)replace ID with the ID of your content type
It should return some list id's, Once you get the list id's that it says are using the Content Type, Open PowerShell and do
$site = Get-SPSite SiteIDHere
$web = Get-SPWeb = $site.OpenWeb(WebIdHere)
$list = $list[ListIdHere]
if ($list -eq $null){
write-host List Does not exist
}
If the list does not exist and it's not in the recycle bin, you'd need to issue sql statement to delete the content type usage record.
Optionally you can disable the feature, uninstall the feature, then go to the ct and set it's IsFeature* to zero in sql and try to delete it in the UI again.
More at this person's blog,
My Blog: http://www.thesug.org/Blogs/ryan_mann1/default.aspx Website: Under Construction
-
Friday, October 05, 2012 6:16 AMOkay. Nevertheless all solutions are quite uncomfortable. Is the CT (and the corresponding lists) updated, when I deploy my solution with several changes on the CT?
-
Friday, October 05, 2012 2:18 PM
Depends on how you deployed. If you use Visual Studio's default deployment it will nuke everything and redeploy them, so no.
Imagine this scenario-
1. You deployed with visual studio
2. Your solutions contains 1 ct and 1 list, the ct is used in the list that is deployed as part of the same wsp as the CT
3. You or someone else uses the deployed CT in another list, not part of the wsp.
You redeploy later and it fails. The retraction process and list conflict resolver that's part of the visual studio deployment process won't know to nuke the list the other user made with your ct, meaning your ct is still in use and doesn't retract with the solution, retraction either fails in the deployment process, or the deployment process fails.
There really is no easy solution to this problem except to prevent it from happening in the first place. If you deploy ct's and lists form visual studio don't update them in the UI, update them in the solution always.
Once they get hosed up that sql query is really the only way to fix it that I've found, that or nuke the entire web app content database and rebuild it.
My Blog: http://www.thesug.org/Blogs/ryan_mann1/default.aspx Website: Under Construction

