Thursday, May 20, 2010

Deploy WebPart as Feature with CAS

Introduction

I had started writing this blog over a year and half ago but I had hirer priority things come up. I still find that a lot SharePoint developers have challenges understanding how to deploy web parts. Specifically CAS, GAC vs bin, rely on CodePlex tools, etc. are a common issue.

As a SharePoint consultant I have seen many struggle with web parts. The issue is not usually with the development of a web parts. There are lots of blogs and books written that show how to develop web parts but the biggest issue I have seen is correctly deploying of web parts. More specifically:

* Creating web part deployment solutions
* Deploying web parts as a feature
* Deploying the web parts in a secure fashion

With Visual Studio 2005, there was a plug-in that developers used to quickly deploy web parts out to a SharePoint environment however there was no control over the deployment package or the deployment process. This plug-in was great for development environments because it allowed developers to quickly deploy and iteratively debug web parts however developers would continue to use this deployment for production deployments. This caused many issues with the control, configuration and change management issues down the road.

With Visual Studio 2008, there is better tooling has been incorporated into Visual Studio by Microsoft for the creation of SharePoint web part projects.

Other tools have been created to help with the authoring WSP deployment files such as WSP Builder. This tool works pretty well but knowing how a WSP solution file is created is equally important. What I have seen is that developers become so dependent on tools such as these, they do not have an understanding of how web parts actually work.

Still the biggest issue we see with deployment is developers run into challenges with deployments of their web parts and they quickly do the following:

* They raise the trust level on their SharePoint environments to either Medium or Full.
* They deploy the web part DLL directly to the GAC.

Both are unacceptable solutions especially when this is a production environment (Intranet or not). What makes this worse is many forums, blogs, etc. usually state to do as such and do not outline the consequences. As well, I have not seen any truly good end to end discussions of this topic.

In this blog I will take a deep dive into how a web part should be properly deployed. The web part that will be developed will be inconsequential ("Hello World" example) because the focus will be on deployment. I will specifically focus on:

* Deploying a web part as a Feature.
* Deploying to web bin directory.
* Code Access Security (CAS).

A lot of this information will become moot because we are expecting the next release of Visual Studio to fix a lot of these gaps and provide all the tooling to build SharePoint deployment packages end-to-end.

The first part of this blog is going to discuss how to create a web part feature and properly deploy it. The interesting stuff about properly setting up CAS will later on. However I believe it is important to understand the entire picture before we jump into CAS with web parts.

Creating a Web Part Project

In this first project I am going to create a basic web part project using no accelerator tools.

* Create a C# code library project which I named WSSDistillery.Deploy.WebPart.
* Add a references to Microsoft.SharePoint and System.Web.
* In the AssemblyInfo.cs you will need to add [assembly: System.Security.AllowPartiallyTrustedCallers]. This will allow SharePoint to call the web part contained within dll.
* Go into the properties of the project and sign the assembly.
* Renamed Class1.cs to something else. I renamed it to SimplePart.cs.
* Add an XML file called manifest.xml.
* Add a file called WSP.ddf.
* Add the following three folders. First "TEMPLATE", then beneath it "FEATURES", then beneath it "WSSDistillery.Deploy.WebPart".
* Under the "WSSDistillery.Deploy.WebPart" folder add the following files elements.xml, Feature.xml and WSSDistillery.Deploy.WebPart.SimplePart.webpart.

It is pretty simple to throw together even without all of these tools out there. The final solution should look like:



I will go into further detail about each file and what goes into them. Some initial notes are:

* It is common practice to create a hierarchy of folders in the Visual Studio project based on the folder hierarchy of files in the 12 Hive (\\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\FEATURES).
* I named the folder "WSSDistillery.Deploy.WebPart" because this is the folder that will be deployed into SharePoint. I put the namespace into the name of the folder to lower the chances of a name conflict for other SharePoint Features that may be created over time.
* Even though the assembly has been signed, it will not be deployed to the GAC.

Creating the Web Part

I mentioned before, this will not be a lesson on how to develop a web part. As such, this web part is going to be a simple implementation; Hello World for now. I will add some code later which will require it to have a CAS policy.

public class SimplePart : System.Web.UI.WebControls.WebParts.WebPart
{
protected override void Render(HtmlTextWriter writer)
{
base.Render(writer);

writer.WriteLine("Hello World");
}

}

Get DLL Strong Name

Might as well go ahead and get this now, because this will be needed in several places. Open the Visual Studio command prompt and run the following command:

* Sn –Tp [path]\[dll name]
* sn -Tp "C:\WSSDistillery\Deploy\WSSDistillery.Deploy\WSSDistillery.Deploy.WebPart\bin\Debug\WSSDistillery.Deploy.WebPart.dll"

Two values will be generated. The first is a Public Key which is really long, go ahead and get that. The second is a Public Key Token which will be used in several places. These will be used in some of the files that will be created next.

Webpart File

I know "WSSDistillery.Deploy.WebPart.SimplePart.webpart" is a long filename. Again, it is good practice to have the namespace in the name of the file to ensure there are no name conflicts down the line during your web part deployments. This file will be deployed into the Web Part Gallery within a site collection. This file has a reference to the DLL that has the web part code. As well, the Data XML elements contain the text that a user will see when adding a to a web part page within SharePoint. A good description here of what the web part is required for the users of SharePoint.


Cannot import WSSDistillery.Deploy.WebPart.SimplePart

Simple Web Part
This is a very simple web part for demonstrating deployments.


<webParts>
    <webPart xmlns="http://schemas.microsoft.com/WebPart/v3">
        <metaData>
            <type name="WSSDistillery.Deploy.WebPart.SimplePart, WSSDistillery.Deploy.WebPart, Version=1.0.0.0, Culture=neutral, PublicKeyToken=aa9a1a08fbf22452" />
            <importErrorMessage>Cannot import WSSDistillery.Deploy.WebPart.SimplePartimportErrorMessage>
        metaData>
        <data>
            <properties>
                <property name="Title" type="string">Simple Web Partproperty>
                <property name="Description" type="string">This is a very simple web part for demonstrating deployments.property>
            properties>
        data>
    webPart>
webParts>


elements.xml File

This file will be responsible for deploying the WSSDistillery.Deploy.WebPart.SimplePart.webpart file to the Web Part gallery in the site collection.



xml version="1.0" encoding="utf-8" ?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
    <Module Name="WebParts" List="113" Url="_catalogs/wp">
        <File Url="WSSDistillery.Deploy.WebPart.SimplePart.webpart" Type="GhostableInLibrary" />
    Module>
Elements>


Feature.xml File

This is a standard SharePoint Feature file. There are references to both elements.xml and WSSDistillery.Deploy.WebPart.SimplePart.webpart files ion the ElementManifests.


xml version="1.0" encoding="utf-8" ?>
<Feature Id="8CD4DE2E-353E-40e1-A2AB-8004F6E8AA5F"
    Title="Simple Web Part"
    Description="This is a very simple web part for demonstrating deployments."
    Version="1.0.0.0"
    Scope="Site"
    Hidden="FALSE"
    DefaultResourceFile="core"
    xmlns="http://schemas.microsoft.com/sharepoint/">
    <ElementManifests>
        <ElementManifest Location="elements.xml" />
        <ElementFile Location="WSSDistillery.Deploy.WebPart.SimplePart.webpart"/>
    ElementManifests>
Feature>




<Solution xmlns="http://schemas.microsoft.com/sharepoint/" SolutionId="052C7D59-7DCF-4782-93B4-51C3F6DECF3B">
    <FeatureManifests>
        <FeatureManifest Location="WSSDistillery.Deploy.WebPart\Feature.xml"/>
    FeatureManifests>
    <Assemblies>
        <Assembly Location="WSSDistillery.Deploy.WebPart\WSSDistillery.Deploy.WebPart.dll" DeploymentTarget="WebApplication" >
            <SafeControls>
                <SafeControl Assembly="WSSDistillery.Deploy.WebPart.SimplePart, WSSDistillery.Deploy.WebPart, Version=1.0.0.0, Culture=neutral, PublicKeyToken=aa9a1a08fbf22452"
                             Namespace="WSSDistillery.Deploy.WebPart"
                             Safe="True"
                             TypeName="*"/>
            SafeControls>
        Assembly>
    Assemblies>
Solution>

 
<trust level=" WSS_Minimal" originUrl="" />




<PermissionSet   class="NamedPermissionSet" version="1" Name="SPRestricted">
<IPermission  class="AspNetHostingPermission"  version="1" Level="Minimal" />
<IPermission class="SecurityPermission" version="1" Flags="Execution" />
<IPermission class="WebPartPermission" version="1" Connections="True" />
PermissionSet>

<IPermission class="SharePointPermission" version="1" ObjectModel="True" />

<IPermission class="Microsoft.SharePoint.Security.SharePointPermission, Microsoft.SharePoint.Security, Version=12.0.0.0, Culture=neutral, Pub

<Solution xmlns="http://schemas.microsoft.com/sharepoint/" SolutionId="052C7D59-7DCF-4782-93B4-51C3F6DECF3B">
    <FeatureManifests>
        <FeatureManifest Location="WSSDistillery.Deploy.WebPart\Feature.xml"/>
    FeatureManifests>
    <Assemblies>
        <Assembly Location="WSSDistillery.Deploy.WebPart\WSSDistillery.Deploy.WebPart.dll" DeploymentTarget="WebApplication" >
            <SafeControls>
                <SafeControl Assembly="WSSDistillery.Deploy.WebPart.SimplePart, WSSDistillery.Deploy.WebPart, Version=1.0.0.0, Culture=neutral, PublicKeyToken=aa9a1a08fbf22452"
                             Namespace="WSSDistillery.Deploy.WebPart"
                             Safe="True"
                             TypeName="*"/>
            SafeControls>
        Assembly>
    Assemblies>
    <CodeAccessSecurity>
        <PolicyItem>
            <Assemblies>
                <Assembly PublicKeyBlob="00240000048000009400000006020000002400005253413100040000010001
00ad51a9cdfbe7db0a0f6d16a257d874a19993707b1bb0e873bda1c18c5b1592e24070f57b637
e0be2b00790fd67bc3e0c61205af5c0e5753780f257acb2c0b4b4830e23ace37be05c7ab52478
2731f85786d7648e6e14a99a83dc474081d5cf5e1fc1b20da22fc3b5a94b44ad3903aa8f081cc
0508e71b5606927824114f2ecd1" />
            Assemblies>
            <PermissionSet class="NamedPermissionSet" Name="WSSDistillery.Deploy.WebPart" version="1" Description="WSSDistillery.Deploy.WebPart">
                <IPermission class="AspNetHostingPermission" version="1" Level="Minimal" />
                <IPermission class="SecurityPermission" version="1" Flags="Execution" />
                <IPermission class="WebPartPermission" version="1" Connections="True" />
                <IPermission version="1" class="Microsoft.SharePoint.Security.SharePointPermission, Microsoft.SharePoint.Security, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" ObjectModel="True" />
            PermissionSet>
        PolicyItem>
    CodeAccessSecurity>
Solution>

No comments:

Post a Comment