Export (0) Print
Expand All

Attaching Files from a Custom SharePoint Web View to an Outlook Message

Office 2010

Summary:  This article shows how to create a custom Microsoft SharePoint web view and extend it to allow attaching versioned documents from a SharePoint site to a Microsoft Outlook message.

Microsoft SharePoint 2010 provide great document management features, Web UI and search facilities. Users can access these features through an Microsoft Office 2010 client, such as Microsoft Excel 2010, Microsoft Outlook 2010 or Microsoft Word 2010, and enjoy a number of options to enhance the experience. Organizations may want to extend the default navigation experience provided for these client applications, perhaps to display information in a manner that is more relevant to the way that organization works.

In some cases, organizations may want to customize how the client application interacts with SharePoint 2010 content. The customization occurs on the application on the client computer. In this case, the challenge is to make the experience as consistent as possible with the default behavior.

This document describes a technique to enhance the default navigation experience in client applications that accesses SharePoint 2010 content using a web view. It then looks at creating a custom Outlook add-in that also utilizes the web view to provide an improved ability to attach documents to emails, directly from SharePoint 2010. For this reason, the content is split up into two broad areas:

  • Instructions on creating a custom web view to provide an enhanced navigation experience in client applications. This customization applies to only the server side in a SharePoint 2010 installation and offers a consistent customized experience to multiple client applications.

  • An explanation of using Office development tools in Visual Studio 2010 to create an Outlook add-in to extend a custom web view in attaching documents to email messages. The add-in and modifications to the web view allow functionality beyond just navigation changes. The functionality includes multi-selection of documents, selection of previous versions, and renaming of files before they are attached (to include document ID and version information in the name).

In an Office client application, a user can open or save a document that is on SharePoint 2010 through a Common File Dialog (CFD). This dialog box allows the user to type a URL to a SharePoint 2010 site and is used in many applications including Excel, Outlook and Word. If this dialog box is pointed to a SharePoint 2010 location, it displays an HTML view of the SharePoint 2010 content that is called a web view. In the following screen shot, a user has clicked Save in Word 2010, and the CFD is displayed.

Figure 1. The Common File Dialog box showing a web view of a SharePoint site

Web View of a SharePoint site

The area with the dark border is a web view of the SharePoint 2010 site. In Figure 1, the web view displays a child document library. Because applications share the same web view into the same SharePoint 2010 site, the web view helps to keep the user experience consistent, and we only need to implement a change one time.

To create our own web view, we need to intercept a request from a client application, identify the SharePoint 2010 location the request is looking at, and what action the request is trying to perform. For example, when we evaluate the request, consider the following:

  • Is it requesting an open or save action in the client application?

  • What file types does the request want to see; for example, Word or Excel files? Or some other file type?

  • Does it want to see contents for an entire SharePoint 2010 site, or for a specific document library in the SharePoint 2010 site?

    After we have examined the request, we respond by using HTML in a way that the CFD understands.

The custom processor

When the CFD requests data from SharePoint 2010, it does so by constructing a URL that posts to owssvr.dll, which is a server-side DLL responsible for handling remote procedure calls in the Microsoft SharePoint Foundation 2010. The specific command that is used is called dialogview, and you can find more information about dialogview in URL Protocol. The construction of this URL contains the information about which site or document library to get information from, which document types to filter on, and whether the client application was requesting information for an open or save action.

Figure 2 is an example that shows the relationship between a client application and a request that is made to SharePoint 2010. On the client side, the CFD is responsible for constructing URLs in a format that is used to post to owssvr.dll. The CFD is also responsible for notifying which folder or document the user selected in the web view. Examples of where the CFD is used include the following commands: Open, Save, Attach File (in Outlook), and Compare (in Word).

It is possible to intercept the request and to respond with custom HTML on the server by using a custom markup for the FileDialogPostProcessor element, which we’ll refer as a custom processor in the rest of this article. In the following scenario, a request comes into the owssvr.dll and then is passed on to a custom processor. The owssvr.dll provides all the location and filter information to the processor. In response, the processor provides custom HTML, which is ultimately rendered in the CFD. In the example in Figure 2, the processor decides the files and folders to display by using the SharePoint API, and then formats this information by using an XSLT style sheet into the response HTML.

Figure 2. The relationships between a client application, its request to display a web view, and SharePoint processing the request to display the appropriate HTML

Client application and the request to SharePoint

Creating a new processor

To create a custom processor, open Visual Studio 2010 and create a new C# Windows Class Library project. Add the following references:

  • System.Web

  • Microsoft.SharePoint

  • Microsoft.SharePoint.Security

  • Make sure that the project our class is in is COM-visible by setting the following property in the AssembyInfo.CS of the project: [assembly: ComVisible(true)]

Create a custom class in the same manner as shown in the following code. The Guid attribute is used later to associate the custom processor with a SharePoint 2010 site, and needs to be unique to each custom processor. The IFileDialogPostProcessor2 interface is the one used in SharePoint 2010.

[Guid("33B06720-F08A-4070-8A47-760BBB7234F6")]
public class CustomFileDialogPostProcessor : MarshalByRefObject, IFileDialogPostProcessor2, IFileDialogPostProcessor

The next step is to put our implementation code into the correct interface member. The method signature resembles the following code.

public void Process(Guid siteId, Guid webId, Guid listId, WffRequestType type, string location, string url, bool largeListThrottled, int lcid, string userAgent, Hashtable webProperties, string defaultPresentation, ref string alternatePresentation)

This method is the one that SharePoint 2010 calls into when it receives a request from a client application. The parameters contain useful information about what the user is trying to do. The most important parameters relevant to creating a custom web view are described in the following table.

Name

Description

Example usage

siteId

The ID of the site collection that the request is pointing at.

using (SPSite site = new SPSite(siteId))

webId

The ID of the web site in the site collection that the request is trying to get to.

using (SPWeb web = site.OpenWeb(webId))

listId

The ID of the document library that the request is attempting to access. Note if this is an empty GUID, then the request is just pointing at the web site itself.

SPDocumentLibrary library = web.Lists[listId] as SPDocumentLibrary

type

The action associated with the request, for example, open or save.

type == WffRequestType.Save

location

Information about the requests destination path. This is useful if the user has selected a subfolder in a document library.

SPFolder folder =

url

The full URL of the request which contains useful query string information.

NameValueCollection queryString =

HttpUtility.ParseQueryString (url.Substring(url.IndexOf("?", StringComparison.OrdinalIgnoreCase)))

The first 5 parameters discussed contain all the information we need to open the correct location in SharePoint 2010, and the query string data in the last parameter, url, contains information about how the view should be filtered. When client applications request data, they include the file types that they support. In the case of Word, this would be docx, doc, dotx, and so on. If results are not filtered based on this key piece of information, the web view can display files that the requesting application is not compatible with. Access the url value as shown below:

queryString["filedialogfiltervalue"]

For example, a request from Word that uses the open WffRequestType gives the following values: *.docx;*.docm;*.dotx;*.dotm;*.doc;*.dot;*.htm;*.html;*.rtf;*.mht;*.mhtml;*.xml;*.odt

Changing the custom processor HTML

An update to the parameter, alternatePresentation, allows the response HTML to be changed. If this value is set to be something different during execution, the CFD displays this instead of the default HTML view. The HTML needs to follow a few simple rules for the CFD to function correctly. The CFD reacts to clicks on table rows. The table that contains these rows has to have an ID of FileDialogViewTable. Thus, the custom response HTML must contain the following table element:

<table class="ms-listviewtable KeyTable" id="FileDialogViewTable" width="100%" border="0" rules="rows" cellspacing="0" cellpadding="1">

Each row in this table is denoted by a TR element. There are two types of rows that can appear in this table. The first type of row denotes a folder or site and has an attribute called fileattribute set to the value folder. When a user selects this type of row, the CFD will attempt to navigate to that location. To tell the CFD which URL it needs to navigate to, set the id attribute of a TR element to that URL. The following snippet shows a folder row that points to a document library called Documents at the root of the server.

<tr fileattribute="folder" id=http://sdg-wks1258/Documents class="ms-itmhover">

The second type of row is for representing files. Similar to the folder row, it uses the id attribute to store the path to the file. However, its fileattribute property is set to file. When users select these rows, the CFD tells the client application to open the document, or save the document over an existing one.

<tr fileattribute="file" id=http://sdg-wks1258/my/personal/benrosc/Personal Documents/Migration Powershell Commands.docx class="ms-itmhover">

A useful technique for generating the HTML for a custom web view is to use the SharePoint API to construct an XML representation of the files and folders that are to be included in the resultant FileDialogViewTable table. Then apply an XSLT style sheet to the XML to generate the response HTML. For instance, suppose the following is the source XML representing the content on a SharePoint 2010 site.

<PageData>
<ListContent>
    <ContentItem>
    <FileUrl>http://sdg-wks1258/my/personal/benrosc/Personal Documents</FileUrl> 
    <FileAttribute>Folder</FileAttribute> 
    <Property Name="Name" Value="Personal Documents" /> 
    <Property Name="Editor" Value="" /> 
    <Property Name="Last_x0020_Modified" Value="" /> 
    <Property Name="ParentFolderName" Value="" /> 
    <Property Name="DocIcon" Value="itdl.png" /> 
    <Property Name="ows__dlc_DocId" Value="" /> 
    <Property Name="ows__UIVersionString" Value="" /> 
    </ContentItem>
</ListContent>
</PageData>

Then in the XSLT, it is possible to render out the content of the FileDialogViewTable table, by applying a template to each content item that represents a row for a file or folder for display.

<table class="ms-listviewtable" id="FileDialogViewTable" width="100%" border="0" rules="rows" cellspacing="0" cellpadding="1">
<xsl:apply-templates select="ListContent/ContentItem"/>

After generating the custom XML data, apply the style sheet and then set the alternatePresentation out parameter to the generated HTML.

alternatePresentation = GetTransformedData(content, xsltPath, args);

Installing the custom processor

For every web front-end in the SharePoint farm, perform the following two actions:

  • Register the SharePoint component in the registry and the global assembly cache:

    gacutil.exe /i SharePoint.CustomWebView.dll

  • Run regasm for the component:

    regasm.exe /codebase SharePoint.CustomWebView.dll

After this, set the SharePoint 2010 site to use the newly registered custom processor, by using the FileDialogPostProcessor property on a site’s SPWeb object. The following PowerShell snippet shows an example of this. Note the FileDialogPostProcessorId value is the same as the Guid attribute added on the custom processor created above in the section Creating a new FileDialogProcessor.

$processor = "33B06720-F08A-4070-8A47-760BBB7234F6"
write-host "Switching Dialog Processor...$processor" -Fore Yellow
$url = $args[0]
$rootWeb = Get-SPWeb $url
$rootWeb.FileDialogPostProcessorId = $processor
$rootWeb.Update()

Debugging a custom processor

Once a custom processor is registered, debugging the processor is straightforward. Perhaps the easiest way to start testing is to use a client application such as Word - select to open a document, and then type in the URL of the SharePoint 2010 site where the custom processor has been registered. You can also type the URL to the owssvr.dll directly in Internet Explorer.

Use the Visual Studio debugger by attaching the debugger to the IIS worker process, w3wp.exe, for the application pool that your SharePoint 2010 site is running in. For more information about how to attach to a running process, see How to: Attach to a Running Process.

Note that if you make any changes to a component in the custom processor, you will need to re-register the updated component in the global assembly cache and restart the application pool in order to debug the latest version of the processor.

The custom web view we have created so far does a good job allowing the selection of a single document from SharePoint 2010. Users can take advantage of the custom web view’s navigation experience inside Outlook. When composing a new email, clicking Attach File shows the same CFD that is used in applications like Word.

Figure 3. Attach File icon in the Outlook user interface

Click Attach File on the ribbon

However, for certain users, this experience can be a little too limiting. When working on documents with external organizations, they might wish to select multiple documents and attach them all at once, without having to add them individually. In some scenarios, it might be necessary to select a specific version of a document – again, something the default CFD does not allow.

We can develop a custom Visual Studio add-in for Outlook to address these kinds of requirements. The add-in should focus on the following areas:

  • Allowing multi-selection of documents to attach or link to in an email message.

  • Allowing selection of previous versions of a document.

  • In the user interface for attaching documents, including version and document ID information in the file name to allow traceability. This would be particularly useful if you are sending documents to an external organization.

  • User interface that is visually consistent with the CFD to improve usability.

Creating a custom dialog box

First, in Visual Studio 2010, create a new Outlook add-in by clicking File, New, and then Project. Give the new project a name, and then click OK.

Figure 4. New Project dialog box in Visual Studio

New Project dialog box

Next, create a button on the ribbon that should be displayed when a user is composing an email. To do this, right-click on the newly created project, click Add, and then New Item. Then, add either a custom Office Fluent ribbon by using XML, or by using the Visual Designer.

After creating an empty ribbon, add a new button with the button label Attach Document to it. The following is a screen shot of the button in the custom ribbon.

Figure 5. Attach Document button in custom ribbon

Image is associated with the XML

The following XML example shows how to add a group labeled SharePoint to the NewMailMessage tab of the ribbon in an Outlook inspector in compose mode. The group contains a button labeled Attach Document. The onAction event calls back to the Control_Clicked function. Note that the button is associated with an image that is included the project.

      <tab idMso="TabNewMailMessage">
        <group id="CCInsert2" label="SharePoint" insertAfterMso="GroupInclude">
          <button id="CCAttachButton2"
                  label ="Attach Document"
                  description="Attaches documents from SharePoint."
                  onAction="Control_Clicked"
                  size="large"
                  image="SiteAttach"/>
        </group>
      </tab>

When users click the button, a custom attachment dialog box should appear. To achieve that, first, add a new Windows form to the project. Then, to display the form when the button is clicked, update the Control_Clicked method to display the dialog box, as shown in the following example:

NewAttachDialog dialog = new NewAttachDialog();
if (dialog.ShowDialog() == DialogResult.OK)

Now that the dialog box is displayed when the user clicks the button, add a WebBrowser control so that the dialog box displays the web view content.

private System.Windows.Forms.WebBrowser webBrowser1;

This control is designed to display the content from web pages in a Windows form. You can find more information about the WebBrowser control in WebBrowser Control Overview. This control should do two things to replicate the default CFD behavior:

  • Navigate to the URL that has been posted to owssvr.dll to get the HTML from the custom web view.

    This control has a DocumentCompleted event that is fired after a web page has loaded. Add an event handler so that as soon as the HTML has completed loading, we can parse the HTML content that the control has rendered.

    this.webBrowser1.DocumentCompleted += new System.Windows.Forms.WebBrowserDocumentCompletedEventHandler(this.WebBrowser1_DocumentCompleted);
    
  • Respond to user actions such as double-clicking on a folder or file row.

    As discussed, the custom web view has an HTML table called FileDialogViewTable with row elements each containing its type (folder or file) and URL. To respond to a user who clicks on one of these rows, add a pair of event handlers (for click and double click) to the row.

    HtmlElement fileDialogViewTable = 
    this.webBrowser1.Document.GetElementById("FileDialogViewTable");
    if (fileDialogViewTable != null)
    {
        foreach (HtmlElement tr in fileDialogViewTable.GetElementsByTagName("tr"))
        {
            if (tr.Id != "headerTr")
            {
                tr.Click += new HtmlElementEventHandler(this.ContentItem_Click);
                tr.DoubleClick += new 
                    HtmlElementEventHandler(this.ContentItem_DoubleClick);
            }
        }
    }
    

When a user selects on one of these rows, the appropriate event handler is called. The corresponding TR element contains a direct link to the file or folder. If the user selects a file row, the direct link gives the information needed to attach a file. But if a user selects a folder row, the custom dialog box should send a request back to the owssvr.dll process to retrieve that folder’s contents. This means it is necessary to translate standard URLs into URLs for the owssvr.dll process. The table below shows examples of how a standard URL on a row needs to be translated into a URL for the owssvr.dll process to retrieve the HTML for the custom web view.

Table 1. Name of Table

URL on TR element

Description

URL sent to owssvr.dll from Client

http://sdg-wks125

A SharePoint 2010 site at the root. Note that the location is empty, so the request is for the view of the site instead of a particular document library.

http://sdg-wks125/_vti_bin/owssvr.dll?dialogview=FileOpen&FileDialogFilterValue=*.*&location=

http://sdg-wks125/ChildSite

A child site. Note how the URL sent to owssvr.dll is relative to the site URL.

http://sdg-wks125/ChildSite/_vti_bin/owssvr.dll?dialogview=FileOpen&FileDialogFilterValue=*.*&location=

http://sdg-wks125/Documents

A path to a child document library at the root. The URL is relative to the site, but this time the location has the name of the document library.

http://sdg-wks125/_vti_bin/owssvr.dll?dialogview=FileOpen&FileDialogFilterValue=*.*&location=Documents

To change the location that the WebBrowser control is pointing at, when a user selects one of the TR elements in the FileDialogViewTable table, the dialog box needs to check to see if the row was a folder that was selected, construct the correct owssvr.dll URL and then call the WebBrowser control’s navigate method.

string fullPath = 
string.Format("{0}_vti_bin/owssvr.dll?dialogview=FileOpen&FileDialogFilterValue=*.*&location={1}", webURL, location);
this.webBrowser1.Navigate(fullPath);

So far, the custom dialog box behaves in the same way as the default CFD. Next, extend the dialog box to display versions and allow multi-select. To let the custom processor know that the request is coming from the custom dialog box in Outlook, call the navigate function on the WebBrowser control with an extra query string parameter appended to the URL. In the following example, the owssvr.dll URL is constructed with an extra Extensions parameter that indicates whether to include versions and multi-select functionality.

string.Format("{0}_vti_bin/owssvr.dll?dialogview=FileOpen&FileDialogFilterValue=*.*&Extensions={1}&location={2}", webURL, multiselect;versions;, location)

The custom processor can then pick up this value to change the HTML output to make it unique for the custom dialog box in Outlook:

queryString["Extensions"].ToLowerInvariant();

Update the XML data generated by the custom processor so that it includes the version information associated with each document.

<Versions>
<Version Url="http://sdg-wks1258/my/personal/benrosc/_vti_history/1/Design.docx" VersionLabel="0.1" Created="14/08/2011 13:50:17" CreatedBy="EUROPE\benrosc" CheckInComment=""/> 
</Versions>

Also, update the XSLT that contains the HTML formatting information to indicate whether the request came from the custom dialog box in Outlook and to conditionally render out versions.

<xsl:when test="count(Versions/Version)&gt;0">

To allow multi-select, there should be check boxes rendered in each row if the row is a file row. Add a check to make sure check boxes appear only for file rows in the custom dialog box, and not in the default CFD.

<xsl:if test="contains($Extensions, 'multiselect')">

Now, when the user opens the dialog box in Outlook, the user can see a check box next to each entry. The user can choose to select versions as well. Using JavaScript in the XSLT, you can keep track of which items are selected. You can improve the user interface so that the list of versions expands and collapses when a user clicks.

Figure 6. Supporting multi-select and versions in the user interface

Displaying multiple versions in the user interface

The final part is to make sure that the selected documents and their versions are attached to the email message when the user clicks OK. To change the file name of the selected documents to include version and document ID information, download each file locally as a file of the changed name.

string newLocation = Path.Combine(Path.GetTempPath(), newFileName);
using (WebClient webClient = new WebClient())
{
    webClient.Credentials = CredentialCache.DefaultCredentials;
    webClient.DownloadFile(fileUrl, newLocation);
}

Then, attach the downloaded files to the email message.

OfficeOutlook.Inspector inspector = this.Application.ActiveInspector();
OfficeOutlook.MailItem mailItem = inspector.CurrentItem as OfficeOutlook.MailItem;
mailItem.Attachments.Add(fileInfo.LocalPath, OfficeOutlook.OlAttachmentType.olByValue, Type.Missing, Type.Missing);

Now, when users select items to attach in the custom dialog box, they appear with formatted file names as shown in the following screen shot.

Figure 7. Attachments with file names that include document ID and version information

Attachments have formatted file names

This article describes how to customize a SharePoint web view for the Common File Dialog. To integrate SharePoint and Outlook, this article also shows a useful technique to extend the custom SharePoint web view to support multi-select of versioned documents on a SharePoint site as message attachments in Outlook.

Ben Roscorla is a Senior Consultant at Microsoft. He is based in the UK.

Show:
© 2014 Microsoft