How to create, deploy, debug & host a web part in SharePoint manually.


In this article, I am going to outline the steps involved for building & deploying the web part manually as well as debugging the web part. In order to achieve this here is the outline of the steps, which we will go in detail.
  1. Create a web part class.
  2. Define the “AllowPartiallyTrustedCallers”
  3. Create the Web Part User Interface Properties
  4. Sign the Assembly
  5. Extract Public Key Token
  6. Add Safe Control Entry
  7. Deploy the Assembly
  8. Create Web Part Definition File
  9. Deploy Web Part Definition File
  10. Add the Web Part to a Page
  11. Debugging a Web Part
Create the Web Part ClassCreation of web part starts by creating a WebPart class:
  1. Create a new project by clicking File->New->Project.
  2. Under Project types, select the Class Library template under Windows in the language of your choice (C# is used in this example).
  3. In the Location text box, browse to “C:\Documents and Settings\Administrator\My Documents\Visual Studio 2008\Projects” and click Open.
  4. Uncheck the Create directory for solution check box.
  5. Give your Web Part project a meaningful name such as “Ticketing”, and click OK.
    The default project created by visual studio will look like this
  6. Create a new project by clicking File->New->Project.
  7. Under Project types, select the Class Library template under Windows in the language of your choice (C# is used in this example).
  8. In the Location text box, browse to “C:\Documents and Settings\Administrator\My Documents\Visual Studio 2008\Projects” and click Open.
  9. Uncheck the Create directory for solution check box.
  10. Give your Web Part project a meaningful name such as “Ticketing”, and click OK.
    The default project created by visual studio will look like this
  11. Add a reference to “System.Web”, “Microsoft.SharePoint.dll”.
  12. Delete the Class1.cs file
  13. Add a new class file, and name it as “Ticket.cs”.At this point, you have an empty class that essentially has no functionality, nor is it a Web Part. In-order to make it as a webpart, we need to inherit from ASP.NET Web Part class i.e from “System.Web.UI.WebControls.WebParts.WebPart”.
  14. Once the “Ticket” class is inherited from “WebPart”, it will look as below
public class Ticket : WebPart
{
}

15. Since you are going to be creating a couple of user interface components for your Web Part you need to add a couple of “using’ statements to your class to reduce the amount of code that you will have to type. Add the following using statements 

using System.Web.UI;
using System.Web.UI.HtmlControls; 
using System.Web .UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using Microsoft.SharePoint;

16.Build your project.

Add AllowPartiallyTrustedCallers Attribute to Assembly

Microsoft states that since the bin directory is a partial trust location, your Web Part does not automatically grant full trust code permissions when it is executed. Because the code that calls into your Web Part will be granted only partial trust permissions, your Web Part needs to have theAllowPartialTrustedCallers attribute set on it.
Another issue is that the code access security permissions for the bin directory are very low by default; only pure execution is allowed. You almost certainly will have to elevate these permissions to make your assembly run correctly.
There are two ways to elevate permissions:
  • In the web.config file in the Web application root, you will see a tag called <trust level> with an attribute of level="WSS_Minimal". You can change this level to WSS_Medium. This change will raise the net trust level of the bin directory. This option is simpler, but because it generically raises the trust level and thus grants arbitrary new permissions you might not need, it is less secure than the other option, which is to create a new trust policy file.
  • Create a new trust policy file, and point your web.config file at the new file. This option is more complicated, but it gives you a more precise attribution of permissions for your Web Parts.
You can set this attribute at the assembly level using the following steps:
  1. Open the AssemblyInfo.cs file and add the following attribute at the bottom of this file.
[assembly: System.Security.AllowPartiallyTrustedCallers()]

2.Build your project.

Create the Web Part User Interface Elements

Now we will design the UI elements programmatically for visual controls. Short description (Textbox) Category (Combo box) Priority (Combo box) Full Description  (Text box) Submit (Button)
1. Declare the protected member variables that will represent your user interface elements, both visible (text box, button) and non visible (table, rows, columns):
TextBox txtShortDesc;
ListBox lstCategory;
ListBox lstPriority;
TextBox txtMessage;
Button btnSendMessage;
Label lblMessageSent;
2. Render the web part user interface components by overriding the CreateChildControlsmethod in your class by adding the following code to it:
protected override void CreateChildControls()
{
 try
            {
                Table t;
                TableRow tr;
                TableCell tc;

                // A table that is used to layout the controls
                t = new Table();

                // Label with instructions for the user
                tr = new TableRow();
                tc = new TableCell();
                tc.ColumnSpan = 2;
                tc.VerticalAlign = VerticalAlign.Top;
                Label lblInstructions = new Label();
                lblInstructions.Text = "Please submit your ticket.";
                tc.Controls.Add(lblInstructions);
                tr.Controls.Add(tc);

                t.Controls.Add(tr);

                #region Short Description Row
                // Short Description label
                tr = new TableRow();
                tc = new TableCell();
                tc.Style["padding-top"] = "7px";
                tc.VerticalAlign = VerticalAlign.Top;
                Label lblContactName = new Label();
                lblContactName.Text = "Short Description:";
                tc.Controls.Add(lblContactName);
                tr.Controls.Add(tc);

                // Short Description textbox
                tc = new TableCell();
                tc.VerticalAlign = VerticalAlign.Top;
                txtShortDesc = new TextBox();
                txtShortDesc.ID = "txtShortDesc";
                txtShortDesc.Width = Unit.Pixel(300);
                tc.Controls.Add(txtShortDesc);
                tr.Controls.Add(tc);

                t.Controls.Add(tr);
                #endregion

                #region Category row
                // Category label
                tr = new TableRow();
                tc = new TableCell();
                tc.Style["padding-top"] = "7px";
                tc.VerticalAlign = VerticalAlign.Top;
                Label lblCategory = new Label();
                lblCategory.Text = "Category:";
                tc.Controls.Add(lblCategory);
                tr.Controls.Add(tc);

                // Category listBox
                tc = new TableCell();
                tc.VerticalAlign = VerticalAlign.Top;
                lstCategory = new ListBox();
                lstCategory.ID = "lstCategory";
                lstCategory.Items.Add(new ListItem("Presentation", "Presentation"));
                lstCategory.Items.Add(new ListItem("MiddleTier", "MiddleTier"));
                lstCategory.Items.Add(new ListItem("Connectivity", "Connectivity"));
                lstCategory.Items.Add(new ListItem("Database", "Database"));
                lstCategory.Width = Unit.Pixel(300);
                tc.Controls.Add(lstCategory);
                tr.Controls.Add(tc);

                t.Controls.Add(tr);
                #endregion

                #region Priority rows
                // Priority label
                tr = new TableRow();
                tc = new TableCell();
                tc.Style["padding-top"] = "7px";
                tc.VerticalAlign = VerticalAlign.Top;
                Label lblPriority = new Label();
                lblPriority.Text = "Priority:";
                tc.Controls.Add(lblPriority);
                tr.Controls.Add(tc);

                // Priority Listbox
                tc = new TableCell();
                tc.VerticalAlign = VerticalAlign.Top;
                lstPriority = new ListBox();
                lstPriority.ID = "lstPriority";
                lstPriority.Width = Unit.Pixel(300);
                lstPriority.Items.Add(new ListItem("Low", "Low"));
                lstPriority.Items.Add(new ListItem("Medium", "Medium"));
                lstPriority.Items.Add(new ListItem("High", "High"));
                tc.Controls.Add(lstPriority);
                tr.Controls.Add(tc);

                t.Controls.Add(tr);
                #endregion

                #region Description
                // Description label
                tr = new TableRow();
                tc = new TableCell();
                tc.Style["padding-top"] = "7px";
                tc.VerticalAlign = VerticalAlign.Top;
                Label lblMessage = new Label();
                lblMessage.Text = "Message:";
                tc.Controls.Add(lblMessage);
                tr.Controls.Add(tc);

                // Message textbox
                tc = new TableCell();
                tc.VerticalAlign = VerticalAlign.Top;
                txtMessage = new TextBox();
                txtMessage.ID = "txtMessage";
                txtMessage.Height = Unit.Pixel(100);
                txtMessage.Width = Unit.Pixel(400);
                txtMessage.TextMode = TextBoxMode.MultiLine;
                txtMessage.Wrap = true;
                tc.Controls.Add(txtMessage);
                tr.Controls.Add(tc);

                t.Controls.Add(tr);
                #endregion

                // Empty table cell
                tr = new TableRow();
                tc = new TableCell();
                tr.Controls.Add(tc);

                // Label for telling the user the message was sent
                tc = new TableCell();
                tc.VerticalAlign = VerticalAlign.Top;
                lblMessageSent = new Label();
                lblMessageSent.Text = "Your message has been sent. Thank you.";
                lblMessageSent.Font.Bold = true;
                lblMessageSent.Visible = false;
                tc.Controls.Add(lblMessageSent);
                tr.Controls.Add(tc);

                t.Controls.Add(tr);

                // Empty table cell
                tr = new TableRow();
                tc = new TableCell();
                tr.Controls.Add(tc);

                // Send Message button
                tc = new TableCell();
                btnSendMessage = new Button();
                btnSendMessage.Text = "Send Message";
                btnSendMessage.Click += new EventHandler(btnSendMessage_Click);
                tc.Controls.Add(btnSendMessage);
                tr.Controls.Add(tc);

                t.Controls.Add(tr);

                this.Controls.Add(t);
            }
            catch (Exception ex)
            {
                Literal _ErrorMessageLiteral = new Literal();
                _ErrorMessageLiteral.Text = ex.Message;

                this.Controls.Clear();
                this.Controls.Add(_ErrorMessageLiteral);
            }
}
3.Add the following event handler code stub to your WebPart class:

protected void btnSendMessage_Click (object sender, EventArgs e)
{
try
            {
                // Build the email subject string
                System.Text.StringBuilder subject = new System.Text.StringBuilder();
                subject.Append("New Ticket submitted : ");
                subject.Append(txtShortDesc.Text);

                // Build the email message string
                System.Text.StringBuilder message = new System.Text.StringBuilder();
                message.Append("Short Description: ");
                message.AppendLine(txtShortDesc.Text);
                message.Append("Category: ");
                message.AppendLine(lstCategory.SelectedValue);
                message.Append("Priority: ");
                message.AppendLine(lstPriority.SelectedValue);
                message.AppendLine();
                message.AppendLine("Message:");
                message.AppendLine(txtMessage.Text);

                // Construct the message header
                System.Collections.Specialized.StringDictionary messageHeader =
                new System.Collections.Specialized.StringDictionary();
                
                messageHeader.Add("to", "support@articledean.com");
                messageHeader.Add("from", "Agent@articledean.com");
                messageHeader.Add("subject", subject.ToString());
                messageHeader.Add("content-type", "text/plain");

                // Send the email
                Microsoft.SharePoint.Utilities.SPUtility.SendEmail(
                SPContext.Current.Web, messageHeader, message.ToString());

                // Let the user know the message was sent
                lblMessageSent.Visible = true;

                // Clear out the input fields
                txtShortDesc.Text = "";
                lstCategory.SelectedIndex = 0;
                lstPriority.SelectedIndex = 0;
                txtMessage.Text = "";
            }
            catch (Exception ex)
            {
                Literal _ErrorMessageLiteral = new Literal();
                _ErrorMessageLiteral.Text = ex.Message;

                this.Controls.Clear();
                this.Controls.Add(_ErrorMessageLiteral);
            }
}
4.Add a public access modifier to the Ticket WebPart class:
public class Ticket : WebPart
{
 . . .
}

5. Build your project. 

Sign the Assembly

  1. Right-click on the project node and select Properties from the context menu.
  2. Click the Signing tab.
  3. Check the Sign the assembly check box.
  4. Select <New…> from the "Choose a strong name key file" drop-down list.
  5. Enter “ArticleDeanTicketing” in the Key file name Text box.
  6. Uncheck the Protect my key file with a password check box.
  7. Click OK.
  8. Save your changes and build the project.
Note: By creating the strong name key file, visual studio automatically creates a file “ArticleDeanTicketing.snk” in the root folder and signs the assembly with a strong name once built. 

Extract Public Key Token

  1. Open a Visual Studio 2008 Command Prompt window by clicking on StartàProgramsàMicrosoft Visual Studio 2008à Visual Studio Toolsà Visual Studio 2008 Command Prompt.
  2. Type sn -T <assembly> where <assembly> is the complete path to the Web Part's assembly within your project. In this case, it will be sn -T "C:\Documents and Settings\Administrator\My Documents\Visual Studio 2008\Projects\Ticketing\bin\Release\ArticleDean.Ticketing.dll"
  3. Copy the public key token into a notepad. 

Add Safe Control Entry

Now we are done with the creating of the web part, we have to let SharePoint know about the new web part we have created. In-order to do that we have make entry in the web.config file.
  1. Navigate to the physical folder that represents the web application that you plan on deploying the Web Part to. If the default settings were used, the path should be something like this: C:\Inetpub\wwwroot\wss\VirtualDirectories\80
  2. Open the web.config file.  Take a moment to locate the SafeControls element. Notice that there are several SafeControl elements already defined in your web.config file. Also notice that the entries each contain the complete signature of the assembly that they represent, including the version and the public key token. Because you signed your assembly with a private key in prior steps, you will need the public key you extracted in the previous steps.
  3. Make a copy of one of the SafeControl entries in the web.config file. Update the Assembly attribute of the copy to the fully qualified name of your Web Part's assembly and the Namespace attribute to the Web Part's namespace. Your SafeControl entry should resemble the following snippet. Make sure that the public key token in your entry matches the public key token you extracted in the previous set of steps.
SafeControl Assembly="ArticleDean.Ticketing, Version=1.0.0.0, Culture=neutral, PublicKeyToken=4872109952d62d28" Namespace="ArticleDean.Ticketing" TypeName="Ticket" Safe="True" AllowRemoteDesigner="True"><span style="font-size: small; font-family: Book Antiqua;"> </span>

Deploy the Assembly

Deploying an assembly can be done by making use of the post build events in the visual studio, but for a better understanding of the system and its flow, we will follow a manual approach towards the deployment.
  1. Compile the solution in the “Release” mode either by click Buildà Build Solution or ctrl+shift+b
  2. Once the build is successful, the assembly “ArticleDean.Ticketing.dll” is created in the Bin\Release folder of the project.
  3. Copy ArticleDean.Ticketing "C:\Inetpub\wwwroot\wss\VirtualDirectories\80\bin\"

Create Web Part Definition File

In order to import your Web Part onto a page, you need to create a .webpart file. This file, once uploaded, is stored in the content database and tells SharePoint the information it needs to find the Web Part code.
  1. Add an XML file to your project, and name it ArticleDeanTicketing.webpart.
  2. Add the following code to the ArticleDeanTicketing.webpart file and save the file. Make sure that the public key token in your file matches the public key token extracted in previous steps. Also notice that you are able to set default values for many of the built-in properties as well as any of the public properties defined in your WebPart class. You are setting default values for both the Title and theDescription properties below.
<?xml version="1.0" encoding="utf-8" ?>
<webParts>
  <webPart xmlns="http://schemas.microsoft.com/WebPart/v3">
    <metaData>
      <type name="ArticleDean.Ticketing, Ticket, Version=1.0.0.0, Culture=neutral, PublicKeyToken=4872109952d62d28"/>
      <importErrorMessage>Could not import the ArticleDean Ticketing webpart.</importErrorMessage>
    </metaData>
    <data>
      <properties>
        <property name="Title" type="string">Ticketing System</property>
        <property name="Description" type="string">This webpart will allow a user to submit a ticket for any issues..</property>
      </properties>
    </data>
  </webPart>
</webParts>

Deploy Web Part Definition File 

  1. Copy ArticleDeanTicketing.webpart to"C:\Inetpub\wwwroot\wss\VirtualDirectories\80\wpcatalog\" 
Note: Incase if the folder “wpcatalog” does not exists, create it. 

Add the Web Part to a Page

The final step in your deployment involves informing SharePoint of the Web Part's existence. There are a few ways to accomplish this task. The ways in which you could inform Share Point of the Web Part are:
  • Since we copied the .webpart file to the wpcatalog folder, it will automatically appear in the Web Part gallery when we attempt to add a new Web Part via the links at the top of your Web Part zones when editing a page.
  • If you did not copied the .webpart file to the wpcatalog folder, you could manually import the.webpart file to any page within your site.
  • If you did not copied the .webpart file to the wpcatalog folder, you could have browsed to the Web Part gallery and added it by clicking on New when viewing the Web Part gallery's Web Parts. SharePoint is smart enough to find your Web Part and display it as an option to add to the gallery. This is possible because of the public access modifier decorating the Web Part class within the assembly (which is in the bin folder).
  1. Browse to the MOSS site and click on Edit Page under Site Actions.
  2. Click in Add a Web Part in one of the two default Web Part zones.
  3. Select the Ticketing System Web Part, and click Add. Your Web Part should be rendered on the page.
  4. Click Exit Edit Mode under the Site Action link.