Throughout this book, I have shown you the integration points between SharePoint and various Microsoft Office products. Generally, I have demonstrated integration points in context when those capabilities were related to the topic at hand. In this chapter, I will cover any additional integration points that have not been presented previously. I will also cover several aspects of custom development with Microsoft Office 2007 including the new open file formats and Visual Studio Tools for Office (VSTO). At the end of this chapter, you should have a strong understanding of all the techniques you can use to leverage Office in your SharePoint solutions.
At this point, you should be well-versed in the basic integration points between Office 2007 and SharePoint. You have seen and worked with both the Document Information Panel (DIP) and the Document Action Panel (DAP) in several places throughout the book. In this section, I cover some additional capabilities that you can use to enhance the integration between Office and SharePoint. I show you how to view related site data with the Document Management Information panel (which is different from the DIP), fill in document metadata values with Quick Parts, and customize the DIP with InfoPath.
The Document Management Information panel is a display present in Office 2003 that has been carried over to Office 2007. In Office 2003, this panel was called the Shared Workspace and presented information about the currently open document and the SharePoint site from which it originated. Although the panel has been renamed, it still presents the information as a series of five tabs named Status, Member, Tasks, Documents, and Links. Figure 9-1 shows a typical Document Management Information panel open in Word 2007.
The Status tab in the Document Management Information panel is used to present document status such as whether it is checked out and by whom. The Members tab lists all the users and groups that have access to the document. Additionally, if the members are running Microsoft Communicator or MSN Messenger, the tab will show presence information. Presence information indicates whether a user is online. Additionally, you can send e-mail and schedule meetings with members using the presence information interface. If a task list exists on the site, the Tasks tab will display the list. The Documents tab shows a list of documents that are in the same library as the currently open document. Finally, if there is a links list on the site, those links will appear in the Links tab.
The Document Management Information panel does not open by default. If you want to see it, you can select Server
Although the Document Management Information panel contains some useful information, you may be confused at first as to why you would see things such as tasks and links. These tabs appear primarily because the Document Management Information panel is actually designed to be used with a specific type of site called a Document Workspace. A Document Workspace is a site that is dedicated to the creation of a single document. You can create a Document Workspace directly from Word, Excel, or PowerPoint and then use it as a way to collaborate.
Follow these steps to create a Document Workspace:
Log in to VSCLIENT.
Select Start
In Word 2007, select Publish
In the Document Workspace creation panel, select My Site from the drop-down list labeled Location for New Workspace.
Click the Create button.
When prompted, save the new document locally on VSCLIENT. You do not have to worry about the exact location because the document will be uploaded automatically to the new Document Workspace.
After the new Document Workspace is created, verify that the Document Management Information panel opens and click the link titled Open Site in Browser.
When the Site opens, verify that your document has been uploaded to the Shared Documents library. You can now invite others to this site to work on the document with you.
Using document workspaces through SharePoint helps end users assign tasks and assemble documents more easily when those documents are primarily built by teams. However, these collaboration features do not help the individual locate the actual information required to create the document. What is missing from the solution is a general tool that can bring back various types of information. This is where the Research Library comes into play. The Research Library is a general-purpose search tool that can search for information in reference books, line-of-business systems, the Internet, and even SharePoint. Out of the box, the Research Library provides access to several sources of information such as a dictionary and thesaurus.
The Research Library is accessible from the ribbon on the Review tab. On the Review tab, you'll find the Research button located in the Proofing group. Using the Research Library is straightforward regardless of the source you want to search. The end user simply selects a service and types a search string into the task pane. The Research Library then searches the selected service for responses to the search string. The responses vary depending upon the service. The Research Library might display definitions, alternative word choices, Internet hyperlinks, or any other kind of appropriate information. In many cases, you can then insert the information directly into your document.
The initial set of services that ship with Office 2003 are only moderately interesting, but the true value of the Research Library lies in the fact that you can extend the library to include SharePoint sites and other services. This is possible because the Research Library architecture is based on web services, and SharePoint web services can be used as a source for the Research Library.
To search a SharePoint Services site, follow these steps:
Open the Research Library in Microsoft Word by clicking the Review tab and then clicking the Research button.
At the bottom of the Research pane, click the Research Options link.
In the Research Options dialog, click the Add Services button.
In the Address box, type the URL http://vsmoss/_vti_bin/search.asmx
.
Click Add.
In the Confirmation and Options dialog, click the Install button.
Close the Research Options dialog.
In the Research pane, select the SharePoint source from under the All Intranet Sites and Portals section of the drop-down list.
Type a search string into the Search For box and click the green arrow.
You have already seen in several examples how the DIP makes it easier for end users to fill in metadata for a document. The DIP presents the metadata fields in the document so that they can be filled in whenever the user knows the values. Additionally, the DIP can support elements such as lists to make it even easier to fill in valid data. While this approach is good, it certainly does not guarantee that good metadata is entered; after all, the end user could just simply type nonsense into the fields.
The solution to getting good metadata out of end users is to automatically populate the metadata from information in the document. This is where Quick Parts come into play. Quick Parts are a way to map the metadata fields in the DIP to text in the document template. In order to utilize Quick Parts, you should start with an existing content type for which you have already defined a template. Then you can enhance the content type with Quick Parts. As an example, you could take the Invoice content type you created in the exercise in Chapter 6 and enhance it to use Quick Parts.
If you completed Exercise 6-1, follow these steps to use Quick Parts:
Log in to VSCLIENT as a SharePoint administrator.
Navigate to the home page of the intranet site you created in Chapter 2.
Click the Document Center tab.
In the Document Center, click the Financial Documents library that you created in Exercise 6.1 in Chapter 6.
In the Financial Documents library, select New
When the new Invoice document opens in Word, select the [Company Name] field in the body of the document and delete it.
Click the Insert tab.
On the Insert tab, select Quick Parts
Click in the Job cell of the table in the Invoice document.
On the Insert tab, select Quick Parts
Select File
Close Word and return to the home page of the intranet site you created in Chapter 2.
Select Site Settings
On the Site Settings page, click the Site Content Types link.
In the Site Content Type Gallery, click the Create link.
On the New Site Content Type page, enter Enhanced Invoice in the Name field.
Select Custom Financial Documents from the drop-down list labeled Select Parent Content Type From.
Select Invoice in the drop-down box labeled Parent Content Type.
Select Custom Financial Documents in the drop-down list labeled Existing Group.
Click the OK button to create the new content type.
In the Site Content Type Gallery, click the link for the new Enhanced Invoice.
On the Site Content Type page, click the Advanced Settings link.
On the Site Content Type Advanced Settings page, select the option to Upload a New Document Template and click the Browse button.
In the Choose File dialog, navigate to the My Documents folder and select the Enhanced Invoice template you saved earlier.
In the Choose File dialog, click the OK button.
On the Site Content Type Advanced Settings page, click the OK button.
Click the Document Center tab.
In the Document Center, click the Financial Documents library in the Quick Launch area.
Select Settings
On the Customize page, click the link titled Add from Existing Content Types.
On the Add Content Types page, select the Enhanced Invoice from the list labeled Available Site Content Types.
Click the OK button to add the content type to the Financial Documents library.
Return to the Financial Documents library and select New
When the new document opens, type a name in the Client Name metadata field in the Document Information Panel. Verify that the name appears in the document after you move the focus away.
Enter some text in the [Title] field in the Job cell of the document and verify that it appears in the Document Information Panel after you move the focus away.
Although SharePoint provides a default DIP for your content types, there may be times when you want to customize the DIP. Customizing the DIP is possible because the DIP is nothing more than an InfoPath form; therefore, you can add validation rules, format, graphics, or other elements to enhance the DIP. You may use any available InfoPath elements and functionality to create your custom DIP, but if you use elements that require full trust, the DIP must be signed just like any other InfoPath form.
Follow these steps to create a custom DIP:
Log in to VSCLIENT as a SharePoint administrator.
Navigate to the home page of the intranet site you created in Chapter 2.
Select Site Settings
On the Site Settings page, click the Site Content Types link.
In the Site Content Type Gallery, click the link for the Financial Document content type.
On the Site Content Type page, click the Document Information Panel Settings link.
On the Document Information Panel Settings page, click the link titled Create a New Custom Template.
When InfoPath starts, click the Finish button in the Data Source wizard.
When the DIP form appears, right-click the Amount field and select Text Box Properties from the context menu.
In the Text Box Properties dialog, click the Data Validation button.
In the Data Validation dialog, click the Add button.
In the Data Validation Condition dialog, select Is Less Than from the operator drop-down list.
Select Type a Number from the Argument list and enter 0.
Enter Value must be a positive number in the Screen Tip field.
Click the OK button.
In the Data Validation dialog, click the OK button.
In the Text Box Properties dialog, click the Format button.
In the Decimal Format dialog, select 2 in the Decimal Places drop-down list.
Click the OK button.
In the Text Box Properties dialog, click the OK button.
Select File
In the Save As dialog, save the form as CustomDIP.xsn to the My Documents folder. The location is not critical because publishing the form will automatically upload it to SharePoint.
After the form is saved, click the Publish Form Template link in the Design Tasks pane.
In the Publishing Wizard, select to publish the form As a Document Information Panel Template for a SharePoint Site Content Type or List Content Type.
Click the Next button.
On the next screen, verify that the correct content type appears, and click the Publish button.
After the form is published, click the Close button and exit InfoPath.
In the browser, click the link titled Go Back to the Document Information Panel Settings Page.
On the Document Information Panel Settings page, click the OK button.
Now you should be able to return to the Financial Documents library, open any existing document, and see the custom DIP in action. Figure 9-2 shows the custom DIP identifying a validation error caused by a negative value and formatting the number to have two decimal places.
Although the SharePoint interface could be used to access all manner of information and documents within an organization, most users still think of Microsoft Outlook as their "home base." Because the information in Outlook is personal in nature, it is the most logical choice to function as the center of a person's day. This means that many end users will want to leverage Outlook as much as possible for consuming information and only leave when it is absolutely necessary.
To this end, Outlook 2007 provides strong integration with SharePoint. In Chapter 3, I describe several of the key integration points between lists and Outlook. In particular, I show that you can synchronize lists with Outlook by selecting Actions
When you take a document library offline, the list of available documents appears inside of Microsoft Outlook and is downloaded to an Outlook PST file named SharePoint Lists.pst
. Outlook will allow you to preview the documents, but they are stored in the PST file as read-only copies. In order to make changes to the documents, they must be opened in the appropriate Office product and then edited offline.
Selecting to edit the document offline will save it into the folder My DocumentsSharePoint Drafts. Office keeps track of the fact that the document is being edited offline and allows you to synchronize it with SharePoint the next time you are online. Although you can check out a document before taking it offline, nothing prevents you from editing a document offline that you did not check out. In these cases, you may have several people making changes to the same document offline, resulting in conflicts that must be resolved during synchronization. Document conflicts such as these are handled by the Office product itself using the Document Updates pane. This pane allows you to merge conflicting changes, open both conflicting documents, and make manual changes, or simply write your changes over the saved changes. Figure 9-3 shows the Document Updates pane.
There is no way to prevent Outlook from downloading all of the documents in a library when you go offline. While this makes it easy to grab a library and run, it also means that you can be downloading a significant amount of information. Documents that are candidates for offline use should be segregated into separate smaller libraries to make downloading efficient.
Support for mobile devices is now built in to SharePoint through a set of pages located in the folder C:Program FilesCommon FilesMicrosoft Sharedweb server extensions12TEMPLATELAYOUTSMOBILE. The pages support a default mobile view for any site in SharePoint by simply navigating to the address of the home page with /_layouts/mobile/default.aspx
appended. For example, you can view the home page of your intranet by navigating to http://vsmoss/intranet/_layouts/mobile/default.aspx
.
While you can certainly view the mobile pages in your desktop browser, it is much more useful to view them as they will actually appear in a device. In order to accomplish this, you can utilize the device emulator that is part of Visual Studio 2005. This emulator simulates several different devices on your desktop so you can target your development. In order to get the emulator working, however, you have to set it up as if you were synchronizing an actual mobile device.
Follow these steps to view your sites in the device emulator:
Log in to VSMOSS as a local administrator.
Download and install the ActiveSync 4.2 software from http://www.microsoft.com/windowsmobile/downloads/activesync42.mspx
. This software is used to connect mobile devices to your desktop.
Select Start
Select Tools
In the Device Emulator Manager dialog, select Pocket PC 2003 SE Emulator.
Select Actions
Select Start
In the Device Emulator Manager dialog, make sure that the Pocket PC 2003 SE Emulator is selected. Select Actions
In the New Partnership wizard, select Guest Partnership and click the Next button.
When the Microsoft ActiveSync dialog indicates that the device is connected, select Start
Enter http://vsmoss/intranet/_layouts/mobile/default.aspx
in the address bar and click the green arrow to open the page. You should now see the mobile version of the intranet home page.
When you first view a site through the emulator, you'll see a page with links to the standard lists and libraries such as Announcements, Tasks, and Shared Documents. If you want to add other lists to the mobile view, you must explicitly designate a list view as mobile. This is accomplished from the Edit View page associated with the view you want to display. The Mobile section contains options that you can select to make the view mobile as well as make it the default mobile view for the list. Figure 9-4 shows the Mobile section on the Edit View page.
In addition to exposing lists for mobile consumption, you can also create your own custom pages for use with mobile devices. When you create your own custom pages, you can tailor them for display on a specific device. Additionally, you can utilize SharePoint object model code in the page. Developing for mobile devices is another broad category that goes beyond the scope of this book, but you can create some simple pages for mobile devices quite easily in Visual Studio.
Follow these steps to create a home page for a mobile device that displays all the sites in a collection:
With Visual Studio 2005 still open from the previous example, select File
In the New Web Site dialog, select ASP.NET Web Site from the list of templates.
Select File System from the Location drop-down list.
Select Visual C# from the Language list.
Click the OK button.
When the new project opens, select the Default.aspx
page in the Solution Explorer and delete it.
Right-click the project in the Solution Explorer and select Add New Item from the context menu.
In the Add New Item dialog, select Mobile Web Form.
Name the new form Home.aspx.
Make sure the box labeled Place Code in a Separate File is not checked. You cannot use code-behind in this solution.
Click the Add button.
When the new page opens, add the bolded code in Listing 9-1 to the page. This code adds references to the SharePoint object model and then uses the object model to get the address for each site in the collection. The address is then displayed in a new instance of a mobile Link
control. I cover the SharePoint object model in detail in Chapter 11.
Example 9.1. A Mobile Home Page
<%@ Page Language="C#" Inherits="System.Web.UI.MobileControls.MobilePage" %> <%@ Assembly Name="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"%> <%@ Import Namespace="Microsoft.SharePoint" %> <%@ Import Namespace="Microsoft.SharePoint.WebControls" %> <%@ Import Namespace="System.Web.UI.MobileControls" %> <%@ Register TagPrefix="mobile" Namespace="System.Web.UI.MobileControls" Assembly="System.Web.Mobile" %> <script language="c#" runat="server"> public void Page_Load() { SPSite site = SPControl.GetContextSite(Context); SPWebCollection webs = site.AllWebs; foreach (SPWeb web in webs) { Link webLink = new Link(); webLink.NavigateUrl = web.Url + "/_layouts/mobile/default.aspx"; webLink.Text = web.Title; welcomeForm.Controls.Add(webLink); } } </script> <html xmlns="http://www.w3.org/1999/xhtml" > <body> <mobile:Form ID="welcomeForm" Runat="server"> <mobile:Image ID="bannerImage" Runat="server" ImageUrl="../images/addtofavorites.gif"> </mobile:Image>List of Sites<br /> </mobile:Form> </body> </html>
Once you have edited the code, save your work.
Open the File Explorer and locate the Home.aspx
page. Copy this page in to the LAYOUTSMOBILE directory.
Using the mobile emulator that you opened earlier, navigate to the address http://vsmoss/intranet/_layouts/mobile/home.aspx
. You should now see a list of available sites with links. Figure 9-5 shows the resulting page displaying various sites.
Microsoft Word, Excel, and PowerPoint have new default XML file formats designed to make Office 2007 more extensible and interoperable. Throughout the book, you have made documents in these new formats, saved them to libraries, and used them for content types. As a user, you might not have even realized that a new file format was in use unless you noticed the new DOCX, XLSX, or PPTX file extensions.
The new file formats are based on the XML Paper Specification written by Microsoft. The idea is to create an open standard for document definitions so that they may be viewed in different tools and transformed between systems. All of this is intended to support interoperability between systems. Saving documents in the older format is still supported as an option, but you must explicitly select it in the Save dialog. As SharePoint developers, we care about these new file formats because they allow us to manipulate documents outside of Word, Excel, and PowerPoint.
In earlier versions of Office, the file format was a proprietary binary format that was completely undocumented. From a development perspective, the only way to manipulate a document was to use the object model through automation. This meant starting Word or Excel programmatically and then executing operations against it, such as creating new documents, importing data, or printing reports.
The problem with automating Word and Excel is that they were never intended to function as server products, but they were often deployed on servers to centralize the automation. Furthermore, the instances started in automation never really seemed to shut down. I have seen many Word and Excel automation applications that left countless copies running on the server. Generally, no one realized this was happening until the server ground to a crawl from lack of resources.
As Office moved forward, Microsoft tried to better this situation by introducing various levels of XML support and new ways to develop with Office applications. While these efforts improved some aspects of development, we were still never able to completely divorce ourselves from Word and Excel. The new XML file formats finally change that situation. Now we can write document-based applications without ever starting a copy of Word or Excel.
The new Office file formats consist of many different XML files all contained in a compressed ZIP file. This compressed ZIP file is called a document package and contains all of the content in a document including text, images, comments, change tracking, properties, and so on. Word, Excel, and PowerPoint all employ this same basic format but utilize different file extensions to designate documents, templates, and macros. Table 9-1 lists all of the file extensions for Word, Excel, and PowerPoint, and the associated document type.
Table 9.1. Office 2007 File Extensions
Extension | Document Type |
---|---|
DOCX | Word 2007 document |
DOTX | Word 2007 template |
DOCM | Word 2007 document containing macros |
DOTM | Word 2007 template containing macros |
XLSX | Excel 2007 document |
XLTX | Excel 2007 template |
XLSM | Excel 2007 document containing macros |
XLTM | Excel 2007 template containing macros |
PPTX | PowerPoint 2007 document |
POTX | PowerPoint 2007 template |
PPTM | PowerPoint 2007 document containing macros |
POTM | PowerPoint 2007 template containing macros |
The simplest way to become familiar with the file formats is to create a new document and then extract the package contents. This is possible because the package is simply a ZIP file. You can use standard ZIP utilities to open the package and view its contents.
Follow these steps to extract package contents:
Log in to VSCLIENT.
Select Start
In Word 2007, select New from the File menu.
In the New Document dialog, select memos from the Templates list.
Select Memo (Contemporary Design) from the Memos list view.
Click the Download button to download the new template from the Microsoft site.
When the new memo appears, click the Insert tab.
On the Insert tab, click the Picture button.
In the Insert Picture dialog, open the Sample Pictures folder.
Select a sample picture from the folder and click the Insert button.
Select Save from the File menu.
Save the document as Memorandum.docx
to the My Documents folder.
Exit Word 2007.
Open the File Explorer and navigate to the My Documents folder.
In the My Documents folder, create a new folder named Package.
Right-click the Memorandum.docx
file and select Rename from the context menu.
Rename the file to Memorandum.docx.zip.
Right-click the Memorandum.docx.zip
file and select Open With
Copy the contents from the open ZIP folder into the Package folder.
Once you have the file extracted, you will see that the package is made up of many files with XML extensions, one file with a JPEG extension, and several files with RELS extensions. Each of the XML files in the package is referred to as a Part Item. Resource files stored in the package, such as images, are referred to as Content Type Items (not to be confused with content types in SharePoint). The files with the RELS extensions are referred to as Relationship Items because they define the relationships between the Part Items and Content Type Items.
You'll also notice in the File Explorer that the package files have a certain folder structure. Initially, this may lead you to believe that the folder structure is specified as part of the package file format. However, this is not the case. The parts and content types are held together by the relationships, which are independent of any particular file folder structure.
Understanding the package structure begins by examining the [Content_Types].xml
file. This file lists all of the parts in the package and their associated content type. If you examine this file, you'll see references to various parts of the document, including the document body, headers, footers, and styles. Listing 9-2 shows some sample entries from the [Content_Types].xml
file.
Example 9.2. The [Content_Type].xml File
<Override PartName="/word/document.xml" ContentType="application/vnd.openxmlformats- officedocument.wordprocessingml.document.main+xml"/> <Override PartName="/word/styles.xml" ContentType= "application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml"/> <Override PartName="/word/settings.xml" ContentType="application/vnd.openxmlformats- officedocument.wordprocessingml.settings+xml"/> <Override PartName="/word/footer2.xml" ContentType="application/vnd.openxmlformats- officedocument.wordprocessingml.footer+xml"/>
The entries in the [Content_Types].xml
file define names for the parts using the PartName
attribute. These entries could be changed to any name and are not related to the package structure. The ContentType
attribute specifies the actual type of information that is found in the part item. The +xml
suffix designates the part item as an XML file.
Because the part items are all XML files, you can open these and examine the contents as well. For example, the document.xml
file contains the bulk of the content for the memorandum document. If you open this document in Visual Studio, you'll see that the XML file has text from the memo and a reference to the picture that you inserted into the body. Any changes made to this file will impact the document as it appears in Word.
Follow these steps to make a document change:
With the Memorandum.docx.zip
file still open in the My Documents window, drag the document.xml
file onto the desktop. Be sure to take this file from the compressed files and not the files you extracted earlier.
Right-click the document.xml
file and select Open With
Select Edit
In the Find dialog, type How to Use This Memo Template and click the Find Next button.
In the Find dialog, click the Cancel button to close it after the search text is located.
Change the selected text to read How to Change the Text in a Document.
Select File
Carefully drag the document.xml
file from your desktop back into the open Memorandum.docx.zip
file.
In the File Explorer, rename the file Memorandum.docx
and open it in Word 2007. You should now see your changes.
The structure of the package is defined by the relationship files. Relationship files are XML files that map content types to specific directories within the structure. This is what allows Word to assemble the document from the part items. Each entry in the file uses a Type
attribute for a content type, and a Target
attribute to reference a file. Listing 9-3 shows a relationship file from the sample in this chapter. Note how it maps the document.xml
file you edited earlier.
Example 9.3. A Relationship File
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"> <Relationship Id="rId3" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships /extended-properties" Target="docProps/app.xml"/> <Relationship Id="rId2" Type="http://schemas.openxmlformats.org/package/2006/relationships /metadata/core-properties" Target="docProps/core.xml"/> <Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships /officeDocument" Target="word/document.xml"/> <Relationship Id="rId4" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships /custom-properties" Target="docProps/custom.xml"/> </Relationships>
While making changes to part items in a package is a neat trick, it's definitely not the way that you want to go about creating production applications with Office 2007. If you did, your application would have to parse countless lines of XML, searching for key elements to replace. That would be maddening to say the least. Fortunately, Microsoft has provided us with an additional layer of abstraction for working with packages in the form of the System.IO.Packaging
namespace.
The Packaging
namespace provides a set of classes that allow you to deal with the constituent parts of a package instead of the raw XML. The Package
class represents the entire package file created by Word, Excel, or PowerPoint. You can use this class to open existing files or create new ones. The PackagePart
class represents all of the part items inside the package file. You can use this class to add or edit part items. The PackageRelationship
class represents all of the relationships in the package file. You can use this class to locate dependent parts.
The System.IO.Packaging
namespace is part of the .NET Framework 3.0. You installed the .NET Framework 3.0 on VSMOSS (or VSWSS) when you created the development environment outlined in Chapter 2. In order to use the Packaging
namespace, you must set a reference to it in Visual Studio 2005. However, the assembly containing the namespace is not easy to find initially. That's because it is located at C:Program FilesReference AssembliesMicrosoftFrameworkv3.0WindowsBase.dll, which is an odd place to put an assembly. Nonetheless, you can browse there and set a reference.
Once you set a reference to the WindowsBase
assembly, you can add some using
statements to your code to make the appropriate namespaces available. You'll want to add not only the System.IO.Packaging
namespace, but also the System.Xml
namespace. Although the Packaging
namespace makes development easier, it does not completely eliminate the need to deal with XML.
If you are going to read a file, the first thing you need to do is open it with the Package
class. The Open
method of the Package
class allows you to open files for reading or writing. Listing 9-4 shows some simple code to open a file passed in as an argument to a console application.
Example 9.4. Opening an Office 2007 File
using System; using System.Collections.Generic; using System.Text; using System.IO; using System.Xml; using System.IO.Packaging; namespace PackageItems { class Program { private const string wordSpace = @"http://schemas.openxmlformats.org/wordprocessingml/2006/main"; static void Main(string[] args) { try { using (Package package = Package.Open (args[0], FileMode.Open, FileAccess.ReadWrite))
{ //Work is done here on the file } } catch (Exception x) { Console.WriteLine(x.Message); } } } }
Once the document is open, the next thing you want to do is locate the part items that you want to manipulate. In this example, I will simply print out all of the lines of text in the open document. In order to print out the text, I need to load the document.xml
part into a stream and then use XPath to return all of the elements named <w:t>
in the file, which is the element Word 2007 uses to mark text. Listing 9-5 shows the code that would be placed inside of Listing 9-4 as designated by the comment in that listing.
Example 9.5. Printing Out Text Elements from a Word File
//Get the document part and load it into XML document Uri uriDocument = new Uri("/word/document.xml", UriKind.Relative); PackagePart documentPart = package.GetPart(uriDocument); Stream partStream = package.GetPart(uriDocument).GetStream( FileMode.Open, FileAccess.ReadWrite); NameTable nameTable = new NameTable(); XmlNamespaceManager manager = new XmlNamespaceManager(nameTable); manager.AddNamespace("w", wordSpace); XmlDocument document = new XmlDocument(nameTable); document.Load(partStream); XmlNodeList textNodes = document.SelectNodes("//w:t", manager); foreach (XmlNode textNode in textNodes) { Console.WriteLine(textNode.InnerText); }
In Listing 9-5 notice that you can locate a part in the package by using the relative URI. You can obtain the URI by examining the relation parts in the package. Once you have a PackagePart
object, you can open the XML file into a Stream
object. Along with the Stream
object, you'll want to create an XmlNamespaceManager
object so that you can load the stream into an XmlDocument
object and use XPath to access the elements. At that point, you simply process the XmlNode
objects.
When you want to process all the nodes of a certain type, you can simply return them all through XPath. If you only want to process a single node, however, then you need some way to identify it in the file. Marking elements in the file can be accomplished by inserting a bookmark near the text of interest, using a field as a placeholder, or by superimposing your own XML schema over the Word document as you could do in Office 2003.
If you want to create a file from scratch, you have to create the part items, the relationships, and the package itself. This process is simple in concept but challenging and tedious in practice. This is because you must first create the part items in accordance with the proper schema for Word, Excel, or PowerPoint. Then you must create relationships for these parts. Finally, you create the package and place the parts and relationships inside.
Listing 9-6 shows a complete example of a console application that creates a Word document with a file name specified by the first argument and containing text specified in the second argument. There is also a complete exercise at the end of this chapter that uses the Open XML file formats to create a SharePoint feature that removes tracked changes and comments from a document.
To get help with schema documentation, visit the XML in Office Developer Portal at http://msdn2.microsoft.com/en-us/office/aa905545.aspx
. Here you will find documentation, blogs, and video presentations about using the Open XML file formats.
Example 9.6. Creating a Word Document Programmatically
using System; using System.Collections.Generic; using System.Text; using System.IO; using System.Xml; using System.IO.Packaging; namespace MakePackage { class Program { private const string wordSpace = @"http://schemas.openxmlformats.org/wordprocessingml/2006/main"; private const string partType = @"application/vnd.openxmlformats- officedocument.wordprocessingml.document.main+xml"; private const string partUri = @"http://schemas.openxmlformats.org/officeDocument/2006/relationships /officeDocument"; private const string partId = "rId1"; static void Main(string[] args) {
try { using (Package package = Package.Open( args[0], FileMode.CreateNew, FileAccess.ReadWrite)) { //Build the document.xml file with text in it XmlDocument documentXml = new XmlDocument(); XmlElement documentElement = documentXml.CreateElement( "w:document", wordSpace); documentXml.AppendChild(documentElement); XmlElement bodyElement = documentXml.CreateElement( "w:body", wordSpace); documentElement.AppendChild(bodyElement); XmlElement pElement = documentXml.CreateElement("w:p", wordSpace); bodyElement.AppendChild(pElement); XmlElement rElement = documentXml.CreateElement("w:r", wordSpace); pElement.AppendChild(rElement); XmlElement tElement = documentXml.CreateElement("w:t", wordSpace); rElement.AppendChild(tElement); XmlNode tNode = documentXml.CreateNode( XmlNodeType.Text, "w:t", wordSpace); tNode.Value = args[1]; tElement.AppendChild(tNode); //Create the part item for document.xml Uri Uri = new Uri("/word/document.xml", UriKind.Relative); PackagePart partDocumentXML = package.CreatePart(Uri,partType); StreamWriter stream = new StreamWriter(partDocumentXML.GetStream( FileMode.Create, FileAccess.Write)); documentXml.Save(stream); stream.Close(); package.Flush(); //Create relationship for document.xml package.CreateRelationship(Uri, TargetMode.Internal, partUri, partId); package.Flush();
package.Close(); } } catch (Exception x) { Console.WriteLine(x.Message); } } } }
Although Office 2007 and SharePoint have many powerful integration points that require little or no effort on your part, if you want complete control over the appearance and functionality of Office 2007 products you should investigate the Visual Studio 2005 Tools for the 2007 Office System. This release of the Visual Studio Tools for Office is sometimes referred to as Second Edition to differentiate it from the first edition that primarily targeted Office 2003. Therefore, you'll often see the acronym VSTO 2005 SE associated with these tools.
VSTO 2005 SE is important because it brings the managed code development model to Office 2007 and lets you create add-ins, custom tabs, and custom task panes using Visual Studio as the development environment. Furthermore, you can deploy these customized documents as templates for content types in SharePoint. This experience stands in contrast to the Visual Basic for Applications (VBA) programming model, which is still available within Office products but does not support the .NET Framework. In this section, I show you how to get up and running with VSTO 2005 SE and give you some ideas of ways to use it with SharePoint.
In order to create VSTO 2005 SE solutions, you must Install Microsoft Office 2007 on the machine where you will be developing. Additionally, you must be sure to install both Visual Basic for Applications (VBA) support and the Microsoft Office Primary Interop Assemblies (PIA). Installing VBA is required to support the development environment, while PIA are the COM assemblies required to integrate managed code with Office. Because your development environment was initially set up with a separate client, you'll need to install Microsoft Office on VSMOSS (or VSWSS) as part of the setup.
Follow these steps to install Microsoft Office 2007 in support of VSTO 2005 SE:
Log in to VSMOSS (or VSWSS) as a local administrator.
Start the installation for Microsoft Office 2007.
When prompted, enter your product key and accept the license agreement as normal.
On the Choose the Installation You Want screen, click the Customize button.
In the Installation Options, select to only install Microsoft Excel, InfoPath, Outlook, PowerPoint, and Word.
For each installed application, expand the options tree and ensure that the .NET Programmability Support option is enabled for installation. Figure 9-6 shows the Installation Options screen with the .NET Programmability option selected for Word.
Expand the Office Shared Features tree and ensure that Visual Basic for Applications is selected to install.
Click the Install Now button.
Once you have Microsoft Office 2007 installed, you can install VSTO 2005 SE. VSTO 2005 SE is available as a download from the Microsoft site. The simplest way to access the download is to visit the Visual Studio Tools for Office Developer Portal located at http://msdn2.microsoft.com/en-us/office/aa905543.aspx
. Once you have the software downloaded, run the installation. The installation process is straightforward and requires no special configuration. Once you have completed the installation, you are ready to create projects.
All VSTO 2005 SE projects, whether they are add-ins, custom tabs, or custom task panes, are started in the same way. Inside of Visual Studio 2005, you select File
When you create a new project in VSTO 2005 SE, you get a new project template that has many of the components you need already stubbed out. The project itself comes with a class module that has several key namespaces referenced and some placeholders for code that should execute when the add-in starts up or shuts down. Additionally, the Add New Item dialog is populated with templates to support add-in development.
Along with the components and stubbed-out code, the new solution also contains a setup project. This setup project is suitable for deploying add-ins directly to client machines. Creating an add-in and making it available to clients using the project templates can be a fairly simple process.
Office 2007 supports the concept of an add-in that lets you add custom functionality to Office applications through the use of buttons that appear on the ribbon. Typically, add-ins are initiated by interacting with buttons on the ribbon that in turn exercise the application object model to achieve some functionality. For example, you could place a button on the Insert tab that adds a standard legal disclaimer to a document when it is pushed. The actual functionality of an add-in is limited only by what you can do with the .NET Framework and the object model of the targeted Office application.
Once you have started a new project in Visual Studio that targets a particular application, you can add buttons to the ribbon by using the Ribbon Support component. The Ribbon Support component is available in the Add New Item dialog. When you add this component, VSTO 2005 SE adds a new class to your project along with an XML file that holds button definitions.
Follow these steps to start a new add-in project:
Select Start
In Visual Studio, select File
In the New Project dialog, select Visual C#
Select Word Add-In from the Visual Studio templates.
Enter HelloAddIn in the Name field and click the OK button.
In the Solution Explorer, right-click the HelloAddIn project and select Add
In the New Item dialog, select the Ribbon Support component.
Name the new component MyAddInsTab.cs and click the Add button.
Loading the Ribbon Support Component
When the Ribbon Support component is added, it comes with some code to automatically add the new elements to the target application's ribbon, but this code is commented out. In order to load your new elements, you simply have to uncomment this code, which overrides the RequestService
method of the add-in. This is the method that is called when the Office application loads your Ribbon Support component. The code in Listing 9-7 shows the uncommented code from the MyAddInsTab.cs
file.
Example 9.7. The RequestService Method
public partial class ThisAddIn { private MyAddInsTab ribbon; protected override object RequestService(Guid serviceGuid) { if (serviceGuid == typeof(Office.IRibbonExtensibility).GUID) { if (ribbon == null) ribbon = new MyAddInsTab(); return ribbon; } return base.RequestService(serviceGuid); } }
Adding Buttons to a Tab
Along with the code file, the Ribbon Support component also provides an XML file that defines what buttons appear in the ribbon. By default, this file comes with a toggle button defined. This type of button has two states: up and down. You could use this type of button to enable and disable parts of your add-in. However, you can also use many other controls such as buttons, check boxes, and lists.
As with all XML editing, it can be difficult to correctly define the elements. Therefore, you'll want to set a schema reference to the CustomUI.xsd
schema, which contains the definitions for the control types. This schema can be found at C:Program FilesMicrosoft Visual Studio 8XmlSchemas1033. In my example, I simply want to add a new button to the existing Insert tab. Therefore, I changed the MyAddInsTab.xml
file to appear as shown in Listing 9-8.
Example 9.8. MyAddInsTab.xml Defining a Single Button
<customUI xmlns=http://schemas.microsoft.com/office/2006/01/customui onLoad="OnLoad"> <ribbon> <tabs> <tab idMso="TabInsert"> <group id="HelloGroup" label="My Add-In"> <button id="helloButton" label="Insert Hello,World!" screentip="Say Hello" onAction="helloButton_Click" supertip="Inserts Hello, World into the document."/> </group> </tab> </tabs> </ribbon> </customUI>
The customUI
element contains the entire definition for the groups and controls that will be added to the ribbon. The onLoad
attribute of this element references a callback method in the associated code file that runs when the controls are loaded. The ribbon
element contains a tabs
element with multiple tab
elements for customizing any tab within the application. Each tab
element contains an idMso
attribute for designating the target tab. This attribute is always the word Tab
plus the name of the tab as it appears in the application. Additionally, you can specify a tab
element with a custom id
attribute and custom label
attribute that will generate a new tab on the ribbon. Listing 9-9 shows how you would modify Listing 9-8 to show the button on a new tab named My Tab.
Example 9.9. Creating a New Tab
<customUI xmlns=http://schemas.microsoft.com/office/2006/01/customui
onLoad="OnLoad">
<ribbon>
<tabs>
<tab id="MyTab" label="My Tab">
<group id="HelloGroup" label="My Add-In">
<button id="helloButton" label="Insert Hello,World!"
screentip="Say Hello" onAction="helloButton_Click"
supertip="Inserts Hello, World into the document."/>
</group>
</tab>
</tabs>
</ribbon>
</customUI>
The group
element is used to create a new group within the targeted tab. Within the group, you can specify box
, button
, buttonGroup
, checkbox
, comboBox
, control
, dialogBoxLauncher
, dropdown
, dynamicMenu
, editBox
, label
, labelControl
, menu
, separator
, splitButton
, or toggleButton
, which all represent different UI elements. These elements support action attributes that let you specify a callback function to receive events for the element.
In my example, I defined a single button with a callback method named helloButton_Click
. Therefore, I will need to define the callback function inside the code file of the Ribbon Support component. In the code file, you will find a region named Ribbon Callbacks. This is the region where the callback functions should be defined. By default, the region already contains a callback for OnLoad
and a callback for the default toggle button that was defined in the template. You can simply delete the toggle button callback and add the code from Listing 9-10 to handle the button callback.
Example 9.10. The Button Callback Function
public void helloButton_Click(Office.IRibbonControl control) { Microsoft.Office.Interop.Word.Range currentRange = Globals.ThisAddIn.Application.Selection.Range; currentRange.Text = "Hello, World!"; }
Notice that the basic approach for the add-in is to access the object model for the target application from the callback function. The root of the object model is obtained through the Globals.ThisAddIn.Application
object. From here, you can go on to manipulate the application as necessary. You're not limited to simply using the object model because now you have the full capability of the .NET Framework to integrate with databases, SharePoint sites, or anything else.
Once you have coded the callback, you should be able to run the add-in directly in Visual Studio. VSTO 2005 SE will start the target application and your add-in will be loaded. When you push the button, text should be added to the document. Figure 9-8 shows the final example.
In addition to customizing the ribbon, you can also add custom task panes to Office 2007. Custom task panes allow you to create a completely custom user interface that can be displayed to the user. Custom task panes are an excellent way to integrate other systems with Office applications. To create a custom task pane, you begin with an add-in project just as you did before.
Custom task panes are designed and built through UserControls. Therefore, once you have a new project started, you must add a UserControl component to the project. On the UserControl, you can add any user interface elements you want from the toolbox. As an example, I created a simple UserControl with a ListBox and a Button. Using these controls, I will load a list of product names and numbers from a database and then use the button to insert them into a Word document. Figure 9-9 shows my UserControl in Visual Studio.
Inside of the UserControl, you can add any code you want. In my example, I simply fill the list with product names and numbers from the AdventureWorks database when the UserControl is loaded. When the Insert button is clicked, I insert the selected product into the current Word document. Listing 9-11 shows the complete code for the UserControl.
Example 9.11. Code for the Custom UserControl
using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Data; using System.Text; using System.Windows.Forms; using System.Data.SqlClient; using Word = Microsoft.Office.Interop.Word; namespace Names { public partial class NamePane : UserControl { public NamePane() { InitializeComponent(); } private void NamePane_Load(object sender, EventArgs e) { try { string connString = "Data Source=win2k3template; Initial Catalog=Adventureworks;Integrated Security=SSPI;"; string sqlString = "Select Name + ', ' + ProductNumber as FullProduct FROM Production.Product ORDER BY Name"; using (SqlConnection connection = new SqlConnection(connString)) { connection.Open(); SqlCommand command = new SqlCommand(); command.CommandText = sqlString; command.CommandType = CommandType.Text; command.Connection = connection; SqlDataReader reader = command.ExecuteReader();
if (reader.HasRows) { while (reader.Read()) { namesList.Items.Add(reader.GetString(0)); } } connection.Close(); } } catch (Exception x) { MessageBox.Show(x.Message); } } private void insertButton_Click(object sender, EventArgs e) { Word.Range currentRange = Globals.ThisAddIn.Application.Selection.Range; currentRange.Text = namesList.SelectedItem.ToString(); } } }
Once the UserControl is designed and coded, all you need to do is create a task pane from the UserControl at run time and display it. This is done in the startup event of the add-in. In this event, you must create a CustomTaskPane
object and add your UserControl. Once this is done, you can run the add-in from Visual Studio. Listing 9-12 shows the code for loading the task pane, and Figure 9-10 shows a picture of the solution in action.
Example 9.12. Loading the New Task Pane
using System; using System.Windows.Forms; using Microsoft.VisualStudio.Tools.Applications.Runtime; using Word = Microsoft.Office.Interop.Word; using Office = Microsoft.Office.Core; namespace Names { public partial class ThisAddIn { private NamePane namePane;
private void ThisAddIn_Startup(object sender, System.EventArgs e) { namePane = new NamePane(); Microsoft.Office.Tools.CustomTaskPane newTaskPane = this.CustomTaskPanes.Add(namePane, "Names"); newTaskPane.Visible = true; } private void ThisAddIn_Shutdown(object sender, System.EventArgs e) { } } }
As I noted earlier, every VSTO 2005 SE solution template includes a setup project. This project can be used to deploy the solution directly to a client desktop. Additionally, you could deploy the solution from SharePoint library. In either case, there are several prerequisites that must be met on the client machine before the solution will run.
Follow these steps to prepare a client machine for VSTO solutions:
Log in to VSCLIENT as an administrator.
Download and install the .NET Framework 2.0 from http://www.microsoft.com/downloads/details.aspx?FamilyID=0856eacb-4362-4b0d-8edd-aab15c5e04f5&displaylang=en
.
Ensure that you have installed the Primary Interop Assemblies and Visual Basic for Applications Support from the Office 2007 setup. If you did a complete install, these components should already be present.
Download and install the VSTO 2005 SE runtime from http://go.microsoft.com/fwlink/?linkid=49612
.
Once you have the prerequisites on the client, you are ready to deploy the VSTO 2005 SE solution. If you are using the setup program created by the project, you can simply run the setup. If, however, you are deploying from SharePoint, the document and the assembly are going to be separated. The document will go into a document library or become the template for a content type while the associated assembly must be stored on a network location accessible through a UNC name. For example, you could create and share a directory on VSMOSS named Assemblies. In either case, the assemblies associated with the solution must be strongly named and you must explicitly trust them using the .NET Framework 2.0 Configuration utility.
Follow these steps to trust the solution assemblies:
On VSCLIENT, select Start
In the .NET Framework 2.0 Configuration dialog, expand the tree down the path Console Root
Right-click the All_Code group and select New from the context menu.
Enter VSTO Assemblies in the Name field and click the Next button.
On the Choose a Condition Type screen, select URL from the drop-down list.
Enter the complete path to the location where you will deploy the assemblies (e.g., (\VSMOSSAssemblies).
Click the Next button.
On the Assign a Permission Set to the Code Group screen, select Full Trust from the drop-down list labeled Use Existing Permission Set.
Click the Next button.
Click the Finish button to complete the wizard.
In the .NET Framework 2.0 Configuration dialog, right-click the new VSTO Assemblies code group and select Properties from the context menu.
In the Properties dialog, check the box labeled Policy Levels Below This Level Will Not Be Evaluated. This ensures that the policy cannot be modified by any other policy.
Click the OK button.
Once you have trusted the assemblies, any project you install directly on the client computer using the setup project should run without trouble. However, if you intend to deploy the document into SharePoint, you must additionally trust the server location where the document will be stored. Trusting the documents is accomplished by creating another policy that is defined in the file MSOSEC.XML
and contained in the assembly MSOSEC.DLL
.
Follow these steps to trust a document location:
On VSCLIENT, open the File Explorer and navigate to C:Program FilesMicrosoft OfficeOFFICE12ADDINS.
Drag the assembly MSOSEC.DLL
from this directory and drop it in C:Windowsassembly to install it in the Global Assembly Cache.
Select Start
In the .NET Framework 2.0 Configuration dialog, expand the tree down the path Console Root
Right-click the All_Code group and select New from the context menu.
Enter VSTO Documents in the Name field and click the Next button.
On the Choose a Condition Type screen, select (custom) from the drop-down list.
Click the Import button.
In the Import Custom Membership from XML dialog, navigate to the C:Program FilesMicrosoft OfficeOFFICE12ADDINS directory.
Select the file MSOSEC.XML
and click the Open button.
Click the Next button.
On the Assign a Permission Set to the Code Group screen, select Full Trust from the drop-down list labeled Use Existing Permission Set.
Click the Next button.
Click the Finish button to complete the wizard.
In the .NET Framework 2.0 Configuration dialog, right-click the new VSTO Documents code group and select Properties from the context menu.
In the Properties dialog, check the box labeled Policy Levels Below This Level Will Not Be Evaluated. This ensures that the policy cannot be modified by any other policy.
Click the OK button.
Once the assembly location is trusted and the documents are trusted, the last thing you have to do is modify the document so that it knows where the assembly is located. The document template created with a VSTO 2005 SE solution contains a deployment manifest that tells it where to find its associated assembly. Normally, the document simply looks in the same directory, but in the case of a SharePoint deployment, that is not possible. Fortunately, we can write a simple command-line application that modifies the deployment manifest. Listing 9-13 shows a complete command-line application that takes the document file name as the first argument and the assembly location as the second and updates the deployment manifest. Once that is done, you should be able to run the solution from a SharePoint library.
Example 9.13. Editing the Deployment Manifest
using System; using System.Collections.Generic; using System.Text; using Microsoft.VisualStudio.Tools.Applications.Runtime; namespace DeploymentManifestEditor { class Program { static void Main(string[] args) { ServerDocument document = null; document = new ServerDocument(args[0]); document.AppManifest.DeployManifestPath = args[1]; document.Save(); document.Close(); } } }
The Office Open XML file formats allow you to create and edit Word, Excel, and PowerPoint documents programmatically. This is an ideal approach for working with documents in SharePoint solutions because you can process documents on the server while using SharePoint libraries as a storage mechanism. In this exercise, you will create a feature for SharePoint that uses the Open XML file formats to purge Word documents of review comments and tracked changes. This kind of functionality is perfect for preparing a document for delivery to a customer.
This exercise is for learning purposes only. The code has not been tested in a wide variety of situations and is not intended to be production-ready. Incorrectly manipulating Office documents can render them unreadable.
This exercise will combine what you have learned about SharePoint features and the Office Open XML file formats. The feature will consist of an assembly designed to purge Word documents that is triggered through a new item on the document drop-down menu in SharePoint. To begin the exercise, you'll need to create a new project in Visual Studio.
Follow these steps to start the new project:
Log in to VSMOSS as a SharePoint administrator.
Select Start
When Visual Studio starts, select File
In the New Project dialog, select Visual C# from the Project Types list.
Select Class Library from the Visual Studio Templates list.
Name the new project WordCleaner and click the OK button.
Right-click Class1.cs
in the Solution Explorer and select Rename from the context menu.
Rename the file Worker.cs and hit the Enter key.
Select Project
In the Add Reference dialog, click the Browse tab.
In the Browse tab, navigate to C:Program FilesReference AssembliesMicrosoftFrameworkv3.0.
Select the WindowsBase.dll
assembly and click the OK button.
In the Worker.cs
code window, add references to System.Xml
, System.IO
, and System.IO.Packaging
. Listing 9-14 shows how your code should appear at this point.
After starting the project, the first thing to do is to create the assembly that will purge the Word documents. This is the part of the project that uses the Open XML file formats. This assembly will open the document to be purged, accept all of the changes made, and delete any comments. This will all be accomplished by manipulating the document part items and XML.
You'll start by creating a Sanitize
and LogMessage
method. The Sanitize
method contains the main functionality, and you will code this over the next few sections. The LogMessage
method is used to record errors in the event log. The code in Listing 9-15 shows the Sanitize
method and the LogMessage
method. Add the bolded code to your project as shown.
Example 9.15. The Sanitize and LogMessage Methods
namespace WordCleaner
{
public class Worker
{
//Namespace and URI constants
private const string wordSpace =
@"http://schemas.openxmlformats.org/wordprocessingml/2006/main";
private const string docUri = @"/word/document.xml";
public void Sanitize(string packagePath)
{
//Code here
}
static void LogMessage(string message, EventLogEntryType entry)
{
if (!EventLog.SourceExists("Word Cleaner"))
EventLog.CreateEventSource("Word Cleaner", "Application");
EventLog.WriteEntry("Word Cleaner", message, entry);
}
}
}
Opening the Package
The Sanitize
method begins by opening the Word document file represented by the packagePath
argument passed in to the method. Once the package is opened, the document part is loaded into a stream for editing. The document part represents the main body of the Word document and is stored in the package in the file document.xml
. In order to purge the document of comments and changes, you must load the document.xml
file into a stream and manipulate the XML. Add the code from Listing 9-16 to the Sanitize
method to open the package and load the document part into a stream.
Example 9.16. Loading the Document Part into a Stream
try { //Open the package using (Package package = Package.Open( packagePath, FileMode.Open, FileAccess.ReadWrite)) { //Get the document part Uri uriDocument = new Uri(docUri, UriKind.Relative); PackagePart documentPart = package.GetPart(uriDocument); //Load the document part into a stream Stream partStream = documentPart.GetStream( FileMode.Open, FileAccess.ReadWrite); //Add the namespace manager to reference the Word namespace NameTable nameTable = new NameTable(); XmlNamespaceManager manager = new XmlNamespaceManager(nameTable); manager.AddNamespace("w", wordSpace); //Create a temporary XML document from the stream //so we can manipulate the XML elements XmlDocument tempDoc = new XmlDocument(nameTable); tempDoc.Load(partStream); //More code will go here } } catch (Exception x) { LogMessage(x.Message, EventLogEntryType.Error); }
Removing Changes and Comments
Once the document part is loaded into a stream, you may use standard XML methods to manipulate the contents. In this exercise, you will remove all changed document text that is marked as deleted and all comments made during review. Additionally, you must promote inserted text changes so that they appear as accepted changes in the document. The whole process involves returning key nodes from the document part and deleting or modifying them.
Document text marked for deletion during a review is tracked in the document part with the element <w:del>
. Inserted text is tracked with the element <w:ins>
. Comments are tracked with three different elements: <w:commentRangeStart>
, <w:commentRangeEnd>
, and <w:commentReference>
. Add the code from Listing 9-17 to the Sanitize
method to manipulate the document elements.
Example 9.17. Modifying the Document Part
//Remove deleted text from temporary XML document XmlNodeList delNodes = tempDoc.SelectNodes("//w:del", manager); foreach (XmlNode delNode in delNodes) { delNode.ParentNode.RemoveChild(delNode); } //Promote the inserted text in temporary XMl document //so it appears normally in the Word document XmlNodeList insNodes = tempDoc.SelectNodes("//w:ins", manager); foreach (XmlNode insNode in insNodes) { foreach (XmlNode childNode in insNode.ChildNodes) { insNode.ParentNode.InsertBefore(childNode, insNode); } insNode.ParentNode.RemoveChild(insNode); } //Remove comments text from temporary XML document //Must remove several different elements to accomplish this XmlNodeList commentStartNodes = tempDoc.SelectNodes( "//w:commentRangeStart", manager); foreach (XmlNode commentStartNode in commentStartNodes) { commentStartNode.ParentNode.RemoveChild(commentStartNode); } XmlNodeList commentEndNodes = tempDoc.SelectNodes( "//w:commentRangeEnd", manager); foreach (XmlNode commentEndNode in commentEndNodes) { commentEndNode.ParentNode.RemoveChild(commentEndNode); } XmlNodeList commentRefNodes = tempDoc.SelectNodes( "//w:commentReference", manager); foreach (XmlNode commentRefNode in commentRefNodes) { commentRefNode.ParentNode.RemoveChild(commentRefNode); } //Save the temporary XMl document changes back to the document part documentPart.GetStream().SetLength(0); tempDoc.Save(documentPart.GetStream()); //More code will follow
Deleting the Comments Part
To finish processing the file, you must remove the comment text from the package. The comment text is saved in the comments.xml
file in the package. You must remove the comments.xml
file from the package and delete the relationship between the document part and the comments part. Add the code from Listing 9-18 to remove the comment text from the package.
Example 9.18. Removing Comments and Relationships
//delete the relationship with the comments part Uri uriComments = new Uri("/word/comments.xml", UriKind.Relative); PackagePart commentsPart = package.GetPart(uriComments); PackageRelationshipCollection relationships = documentPart.GetRelationships(); foreach (PackageRelationship relationship in relationships) { if (relationship.TargetUri.ToString() == "comments.xml") { documentPart.DeleteRelationship(relationship.Id); break; } } //Delete comments part from package package.DeletePart(uriComments); //Save the package changes package.Flush(); package.Close();
Compiling the Assembly
Once the code is completed for the Worker
class, it can be compiled. In this exercise, you will deploy the assembly to the Global Assembly Cache (GAC), so it must be digitally signed. Once signed, it can be built.
Follow these steps to build the assembly:
In the Solution Explorer, right-click the WordCleaner project and select Properties from the context menu.
In the Properties dialog, click the Signing tab.
On the Signing tab, check the box labeled Sign the Assembly.
Select <New...> from the drop-down list labeled Choose a Strong Name Key File.
In the Create Strong Name Key dialog, uncheck the box labeled Protect My Key File with a Password.
Enter WordCleanerKey in the Key File Name field.
Click the OK button.
Make sure that the configuration drop-down is set to release and select Build
Although the basic purge functionality is contained in the assembly, we still need to create a mechanism for invoking the assembly. In this exercise, you'll invoke the assembly through an ASPX page that will be called from a new menu item in a document library. We could also have chosen to invoke the assembly as part of a workflow or in response to a list event. The point is that there are many options in SharePoint for implementing such functionality.
Follow these steps to create the ASPX page:
In the Solution Explorer, right-click the WordCleaner project and select Add
In the Add New Item dialog, select Text File.
Name the Text File Worker.aspx and click the Add button. You are adding the ASPX page in this manner because we are not creating a web application and will simply deploy the file to the TEMPLATES directory later.
Add the code from Listing 9-19 to create the page. Notice that the page references both the Microsoft.SharePoint
and the WordCleaner
assemblies.
Example 9.19. The Worker.aspx Page
<%@ Page Language="C#" Debug="true" %> <%@ Assembly Name="WordCleaner, Version=1.0.0.0, Culture=neutral, PublicKeyToken=0e47d66474f01e8d" %> <%@ Assembly Name="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"%> <%@ Import Namespace="WordCleaner" %> <%@ Import Namespace="System.IO" %> <%@ Import Namespace="Microsoft.SharePoint" %> <%@ Import Namespace="Microsoft.SharePoint.WebControls" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"> <head id="Head1" runat="server"> <title>Word Cleaner Worker Page</title> </head> <body> <form id="form1" runat="server"> <div> <% try { //Code will go here } catch (Exception x) { Response.Write(x.Message + " "); } %> </div> </form> </body> </html>
In order for the assembly to access a Word document, the document must be downloaded from SharePoint and manipulated locally. Once the changes are made, the document needs to be uploaded back to the document library. The Worker.aspx
page performs the download of the file onto the server, invokes the cleaning assembly, and then uploads the file. After the page completes, it redirects back to the document library page. In this way, the user experiences a postback and then has a purged document in the library. Add the code from Listing 9-20 to the Worker.aspx
page to download, purge, and upload the document.
Example 9.20. Downloading, Purging, and Uploading the Document
//Get top-level site SPSite site = SPControl.GetContextSite(Context); //Build the destination path string source = "http://" + site.HostName + Request.QueryString["Item"]; string cache = System.Environment.GetFolderPath(Environment.SpecialFolder.InternetCache); string downPath = cache + "\" + source.Substring(source.LastIndexOf("/") + 1); string extension = source.Substring(source.LastIndexOf(".") + 1);
//Make sure it is a DOCX file if(extension.ToUpper()!="DOCX") throw new Exception("Only DOCX files can be cleaned."); //Download file System.Net.WebClient client = new System.Net.WebClient(); client.Credentials = System.Net.CredentialCache.DefaultCredentials; client.DownloadFile(source, downPath); //Sanitize Document WordCleaner.Worker worker = new WordCleaner.Worker(); worker.Sanitize(downPath); //Upload File FileStream stream = new FileStream(downPath, FileMode.Open, FileAccess.Read); BinaryReader reader = new BinaryReader(stream); byte[] bytes = reader.ReadBytes((int)stream.Length); reader.Close(); stream.Close(); client.UploadData(source, "PUT", bytes); //Redirect back to library Response.Redirect(source.Substring(0,source.LastIndexOf("/")) + "/Forms/AllItems.aspx");
As I stated earlier, the Worker.aspx
page will be invoked from a new item on the document's drop-down menu. In order to create this new item, you'll have to create a Feature.xml
file to represent the new feature. The Feature.xml
file is straightforward and created in a manner that should be familiar to you by now.
Follow these steps to create a Feature.xml
file:
In the Solution Explorer, right-click the WordCleaner project and select Add
In the Add New Item dialog, select XML File.
Name the XML file Feature.xml and click the Add button.
Add the code from Listing 9-21 to create the Feature.xml
file.
Example 9.21. The Feature.xml File
<?xml version="1.0" encoding="utf-8" ?> <Feature Title="Word Document Cleaner" Description="Accepts changes and removes comments from Word 2007 files." Scope="Site"
Id="C67EBE69-0372-425f-A939-23F8A74418AF" xmlns="http://schemas.microsoft.com/sharepoint/"> <ElementManifests> <ElementManifest Location="Elements.xml" /> </ElementManifests> </Feature>
The Elements.xml
file is the manifest file for the new feature. This file is used to define the new menu item and link it to the Worker.aspx
page. In this section, you will create the manifest file and code it to add a new item to the document's drop-down menu.
Follow these steps to create the Elements.xml
file:
In the Solution Explorer, right-click the WordCleaner project and select Add
In the Add New Item dialog, select XML File.
Name the XML file Elements.xml and click the Add button.
Add the code from Listing 9-22 to create the Elements.xml
file.
Example 9.22. The Elements.xml File
<?xml version="1.0" encoding="utf-8" ?> <Elements xmlns="http://schemas.microsoft.com/sharepoint/"> <CustomAction Id="UserInterfaceLightUp.ECBItemToolbar" RegistrationType="List" RegistrationId="101" Location="EditControlBlock" Sequence="106" Title="Cleanse Document" ImageUrl="/_layouts/images/AddToFavorites.gif"> <UrlAction Url="/_layouts/Worker.aspx?Item={ItemUrl}" /> </CustomAction> </Elements>
In order to install the new feature, you must create a folder in the TEMPLATES directory and copy the Feature.xml
and Elements.xml
files to this location. Additionally, you must copy the Worker.aspx
file to the LAYOUTS directory. Finally, you must install the assembly in the GAC. You could certainly do all this by hand, but you'll create a batch file to automate the process instead.
Follow these steps to create the batch file:
In the Solution Explorer, right-click the WordCleaner project and select Add
In the Add New Item dialog, select Text File.
Name the text file Install.bat and click the Add button.
Add the code from Listing 9-23 to create the Install.bat
file. When you are done, run the batch file to install the feature.
Example 9.23. The Install.bat File
@SET FEATUREDIR="c:program filescommon filesmicrosoft shared web server extensions12TemplateFeatures" @SET LAYOUTDIR="c:program filescommon filesmicrosoft shared\ web server extensions12TemplateLayouts" @SET STSADM="c:program filescommon filesmicrosoft shared\ web server extensions12instsadm.exe" @SET GACUTIL="C:Program FilesMicrosoft Visual Studio 8\ SDKv2.0BinGacUtil.exe" md %FEATUREDIR%WordCleaner xcopy /e /y Feature.xml %FEATUREDIR%WordCleaner xcopy /e /y Elements.xml %FEATUREDIR%WordCleaner xcopy /e /y Worker.aspx %LAYOUTDIR% %GACUTIL% -if bin eleaseWordCleaner.dll %STSADM% -o installfeature -filename WordCleanerfeature.xml -force IISRESET ECHO Finished PAUSE
Once the feature is installed, you may activate it. This feature is defined at the site collection level, so you will go to the Site Settings page for the site collection to activate it. Once activated, the new menu item should show up for all documents in the site collection.
Follow these steps to activate the feature:
Open the home page of the intranet site you created in Chapter 2.
Select Site Settings
On the Site Settings page, click the link titled Site Collection Features under the Site Collection Administration section.
On the Site Collection Features page, click the Activate button associated with the Word Document Cleaner feature.
Once the feature is activated, navigate to any document library containing Word documents. If you drop the menu associated with a document, you should see the new Cleanse Document item. Before you select it, however, open the document in Word, turn on Track Changes, and add some comments. Then save the document and try purging it.