Introduction to SharePoint Development in Visual Studio 2010
Visual Studio 2010 provides the templates and tools you need to develop complete SharePoint solutions. In this chapter you will create your first SharePoint solution and we will introduce you to some of the projects, project item templates, and tools that are in Visual Studio 2010 for SharePoint development.
Creating a SharePoint Solution
First, make sure you have followed the setup instructions in Appendix A, "Preparing for SharePoint Development." Once your machine is set up, you will need to launch Visual Studio as an administrator. The SharePoint projects in Visual Studio require administrator privileges to interact with SharePoint. To launch Visual Studio as an administrator, locate the Microsoft Visual Studio 2010 shortcut in the Start Menu under All Programs > Microsoft Visual Studio 2010. Right click on the Microsoft Visual Studio 2010 shortcut. You can choose Run as administrator from the context menu to run Visual Studio as an administrator.
Alternatively, if you just want to make Visual Studio start up with administrator privileges every time you launch it, you can change the Microsoft Visual Studio 2010 shortcut properties to always run as administrator. To do this, right click on the Microsoft Visual Studio 2010 shortcut and choose Properties. Click the Compatibility tab as shown in Figure 2-1. Then check the Run this program as an administrator check box and press OK.
Figure 2-1 Setting the Microsoft Visual Studio 2010 shortcut to start as administrator
Now use the modified Microsoft Visual Studio 2010 shortcut or the Run as administrator command in the context menu to launch Visual Studio with administrator privileges. Once Visual Studio has started up, choose New > Project... from the File menu. This brings up the New Project dialog. Select Visual C# as the language from the tree view control on the left. Then expand the Visual C# node and select SharePoint under the Visual C# node. Expand the SharePoint node and click the 2010 node. This will display all the available SharePoint project types as shown in shown in Figure 2-2.
Figure 2-2 SharePoint projects in the New Project dialog in Visual Studio
Visual Studio has 12 basic SharePoint project types; they are listed in Table 2-1. The most basic SharePoint project type is the empty SharePoint Project. This project begins empty but lets you create and add any SharePoint project items you want to it as you go along. So in an empty SharePoint project you could add a web part, a list definition, and so on.
Table 2-1. SharePoint Project Types
Project Type |
Description |
Empty SharePoint Project |
An empty SharePoint project; as with all projects in this table, you can add and remove arbitrary SharePoint item types once they are created. |
Visual Web Part |
A SharePoint project prepopulated with a visual web part project item; web parts are controls written using ASP.NET that users can place in a SharePoint web part page. |
Sequential Workflow |
A SharePoint project prepopulated with a Sequential Workflow project item; when you create a workflow, you are writing a program that is structured as a multistep process that may be long running, waiting for humans or external systems to complete tasks or other processes before continuing. A sequential workflow proceeds in a linear top-to-bottom fashion. |
State Machine Workflow |
A SharePoint project prepopulated with a State Machine Workflow project item; a state machine workflow uses concepts such as states, events, and transitions to model more complex business processes with multiple possible paths through the workflow. |
Business Data Connectivity Model |
A SharePoint project prepopulated with a Business Data Connectivity Model project item; a business data connectivity model allows you to define a data model and code that lets you integrate external data into SharePoint. |
Event Receiver |
A SharePoint project prepopulated with a List Definition project item; a list definition defines the schema of a list along with other things that define the list, such as views and forms used by the list. |
List Definition |
A SharePoint project prepopulated with a List Definition project item; a list definition defines the schema of a list along with other things that define the list, such as views and forms used by the list. |
Content Type |
A SharePoint project prepopulated with a Content Type project item; a content type defines the schema for an item in a list—examples of content types in SharePoint include the Contact content type and the Announcement content type. Content types can also be associated with document libraries, allowing you to create a specialized document type, such as an expense report content type complete with a document template, such as an Excel workbook or Word document, to be used when a new expense report is created. |
Module |
A SharePoint project prepopulated with a Module project item; a module is used when creating deployments to provision the SharePoint site with one or more files that are needed by a solution—for example, you might use this to deploy a custom document to a document library or some other custom resource like an image file or an application page. |
Site Definition |
A SharePoint project prepopulated with a Site Definition project item; a site definition is a template that is used when creating a new SharePoint site and defines all the initial content in that site—for example, the subsites that we saw in Chapter 1, Table 1-7 are all backed by custom site definitions. |
Import Reusable Workflow |
A SharePoint project created by importing a workflow that was initially created in SharePoint Designer. |
Import SharePoint Solution Package |
A SharePoint project created by importing a .WSP SharePoint Solution Package exported from SharePoint or SharePoint Designer. |
A second class of SharePoint project is prepopulated with one particular SharePoint project item type. This class includes the Visual Web Part, Sequential Workflow, State Machine Workflow, Business Data Connectivity Model, Event Receiver, List Definition, Content Type, Module, and Site Definition projects. These projects are empty SharePoint projects that have one SharePoint project item preadded to them—the item type specified by the project type designation. So, for example, the Content Type SharePoint project is an Empty SharePoint project with a Content Type project item preadded to it. As with the Empty SharePoint project type, you can continue to add SharePoint project item types to this class of projects or even remove from them the initially preadded SharePoint project item type.
A third class of SharePoint projects is populated by a wizard that runs when the project is first created. This class of SharePoint projects includes the Import Reusable Workflow and Import SharePoint Solution Package. The Import Reusable Workflow project creates a SharePoint project by importing a workflow from a workflow created in SharePoint or SharePoint Designer. The Import SharePoint Solution Package project creates a SharePoint project by importing a .WSP file exported from SharePoint Designer.
It is worth noting at this point that you have two general options for how you structure your SharePoint solutions. You can use a single project and add as many SharePoint project items as you need to that project. Or you can divide your solution into multiple projects. A key limitation of a project is that a single project can only produce a single .NET assembly (a .DLL file). So in cases where you need to factor your solution to produce multiple .NET assemblies you need to create multiple projects. You might also choose to divide your solution into multiple projects if you are developing a solution with other developers. This can make it easier for a solution to be simultaneously worked on by multiple developers.
Later in this chapter we will discuss in more detail what each of these project items and projects do. For now, let's start by creating an Empty SharePoint Project. As shown in Figure 2-2, you can specify a name and location for your project. You can also optionally add the project to source control by checking the Add to Source Control check box. Once you've set the name and location for your project, click the OK button to create the project.
A second dialog will appear to configure the site URL and security level for the newly created project as shown in Figure 2-3. The site URL should designate the SharePoint site where you want to deploy and test your SharePoint solution. As discussed in Chapter 1, a particular machine can host multiple SharePoint sites. If you click the Validate button, Visual Studio will verify that the URL you have typed corresponds to an already created SharePoint site.
Figure 2-3 Debugging options for empty projects
In order for you to successfully deploy and debug your SharePoint solution, you must also have the proper permissions on the SharePoint site you designated with the site URL. Your user account must be added as the Site Owner or Site Collection Administrator for the site URL. In some cases, a customization you build may be deployed at the site level and at other times a customization may only be deployable at the site collection level. For more information on setting up the SharePoint site properly so you can deploy and debug, see Appendix A, "Preparing for SharePoint Development."
In the same dialog shown in Figure 2-3, you must choose the trust level for the SharePoint solution. After the project is created, you can change the trust level later by using the Properties window for the project as shown in Figure 2-5 (see page 114). The property to change is the Sandboxed Solution property—if this is set to False the solution will have a Farm solution trust level.
Sandboxed solutions run in a secure, monitored process. Sandboxed solutions can be deployed without requiring SharePoint administrative privileges. If you choose a sandboxed solution, you can only use project item types that are valid in sandboxed solutions.
If you choose the option "Deploy as a farm solution," Visual Studio will deploy the solution as a fully trusted farm solution. If you choose a farm solution, you can use all available SharePoint project item types in your project, but deployment will require administrative privileges and the solution will run in full trust.
For this example, choose Deploy as a sandboxed solution. Click the Finish button as shown in Figure 2-3 to complete the creation of the project.
Sandboxed Solutions versus Farm Solutions
Early in the project creation process, Visual Studio asks you to decide between using a sandboxed solution or a farm solution. It is worth considering in more detail the difference between a sandboxed solution and a farm solution and when to choose one over the other.
Prior to SharePoint 2010, all solutions you could create were farm solutions. In Chapter 1 we saw that SharePoint solutions are deployed to a farm that could consist of one to many servers. Each server in the farm can have multiple web applications running on it. A web application can in turn have one or more site collections, and a site collection has one or more sites. Farm solutions can impact the entire SharePoint system and are available to all site collections and sites in the farm. This is sometimes desirable, but sometimes can have undesired effects because a farm solution that is misbehaving can impact all sites and site collections in the system.
In SharePoint 2010, you can create a new type of solution called a sandboxed solution. Sandboxed solutions are deployed at the site collection level rather than the farm level, so this lets you isolate a solution so it is only available to one site collection within the farm. Sandboxed solutions also run in a separate process from the main SharePoint IIS web application process, and the separate process is throttled and monitored with quotas to protect the SharePoint site from becoming unresponsive due to a misbehaving sandboxed solution.
It is worth mentioning that sandboxed solutions solve an organizational problem as well—in many organizations it is difficult to get permission to install a farm solution because of the possible impact that could have on the SharePoint system. System administrators in charge of running a SharePoint site have been reluctant in the past to allow custom solutions to run on their sites. With the advent of SharePoint 2010, there is now a robust system in place to monitor and throttle these custom solutions so that system administrators don't have to worry about a custom solution bringing the entire SharePoint site down. In addition, with sandboxed solutions, users can upload solutions without requiring administrator approval.
So if sandboxed solutions are so great, why are farm solutions still around at all in SharePoint 2010? Well, because of the need to restrict and throttle a sandboxed solution so that it cannot negatively impact the entire site, there are restrictions on the kinds of solutions you can build with a sandboxed solution. The most significant restrictions disallow creation of application pages, visual web parts, or code-based workflows with a sandboxed solution. You can, however, create a web part without using the visual designer and deploy it in a sandboxed solution—we will see how to work around this particular limitation in Chapter 9, "SharePoint Web Parts."
So in the end, the choice between sandboxed and farm solutions should come down to whether or not you need to create an application page or a workflow with code in it. For these kinds of solutions, you should pick a farm solution. For all other solutions, pick a sandboxed solution. The only other reason to use a farm solution over a sandboxed solution is if you really have some code that needs to run at the web application or farm level, perhaps because it needs to interact with or move data between multiple site collections. In this case, you would create a farm solution as well.
Exploring an Empty SharePoint Project
Returning now to the project we just created, let's inspect the structure of an empty SharePoint project as shown in Figure 2-4. First, click on the root node, Solution 'SharePointProject1' in our example. In the Properties window, you will see the properties associated with the solution. The two most interesting properties are the Active config and the Startup project properties. Active config sets whether to build debug or release assemblies. By default this starts out as Debug|Any CPU. Typically, during development you will use debug, but when you are ready to deploy the solution you will use Release|Any CPU setting. The Startup project will set which project's startup settings will be used when you press F5 when there are multiple projects in the solution. Since in typical solutions all projects will be deploying to the same SharePoint site URL, this won't matter much in practice unless you are building one solution that creates multiple deployments.
Figure 2-4 An empty SharePoint project
Now, click on the Project node, SharePointProject1, in our example. In the Properties window are a number of SharePoint specific properties as shown in Figure 2-5. Table 2-2 describes the functions of each of these properties. Two of the properties you configured during project creation can be changed here: Site URL—which designates the SharePoint site where you deploy and test your SharePoint solution, and Sandboxed Solution—which when set to True indicates that the solution will be a sandboxed solution and when set to False indicates that the solution will be a farm solution.
Figure 2-5 SharePoint project Properties window
Table 2-2. SharePoint Project Properties
Project Properties |
Description |
Project File |
The name of the Visual Studio project file. |
Project Folder |
The name of the folder where the project file is saved. |
Active Deployment Configuration |
If set to Default, this does the standard deployment when deploying a SharePoint solution. If set to No Activation then when a solution is deployed to the SharePoint site, Visual Studio won't try to activate the solution. For more information, see Chapter 11, "Packaging and Deployment." |
Assembly Deployment Target |
Sets where the assembly created by this project will be deployed; for sandboxed solutions, this property is disabled because in a sandboxed solution the management of where the assembly is loaded and runs is controlled by SharePoint. For a farm solution, this can be GlobalAssemblyCache or WebApplication. For some SharePoint solutions, the assembly must go in the global assembly cache, for others it can be put at the web application level in a directory specific to the web application. For more information see Chapter 9, "SharePoint Web Parts." |
Include Assembly in Package |
Sets whether the assembly created by this project is packaged into the .WSP file created when the project is built; you will typically set this to True unless you have a project that is only used for deploying CAML-based SharePoint artifacts like a list definition. |
Sandboxed Solution |
If set to True, the project will deploy as a partially trusted sandboxed solution, if set to False, the project will deploy as a fully trusted farm solution. |
Site URL |
The URL for the SharePoint site where you want to deploy and test your SharePoint solution. |
Startup Item |
The item in the project that will be started when you press F5. For example, if you have an application page in your project, it will open the application page in the browser when you press F5. |
Next, consider the Properties folder in the Solution Explorer. In this folder, you will find an AssemblyInfo.cs file that contains the attributes that will be added to the assembly that is created when the project is built. Almost all of these attributes are identical to the ones you would find when creating a simple class library project. The only one that is new is the AllowPartiallyTrustedCallers attribute. This attribute is used for partially trusted solutions (sandboxed solutions or farm solutions that have Assembly Deployment Target set to WebApplication as we saw in Table 2-2). For projects that have Assembly Deployment Target set to GlobalAssemblyCache, the AllowPartiallyTrustedCallers attribute can be removed.
The References folder in the Solution Explorer contains all the referenced assemblies for the project. The set of referenced assemblies are identical to the ones you would find when creating a simple class library project with two additions: Microsoft.SharePoint and Microsoft.SharePoint.Security. The Microsoft.SharePoint assembly contains the server object model for SharePoint that you will use when writing code against SharePoint. The Microsoft.SharePoint.Security assembly contains code access security objects that are used for partially trusted solutions.
The Features folder is a special folder that is found only in a Visual Studio SharePoint project. This folder contains SharePoint features that have been created for the project. A SharePoint project can contain zero or more features. By default, when you add a new SharePoint item to a SharePoint project that requires a feature, Visual Studio will create a new feature automatically or reuse an existing feature if there is already a feature in the project with the same scope (Farm, Site, Web, or Web Application). For more information on working with features, see Chapter 11, "Packaging and Deployment."
The Packages folder is another special folder that is found in SharePoint projects. This folder contains information that allows the project to create a package file or .WSP file. Package files are used to deploy SharePoint features to a SharePoint site. By default, when you add a new SharePoint item to a SharePoint project that results in the creation of a new feature, that new feature will automatically be added to the package file associated with the project. For more information on working with packages, see Chapter 11, "Packaging and Deployment."
The next file you will find in a SharePoint project is the key.snk file. This is a strong name key that is used to sign the output assembly of the project.
Mapped Folders, Deployment, and the Hive
One item you will often find in a SharePoint project that isn't found in our example is a mapped folder. Mapped folders give you a way to take resources and other files in your project and add them to folders in the Visual Studio project that are mapped to file system locations where those files need to be deployed on the SharePoint server. For example, imagine you have an application page you have developed that needs to deploy a file to the SharePoint server's images folder. To do this you would right click on the Project node and choose Add, then SharePoint Images Folder. This creates a mapped folder in the project called Images. Any folders you add to the images folder will be created on disk (if they aren't already there) and the contents of those folders will be copied to the SharePoint server's images folder when the project is deployed.
It is time for another aside regarding SharePoint terminology. We've just implied that SharePoint has an images folder—what is this and what other special folders does SharePoint have? When you build a deployment for SharePoint you build a SharePoint package, which is basically a CAB file (like a ZIP file if you aren't familiar with the CAB format) that has in it a set of files and instructions that are used to install your SharePoint solution. The instructions are encapsulated in one or more SharePoint Feature files, which consist of XML markup that is read at install time. A special program called stsadm.exe takes the SharePoint package file (which is a CAB file with a .WSP extension) and reads the SharePoint feature files in the package to determine how to install the SharePoint solution. These SharePoint feature files in turn can refer to additional files that are packaged within the SharePoint package. Stsadm.exe then does two major things—it adds information to the SharePoint content database and it copies files to the file system. So a SharePoint solution typically modifies the SharePoint content and configuration databases and adds files to the file system of the SharePoint server machine.
There are three general locations where SharePoint copies files to the file system of the server during deployment. The first location is the global assembly cache of the server machine. Solutions that have assemblies that need full trust will copy to this directory when Assembly Deployment Target is set to GlobalAssemblyCache as we saw in Table 2-2.
The second location is directories specific to a web application (which is an IIS concept we described in Chapter 1). One of those web application-specific directories is the bin directory. This is where assemblies are deployed if you set the Assembly Deployment Target property to WebApplication. To determine where the web application directory is, launch the Internet Information Services (IIS) manager on the SharePoint server (use the search box in the Start menu to search for it). Once you've launched the IIS manager, expand the Sites folder and find the web application you are interested in—in a default install it will be called SharePoint -80 as shown in Figure 2-6. Right click on the SharePoint -80 node, and pick Explore from the context menu. This will open the base directory for your web application as shown in Figure 2-7. Of interest here are several directories and files you may use. The web.config file is used to configure ASP.NET specific settings—you have to modify this file for some SharePoint development scenarios we will see later in this book. The bin folder is the bin directory associated with the web application where assemblies are sometimes deployed. There are other directories here that are used for web part development, such as the wpresources folder.
Figure 2-6 The Internet Information Services (IIS) Manager showing the web application SharePoint -80
Figure 2-7 Directories and files associated with the SharePoint -80 web application
The third location of interest for deployment is known in the SharePoint developer world as the hive, which is the location on disk where SharePoint installs feature definitions, site definitions, and other content used to provision the web site. SharePoint builds on its own extensibility model—many of the features in the SharePoint web site correspond to actual files you can inspect and learn from in these directories. The hive can be found at Program Files\Common Files\Microsoft Shared\Web Server Extensions\14. Some of the folders found in the hive are shown in Figure 2-8.
Figure 2-8 Directories and files in the SharePoint hive
When you add a mapped folder in Visual Studio by right clicking on the Project node and choosing Add, then SharePoint Mapped Folder, you will see the dialog shown in Figure 2-9, which lets you view all the folders in the hive to which you might want to deploy items. In Figure 2-9, we have expanded the TEMPLATE folder, which is the main place to which you will deploy items. In this folder, you can see there is an IMAGES folder, where you can deploy arbitrary images you want to use from web parts or application pages. There are other directories as well—for example, the SiteTemplates folder, where you install Site Definitions files and the LAYOUTS folder, where you can find the master page being used for the SharePoint server. You will typically create a subdirectory within the LAYOUTS folder if you want to install your own application pages. We will learn more about the hive throughout this book.
Figure 2-9 Adding a Mapped Folder in Visual Studio to the Layouts folder
SharePoint Project Items
So now that we've seen the basic structure of an empty SharePoint project and learned a little bit more about deployment, let's consider what happens when we add a SharePoint project item to the SharePoint project. To add a SharePoint project item, right click on the Project node in Server Explorer (titled SharePointProject1 in our example) and choose Add, then New Item... from the context menu. The Add New Item dialog shown in Figure 2-10 appears. There are a number of SharePoint project items that can be added to a SharePoint project. Table 2-3 lists the project item types and briefly describes each one. It also lists the chapter in this book where each project item type is described in detail.
Figure 2-10 Add New Item dialog
Table 2-3. SharePoint Project Item Types
Project Item Type |
Description |
Described in Chapter |
Application Page |
An ASP.NET web page that is displayed within a SharePoint site |
Chapter 10, "SharePoint Pages" |
Business Data Connectivity Model |
A business data connectivity model allows you to define a data model and code that lets you integrate external data into SharePoint. |
Chapter 6, "Working with Business Data" |
Content Type |
A content type defines the schema for an item in a list—examples of content types in SharePoint include the Contact content type and the Announcement content type. Content types can also be associated with document libraries, allowing you to create a specialized document type such as an "Expense Report" content type complete with a document template (e.g., an Excel workbook or Word document) to be used when a new expense report is created. |
Chapter 7, "SharePoint Content Types" |
Empty Element |
An empty element is used to create a SharePoint project item that has a single XML file called Elements.xml associated with it. In this file you can define SharePoint elements that aren't natively supported yet by Visual Studio, such as a site column for a list. This element can then be referenced by other project items and installed with the rest of the solution. |
Chapter 11, "Packaging and Deployment" |
Event Receiver |
An event receiver handles events that are raised by lists and other key objects in SharePoint. For example, an event receiver could execute custom code when a new item is added to a SharePoint list. |
Chapter 5, "SharePoint Event Receivers" |
List Definition |
A list definition defines the schema of a list along with other things that define the list, such as views and forms used by the list. |
Chapter 4, "SharePoint Lists" |
List Definition from Content Type |
Allows you to create a list definition based on a content type already in the project or on the local SharePoint server |
Chapter 4, "SharePoint Lists" |
List Instance |
A list instance allows you to create an instance of a list as part of your solution; for example, you could have a project with a custom list definition called Expense Reports and two instances of that list, one called "International Expense Reports" and one called "Domestic Expense Reports." |
Chapter 4, "SharePoint Lists" |
Module |
A module is used when creating deployments to provision the SharePoint site with one or more files that are needed by a solution—for example, you might use this to deploy a custom document to a document library or some other custom resource (e.g., an image file or an application page). A module has an Elements.xml file that you can edit to specify the file or files associated with the module. |
Chapter 11, "Packaging and Deployment" |
Sequential Workflow |
A multistep process that can be long running, waiting for humans or external systems to complete tasks or other processes before continuing. A sequential workflow proceeds in a linear top-to-bottom fashion. |
Chapter 8, "SharePoint Workflow" |
State Machine Workflow |
A state machine workflow uses concepts such as states, events, and transitions to model more complex business processes with multiple possible paths through the workflow. |
Chapter 8, "SharePoint Workflow" |
User Control |
User controls are ASP.NET controls that can be deployed and reused by application pages or web parts. For example, you might create a custom user control that provides a drop-down control with custom behavior you want to reuse in several application pages and web parts. |
Chapter 9, "SharePoint Web Parts" |
Visual Web Part |
Web parts are controls written using ASP.NET that users can place in a SharePoint web part page. The Visual Web Part project gives you a user control that you can visually edit combined with a class deriving from ASP.NET's web part class that hosts the user control. |
Chapter 9, "SharePoint Web Parts" |
Web Part |
Web parts are controls written using ASP.NET that users can place in a SharePoint web part page. The Web Part project does not use ASP.NET user controls or the visual designer for an ASP.NET user control; instead it has you edit a class deriving from ASP.NET's web part class. |
Chapter 9, "SharePoint Web Parts" |
Table 2-3 shows the SharePoint project items available when you right click on the Project node item and choose Add New Item. In addition, there are four more SharePoint project items that are only available when you right click on an existing item in a SharePoint project and then choose Add > New Item... . It can be confusing that these items don't appear if you have the Project node selected but only when you have an existing project item selected. But this reinforces the idea that these project items only make sense when used in conjunction with other SharePoint project items. These four additional project items are listed in Table 2-4.
Table 2-4. SharePoint Project Item Types Dependent on Other Project Item Types
Project Item Type |
Description |
Described in Chapter |
Business Data Connectivity Resource Item |
Dependent on Business Data Connectivity (BDC) Model; allows you to add a resource file to your BDC solution to provide localized names for a BDC model. |
Chapter 7, "SharePoint Content Types" |
Global Resources File |
Dependent on having other SharePoint project items in the project; allows you to add a resource file to provide localized names that can be used by any feature or element file in the solution. |
Chapter 11, "Packaging and Deployment" |
Workflow Association Form |
Dependent on having a Sequential or State Machine workflow in the project; an ASP.NET form that can be displayed when a workflow is associated with a SharePoint list, document library, or site. This can be used to configure initial settings for the workflow. |
Chapter 9, "SharePoint Web Parts" |
Workflow Initiation Form |
Dependent on having a Sequential or State Machine workflow in the project; an ASP.NET form that is displayed when an instance of a workflow is begun for an item in a list or document library or for a site workflow. |
Chapter 8, "SharePoint Workflow" |
For the purposes of this chapter, let's create an event receiver. An event receiver handles events that are raised by lists, items in a list, webs (Share- Point sites), and workflow. To create an event receiver, select Event Receiver from the list of project item types that can be added, as shown in the Add New Item dialog in Figure 2-10. Accept the default name (EventReceiver1) and press the Add button. The SharePoint Customization Wizard dialog appears. Here you can choose the type of event receiver you want to create, as shown in Figure 2-11.
Figure 2-11 The SharePoint Customization Wizard dialog configured to handle list item events for the Announcements list
There are five types of event receivers you can create: a list event receiver, a list item event receiver, a list e-mail event receiver, a web (SharePoint site) event receiver, and a list workflow event receiver. List item, list workflow, and list e-mail event receivers act on a specific list instance that you must also elect in the dialog in Figure 2-11. List and web event receivers pertain to a web scope and act on the current SharePoint site to which you are deploying.
For this example, let's create an event receiver that handles list item events for the Calendar list associated with the SharePoint site. To do this, pick List Item Events from the first drop-down in the dialog and select Announcements as the specific list for which we will handle events. After making these selections, the list box at the bottom of the dialog shows the different list item events that can be handled by your code. Check the check boxes next to An item is being added, An item is being deleted, An item was added, and An item was deleted. The dialog should look like Figure 2-11. Then press the Finish button.
Visual Studio adds the SharePoint project item representing an event receiver. The resulting project structure now looks like Figure 2-12.
Figure 2-12 A SharePoint project with a single SharePoint project item for an Event Receiver
Exploring a SharePoint Project Item
Now that we have added our first SharePoint project item to this project, we will explore some of the new things we can see in the project with the addition of a SharePoint project item. First note that there is a project item icon in Solution Explorer titled EventReceiver1, and parented under that icon are two additional items: an XML file called Elements.xml and a code file called EventReceiver1.cs. As we will see throughout this book, this is a common pattern for many SharePoint project items.
The root SharePoint project item node "EventReceiver1" has properties that configure the event receiver. This root node is actually a folder that contains two files. The Elements.xml file contains the XML that is used to describe the customization to SharePoint and is read by stsadm.exe as part of installing and configuring the solution. The EventReceiver1.cs file contains custom code that defines the behavior of the SharePoint customization and will be compiled into an assembly to be deployed to the SharePoint site. Let's consider each of these files in more detail.
The Elements.xml File
The first file to consider is the Elements.xml file. This is sometimes referred to as an Element Manifest file, and is an XML file that contains information that describes the SharePoint item being created to SharePoint, in this case an event receiver. Behind the scenes, Visual Studio will refer to this Elements.xml file in a feature file it has created. The feature file in turn is contained by a package—a package can contain one or more features as shown in Figure 2-13. When Visual Studio deploys the package, each feature file and associated Elements.xml file will be copied to the SharePoint server. SharePoint will read the feature file that will refer to the Elements.xml file. The Elements.xml file, as we will see, in turn refers to event handlers defined in an assembly. Once SharePoint has read the feature file and associated Elements.xml and assembly files, it can make the feature available for activation in the SharePoint site. We will consider the Visual Studio project support for features and packages in more detail later in this chapter and in Chapter 11, "Packaging and Deployment." Note that in this diagram, one feature has custom code associated with it represented by a .NET assembly. It is possible for multiple features to use code written within the same assembly.
Figure 2-13 The relationship among a package, a feature, element manifests, and an assembly
When you click on the Elements.xml file node in the Solution Explorer, you will see several properties in the Properties window that can be configured as shown in Figure 2-14. Note that the properties in the Properties window change if you click in the contents of the Elements.xml file, so be sure you've clicked on the node in the Solution Explorer tree view. These properties are organized into three categories: Advanced, Misc, and SharePoint. Let's consider the properties in each of these three categories.
Figure 2-14 The properties associated with the Elements.xml file node
Under the Advanced category of properties there are four properties: Build Action, Copy to Output Directory, Custom Tool, and Custom Tool Namespace. These properties tell Visual Studio how to process the Elements.xml file and you should just leave these properties set to their original values—Build Action is set to Content, Copy to Output Directory is set to Do not Copy, and the other two properties have no setting.
Under the Misc category of properties there are two properties—the File Name and the Full Path to the file so you can locate where it is stored on disk. As with the Advanced properties, there is no good reason to change these properties; they should be left set to their original values.
Finally, the SharePoint category of properties includes the property Deployment Location with child properties Root and Path and the property Deployment Type. The Deployment Location property tells you where on the SharePoint server the Elements.xml file will be deployed when you build and deploy the solution. In our example, it is set to {SharePointRoot}\Template\Features\{FeatureName}\EventReceiver1\. In our example, {SharePointRoot} is a substitution token that will be replaced by the actual root file location where SharePoint features are deployed on a server, typically a path such as "C:\Program files\Common Files\Microsoft Shared\web server extensions\14\, although SharePoint could be installed to a different drive or program file location than in this example. Another term you will hear used for this set of directories found under {SharePointRoot} is the SharePoint hive. {FeatureName} is another substitution token that will be replaced by the name of the feature that this SharePoint project item file is associated with, in our example: Feature1.
The Deployment Type property is set to ElementManifest—this reflects that Elements.xml is an element manifest and must be deployed to a folder corresponding to the feature with which the SharePoint project item file is associated. Changing this property would be a bad idea for this file because it would change the location where the file is deployed to one not appropriate for an element manifest.
Now that we've considered the properties associated with the Elements.xml file node, double click on the Elements.xml file node in the Solution Explorer window to open the contents of the Elements.xml file. The contents of the file are shown in Listing 2-1. Note that this is representative of the contents of an Elements.xml file for an event receiver. But for other SharePoint project item types—for example a list definition—the contents of the Elements.xml file will look quite different. This can be confusing to new SharePoint developers because they think that all Elements.xml files have similar contents when in truth, the contents of Elements.xml are specific to the SharePoint project item type.
Listing 2-1: The Elements.xml file defining event receivers for four list item events
<?xml version="1.0" encoding="utf-8"?> <Elements xmlns="http://schemas.microsoft.com/sharepoint/"> <Receivers ListTemplateId="104"> <Receiver> <Name>EventReceiver1ItemAdding</Name> <Type>ItemAdding</Type> <Assembly>$SharePoint.Project.AssemblyFullName$</Assembly> <Class>SharePointProject1.EventReceiver1.EventReceiver1</Class> <SequenceNumber>10000</SequenceNumber> </Receiver> <Receiver> <Name>EventReceiver1ItemDeleting</Name> <Type>ItemDeleting</Type> <Assembly>$SharePoint.Project.AssemblyFullName$</Assembly> <Class>SharePointProject1.EventReceiver1.EventReceiver1</Class> <SequenceNumber>10000</SequenceNumber> </Receiver> <Receiver> <Name>EventReceiver1ItemAdded</Name> <Type>ItemAdded</Type> <Assembly>$SharePoint.Project.AssemblyFullName$</Assembly> <Class>SharePointProject1.EventReceiver1.EventReceiver1</Class> <SequenceNumber>10000</SequenceNumber> </Receiver> <Receiver> <Name>EventReceiver1ItemDeleted</Name> <Type>ItemDeleted</Type> <Assembly>$SharePoint.Project.AssemblyFullName$</Assembly> <Class>SharePointProject1.EventReceiver1.EventReceiver1</Class> <SequenceNumber>10000</SequenceNumber> </Receiver> </Receivers> </Elements>
The contents of the Elements.xml file have a root element called Elements. Elements has a child element called Receivers. Receivers contains a Receiver element for each of the four event receivers we defined for our Event Receiver project item. Each Receiver element contains 5 subelements listed in Table 2-5. You might also notice the ListTemplateId attribute, which is set to 104. To find out where this magic number comes from, use the Server Explorer that we saw in Chapter 1 to browse the site. Under Team Site, List Templates, Communications select the Announcements list template. In the Properties window, you will see that its Type_Client property is 104. The number 104 tells SharePoint to associate the event receiver with the Announcements list definition.
Table 2-5. Subelements Contained within the Receiver Element in Elements.xml
Element |
Description |
Name |
The name of the receiver |
Type |
The type of the event handler; this name is defined by SharePoint and must also match the name of the method defined in the class handling the event. |
Assembly |
The full name of the assembly where the event handler for this event is defined; Visual Studio allows a token to be used here, $SharePoint.Project.AssemblyFullName$, which will be replaced with the full name of the assembly when the project is built. |
Class |
The fully qualified name of the class where the event handler for this event is defined, e.g., SharePointProject1.EventReceiver1.EventReceiver1 |
SequenceNumber |
The number inside the SequenceNumber element defines the order in which events are executed. If there are two or more event receivers and they are handling the same events, the one that has the smallest number in the SequenceNumber element is executed first. |
As you might imagine, the Elements.xml or element manifest for other SharePoint project item types contains different content that defines that particular SharePoint project item type. Every Elements.xml file, regardless of type, has a root element called Elements, however.
The Code File (EventReceiver1.cs)
Below the SharePoint project item node "EventReceiver1" you will see a code file called EventReceiver1.cs, shown in Listing 2-2. This contains a class that derives from Microsoft.SharePoint.SPItemEventReceiver. Event handlers are added with calls to the base class implementation of the event handler. Note that the names of these event handlers map to the names used in the Elements.xml file.
Listing 2-2: EventReceiver1.cs
using System; using System.Security.Permissions; using Microsoft.SharePoint; using Microsoft.SharePoint.Security; using Microsoft.SharePoint.Utilities; using Microsoft.SharePoint.Workflow; namespace SharePointProject1.EventReceiver1 { /// <summary> /// List Item Events /// </summary> public class EventReceiver1 : SPItemEventReceiver { /// <summary> /// An item is being added. /// </summary> public override void ItemAdding(SPItemEventProperties properties) { base.ItemAdding(properties); } /// <summary> /// An item is being deleted. /// </summary> public override void ItemDeleting(SPItemEventProperties properties) { base.ItemDeleting(properties); } /// <summary> /// An item was added. /// </summary> public override void ItemAdded(SPItemEventProperties properties) { base.ItemAdded(properties); } /// <summary> /// An item was deleted. /// </summary> public override void ItemDeleted(SPItemEventProperties properties) { base.ItemDeleted(properties); } } }
We will add some code to the ItemDeleting and ItemAdded event as shown in Listing 2-3. In ItemDeleting, we first call the base ItemDeleting method. Then we use the properties parameter that is passed to the function and use the ListItem property. The ListItem property is a parameterized property to which we can pass a field name to read and write a field from the item being deleted from the list. We use the ListItem property to access the Title field and append the Title field with an asterisk. Next, we call the Update method on the ListItem to update the item being deleted with the new Title. Finally, we use the Cancel property on the properties parameter to cancel the deletion of the item. We can stop an item from being deleted in the ItemDeleting event because this event is fired before the item is deleted—the ItemDeleted event happens after the item is deleted, so putting this code into that event would not work.
We also add code to the ItemAdded event. Here, we again use the ListItem property on the properties parameter passed to the event. We modify the Title to add the string "added" to it after it is added to the list. We then call the Update method on the ListItem to update the item that was added so our change will be shown in the list.
Listing 2-3: EventReceiver1.cs with custom event handlers for ItemDeleting and ItemAdded
using System; using System.Security.Permissions; using Microsoft.SharePoint; using Microsoft.SharePoint.Security; using Microsoft.SharePoint.Utilities; using Microsoft.SharePoint.Workflow; namespace SharePointProject1.EventReceiver1 { /// <summary> /// List Item Events /// </summary> public class EventReceiver1 : SPItemEventReceiver { /// <summary> /// An item is being added. /// </summary> public override void ItemAdding(SPItemEventProperties properties) { base.ItemAdding(properties); } /// <summary> /// An item is being deleted. /// </summary> public override void ItemDeleting(SPItemEventProperties properties) { base.ItemDeleting(properties); SPWeb web = properties.OpenWeb(); properties.ListItem["Title"] = properties.ListItem["Title"] + "*"; properties.ListItem.Update(); properties.Cancel = true; } /// <summary> /// An item was added. /// </summary> public override void ItemAdded(SPItemEventProperties properties) { base.ItemAdded(properties); SPWeb web = properties.OpenWeb(); properties.ListItem["Title"] = properties.ListItem["Title"] + " added"; properties.ListItem.Update(); } /// <summary> /// An item was deleted. /// </summary> public override void ItemDeleted(SPItemEventProperties properties) { base.ItemDeleted(properties); } } }
The Root Project Item Node or Folder (EventReceiver1)
When you click on the root level SharePoint project item node EventReceiver1, you will see several properties in the Properties window that can be configured as shown in Figure 2-15. First note that the Properties window indicates that EventReceiver1 is a folder—the Properties window says Folder Properties. The properties for EventReceiver1 are organized into three categories: Misc, SharePoint, and SharePoint Events. Let's consider the properties in each of these three categories.
Figure 2-15 The properties associated with the EventReceiver1 node
Misc Properties
The sole property under the Misc category in Figure 2-15 is Folder Name. If you change the name of the project item node—either by changing the Folder Name property or by renaming the project item node in the Solution Explorer, it will automatically change some but not all areas in the project that refer to the project item node. For example, if you were to rename EventReceiver1 to EventReceiver2, Visual Studio automatically fixes up the feature "Feature1" associated with the SharePoint project item to refer to the new project item name. But it doesn't change the names of the files contained in the (now EventReceiver2) folder or any of the classes that were created. So after changing the node to EventReceiver2, the code file is still titled EventReceiver1.cs and the class inside the code file is still titled EventReceiver1. More critically, the Elements.xml file still refers to EventReceiver1.
You could manually rename EventReceiver1.cs to EventReceiver2.cs and even refactor the class contained in the newly renamed EventReceiver2.cs file to be EventReceiver2. In this case, the Elements.xml file will be updated correctly. But in some cases the Elements.xml file will not be updated correctly after a refactor. For example, if you change the namespace that your class is defined in from SharePointProject1.EventReceiver1 to SharePointProject1.MyEventReceiver, the Elements.xml file will not be updated to have the right fully qualified class names in the Class elements. You would have to manually update the Elements.xml file to ensure it contains the new SharePointProject1.MyEventReceiver namespace or the project won't run successfully.
SharePoint Properties
Continuing with our exploration of the properties associated with the root level SharePoint project item node EventReceiver1, you will see a number of properties under the category SharePoint in Figure 2-15. Feature Properties is a collection of key value pairs that are used when deploying the feature associated with the event receiver to SharePoint. These properties are deployed with the feature and can be accessed later in SharePoint using the SPFeaturePropertyCollection object. So for example, you might use feature properties to associate some configuration information or other static data with your feature.
The Feature Receiver set of properties includes the subproperties Assembly and Class Name. You can use these properties to specify an assembly and class name that you want to handle events that are raised when the Feature associated with your EventReceiver1 item is raised. You can create a class in your current solution and refer to it or include another assembly in your SharePoint package—for more information on how to include additional assemblies in your SharePoint package, see Chapter 11, "Packaging and Deployment."
Events that your feature receiver can handle include FeatureInstalled, FeatureUninstalling, FeatureActivated, and FeatureDeactivating. So you could write code that runs when your EventReceiver1 is installed and uninstalled from the SharePoint site, maybe to add additional resources or lists required on install and remove those additional resources or lists on uninstall. We will discuss feature event receivers more in Chapter 5, "SharePoint Event Receivers."
Project Output References are used to tell Visual Studio about any dependent assemblies your project item requires to run. For example, maybe your event receiver uses a helper class library called HelperLibrary.dll. You can use the Project Output References project to tell Visual Studio about the helper class library and then Visual Studio will package the dependent assembly in the final solution. For more on Project Output References, see Chapter 11, "Packaging and Deployment."
Finally Safe Control Entries is used to designate whether an ASPX control or web part is trusted and can be used by users on the site. In the context of an Event Receiver, this property is not applicable and doesn't do anything. We will see this property used in Chapter 9, "SharePoint Web Parts."
SharePoint Events Properties
In Figure 2-15, under the category SharePoint Events are a number of properties that correspond to the list of events we saw earlier in the wizard shown in Figure 2-11. For the events that we checked earlier, the properties Handle ItemAdded, Handle ItemAdding, HandleItemDeleted, and HandleItemDeleting are set to True. To add and remove events that this event receiver handles you can change which SharePoint event "Handle" properties are set to True or False. To see the impact of setting a property that was previously set to False to True, open the Elements.xml file and the EventReceiver1.cs files under the EventReceiver1 node and arrange your windows so these files are visible while you change "Handle" properties under the SharePoint Events category to True or False. You will notice that setting a property like Handle ItemCheckedIn, which was previously False to True, adds a block of XML to the Elements.xml file and adds a new event handler to the EventReceiver1.cs file. If you then set that property back to False, you will see that Visual Studio removes the block of XML that it previously added from the Elements.xml file, but leaves the event handler it added to the EventReceiver1.cs file intact. It leaves the code in EventReceiver1.cs intact because you might have written some code in the handler and Visual Studio wants to preserve any code you wrote. Also, having an inactive event handler in EventReceiver1.cs (inactive because it isn't registered in the Elements.xml file) will have no ill-effect on your remaining active event handlers (active because they are registered in the Elements.xml file).
Features and Packages in a Visual Studio Project
We've now explored the properties and files that are associated with a new SharePoint project item. We've seen the Elements.xml file, the code file associated with an event receiver, and the properties associated with each of these files and the root EventReceiver1 folder for the SharePoint project item.
You may have noticed that when we added the event receiver project item to our blank solution, some new items appeared under the Features folder. Let's examine the Features and Package folders in the SharePoint project to start to get an idea of what Visual Studio does to package and deploy our SharePoint solution.
Features
Just to make things a little more interesting, let's create a second event receiver. Follow the steps we did earlier in the chapter to create a second event receiver called EventReceiver2. For the second event receiver, choose List Item Events as the type of event receiver to create, use Calendar as the event source, and handle the event when an item is being added.
Now double click on the project item called Feature1 under the Features folder. The Visual Studio Feature designer appears as shown in Figure 2-16. Note that we now have two event receivers in our solution, EventReceiver1 and EventReceiver2, and Feature1 is configured to install both event receivers.
Figure 2-16 Visual Studio's Feature designer with two SharePoint project items to deploy
It is possible to add features to the Features folder. For example, maybe you want EventReceiver1 and EventReceiver2 to be deployed as separate features. You could create a separate feature called "Feature2" and install EventReceiver1 in Feature1 and EventReceiver2 in Feature2. Doing this would enable the event receivers to be installed and uninstalled separately. Another reason you might need to have separate features is when you have SharePoint project items you want to deploy that need to be installed at a different scope. If you drop down the Scope drop-down in Figure 2-16, you can see that a feature can be installed to one of four scopes: Farm, Site (the Site Collection Level), Web (the Site level), and WebApplication (all sites hosted by an IIS web application). Due to historical reasons, SharePoint sometimes uses the word Site to refer to a Site Collection and Web to refer to a SharePoint Site.
Let's create a second feature by right clicking on the Features folder and choosing Add Feature. A new Feature called Feature2 is created. In the Feature designer that will appear for Feature2, click on the EventReceiver2 SharePoint item and click the > button to move the feature from the left-hand list to the right-hand list. Then back in the Feature1 designer, ensure that EventReceiver2 is not installed by Feature1 by clicking on EventReceiver2 and pressing the < button to move it from the right-hand list to the left-hand list. The resulting Feature1 designer is shown in Figure 2-17. This shows that Feature1 will now install only EventReceiver1 not EventReceiver2. The right-hand list contains the features that will be installed; the left-hand list contains other items in the solution that have not been added to this feature. Also in Figure 2-17, we have expanded the Files outline and the Feature Activation Dependencies area of the Feature designer. We will discuss these two areas of the designer next.
Figure 2-17 Visual Studio's Feature designer with one SharePoint project item to deploy
The Files outline shows the actual files that will be included in the feature to install the associated SharePoint project item. In this case, you can see that the Elements.xml file will be included. The assembly built with the current project is also implicitly included in the feature, even though it doesn't show in this designer.
Also, at the bottom of the dialog you can now see the Feature Activation Dependencies area of the Feature designer. Here you can add dependencies that your feature has on other features in the solution or on other features that must be installed in advance to the SharePoint site where this feature will be installed. For example, you might have a situation in which you've created two features in your solution but Feature1 needs Feature2 to be installed first. Let's enforce this constraint. Click the Add... button in the Feature Activation Dependencies area for Feature1 to specify that Feature2 is a dependency. When you click the Add... button, the dialog shown in Figure 2-18 appears. If you click the feature SharePointProject1.Feature2 and then press the Add button, Feature2 will be added to the list of Feature Activation Dependencies for Feature1.
Figure 2-18 The Add Feature Activation Dependencies dialog
You also might want to add a dependency on another custom or built-in SharePoint feature. For example, you might need to ensure that the Announcement Lists feature is installed on the SharePoint site because your event receiver modifies or creates announcement lists. If announcement lists are not there, your event receiver will fail. The dialog shown in Figure 2-18 also lets you add dependencies to SharePoint features not in your solution by specifying the Feature ID of the feature on which you are dependent. As you might remember from Chapter 1, you can use the Server Explorer and the Properties window to determine the Feature ID for a particular feature as shown in Figure 1-76's DefinitionID. This ID could be added as a custom dependency for our Feature1 using the dialog in Figure 2-18.
Package Designer
Features in a project are useless unless they are deployed into what is called a Package or a .WSP file. Visual Studio helps you configure the Package created by your solution with the Package Designer. To see the Package Designer, double click on the Package.package project item under the Package folder in your solution. The designer shown in Figure 2-19 appears.
Figure 2-19 The Package Designer
When you first open the designer it won't exactly match Figure 2-19 because Visual Studio will automatically place both features we created into the items to install in the package that is created by the project. We used the < button to remove Feature2 from the package because we don't really want to install EventReceiver2 since we have no code added to it yet. Each project can build only one package, but you can have a package created by other projects in your solution. Visual Studio also lets you mix and match where features come from—that is, a feature can come from Project1 in a solution but be installed by the Package built by Project2.
If you click on the Advanced button at the bottom of the Package Designer, options are provided to add additional assemblies to the package—either assemblies created by other projects in the solution or additional external assemblies. The Advanced page of the Package Designer is shown in Figure 2-20.
Figure 2-20 The Package Designer's Advanced Page
This has given you a brief introduction to Visual Studio's support for features and packages. We will consider features and packages in more detail in Chapter 11, "Packaging and Deployment."
Building
So we now have a SharePoint solution with two event receivers: EventReceiver1 and EventReceiver2, two features: Feature1 and Feature2, and one package: Package.package. Feature1 includes EventReceiver1, Feature2 includes EventReceiver2, but Package.package only includes Feature1, so the EventReceiver2 will not be packaged or installed. If we build currently, we will get a missing dependency error because we made Feature2 a dependency for Feature1 and Feature2 is not currently being packaged. Use the Feature designer's Feature Activation Dependencies area for Feature1 to remove the dependency on Feature2 by clicking the Remover button.
We are now ready to build our project in preparation for running and debugging it. When you build the project by choosing Build Solution from the Build menu, the Output window indicates pretty much what you would expect—it says that a DLL has been built in the Debug folder of your project called SharePointProject1.dll. When we go to the bin\debug directory for the project in Windows Explorer, you will see the DLL and the PDB for the DLL, which contains debugging information. If you package the project by choosing Package from the Build menu, you will see something a little different, as shown in Figure 2-21. You will now find in addition to the DLL and PDB files, there is a .WSP file. This is the SharePoint package file that the Feature and Package Designer helped us to create.
Figure 2-21 What Visual Studio built after choosing Package from the Build menu
Let's look at the .WSP file in a little more detail. Click the SharePointProject1.wsp file in the bin\debug folder of your project. Copy the SharePointProject1.wsp then Paste to make a copy of the .WSP file. Rename its extension from .WSP to .CAB. Remember we said that a .WSP file was actually a .CAB file? Now that we've renamed it to a .CAB file, you should be able to double click on it and see the contents of the .WSP file as shown in Figure 2-22.
Figure 2-22 Inside the .WSP File
As you can see, there are 4 files inside the .WSP file: Elements.xml, Feature.xml, manifest.xml, and the assembly created by our project (a copy of the one we saw in the debug directory). Let's look at the contents of these files briefly. Drag Elements.xml, Feature.xml, and manifest.xml out of the renamed .CAB file to your desktop.
Manifest.xml is shown in Listing 2-4 and is the top-level manifest for the .WSP file. It tells about any assemblies included in the package (in this case SharePointProject1.dll). Additional assemblies could be included if you use the Advanced page of the Package Designer to add additional project or external assemblies. Manifest.xml also lists any features contained in the Package, in this case Feature1. You can see what manifest.xml will look like within Visual Studio by double clicking on the Package.package project item to show the Package Designer then clicking on the Manifest button at the bottom of the Package Designer. The same file shown in Listing 2-4 will be shown.
Listing 2-4: Manifest.xml inside the .WSP file
<?xml version="1.0" encoding="utf-8"?> <Solution xmlns="http://schemas.microsoft.com/sharepoint/" SolutionId="00257823-9b84-48c4-814a-fd754b21073f" SharePointProductVersion="14.0"> <Assemblies> <Assembly Location="SharePointProject1.dll" DeploymentTarget="GlobalAssemblyCache" /> </Assemblies> <FeatureManifests> <FeatureManifest Location="SharePointProject1_Feature1\Feature.xml" /> </FeatureManifests> </Solution>
Feature.xml is shown in Listing 2-5 and corresponds to Feature1 of our two features. In fact, you can see this XML file by double clicking on Feature1.feature to show the Feature designer, then clicking the Manifest button at the bottom of the form. This XML file describes the Feature and tells about the manifests included in the feature. Because Feature1 includes EventReceiver1, there is one Elements.xml file associated with EventReceiver1, which is the same Elements.xml file that we found under the EventReceiver1 folder.
Listing 2-5: Feature.XML inside the .WSP file
<?xml version="1.0" encoding="utf-8"?> <Feature xmlns="http://schemas.microsoft.com/sharepoint/" Title="SharePointProject1 Feature1" Id="d4050cd0-e7d5-48b0-88a2-fb4257b461b7" Scope="Site"> <ElementManifests> <ElementManifest Location="EventReceiver1\Elements.xml" /> </ElementManifests> </Feature>
Elements.xml is just the same file we saw under the EventReceiver1 folder as shown in Listing 2-6. As you can see, there is no magic here, the .WSP file packages up files we've already been able to see in the Package and Feature designers and the Elements.xml file we edited in Visual Studio associated with EventReceiver1.
Listing 2-6: Elements.xml inside the .WSP File
<?xml version="1.0" encoding="utf-8"?> <Elements xmlns="http://schemas.microsoft.com/sharepoint/"> <Receivers ListTemplateId="104"> <Receiver> <Name>EventReceiver1ItemDeleting</Name> <Type>ItemDeleting</Type> <Assembly>$SharePoint.Project.AssemblyFullName$</Assembly> <Class>SharePointProject1.EventReceiver1.EventReceiver1</Class> <SequenceNumber>10000</SequenceNumber> </Receiver> <Receiver> <Name>EventReceiver1ItemAdded</Name> <Type>ItemAdded</Type> <Assembly>$SharePoint.Project.AssemblyFullName$</Assembly> <Class>SharePointProject1.EventReceiver1.EventReceiver1</Class> <SequenceNumber>10000</SequenceNumber> </Receiver> <Receiver> <Name>EventReceiver1ItemDeleted</Name> <Type>ItemDeleted</Type> <Assembly>$SharePoint.Project.AssemblyFullName$</Assembly> <Class>SharePointProject1.EventReceiver1.EventReceiver1</Class> <SequenceNumber>10000</SequenceNumber> </Receiver> <Receiver> <Name>EventReceiver1ItemAdding</Name> <Type>ItemAdding</Type> <Assembly>$SharePoint.Project.AssemblyFullName$</Assembly> <Class>SharePointProject1.EventReceiver1.EventReceiver1</Class> <SequenceNumber>1000</SequenceNumber> </Receiver> </Receivers> </Elements>
Debugging
Now that we've built our project and created the .WSP file, let's debug our solution. To debug the solution, press F5 or choose Run from the Debug menu. Now we see much more activity in the Output window as shown in Listing 2-7. The Build phase does what we saw before—compiles a DLL from any code in the project and builds a package. Then in Deploy several things of interest happen. First, there are some steps to Retract the previous version of the solution. This is so the edit code, run, edit code and run again cycle will work. Visual Studio automatically removes the package and features you installed on your last debug session before deploying your updated package to ensure that you will always have the most recent version of your solution on the server and that the old one won't conflict with the new one. You can also manually Retract a solution from the Server using the Retract command from the Build menu—for example, if you want to ensure that the Server you were testing on doesn't have your solution on it when you are done.
The next thing that Visual Studio does is deploy your .WSP file to the server—the equivalent of using stsadm.exe on the .WSP file at the command line. This installs the package, but there is also a second step after installation called activation. An installed solution is still not active for the web site. Visual Studio also activates the features in the solution to ensure they are installed and active on the web site. Visual Studio will also do an IIS Application Pool recycle if necessary—this ensures that the most current version of the site is running with your new solution installed on it. Finally, Visual Studio launches the site URL in a browser window.
Listing 2-7: Output when you start the solution
------ Build started: Project: SharePointProject1, Configuration: Debug Any CPU ------ SharePointProject1 -> C:\Users\ecarter\Documents Visual Studio 2010\Projects\SharePointProject1\SharePointProject1 bin\Debug\SharePointProject1.dll Successfully created package at: C:\Users\ecarter\Documents\Visual Studio 2010 Projects\SharePointProject1\SharePointProject1 bin\Debug\SharePointProject1.wsp ------ Deploy started: Project: SharePointProject1, Configuration: Debug Any CPU ------ Active Deployment Configuration: Default Run Pre-Deployment Command: Skipping deployment step because a pre-deployment command is not specified. Recycle IIS Application Pool: Skipping application pool recycle because no matching package on the server was found. Retract Solution: Skipping package retraction because no matching package on the server was found. Add Solution: Adding solution 'SharePointProject1.wsp'... Deploying solution 'SharePointProject1.wsp'... Activate Features: Activating feature 'Feature1' ... Run Post-Deployment Command: Skipping deployment step because a post-deployment command is not specified. ========== Build: 1 succeeded or up-to-date, 0 failed, 0 skipped ========== ========== Deploy: 1 succeeded, 0 failed, 0 skipped ==========
Let's see if our event receiver is working. As you may remember, we tied our event receiver to the Announcements list. First, let's set a break point in EventReceiver1.cs. Click on the ItemAdded event in that file and add a breakpoint by clicking in the left margin of the code editor. Now, go back to the web browser that Visual Studio opened up for you and navigate to the Announcements list. To get there, click on the Site Actions drop-down in the top left corner of the page and choose View All Site Content. On the page that appears, scroll down to the Lists section and click on the Announcements list. Click on the Add new announcement link at the bottom of the list as shown in Figure 2-23.
Figure 2-23 The Announcements List
In the dialog that pops up, type some text for your new announcement, something like "Test" as shown in Figure 2-24. Then click the Save button.
Figure 2-24 Creating a new announcement
When you click the Save button your breakpoint should be hit in the debugger in the ItemAdded event. You can step through the code to watch it modify the newly added item by appending the text "added" to it using the F10 key. Press F5 to continue. You will now see the announcement list in the browser with the newly added announcement with the text "added" appended to the text you entered "Test."
You can also click the check box next to the newly added announcement and press the Delete Item button to try to delete it. For this case, the event receiver we created called ItemDeleting runs and cancels the deletion of the announcement. SharePoint shows the dialog in Figure 2-25, notifying the user that the announcement cannot be deleted.
Figure 2-25 An Event Receiver canceled the Request dialog
To stop debugging, close the browser window or choose Stop Debugging from the Debug window.