Paul Pascha

Als SharePoint Developer bij Wortell hou ik me bezig met het ontwerpen en ontwikkelen van maatwerkoplossingen bovenop het SharePoint platform


Posts by Paul Pascha

Disable code execution in Sandboxed Solutions for specific sitecollections

Code in Sandboxed Solutions can execute as soon the ”Microsoft SharePoint Foundation Sandboxed Code Service” is started on some server somewhere in your Farm. Sandboxed Solutions are hosted withing a specialized gallery within a SiteCollections’ top level website. The provisioning of this gallery is controlled by the GLOBAL SiteDefinition meaning each SiteCollection you create (whether this Sandboxed Code service is running or not) will contain this gallery and by this enable SiteCollection Administrators to Upload and Activate Sandboxed Solutions.  

So by default, when the Sandboxed Code Service is started, each SiteCollection whithin each WebApplication in your Farm is enabled to execute code in Sandboxed Solutions. Sometimes however you might want to disable the execution of code in Sandboxed Solutions on specific sitecollections while still allowing them to execute on other SiteCollections. There is no neat way to disable code execution from Sandboxed Solutions entirely on a specific SiteCollections. Maybe you’d expect to find a checkbox labeled “Disable Code Execution in Sandboxed Solutions”  somewhere under Site Collection Settings  in Central Admin but there isn’t.

This requirement could be achieved however by specifying a Quota Template and configure a specific SiteCollection to use it. Follow the steps below to specifiy a Quota Template effectively disabling Sandboxed code execution on a certain SiteCollection.

1. Open Central Administration

2. Browse to Application Management

3. Under Site Collections click “Specify Quota Templates”

4. Specify “Create a new quota template” and specify a name for it. Optionally you could start from an existing template here.

5. At the bottom of this page there’s a section with options to control Sandboxed Solutions called “Sandboxed Solutions With Code Limits”. Specify “0″ points in the TextBox labeled “Limit maximum usage per day to”

6. Click OK to save this template

7. Back on the Application Management Page, click “Configure Quotas and Locks”

8. On this Page, select the SiteCollection to apply the new quota template to

9. Under “Site Quota Information”, select the template just created

10. Click OK to save changes

Note that this will only block execution of custom code from within the Sandbox entirely. You are still able to provision declarative elements like List Instances for example to the Sandbox and use them without being blocked. I don’t think this is a problem however because otherwise the Site Collection administrator would have been able to create these kind of elements from within the browser or SharePoint designer anyway.

Tags: , ,

Using a Module to deploy a Solution to the Solution Gallery

For one of our projects I created several WebParts as part of a Sandboxed Solution. These WebParts were developed to be used on sites for which ultimately a SiteDefinition needed to be created. Since the WebParts are part of a Sandboxed Solution, my goal was to provision this solution as part of the SiteDefinition to the Solution Gallery located in the RootWeb.

Since the Solution Gallery is just a specialized Document Library in which .wsp Files get placed, I thought using the Module element would help me here. Off course, you could use the Module element inside as a Feature element too, instead of the SiteDefintion I’m using it in. So, first of all I declared my Module element as follows:

<Module Name="Solutions" Path="Solutions" Url="_catalogs/solutions">
    <File Url="HelloSandbox.wsp"/>
</Module>

After creating a new SiteCollection based on the SiteDefinition containing this Module, I navigated to the solution gallery to find my .wsp file there in order to Activate the solution but it wasn’t there. It took me a while to figure out that in order to actually find the .wsp here, I needed to specify the Type within the <File>element with the value “GhostableInLibrary”.

<Module Name="Solutions" Path="Solutions" Url="_catalogs/solutions">
    <File Url="HelloSandbox.wsp" Type="GhostableInLibrary"/>
</Module>

Changing this made the .wsp appear but I wasn’t able to Activate the solution. I was wondering why until I chose to edit the properties of the .wsp and Save the changes without changing anything. After this, I was actually able to activate the solution!

So, editing the properties apparently caused some properties to be set under the hood. In order to figure out which properties, I decided to fire up SharePoint Manager 2010. This is a great tool to get useful insights. It helped me to figure out the following properties were added after editing the .wsp properties:

  • ContentType
  • ContentTypeId
  • SolutionHasAssemblies
  • SolutionHash
  • SolutionId

I decided to (as far as possible) specify the properties listed above one at a time in <Property> elements within the <File> element within the <Module>. By adding them one at a time I was hoping to find the minimum set of properties needed to be set.

I tried the ContentType property first. The value for ContentType (as I could see in SPM2010) was set to “Solution Gallery” so I declared the following <Property> element:

<Property Name="ContentType" Value="Solution Gallery"/>

I then created a new SiteCollection and now I was able to activate the solution! So this one property did the trick! Switching back to SPM2010 showed me that the other 4 properties from the listing above were also set now…

Hope this helps you too!

Tags: ,

Utilizing a Delegate Control to redirect to a custom User Profile Page

For one of our customers’ intranet we are using a custom page to display User Profile information. By default, clicking a user’s name anywhere in SharePoint redirects you to the page Person.aspx within the “MySite Host”. This redirection is performed by a Control within the Application Page “userdisp.aspx” (_layouts/userdisp.aspx). The actual control is inserted by means of a Delegate Control. This means you’re able to replace it with whatever custom Control you want by activating a Feature with a properly declared Control element.

The Delegate Control is declared with ControlID value “ProfileRedirection” and Scope “Farm”. This means the Feature with the Control element to insert a custom Control also needs to be Farm scoped. Thus, activating this Feature will result in replacing the redirect behaviour through the entire Farm. In our case, this was not a problem but be sure to keep this in mind.

The Feature’s Control Element declaration looks something like this:

<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <Control ControlAssembly="Customer.Intranet, Version=1.0.0.0, Culture=neutral, PublicKeyToken=fe3fb3dd06bf9154"
           ControlClass="Customer.Intranet.ProfileRedirectControl"
           Id="ProfileRedirection"
           Sequence="1"/>
</Elements>

Developing, Deploying and Debugging Sandboxed Solutions – What if it doesn’t work right away?

Up to last week I used the simple “next, next, finish” single server installations for my developer workstation for SharePoint 2010. Everything including the sandbox worked fine and development went pretty smooth. Last week however I started developing on a new image with a more advanced installation of SharePoint 2010 in which Windows 2008 was setup as a domain controller.

When I launched Visual Studio for the first time to create  a simple Sandboxed WebPart and pressed <F5> to start debugging, I received an error stating that the SPUserCodeV4 service was not running:

firsterror

The error above was a quite obvious one and easy to fix by just starting this service from the “Services on Server” screen in Central Administrion:

second

So, I thought I was ready to press <F5> again but now another error appeared stating that Visual Studio was unable to attach to the SPUCWorkerProcess. My first thought was that this was probably some beta issue or an issue caused by not running Visual Studio as an administrator or something like that. My Solution was deployed to the solution gallery anyway so I planned to contiue placing my webpart on the page and attaching the debugger manually if needed. Placing the WebPart on the page however resulted in well ehh…nothing.

In order to confirm I was not doing anything not allowed in my code I changed the WebPart’s functionality to do nothing more then the  classical “Hello, World!”. That didn’t work either which meant I had to dig deeper. After binging around for a while, I found a blogpost by Jie Li in which he describes a PowerShell script to be run on computers that were setup as a domain controller (like mine). After running the PowerShell script below, everything worked fine!

$acl = Get-Acl HKLM:\System\CurrentControlSet\Control\ComputerName
$person = [System.Security.Principal.NTAccount]"Users"
$access = [System.Security.AccessControl.RegistryRights]::FullControl
$inheritance = [System.Security.AccessControl.InheritanceFlags]"ContainerInherit, ObjectInherit"
$propagation = [System.Security.AccessControl.PropagationFlags]::None
$type = [System.Security.AccessControl.AccessControlType]::Allow
$rule = New-Object System.Security.AccessControl.RegistryAccessRule($person, $access, $inheritance, $propagation, $type)
$acl.AddAccessRule($rule)
Set-Acl HKLM:\System\CurrentControlSet\Control\ComputerName $acl

Tags:

Using SPContext anonymously

For one of our projects – a public facing site – we developed a custom control which renders an image. The control is placed within the MasterPage and the URL of the image to render is being determined by some rules. One of these rules is related to the PageLayout being used by the Page the user is visiting. For this rule to evaluate, we need the name of the PageLayout.

The most basic code I could think of for retrieving this value was the following

SPSecurity.RunWithElevatedPrivileges(delegate() {
  PublishingPage currentPage = PublishingPage.GetPublishingPage(SPContext.Current.ListItem);
  string pageLayoutName = currentPage.Layout.Name;
});

Running this code using Windows authentication works fine. Running this code in anonymous context however caused a challenge to appear when executing the line where pageLayoutName is assigned a value. The reason for this is that some objects referenced in the SPContext object were already created outside of the elevated context. So, to retrieve the name of the current PageLayout, I had to instantiate most of the objects needed to get to the PageLayout object manually. The following code worked for me:

SPSecurity.RunWithElevatedPrivileges(delegate() {
  using (SPSite siteCollection = new SPSite(SPContext.Current.Web.Site.Url))
 
{
    using (SPWeb web = siteCollection.OpenWeb())
    {
      PublishingWeb publishingWeb = PublishingWeb.GetPublishingWeb(web);
      SPListItem pageListItem = ublishingWeb.PagesList.ItemsSPContext.Current.File.UniqueId];
      PublishingPage currentPage = PublishingPage.GetPublishingPage(pageListItem);
      PageLayout currentPageLayout = currentPage.Layout;
      currentPageLayoutName = currentPageLayout.Name;
    }
  }
});

The example above is obviously a very specific case in which we needed the name of the PageLayout used by the current Page. The key message here however is to watch out using SPContext (and other high-level SharePoint objects) within an RunWithElevatedPrivileges block while in anonymous context. It’s very likely to run into some differences compared to using the same elevated code in Windows authenication context.

TryGetList method in SharePoint 2010

There are many cases in which you want to retrieve a SPList object. In some cases you can’t just assume the list exists so before referencing it, you’d want to check this first. Within the WSS v3 object model there was no neat way to check for the existence of a list. Indexing into a SPListCollection based on for example the name of a non-existing list resulted in a System.NullReferenceException. For this reason, it was quite common to check for the existence of a SPList whitin a try-catch block.

In SharePoint 2010’s object model the SPListCollection Class has a new method called “TryGetList”. This method does exactly what the name suspects. Within the SPListCollection is being searched to a SPList with the specified name. If the list does not exist, a null reference is returned

SPSite currentSite = SPContext.Current.Site;
SPList mySPList = currentSite.RootWeb.Lists.TryGetList("VoorbeeldLijst");


if (mySPList != null)
{
  ...
  ...
}

Tags:

SharePoint and Office 2010 public beta’s available now!

The pubic beta’s for SharePoint 2010 and Office 2010 are available now!

http://bit.ly/ZI2010

SharePoint 2010: Developer Documentation (Technical Preview)

Together with the 3 preview videos released today about SharePoint 2010, Microsoft released a first technical preview of the SharePoint 2010 developer documentation
Download here

SharePont 2010: Sneak Peek videos

Today Microsoft published three videos as a Sneak Peek into SharePoint 2010:

The videos present a broad overview about what SharePoint 2010 will offer. Since I’m primarily a developer I had a very pleasant time watching the developer video. I can’t wait to get my hands on it and to see, hear & feal more about SharePoint 2010 at the SharePoint Conference 2009 in Las Vegas!

Sending an e-mail with SPUtility from a site with anonymous access enabled

When using SPUtility.SendEmail() to send an e-mail message from within a site on which anonymous access is enabled, you have to specify the from address.

The code in the fragment below is executed in the SendEmail method and explains why:

email = messageHeaders["from"];

if (email == null){  email = web.CurrentUser.Email;}else{  email = FoldEmailHeader(email, "from", true);  count--;}

The code listed above is being executed in the SendEmail method (obtained by using Reflector). As you can see, if the “from” address is not in the StringDictionary “messageHeaders”, the from address is being retrieved from web.CurrentUser. Since anonymous access is being used, this will obviously fail.