Tuesday, February 19, 2013

Building custom SharePoint 2010 Site Pages using Visual Studio (Part II)

Hello again. In my previous post I showed you how to create customized Site Pages using Visual Studio (VS) instead of being limited by SharePoint Designer (SPD). Now I am going to explain how to instruct SharePoint that it is alright to allow code-behind for these Site Pages. Which by default, is not allowed.

NOTE: You will absolutely want to configure your event handler to undo these changes when appropriate and to make these changes when appropriate. This way you can be sure that when the feature is activated / deactivated.... you get the drift. My recommendation would be to create a separate feature just for this security change. My previous feature was called CustomPages so I will name this one CustomPages Security.

  1. Add SafeControls
    • Click on your module (SitePages from my last post) and open your properties window.
    • Under the SafeControls section add a new SafeControl.
      • Assembly = $SharePoint.Project.AssemblyFullName$
      • Namespace = CustomPages
      • TypeName = MyCustomPageTemplate
      • Safe = true
      • SafeAgainstScript = false
  2. What happens to my web.config?
    • What is getting added to the web.config is the following:

      <SafeMode MaxControls="200"
                         
      CallStack
      ="false"
                         
      DirectFileDependencies
      ="10"
                         
      TotalFileDependencies
      ="50"
                         
      AllowPageLevelTrace="false">
          <PageParserPaths>
              <PageParserPath VirtualPath="/SitePages/MyCustomPage.aspx*"
                                          CompilationMode="Always"
                                          AllowServerSideScript="true"
                                          IncludeSubFolders="true" />
          </PageParserPaths>
      </SafeMode>
    • Create a new feature and add an event receiver to it. This feature's scope also needs to be WebApplication (you can check by double-clicking the feature to bring up designer view).
    • Add the following code and change as is appropriate for your needs. This is the sample and shouldn't be used as a straight copy / paste.

      using System;
      using System.Collections.ObjectModel;
      using System.Runtime.InteropServices;
      using System.Security.Permissions;
      using Microsoft.SharePoint;
      using Microsoft.SharePoint.Security;
      using Microsoft.SharePoint.Administration;

      namespace CustomPages.Features.CustomPages_Security
      {
          /// <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("674c2a19-9913-4465-af57-198bd0416b49")]
          public class CustomPages_SecurityEventReceiver : SPFeatureReceiver
          {       
              public override void FeatureActivated(SPFeatureReceiverProperties properties)
              {
                  SPWebApplication webApp = properties.Feature.Parent as SPWebApplication;

                  SPSecurity.RunWithElevatedPrivileges(delegate()
                  {
                      SPWebConfigModification wcMod = new SPWebConfigModification();

                      wcMod.Path = "configuration/SharePoint/SafeMode/PageParserPaths";
                      wcMod.Name = "PageParserPath[@VirtualPath='/SitePages/MyCustomPage.aspx']";
                      wcMod.Owner = "CustomPages";
                      wcMod.Sequence = 0;
                      wcMod.Type = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode;
                      wcMod.Value = "<PageParserPath VirtualPath='/SitePages/MyCustomPage.aspx' CompilationMode='Always' AllowServerSideScript='true' />";

                      webApp.WebConfigModifications.Add(wcMod);
                      webApp.Farm.Services.GetValue<SPWebService>().ApplyWebConfigModifications();
                      webApp.Update();
                  });

              }

              public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
              {
                  SPWebApplication webApp = properties.Feature.Parent as SPWebApplication;

                  SPSecurity.RunWithElevatedPrivileges(delegate()
                  {
                      Collection<SPWebConfigModification> wcMods = webApp.WebConfigModifications;
                      int initialModificationsCount = wcMods .Count;

                      for (int i = initialModificationsCount - 1; i >= 0; i--)
                      {
                          if (wcMods [i].Owner == "CustomPages")
                          {
                              SPWebConfigModification modToRemove = wcMods[i];
                              wcMods.Remove(modToRemove);
                          }
                      }

                      if (initialModificationsCount > wcMods.Count)
                      {
                          webApp.Farm.Services.GetValue<SPWebService>().ApplyWebConfigModifications();
                          webApp.Update();
                      }

                  });
              }

          }
      }
There you have it. Not only do you have a customized Site Page from Visual Studio but, it also is allowed to use code-behind. I hope this helps you.