Unanswered 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
     
      Has Code

    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
     
      Has Code

    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

    • Marked As Answer by Gozar15 Thursday, August 30, 2012 9:15 AM
    • Unmarked As Answer by Gozar15 Monday, October 01, 2012 9:05 AM
    •  
  • Monday, October 01, 2012 9:10 AM
     
      Has Code

    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
     
      Has Code

    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
     
      Has Code

    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 PM
     
     
    So 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
     
      Has Code

    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
     
      Has 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."

    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...).
  • 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, 

    http://akifkamalsyed.wordpress.com/2011/12/24/unable-to-delete-sharepoint-2010-contenttype-contenty-type-in-use/


    My Blog: http://www.thesug.org/Blogs/ryan_mann1/default.aspx Website: Under Construction

  • Friday, October 05, 2012 6:16 AM
     
     
    Okay. 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