1

I have a custom content type which I am deploying to a Site collection in which content type hub is configured. To use the content types in different site collection after the content type is deployed we have to perform three steps:

1) Publish the content type

2) Run the Content Type Hub timer job

3) Run the Content Type Subscriber timer job.

I found this blog here, which is doing the same in feature activation.

My Code

public override void FeatureActivated(SPFeatureReceiverProperties properties)
        {
            //bool remoteAdministratorAccessDenied = SPWebService.ContentService.RemoteAdministratorAccessDenied;
            try
            {
                //SPWeb spWeb = properties.Feature.Parent as SPWeb;
                //SPSite spSite = spWeb.Site;

                string contentTypeHubSiteURL = string.Empty;

                //System.Configuration.Configuration config = WebConfigurationManager.OpenWebConfiguration("/", spSite.WebApplication.Name);

                // App settings are retrieved this way
                if (properties.Feature.Properties["CTHubUrl"] != null)
                {
                    contentTypeHubSiteURL = Convert.ToString(properties.Feature.Properties["CTHubUrl"].Value);
                }
                else
                {
                    contentTypeHubSiteURL = "hardcoded url";
                }


                if (!string.IsNullOrEmpty(contentTypeHubSiteURL))
                {
                    using (SPSite siteCtHub = new SPSite(contentTypeHubSiteURL))
                    {
                        using (SPWeb webCtHub = siteCtHub.RootWeb)
                        {
                            if (ContentTypePublisher.IsContentTypeSharingEnabled(siteCtHub))
                            {
                                ContentTypePublisher ctPublisher = new ContentTypePublisher(siteCtHub);

                                IEnumerable<SPContentType> spContentTypes =
                                    webCtHub.AvailableContentTypes
                                    .Cast<SPContentType>().Where(ct => ct.Group == "My group");

                                foreach (SPContentType spContentType in spContentTypes)
                                {
                                    ctPublisher.Publish(spContentType);
                                    Thread.Sleep(100);
                                }
                            }
                        }
                    }


                    using (SPSite siteCtHub = new SPSite(contentTypeHubSiteURL))
                    {
                        using (SPWeb webCtHub = siteCtHub.RootWeb)
                        {
                            //SPWebService.ContentService.RemoteAdministratorAccessDenied = false;
                            SPWebApplication spWebApp = siteCtHub.WebApplication;

                            SPService saMMS = spWebApp.Farm.Services.Cast<SPService>()
                                .FirstOrDefault(s => s.TypeName == "Managed Metadata Web Service");

                            SPJobDefinition ctHubTimerJob = null;

                            //Run the Content Type Hub Job
                            //This timer job is associated with the MMS service application    
                            ctHubTimerJob = saMMS.JobDefinitions.Cast<SPJobDefinition>()
                                .FirstOrDefault(jd => jd.Title == "Content Type Hub");
                            if (ctHubTimerJob == null)
                            {
                                saMMS = spWebApp.Farm.Services.Cast<SPService>()
                                    .FirstOrDefault(s => s.TypeName ==
                                        "Microsoft SharePoint Foundation Timer");

                                ctHubTimerJob = saMMS.JobDefinitions.Cast<SPJobDefinition>()
                                    .FirstOrDefault(jd => jd.Title ==
                                        "Content Type Hub");
                            }

                            DateTime startTime = DateTime.Now.ToUniversalTime();
                            ctHubTimerJob.RunNow();

                            while ((from SPJobHistory j in saMMS.JobHistoryEntries
                                    where j.JobDefinitionId ==
                                        ctHubTimerJob.Id && j.StartTime >
                                        startTime
                                    select j).Any() == false)
                            {
                                Thread.Sleep(100);
                            }

                            //Run the Content Type Subscriber Job
                            //This timer job is associated with the subscriber's web application
                            SPJobDefinition ctHubSubTimerJob = spWebApp.JobDefinitions.Cast<SPJobDefinition>()
                                .FirstOrDefault(jd => jd.Title == "Content Type Subscriber");
                            startTime = new DateTime();

                            startTime = DateTime.Now.ToUniversalTime();

                            ctHubSubTimerJob.RunNow();

                            while ((from SPJobHistory j in spWebApp.JobHistoryEntries
                                    where j.JobDefinitionId ==
                                        ctHubSubTimerJob.Id && j.StartTime >
                                        startTime
                                    select j).Any() == false)
                            {
                                Thread.Sleep(100);
                            }
                        }
                    }
                }
            }
            catch (Exception)
            {

                throw;
            }
            finally
            {
                //SPWebService.ContentService.RemoteAdministratorAccessDenied = remoteAdministratorAccessDenied;
            }
        }

My feature is scoped at web level(also tried with SiteCollection level), but getting access denied error in this line

ctHubSubTimerJob.RunNow();

Also tried RunwithElevatedPrivelege, anyways I am having farm administrator privilege.

Am I doing something wrong? Are there any workaround?

1 Answer 1

1

When a timer job instance is created, it is persisted to the farm configuration database. Accessing this database for write purposes is a privileged operation; as a rule of thumb, only the farm service account (that is, the account under which OWSTIMER.EXE executes) or accounts that explicitly have the rights required to carry out such an operation on the config database (typically administrators) will succeed.

By default, attempting to instantiate a timer job from within the site collection context is going to fail. Attempting the operation in an elevated privilege block (via SPSecurity.RunWithElevatedPrivileges) is only going to result in the web application's application pool account context being used instead of the current user context; this only succeeds if the app pool account has rights to write to the farm configuration database. If this happens, it's typically because (a) the farm service account is being used in roles that it shouldn't be in (to run content web apps, for example), or (b) extra permissions have been granted to the application pool account. Both cases represent a deviation from a best-practices operating model.

References:

https://stackoverflow.com/questions/1036589/problem-in-creating-timer-job

Run Sharepoint timer job programatically using RunNow() using account having non admin rights

http://www.sharepointblues.com/2010/10/22/custom-spjobdefinition-and-access-denied-error/

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.