Deploying a Web Part with Code Access Security in Visual Studio 2010 (SP2010)
Posted
Friday, November 20, 2009 2:38 PM
by
CoreyRoth
By now, you have heard about how the SharePoint 2010 development experience has been improved. We can easily deploy web parts and other code without having to manually manipulate any XML files. What about under partial trust though? Many of you that know me know that I have pushed using Code Access Security quite a bit through a series of blog posts and talks. So it would be irresponsible of me not to talk about how we can do that in Visual Studio 2010. The good news is that it is a lot easier.
Let’s start by creating a new SharePoint project in Visual Studio 2010 and creating a new Web Part project item. In this case we are talking about deploying a Farm Solution, not a Sandboxed Solution. Note: we are going to talk about a traditional web part today, and not a Visual Web Part. Visual Web Parts are simply not supposed under partial trust. More on that later below. My web part has some simple code which uses ASP.NET and also hits the SharePoint object model to display the title of the site in a label. Here is what the code looks like.
protected override void CreateChildControls()
{
Controls.Add(new Label(){Text = "<div>My Cool Web Part!</div>"});
Controls.Add(new Label() { Text = string.Format("Site Title: {0}", SPContext.Current.Web.Title) });
base.CreateChildControls();
}
When you create a new project, it deploys to the GAC by default. We start by changing this on the project properties.
This effectively changes the DeploymentTarget attribute on Assembly element in the Manifest.xml. At this point, you may be asking. “Sweet, is that it? Does it take care of the CAS policy for me?” The answer to that of course is “No.” However, it is quite easy to add it. Let’s see what happens if we try to deploy it as is. I’ll just hit F5 to start debugging. I then add my web part to any existing page, and I immediately get hit with the following in Visual Studio.
System.Security.SecurityException: Request for the permission of type 'Microsoft.SharePoint.Security.SharePointPermission, Microsoft.SharePoint.Security, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c' failed.
Luckily we know how to fix this. Hopefully, this will also help new developers when they get this error in the future and aren’t sure what to do. We need to grant permissions to this assembly to use the object model as well as a few other things. We’ll start by using a standard set of IPermission elements that I have used in past posts. This gives me basic ASP.NET, SharePoint object model, and Security permissions.
<CodeAccessSecurity>
<PolicyItem>
<PermissionSet class="NamedPermissionSet" version="1" Description="Permission set for VisualWebPartProject1.">
<IPermission class="AspNetHostingPermission" version="1" Level="Minimal" />
<IPermission class="SecurityPermission" version="1" Flags="Execution,ControlPrincipal,ControlAppDomain,ControlDomainPolicy,ControlEvidence,ControlThread" />
<IPermission class="Microsoft.SharePoint.Security.SharePointPermission, Microsoft.SharePoint.Security, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"
version="1" ObjectModel="True" />
<IPermission class="System.Security.Permissions.EnvironmentPermission, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Read="UserName" />
<IPermission class="System.Security.Permissions.FileIOPermission, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Read="$AppDir$" Write="$AppDir$" Append="$AppDir$" PathDiscovery="$AppDir$" />
</PermissionSet>
<Assemblies>
<Assembly Name="VisualWebPartProject1" />
</Assemblies>
</PolicyItem>
</CodeAccessSecurity>
You can use this in your code almost exactly but two small changes are required. First, you need to change your assembly name to whatever you have called yours. Secondly, if you look at that SharePointPermission, you’ll notice it says version 12.0.0.0. We need to change this to 14.0.0.0 since we are working with SharePoint 2010 now. Adding this to your package is quite easy. In the Solution Explorer, locate Package and then Package.package and open it. This will bring open the package designer. Click on the Manifest tab at the bottom and then expand Edit Options. The way this works is that you can paste any additional elements here and it will merge your items with the ones it automatically generates. Here is what I would paste in.
<?xml version="1.0" encoding="utf-8"?>
<Solution xmlns="http://schemas.microsoft.com/sharepoint/">
<CodeAccessSecurity>
<PolicyItem>
<PermissionSet class="NamedPermissionSet" version="1" Description="Permission set for VisualWebPartProject1.">
<IPermission class="AspNetHostingPermission" version="1" Level="Minimal" />
<IPermission class="SecurityPermission" version="1" Flags="Execution,ControlPrincipal,ControlAppDomain,ControlDomainPolicy,ControlEvidence,ControlThread" />
<IPermission class="Microsoft.SharePoint.Security.SharePointPermission, Microsoft.SharePoint.Security, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"
version="1" ObjectModel="True" />
<IPermission class="System.Security.Permissions.EnvironmentPermission, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Read="UserName" />
<IPermission class="System.Security.Permissions.FileIOPermission, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Read="$AppDir$;C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\TEMPLATE\CONTROLTEMPLATES\VisualWebPartProject1" Write="$AppDir$" Append="$AppDir$" PathDiscovery="$AppDir$" />
</PermissionSet>
<Assemblies>
<Assembly Name="VisualWebPartProject1" />
</Assemblies>
</PolicyItem>
</CodeAccessSecurity>
</Solution>
Here is what it would look like on the screen.
If everything is correct, you will see the merged result up top. If there is an error in your XML, you will also see it there. Now let’s deploy the solution and see if we can add the web part to an existing page.
Unfortunately, this is the error we get and it actually gives us good information. We simply forgot to add the APTCA attribute (or AllowPartiallyTrustedCallers). Just open your AssmeblyInfo.cs file and add the following line.
[assembly: AllowPartiallyTrustedCallers()]
Redeploy your solution and try to add your web part again. If all goes well, you will have a lovely web part on the screen that looks like this.
With the above set of CAS policies, you can probably get most of the code you want to do to work. I mentioned Visual Web Parts above. Here is the issue I am currently seeing. If you remember my post on the Visual Web Part, you will know that this is just a web part with a Page.LoadControl() method calling a User Control (.ascx). Page.LoadControl requires a ton of permissions and I haven’t been able to figure them out. This means, it simply will not work. I posted something to the forums about it. Paul Andrew was nice enough to respond to my post and state that Page.LoadControl simply will not function under partial trust. It has a check in it to verify that it is not running under partial trust. He also goes on to explain this is why you can’t use Visual Web Parts in sandboxed solutions.
This may seem like a lot of steps, but really I just posted a lot of pictures. Trust me it’s a lot fewer steps than it was before in MOSS 2007. Just look at my old post if you don’t believe me. Now, you might ask why would I do this instead of a Sandboxed solution? Sandboxed solutions are severely limited on what they can do with the SharePoint object model. By default, the CAS policy that defines them can’t even connect to a database. I can specify at a per assembly level here what each one can do. That is a big advantage.