Office Apps
Integrate VSTO with SharePoint Content Types
Steve Fox
This article discusses:
|
This article uses the following technologies: VSTO, SharePoint, SQL Server |
Contents
VSTO Customization Basics
Building the VSTO Customization
Creating User Controls
Deployment and Security
Creating a New Content Type
Finishing Up
Office Business Applications (OBAs) are composite applications built using the services, tools, and servers that comprise the Microsoft® 2007 Office system. These applications integrate with line of business (LOB) systems such as SAP, PeopleSoft, and Microsoft Dynamics. The primary goal behind OBAs is to build on existing investments in LOB systems by bridging the gap that exists when employees don't have direct access to business data residing in the LOB system.
As a result of this gap, many employees must work with outdated business data. This leads to potentially misinformed business decisions and causes unnecessary requests to workers who do have access to the LOB systems. There are costs in terms of time and, often, money with this situation.
OBAs have other advantages as well, such as bringing business data into the context of the everyday work environment—typically via familiar Microsoft Office applications. Building on familiar tools helps mitigate training costs for LOB systems that are, to put it kindly, sometimes cumbersome and difficult to navigate.
You can build effective OBAs with four core pieces: the LOB system, a customized Office client application, Microsoft Office SharePoint® Server (MOSS) 2007, and the services that tie the other three pieces together. Other products such as Exchange Server or Office Communications Server (OCS) can also be tied into OBAs to extend their reach and functionality, and Visual Studio® Tools for Office (VSTO) provides built-in features to help you build the solution quickly.
You could, for instance, create an Excel® Services Web Part that points to data within an Excel 2007 spreadsheet, enabling developers to build business intelligence views within SharePoint. Or you could provide rich client-side customizations by integrating Visual Studio Tools for Office (VSTO) customizations into SharePoint so users can invoke the custom templates or documents directly from their document libraries.
This particular type of integration has a significant number of benefits, such as building on the Office client application feature-set (thus not needing to reproduce it in your solutions), enabling efficient management and deployment of document or template assemblies (the VSTO customizations), and allowing for data to be stored and managed centrally while simultaneously allowing it to be manipulated in a collaborative, workflow-driven environment.
This article focuses on the second and third benefits mentioned: building a document-level VSTO customization and integrating it with a content type in SharePoint. The combination of these allows you to leverage the rich user functionality of the Office platform on the client while at the same time seamlessly extends the data captured on the client to the enterprise.
Specifically, I will show you how to create, deploy, and secure a VSTO document-level solution that uses Microsoft Word content controls bound to centrally managed data through a custom actions pane. I will then show you how to create a content type within SharePoint, and I will conclude by showing you how to map the content type to the custom VSTO document-level solution.
VSTO Customization Basics
Note that there are two types of VSTO add-ins you can build. The first, which will be discussed in this article, is a document-level solution—essentially a customization that appears only within a specific document or template. The second, not discussed in this article, is an application-level add-in—essentially a customization that appears every time you open the host application.
Because OBAs are often associated with processes, I'm going to create a fairly simple VSTO customization for Word that is a smaller part of a wider purchase order (PO) process. The process, for the sake of this article, includes three key steps: a PO is created for work requested by a customer, a statement of work (SOW) is generated from the purchase order, and an invoice is generated from the completion of the work. Of course, your PO process may vary, but these are the essential ingredients for the example in this article.
In this scenario, also imagine that the company uses an LOB system to centrally manage data such as work or customer details. For the sake of this article (and to keep things simple), I'll use a SQL Server® connection; however, in a real-world implementation, you'd likely be connecting to the LOB system with a Windows® Communication Foundation (WCF) service or Web service.
This article will focus on the invoicing portion of the process. To do this, I'll create a custom invoice that consumes centrally managed data and then integrates that with SharePoint. Along the way, think about how you could build and integrate the other steps in the process and potentially build a workflow around the custom invoice that will live on SharePoint.
Before you begin coding, however, you will want to use a custom document or template for the invoice. As you can see in Figure 1, I have created a very simple customer invoice with the basic information and not too many frills.
Figure 1** Customer Invoice Document **(Click the image for a larger view)
Building the VSTO Customization
Further Reading
The resources listed here represent a good starting point for not only learning about OBA development but also about the individual technologies and options you have for your development.
After you've created your document, you can begin the fun part: building your document-level customization. To do this, create a new Word 2007 Document project using Visual Studio 2008 (click File | New | Project. Then, under Visual C#® or Visual Basic®, click Office | 2007 | Word 2007 Document).
Before Visual Studio creates your project shell, it will prompt you to select a document for your application. This is where you link a document (my invoice, in this case) with the project. You can specify an existing file, like I did, or you can create a new file. Visual Studio will then load all of the Word menu options and functionality into the development environment.
VSTO 3.0 is a technology included in Visual Studio Professional Edition and above and is the technology that enables you to build solutions for Office using managed code. One of the things I really like about VSTO document-level solutions is that the document or template you use in the project acts much like a designer in Visual Studio. You can drag controls from the Toolbox and drop them onto your document and even add events to your document just like you would with Windows Forms or Windows Presentation Foundation (WPF) user controls.
Visual Studio creates a project shell for you that uses the custom document as a core part of the project. With the project shell created, I add two main customizations to the invoice document and then add some code behind the document to handle the customer data. Specifically, I add some Word content controls to the document. Then I create a custom actions pane to manage a view of the data loaded into the content controls.
Figure 2 shows a project view with the document open in design mode. In the Toolbox pane, you can see the Word Controls—these are the Word content controls that you can drop onto the document surface. I've added them throughout the document. In Figure 2, the text "Click here to enter text." identifies the content controls I have added to the document. For this project, I've used the Rich Text Content Control, which gives me a little more power over text presentation and formatting. You can also add other types of controls such as images, date pickers, or comboboxes.
Figure 2** Editing a VSTO Custom Document **(Click the image for a larger view)
After adding the content controls to the document surface, you'll next want to integrate a data source into your project. In the context of an OBA, this will likely mean integrating a service into your project and then implementing members within that service to read data from or write data to an LOB system. I'm going to keep things simple and use a SQL Server database as an example LOB system. My data source is a table called PODetails—it is defined by columns that include the PO ID (my primary key), customer name, address and contact person, PO details, and a total for the PO.
Enabling the PODetails data for use in my solution is accomplished by using the Add New Data Source Wizard (Data | Add New Data Source | New Connection). The wizard prompts for the tables to integrate into the project and then provides a default connection string for the project.
Creating User Controls
Now I create a user control, which will be hosted inside the actions pane (see Figure 3). The user control includes six fields with labels and four button controls. The fields are each bound to a record in the database table using the data binding property. The purpose of the buttons is to enable you to load the data from SQL Server into the control, to browse back and forth across the data, and to add the selected data to the content controls in the custom invoice document.
Figure 3** Customer PO Information User Control **(Click the image for a larger view)
After creating the user control, I add events for each of the button controls. For the load data event, I added the following code:
namespace CustomerInvoice {
public partial class CustomerDataFilterControl : UserControl {
private void btnLoadPOData_Click(object sender, EventArgs e) {
CustomerInvoice.PODataDataSetTableAdapters.
PurchaseOrderDetailsTableAdapter poAdapter = new
CustomerInvoice.PODataDataSetTableAdapters.
PurchaseOrderDetailsTableAdapter();
poAdapter.Fill(this.pODataDataSet.PurchaseOrderDetails);
}
}
}
An alternative design might be loading the data during the core Add-in class's StartUp method, which executes when the host application loads the assembly.
I also added a couple of events to manage browsing back and forth through the data, so a user could move across the customer data in the table by clicking a button element. To do this, I used the MovePrevious and MoveNext methods on the binding source:
namespace CustomerInvoice {
public partial class CustomerDataFilterControl : UserControl {
private void btnDataPrevious_Click(object sender, EventArgs e) {
purchaseOrderDetailsBindingSource.MovePrevious();
}
private void btnDataNext_Click(object sender, EventArgs e) {
purchaseOrderDetailsBindingSource.MoveNext();
}
}
}
To add the data to the content controls, I employ the straightforward approach of reading a series of string variables from the Text property on each of my user control's textboxes. I then take those strings as arguments and set each of the Text properties on the corresponding content controls in the document. Figure 4 illustrates this sample technique.
Figure 4 Adding Data to the Word Document
namespace CustomerInvoice {
public partial class CustomerDataFilterControl : UserControl {
private void btnAddData_Click(object sender, EventArgs e) {
string companyName = txtCompanyName.Text;
string purchaseOrder = txtPONum.Text;
string workDetails = txtPODetails.Text;
string companyAddress = txtAddress.Text;
string contactPerson = txtContact.Text;
string poTotal = txtTotal.Text;
addDataToWCCs(companyName, purchaseOrder, workDetails,
companyAddress, contactPerson, poTotal);
}
public void addDataToWCCs(string cmpyName, string poNum,
string poDetails, string address, string contact, string total) {
Globals.ThisDocument.wccCustomerName.Text = cmpyName;
Globals.ThisDocument.wccCustomerAddress.Text = address;
Globals.ThisDocument.wccCustomerContact.Text = contact;
Globals.ThisDocument.wccWorkDescription.Text = poDetails;
Globals.ThisDocument.wccWorkItem.Text = poDetails;
Globals.ThisDocument.wccPurchaseOrderNum.Text = poNum;
Globals.ThisDocument.wccPurchaseOrderTotal.Text = total;
Globals.ThisDocument.wccTotalCharges.Text = total;
}
}
}
You may notice that there are a couple of duplicate string variable assignments to the content controls. This is by design, but I should mention that in your solution you may have multiple PO work items for a given invoice, so the second total (assigned to wccTotalCharges in my case) might want to treat the string variables as decimals and call a function to sum them for a total invoice charge. In the case of the second work details content control (wccWorkItem), one approach could be to have an abbreviated description for the table and a longer one for the details. I chose to keep things simple and reused the strings across the two content controls.
I designed my solution with content controls for three reasons. First, content controls are a great way to bind data to a Word document (and are quite stable). Second, I can lock the contents of the controls so users cannot delete the controls or edit the content in the controls. And finally, I can treat the controls in a way that is similar to other objects in a VSTO project. For example, in Figure 4, note the use of Globals to access the Text property of each content control. This is just one of a few properties that can be managed. Figure 5 demonstrates programmatically locking the content controls so users cannot delete or edit the controls.
Figure 5 Locking the Content Controls
public void lockAllContentControls() {
Globals.ThisDocument.wccCustomerName.LockContentControl = true;
Globals.ThisDocument.wccCustomerAddress.LockContentControl = true;
Globals.ThisDocument.wccCustomerContact.LockContentControl = true;
Globals.ThisDocument.wccWorkDescription.LockContentControl = true;
Globals.ThisDocument.wccWorkItem.LockContentControl = true;
Globals.ThisDocument.wccPurchaseOrderNum.LockContentControl = true;
Globals.ThisDocument.wccPurchaseOrderTotal.LockContentControl = true;
Globals.ThisDocument.wccTotalCharges.LockContentControl = true;
}
At this point I build and run the solution. The result should look something like Figure 6. I'll also mention that my design does not come close to taking advantage of all the VSTO features available to you. For example, you could also extend the ribbon using the ribbon designer or use WPF controls to enhance the visualization of data in the actions pane. (For an example of using WPF with a VSTO action pane, see msdn2.microsoft.com/magazine/cc163292.aspx.)
Figure 6** VSTO Customization in Debug Mode **(Click the image for a larger view)
I'm going to leave the design as is and move on to the more important task of getting this assembly into a shared environment. Ultimately, since the PO scenario involves multiple people, I want to make sure this assembly lives in a shared and secure environment. But first, I'm going to deploy and secure the customization so employees can consume it from within SharePoint.
Deployment and Security
Before you do anything further, right-click your solution and select Clean Solution. This will remove any builds from your development environment. You'll also want to make sure you have created a document library for your VSTO customization—you'll use this later on in the article. To create a document library, simply navigate to your SharePoint site and click Document Center | Hierarchy | Create | Document Library. You'll need to provide some details describing the document library before clicking OK. After you've created your document library, you'll need the URL when deploying and securing the VSTO customization.
Now you need to set up a share. My development environment consists of Windows Server® 2003, MOSS 2007, Visual Studio 2008 with VSTO 3.0, and the 2007 Office system Professional Edition, so I set up the share on my local server (which was called MOSS). You can also select a secure share in your enterprise as the publishing point for this assembly. To do this, you'll need to create a directory for your assembly (for example, C:\CustomerInvoice). Right-click the newly created folder and choose Sharing and Security. Click the Share this folder radio button and give the share a name (for example, CustomerInvoice). Click the Sharing tab and then click the Permissions button. Add Everyone and give them Read permissions, and add Administrators with Full Control permissions. Click the Security tab, and then add Everyone with Read and Execute, List Folder Contents, and Read permissions.
At this point, the share is ready to receive the VSTO customization. (Note that, depending on your security policies, how you delegate permissions against this share may differ from what I've done here.)
The next step is to publish the VSTO assembly files to that particular location. With the VSTO project open in Visual Studio 2008, right-click the project and select Properties. In the Project Properties view, on the Build tab, make sure the output path is set to the share you just created for your project. In my case, this was \\moss\CustomerInvoice. Now click the Publish tab and set the Publishing Folder Location and Installation URL to the share (see Figure 7). Again, for me this is \\moss\CustomerInvoice. Click the Publish Now button. After the VSTO project has successfully published to your share, you can close the project.
Figure 7** Publishing the VSTO Customization **(Click the image for a larger view)
At this point, the project has been published to an installation location, but it is not yet a trusted assembly in Word. However, in order to make it a trusted assembly, you need to add the location of the document (stored at your publishing folder location) to the Word Trust Center.
Open Word and click the Office button (the large round button in the top-left-hand corner of the document). Click the Word Options button at the bottom of the menu and select Trust Center from the pane on the left. Then click the Trust Center Settings button and choose Trusted Locations from the pane on the left (see Figure 8). Check the Allow Trusted Locations on my network checkbox, and click the Add New Location button. In the Add New Location Path dialog, add the publish location for your project assemblies (for example, \\moss\CustomerInvoice) and check the Subfolders of this location are also trusted checkbox.
Figure 8** Adding the Customization to Word Trust Center **(Click the image for a larger view)
You also need to add the SharePoint document library location where your users will be using this VSTO customization (for example, moss.litware.com/Docs/CustomerInvoice). After you've added your publish and SharePoint locations, click OK twice and then exit Word.
You'll also need to configure the trusted sites for your browser. First, open Internet Explorer® and click Tools | Internet Options, then click the Security tab. Select Trusted Sites and click the Sites button. You'll want to add the sites on which your VSTO assembly is running (for example, moss.litware.com in this scenario) and be sure to uncheck Require server verification.
You can now test the Word document by navigating to the publish share (for example, \\moss\CustomerInvoice) and opening your document (in my case, CustomerInvoice.docx). Whatever customizations you've added within your VSTO project should work fine, but at this point you don't want to save anything, so close the document without saving it. The last thing to do is to create a new SharePoint content type and link it to the customized document.
Creating a New Content Type
A content type is a type definition in Windows SharePoint Services (WSS) that lets you define the behavior of an item in a list or a document within a document library. You can create a custom content type that is mapped to a document library that uses the custom template created earlier in this article.
There are essentially three simple steps to mapping a content type to a custom VSTO assembly. The first is to actually create the content type within SharePoint. The second is to associate that content type with the custom VSTO assembly. And the third is to add the new content type to the SharePoint document library.
In order to create a new content type, you have to navigate to the Document Center and click Site Settings | Site Content Type Gallery | New Site Content Type. Doing this invokes the New Site Content Type page (see Figure 9) on which you can set the core properties of the content type. For my content type, I've called it Customer Invoice, provided a description, and then selected Document as the parent content type. I've also selected the Document Content Types for categorizing my content type. After you've done this, click OK. This creates your new content type.
Figure 9** Creating a New Content Type **(Click the image for a larger view)
Now that you've created the content type, you need to associate your custom VSTO assembly (the customized Word document) with the new content type. To do this, in your SharePoint site Document Center click Site Settings | Modify All Site Settings | Site Content Types, then click your newly created content type (in this case, it is Customer Invoice). Now click Advanced Settings. On the Advanced Settings page (see Figure 10), click the Upload a new document template radio button, browse to the publish location where you've stored the custom document, and then click OK.
Figure 10** Customer Invoice Document **(Click the image for a larger view)
The last step is to add the custom content type (with the VSTO custom document associated with it) to your document library so that when users click the New button in your document library, the document that is invoked is the custom document. To do this, navigate to your document library (in my case, the Customer Invoice library) and click Settings. This invokes the Settings page for your document library. Under Content Types, click Add from existing site content types. On the Add Content Types page, select your custom content type (in my case, Customer Invoice) from the Available Site Content Types list (see Figure 11) and click Add.
Figure 11** Add Content Types Page **(Click the image for a larger view)
Finishing Up
While not mandatory, you might also want to complete one last step, and that step is simply setting the custom document content type button as the top-most option when the user clicks New in your document library. The benefit here is that your customization displays as the top option. Obviously, being at the top of the list makes it much easier for users to find your custom document.
To do this, navigate to your document library and click Settings. Under Content Types, click Change new button order and default content type, and then change your custom content type button to 1 and click OK. Again, not a deal breaker, but it does help place the custom document at the top of the available choices when selecting New in your document library.
You can now navigate to your document library. Click New, and your new custom document (in my case, my Customer Invoice) appears ready for use. This document will appear exactly as it did in Figure 6, the major difference being that it is loaded and managed from a central location: the SharePoint site.
You now have a readily accessible document via SharePoint that integrates a centrally managed data store. You also have a document to which you can attach custom workflows to help manage processes around the wider PO process.
As you begin to design other features into your OBA solutions, you can take advantage of not only additional client-side features within VSTO—such as custom ribbons, WPF, and LINQ—but also the server-side features within SharePoint such as Excel Services, the Business Data Catalog, blogs. And there are many other features that ship with MOSS 2007.
If you're interested in finding out more about the topics discussed in this article, you can check out the helpful resources listed in the "Further Reading" sidebar. These resources include a few books and pertinent Microsoft resource centers.
Steve Fox is a Program Manager with the Developer and Platform Evangelist team at Microsoft. He divides his time between working externally with VSTO customers by providing VSTO and OBA training and delivering VSTO and, more generally, Office Platform Development sessions at conferences and working internally with the development team to help evolve the VSTO product.