10

I've got a WebApplication which should contain a publishing site collection and a custom masterpage for that site collection. I wanted to achieve, if this site collection is created during deployment, the custom masterpage should be automatically applied to it. So the following subsites, that will be created after that during deployment, will automatically inherit the masterpage of the site collection on creation.

In the meantime I solved several errors myself - the major ones can be found at the bottom. Currently I've got a new problem:

I can activate the provisioning feature manually and it works without throwing exceptions. But it doesn't activate automatically on sitecollection creation, although the stapler feature at WebApplication level is active...

I tried to create a feature stapling. So I created a feature called PortalMasterPageStapler.feature and set the scope to WebApplication.

After that I created an empty element called PortalMasterStapler and inside the Elements.xml

<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <FeatureSiteTemplateAssociation Id="8e0965b6-2128-44d9-bcf6-98fc3b1cac98" TemplateName="CMSPUBLISHING#0" />
</Elements>

I've got a module called PortalMaster (inside a folder "Modules") including the masterpages Portal.master and PortalSystem.master. It also includes an Elements.xml (at the moment it also includes another masterpage, but I wanted to test the feature with just one masterpage, first).

<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <Module Name="PortalMaster" List="116" Url="_catalogs/masterpage" Path="PortalMaster" RootWebOnly ="false">
    <File Path="PortalMaster\Portal.master" Url="Portal.master" IgnoreIfAlreadyExists="TRUE" Type="GhostableInLibrary">
      <Property Name="UIVersion" Value="4" />
      <Property Name="ContentTypeId" Value="0x010105" />
      <Property Name="Title" Value="Jasmin Publishing Master Page (Portal)" />
    </File>
    <File Path="PortalMaster\PortalSystem.master" Url="PortalSystem.master" IgnoreIfAlreadyExists="TRUE" Type="GhostableInLibrary">
      <Property Name="UIVersion" Value="4" />
      <Property Name="ContentTypeId" Value="0x010105" />
      <Property Name="Title" Value="Jasmin Publishing System Master Page (Portal)" />
    </File>
</Module>
</Elements>

Then there's the feature PortalMasterProvisioning for the masterpage activation itself with an event receiver (set to scope site):

using System;
using System.Runtime.InteropServices;
using System.Security.Permissions;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Security;

namespace abc.MasterPages.Features.PortalMasterProvisioning
{
/// <summary>
/// This class handles events raised during feature activation, deactivation, installation, uninstallation, and upgrade.
/// </summary>
/// <remarks>
/// The GUID attached to this class may be used during packaging and should not be modified.
/// </remarks>

[Guid("f6224605-7edf-42cf-9eef-c2a5159fee21")]
public class PortalMasterProvisioningEventReceiver : SPFeatureReceiver
{
    // Uncomment the method below to handle the event raised after a feature has been activated.

    public override void FeatureActivated(SPFeatureReceiverProperties properties)
    {
        try
        {
            using (SPWeb web = properties.Feature.Parent as SPWeb)
            {
                using (SPSite site = web.Site)
                {
                    string masterPageUrl = string.Format("{0}/_catalogs/masterpage/Portal.master", site.ServerRelativeUrl.Replace("//", "/"));
                    web.CustomMasterUrl = masterPageUrl;
                    web.MasterUrl = masterPageUrl;

                    web.Update();
                }
            }
        }
        catch (Exception ex)
        {
            string errorMessage = string.Format("Error at activation of feature: {0}", ex.Message);
            throw new SPException(errorMessage);
        }
    }


    // Uncomment the method below to handle the event raised before a feature is deactivated.

    public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
    {
        try
        {
            using (SPWeb web = properties.Feature.Parent as SPWeb)
            {
                using (SPSite site = web.Site)
                {
                    string masterPageUrl = string.Format("{0}/_catalogs/masterpage/v4.master", site.ServerRelativeUrl.Replace("//", "/"));
                    web.CustomMasterUrl = masterPageUrl;
                    web.MasterUrl = masterPageUrl;

                    web.Update();
                }
            }
        }
        catch (Exception ex)
        {
            string errorMessage = string.Format("Error at activation of feature: {0}", ex.Message);
            throw new SPException(errorMessage);
        }
    }
}

}

And here's the event receiver to apply the masterpage to the childsites:

using System;
using System.Security.Permissions;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Security;
using Microsoft.SharePoint.Utilities;
using Microsoft.SharePoint.Workflow;
using System.IO;
using System.Linq;

namespace abc.MasterPages.ChildSiteInit
{
/// <summary>
/// Web Events
/// </summary>
public class ChildSiteInit : SPWebEventReceiver
{
    //Search Template IDs
    private static readonly Int32[] SearchTemplatesIds = {
        (Int32)WebTemplateId.BasicSearchCenter,
        (Int32)WebTemplateId.EnterpriseSearchCenter,
        (Int32)WebTemplateId.FastSearchCenter
    };

   /// <summary>
   /// A site was provisioned.
   /// </summary>
   public override void WebProvisioned(SPWebEventProperties properties)
   {
       SPWeb childSite = properties.Web;
       SPWeb topSite = childSite.Site.RootWeb;
       //set Search Master
       if (SearchTemplatesIds.Contains(childSite.WebTemplateId))
       {
           childSite.MasterUrl = "/_catalogs/masterpage/Search.master";
           childSite.CustomMasterUrl = childSite.MasterUrl;
           childSite.AlternateCssUrl = "";
       }
       else
       {
           childSite.MasterUrl = topSite.MasterUrl;
           childSite.CustomMasterUrl = topSite.CustomMasterUrl;
           childSite.AlternateCssUrl = topSite.AlternateCssUrl;
           childSite.SiteLogoUrl = topSite.SiteLogoUrl;
           childSite.Update();
       }
   }


}
}

But when I try to deploy the WSP, I get this error:

Install-SPSolution : Failed to create receiver object from assembly "abc.MasterPages, Version=0.0.0.0, C
ulture=neutral, PublicKeyToken=0bc15e792b3fcfaf", class "$SharePoint.Type.f6224605-7edf-                42cf-9eef-c2a5159fee21.FullName
$" for feature "abc.MasterPages_PortalMasterProvisioning" (ID: bd6aee09-9381-4f66-9997-    23bd2a3dfc4c).: S
ystem.ArgumentNullException: Value cannot be null.
Parameter name: type
   at System.Activator.CreateInstance(Type type, Boolean nonPublic)
   at Microsoft.SharePoint.Administration.SPFeatureDefinition.get_ReceiverObject()
At line:1 char:19
+ Install-SPSolution <<<<  -Identity abc.masterpages.wsp -GACDeployment -Local
    + CategoryInfo          : InvalidData:     (Microsoft.Share...InstallSolution:SPCmdletInstallSolution) [Install-SPSolu
   tion], InvalidOperationException
    + FullyQualifiedErrorId : Microsoft.SharePoint.PowerShell.SPCmdletInstallSolution

#### Edit ####

In the meantime I found out, that I have to use the SharePoint Management Shell instead of the normal PowerShell. It seems that this caused the mentioned error. After I used the SP Management Shell I could deploy the WSP without errors. But now I'm facing new problems. After deploying the WSP the feature stapler is active at web application level but if I try to activate the MasterPageProvisioning Feature for the SiteCollection manually, I get this error:

Feature receiver assembly 'abc.MasterPages, Version=0.0.0.0, Culture=neutral, PublicKeyToken=0bc15e792b3fcfaf', class     'abc.MasterPages.Features.PortalMasterProvisioning.PortalMasterProvisioningEventReceiver', method 'FeatureActivated' for     feature 'bd6aee09-9381-4f66-9997-23bd2a3dfc4c' threw an exception: Microsoft.SharePoint.SPException: Error
 at activation of feature: Object reference not set to an instance of an object.    
 at abc.MasterPages.Features.PortalMasterProvisioning.PortalMasterProvisioningEventReceiver.FeatureActivated    (SPFeatureReceiverProperties properties)    
 at Microsoft.SharePoint.SPFeature.DoActivationCallout(Boolean fActivate, Boolean fForce)    

Sounds like the problem lies inside FeatureActivated of the PortalMasterProvisioning feature, but I can't tell where exactly.

#### Edit 2 ####

Again I could solve the problem myself. I replaced the FeatureActivated Code with this one:

public override void FeatureActivated(SPFeatureReceiverProperties properties)
    {
        try
        {
            SPWeb site;

            if (properties.Feature.Parent is SPWeb)
            {
                site = (SPWeb)properties.Feature.Parent;
            }
            else if (properties.Feature.Parent is SPSite)
            {
                site = ((SPSite)properties.Feature.Parent).RootWeb;
            }
            else
            {
                throw new Exception("Error: Unable to retrieve SPWeb - this feature is not Site or Web-scoped.");
            }                

            string masterPageUrl = string.Format("{0}_catalogs/masterpage/Portal.master", site.ServerRelativeUrl.Replace("//", "/"));
            site.CustomMasterUrl = masterPageUrl;
            site.MasterUrl = masterPageUrl;

            site.Update();

        }
        catch (Exception ex)
        {
            string errorMessage = string.Format("Error at activation of feature: {0}", ex.Message);
            throw new SPException(errorMessage);
        }
    }

But it would be boring, if it worked now... So the current problem is, that I can activate the provisioning feature manually and it works without throwing exceptions. But it doesn't activate automatically on sitecollection creation, although the stapler feature at WebApplication level is active...

  • solved previous problem, but got new one instead =/ – Jessica Jun 18 '13 at 19:25
  • Where's the base project xml? Or the webtemplate element? – Christoffel de Gruyter Aug 13 '14 at 20:46
1

looks like it has been a while since you posted this.

anyway, for the purpose of future reference, my suggestion is first, to always check the template id of a newly created site, so that there is no doubt that the association is correct (web.WebTemplate + web.Configuration)

then, perhaps you want to use a farm scoped solution for the stapler, instead of webapplication, as there are known problems with the later refer this blog

the scope of the actual master page changing feature is also important, but in your case it seems to be fine.

feel free to share your resolution if you found it.

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.