Creating a Custom Data Provider with Visio Services

Applies to: SharePoint Server 2010

In this article
Custom Data Providers
Visio Services API
Creating a Custom Data Provider
Create the Sample Files
Creating the Custom Data Provider and Deploying it to SharePoint Server
Create and Compile the Visual Studio 2010 Solution
Creating and Running the PowerShell Script
Adding a New Trusted Data Provider to Visio Graphics Service
Testing the Sample Custom Data Provider

Note

The information in this topic applies to SharePoint 2013 as well as to SharePoint 2010.

Visio Services makes it possible to display Microsoft Visio 2010 drawings published as .vdw files in the Visio Web Access Web Part in Microsoft SharePoint Server 2010.You can use the Visio Services class library to build custom Visio Services data modules, or custom data providers, which permit you to programmatically refresh data derived from custom data sources in Visio 2010 Web drawings hosted on a Microsoft SharePoint Server 2010 site.

This topic describes the most important classes and methods in the Visio Services class library, how to create and deploy a sample custom data provider that uses data from an XML file, and how to create a sample Visio .vdw file that contains a connection to the data that can be refreshed by the custom data provider.

Custom Data Providers

Visio drawings can consume data from a variety of standard data providers, including Microsoft Excel files, SharePoint lists, SQL databases, and any other ODBC-compatible data source. This functionality extends to drawings displayed in the Visio client, and to Visio drawings (.vdw files) displayed in the Visio Web Access Web Part on a SharePoint page. In situations where when you want a drawing to derive data from another data source that is not one of the preceding data sources, you can create a custom data provider. Your custom data provider can connect to data from XML files, as in the example beginning in the section "Creating a Custom Data Provider" in this article; Web services; OLAP cubes; and many other data sources. You must write the code to create a custom data provider, install that custom data provider on a server that has SharePoint Server 2010 installed and that is running Visio Services, and then add your custom data provider to the list of trusted data providers for Visio Services.

Visio Services API

The Visio Services API consists of two classes and their associated methods: the AddonDataHandler abstract base class, and the AddonDataHandlerException class. These classes make up the Microsoft.Office.Visio.Server namespace, and are distributed in the file Microsoft.Office.Visio.Server.dll. In your solution code, for example, create a class named VisioCustomDataProvider that inherits from and implements the AddonDataHandler base class and the IAsyncResult interface. The VisioCustomDataProvider.cs file described in this article provides an example of how to implement this interface.

AddonDataHandler Base Class

Custom data modules are used to query data sources for which the server does not have built-in support. A custom data module is represented by a public class that inherits from AddonDataHandler and implements its abstract members, as well as the IAsyncResult interface. The sample solution described in this article provides an example of how to implement these members.

Table 1. AddonDataHandler base class members

Member Name

Description

BeginGetData(HttpContext, AsyncCallback, Object) method

Called by Visio Services to start retrieving data from the data source specified by the custom data provider. When you implement this method, design it to return as quickly as possible, because custom data providers are meant to be run asynchronously.

EndGetData(IAsyncResult) method

Called by Visio Services when this custom data provider has finished retrieving data. This method must return to Visio Services the data retrieved by the custom data provider in the form of an ADO.NET DataSet object.

Cancel() method

Called by Visio Services to stop the asynchronous processing of the data when it detects an error, or when the maximum time allocated for retrieving data has elapsed and data retrieval is not complete.

Data property

Specifies the ADO.NET DataSet object that the custom data provider must fill with updated data and return to Visio Services.

QueryString property

Specifies the command string associated with the Visio DataRecordset object that the custom data provider is refreshing. Visio Services parses this string out of the Web drawing (.vdw file) at the time the drawing is refreshed, and assigns its value to this property. This string is a semicolon-delimited list of key/value pairs. Each pair contains the key and value, separated by an equal sign. The format of the string should be as follows: "DataModule=ClassFullName, SimpleAssemblyName; Key1=Value1;Key2=Value2;…", where ClassFullName is the name of the class, including the namespace, and where SimpleAssemblyName is the name of the assembly, without any additional identity information. As a developer, you can use the remainder of the string (the key/value pairs) as you choose. For more information about this string, see the section "Specifying the Data Module to Use on the Server in the .vdw File" in this article.

The value of this property is equal to that of the CommandString property of the associated Visio DataRecordset object.

Note

See the code in this article for an example of this string.

ConnectionString property

Specifies the connection string associated with the Visio DataRecordset object that the custom data provider is refreshing. Visio Services parses this string out of the Web drawing (.vdw file) at the time the drawing is refreshed, and assigns its value to this property. The format of this string is a semicolon-delimited list of key/value pairs. Each pair contains the key and value, separated by an equal sign.

The value of this property is equal to that of the ConnectionString property of the associated Visio DataRecordset object.

Error property

Returns an exception object that describes an error that occurred if this custom data provider failed to retrieve data from its associated external data source. This property can be used to propagate error information to the caller about a failure that occurred during the asynchronous processing. If the type of this exception is AddonDataHandlerException, the exception message is presented to the user as is; otherwise, a generic message is presented to the user.

AddonDataHandlerException Class

The AddonDataHandlerException base class represents an exception that Visio Services can throw to communicate an error message to the user.

You can set the Error property of the AddonDataHandler class to an exception of any type. If the exception is of type AddonDataHandlerException, the error message describing the exception, which consists of the value of the message parameter passed to the constructor of the AddonDataHandlerException object, is displayed to the user; otherwise, a generic error message is displayed.

Creating a Custom Data Provider

Follow these general steps to create a custom data provider. Each step is described in more detail later in this article, starting with the next section, "Create the Sample Files".

To create a custom data provider

  1. Create the sample files and deploy them to the SharePoint Server 2010 computer.

    These sample files include the XML file to hold the data on the server and the Visio 2010 Web drawing (.vdw) file that you want to display on a SharePoint site. This drawing will display the data retrieved by the custom data provider from a data source that is not natively supported by Visio 2010.

  2. On the SharePoint Server 2010 computer, create and compile a Visual Studio 2010 solution that implements the Visio Services API to create the custom data provider.

  3. Use a Windows PowerShell script or another method to deploy the custom data provider to the SharePoint Server 2010 computer.

  4. In SharePoint Central Administration, add the custom data provider to the list of Visio Graphics Service trusted data sources.

  5. Test the sample custom data provider by rendering the Visio drawing in a Visio Web Access Web Part on the server.

    Now, when you change the data in the data source and refresh the Visio drawing, the current Web drawing page is refreshed with data from the server, which ultimately reflects the changes you make.

    Note

    Because of the way data is cached on the server, refreshing the drawing does not always immediately reflect the changes you make in the data source.

Create the Sample Files

You must create an XML data file and a sample Visio .vdw file to publish to the SharePoint Server computer. The sample .vdw file will display the initial data that you import into the drawing, by using Visual Basic for Applications (VBA) code. After the drawing is rendered in the Visio Web Access Web Part, you can modify the data in the XML file, which is initially the same data that is in the drawing, and then refresh the drawing to display the modified data.

Figure 1 shows how your Visio drawing will look when it is finished.

Figure 1. Finished Visio drawing

Finished Visio File

Creating the XML Data File to Post on the Server

To create the XML data file to post on the server, follow these steps.

To create the XML data file to post on the server

  1. In Notepad or another text editor, create a file.

  2. Paste the following code into the file.

    <?xml version="1.0" standalone="yes"?>
    <DemoDataDataSet>
      <xs:schema id="NewDataSet"  xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
        <xs:element name="DemoDataDataSet" msdata:IsDataSet="true" msdata:UseCurrentLocale="true">
          <xs:complexType>
            <xs:choice minOccurs="0" maxOccurs="unbounded">
              <xs:element name="SuperMarketData">
                <xs:complexType>
                  <xs:sequence>
                    <xs:element name="Name" minOccurs="0">
                      <xs:simpleType>
                        <xs:restriction base="xs:string">
                          <xs:maxLength value="50" />
                        </xs:restriction>
                      </xs:simpleType>
                    </xs:element>
                    <xs:element name="IP" minOccurs="0">
                      <xs:simpleType>
                        <xs:restriction base="xs:string">
                          <xs:maxLength value="50" />
                        </xs:restriction>
                      </xs:simpleType>
                    </xs:element>
                    <xs:element name="Status" minOccurs="0">
                      <xs:simpleType>
                        <xs:restriction base="xs:string">
                          <xs:maxLength value="50" />
                        </xs:restriction>
                      </xs:simpleType>
                    </xs:element>
                  </xs:sequence>
                </xs:complexType>
              </xs:element>
            </xs:choice>
          </xs:complexType>
        </xs:element>
      </xs:schema>
      <SuperMarketData>
        <Name>sql-sales-01</Name>
        <IP>10.0.5.1</IP>
        <Status>Online</Status>
      </SuperMarketData>
      <SuperMarketData>
        <Name>sql-sales-02</Name>
        <IP>10.0.5.2</IP>
        <Status>Online</Status>
      </SuperMarketData>
      <SuperMarketData>
        <Name>filestore-sales-01</Name>
        <IP>10.0.5.3</IP>
        <Status>Online</Status>
      </SuperMarketData>
      <SuperMarketData>
        <Name>webserver-01</Name>
        <IP>10.0.5.0</IP>
        <Status>Online</Status>
      </SuperMarketData>
    </DemoDataDataSet>
    
  3. Name the file VisioCustomData.xml, and then save it to a location you can easily access.

In the previous XML code, the actual data to be displayed is contained within the sets of <SuperMarketData> tags near the end of the file, and is shown in Table 2.

Table 2. Data to be displayed in the Visio file

Computer Name

IP Address

Status

sql-sales-01

10.0.5.1

Online

sql-sales-02

10.0.5.2

Online

filestore-sales-01

10.0.5.3

Offline

webserver-01

10.0.5.0

Online

When you construct the Visio 2010 diagram, you use VBA code shown in the next section to import this data directly into the diagram to establish the initial data to display. Then, after you display the diagram in SharePoint Server 2010, you can modify the data in the XML file on the server and refresh the rendered drawing with data from the server.

Creating the Sample Visio .vdw File

First, you use a combination of the Visio user interface (UI) and VBA code in the Visual Basic Editor in Visio to create the Visio drawing to display the data. Next, use VBA to import the data into a data record set in Visio, and then link the data in that data record set to shapes on the drawing page. You also assign the command string that enables the connection between the posted drawing and the custom data provider on the server to the newly created data record set. Finally, use the Visio UI to customize the data graphics that display the data associated with individual shapes.

In the ImportData procedure, the VBA code uses the DataRecordset.AddFromXML method to seed the drawing with data. If you use this method in your own projects, the XML file that you post to the server must contain the same data, and must have the same data structure as the data you import into the drawing by using VBA: that is, it must have the same number of columns, the same number of rows, and the same data types for each column.

To create the sample Visio .vdw file

  1. In Visio 2010, create a blank drawing. Click File, and then click New. Under Other Ways to Get Started, click Blank Drawing, and then click Create.

  2. Save the drawing as a .vdw file. Click File, and then click Save. Browse to the location where you want to save the file. For the file name, type SampleDiagram. In the Save as Type list, click Web Drawing (*.vdw), and then click Save.

  3. Press ALT+F11 to open the Visual Basic Editor.

  4. In the Project Explorer pane, double-click the ThisDocument(SampleDiagram) project.

  5. Paste the following code into the code pane.

    Note

    The following code opens stencils that have U.S. units. If you want to use stencils that have metric units, modify the stencil names to read "COMPS_M.VSS," "NETLOC_M.VSS," and "SERVER_M.VSS," respectively.

    Sub ChangeOrientationAndOpenStencils()
    
        'Enable diagram services.
        Dim DiagramServices As Integer
        DiagramServices = ActiveDocument.DiagramServicesEnabled
        ActiveDocument.DiagramServicesEnabled = visServiceVersion140
    
        Application.ActiveWindow.ViewFit = visFitPage
    
        Application.ActiveWindow.Page.PageSheet.CellsSRC(visSectionObject, visRowPage, visPageWidth).FormulaU = "11 in"
        Application.ActiveWindow.Page.PageSheet.CellsSRC(visSectionObject, visRowPage, visPageHeight).FormulaU = "8.5 in"
        Application.ActiveWindow.Page.PageSheet.CellsSRC(visSectionObject, visRowPrintProperties, visPrintPropertiesPageOrientation).FormulaForceU = "2"
        Application.EndUndoScope UndoScopeID1, True
    
        Application.Documents.OpenEx "server_u.vss", visOpenRO + visOpenDocked
    
        Application.Documents.OpenEx "netloc_u.vss", visOpenRO + visOpenDocked
    
        Application.Documents.OpenEx "comps_u.vss", visOpenRO + visOpenDocked
    
        'Restore diagram services
        ActiveDocument.DiagramServicesEnabled = DiagramServices
    
    End Sub
    
    Sub DropAndConnectShapes()
    
        Dim DiagramServices As Integer
        Dim vsoShapeServer1 As Shape
        Dim vsoShapeServer2 As Shape
        Dim vsoShapeServer3 As Shape
        Dim vsoShapeWebServer As Shape
        Dim vsoShapeCloud As Shape
        Dim vsoShapePC As Shape
        Dim vsoSelection As Selection
    
        'Enable diagram services.    
        DiagramServices = ActiveDocument.DiagramServicesEnabled
        ActiveDocument.DiagramServicesEnabled = visServiceVersion140
    
    
        Set vsoShapePC = Application.ActiveWindow.Page.Drop(Application.Documents.Item("COMPS_U.VSS").Masters.ItemU("PC"), 10#, 4.5)
    
        Set vsoShapeCloud = Application.ActiveWindow.Page.Drop(Application.Documents.Item("NETLOC_U.VSS").Masters.ItemU("Cloud"), 8#, 4.5)
        vsoShapeCloud.AutoConnect vsoShapePC, visAutoConnectDirRight
    
        Set vsoShapeWebServer = Application.ActiveWindow.Page.Drop(Application.Documents.Item("SERVER_U.VSS").Masters.ItemU("Web Server"), 6#, 4.5)
        vsoShapeWebServer.AutoConnect vsoShapeCloud, visAutoConnectDirRight  
    
        Set vsoShapeServer1 = Application.ActiveWindow.Page.Drop(Application.Documents.Item("SERVER_U.VSS").Masters.ItemU("Server"), 2#, 2)
        vsoShapeServer1.AutoConnect vsoShapeWebServer, visAutoConnectDirRight
    
        Set vsoShapeServer2 = Application.ActiveWindow.Page.Drop(Application.Documents.Item("SERVER_U.VSS").Masters.ItemU("Server"), 2#, 4.5)
        vsoShapeServer2.AutoConnect vsoShapeWebServer, visAutoConnectDirRight  
    
        Set vsoShapeServer3 = Application.ActiveWindow.Page.Drop(Application.Documents.Item("SERVER_U.VSS").Masters.ItemU("Server"), 2#, 7)
        vsoShapeServer3.AutoConnect vsoShapeWebServer, visAutoConnectDirRight
    
        ActiveWindow.DeselectAll
        ActiveWindow.Select vsoShapeWebServer, visSelect
        Application.ActiveWindow.Selection.Move 1.5, 0#
    
        'Restore diagram services.
        ActiveDocument.DiagramServicesEnabled = DiagramServices
    
    End Sub
    
    Sub ImportData()
    
        'Enable diagram services
        Dim DiagramServices As Integer
        DiagramServices = ActiveDocument.DiagramServicesEnabled
        ActiveDocument.DiagramServicesEnabled = visServiceVersion140
    
        Application.ActiveWindow.Windows.ItemFromID(visWinIDExternalData).Visible = True
    
        Dim strXML As String
        Dim strXML1 As String
        Dim strXML2 As String
        Dim strName As String
        Dim vsoDataRecordset As Visio.DataRecordset
    
        strName = "Server Data"
    
        strXML1 = "<xml xmlns:s='uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882'" + Chr(10) _
                    & "xmlns:dt='uuid:C2F41010-65B3-11d1-A29F-00AA00C14882'" + Chr(10) _
                    & "xmlns:rs='urn:schemas-microsoft-com:rowset'" + Chr(10) _
                    & "xmlns:z='#RowsetSchema'><s:Schema id='RowsetSchema'>" + Chr(10) _
        & "<s:ElementType name='row' content='eltOnly' rs:updatable='true'>" + Chr(10) _
        & "<s:AttributeType name='c0' rs:name='_Visio_RowID_' rs:number='1'" + Chr(10) _
        & "rs:nullable='true' rs:maydefer='true' rs:write='true'>" + Chr(10) _
        & "<s:datatype dt:type='int' dt:maxLength='4' rs:precision='0'" + Chr(10) _
        & "rs:fixedlength='true'/></s:AttributeType>" + Chr(10) _
        & "<s:AttributeType name='Name' rs:number='2' rs:nullable='true'" + Chr(10) _
        & "rs:maydefer='true' rs:write='true'>" + Chr(10) _
        & "<s:datatype dt:type='string' dt:maxLength='255' rs:precision='0'/>" + Chr(10) _
        & "</s:AttributeType>" + Chr(10) _
        & "<s:AttributeType name='IP' rs:number='3' rs:nullable='true'" + Chr(10) _
        & "rs:maydefer='true' rs:write='true'>" + Chr(10) _
        & "<s:datatype dt:type='string' dt:maxLength='255' rs:precision='0'/>" + Chr(10) _
        & "</s:AttributeType>"
    
    
        strXML2 = " <s:AttributeType name='Status' rs:number='4' rs:nullable='true'" + Chr(10) _
        & "rs:maydefer='true' rs:write='true'>" + Chr(10) _
        & "<s:datatype dt:type='string' dt:maxLength='255' rs:precision='0'/>" + Chr(10) _
        & "</s:AttributeType>" + Chr(10) _
        & "<s:extends type='rs:rowbase'/>" + Chr(10) _
        & "</s:ElementType></s:Schema>" + Chr(10) _
        & "<rs:data>" + Chr(10) _
        & "<z:row c0='1' Name='sql-sales-01' IP='10.0.5.1' Status='Online'/>" + Chr(10) _
        & "<z:row c0='2' Name='sql-sales-02' IP='10.0.5.2' Status='Online'/>" + Chr(10) _
        & "<z:row c0='3' Name='filestore-sales-01' IP='10.0.5.3' Status='Offline'/>" + Chr(10) _
        & "<z:row c0='4' Name='webserver-01' IP='10.0.5.0' Status='Online'/>" + Chr(10) _
        & "</rs:data></xml>"
    
        strXML = strXML1 + strXML2
    
        ' Create a new DataRecordset object. For more information about 
        ' connecting to data in Visio, see "About Connecting to Data" 
        ' in the Visio Developer Reference.
        Set vsoDataRecordset = ThisDocument.DataRecordsets.AddFromXML(strXML, 0, strName)
        vsoDataRecordset.CommandString = "DataModule=DataModules.VisioCustomDataProvider,VisioCustomDataProvider;File=c:\VisioCustomData.xml"
    
        'Restore diagram services.
        ActiveDocument.DiagramServicesEnabled = DiagramServices
    
    End Sub
    
    ' Link the data in the DataRecordset object to the shapes on the page. 
    ' For more information about linking data to shapes in Visio, 
    ' see "About Linking Shapes to Data" in the Visio Developer Reference.
    Sub LinkDataToShapes()
    
        'Enable diagram services.
        Dim DiagramServices As Integer
        DiagramServices = ActiveDocument.DiagramServicesEnabled
        ActiveDocument.DiagramServicesEnabled = visServiceVersion140
    
        ActiveWindow.DeselectAll
        ActiveWindow.Select Application.ActiveWindow.Page.Shapes(10), visSelect
        Application.ActiveWindow.Selection.LinkToData 1, 1, True
    
        ActiveWindow.DeselectAll
        ActiveWindow.Select Application.ActiveWindow.Page.Shapes(8), visSelect
        Application.ActiveWindow.Selection.LinkToData 1, 2, True
    
        ActiveWindow.DeselectAll
        ActiveWindow.Select Application.ActiveWindow.Page.Shapes(6), visSelect
        Application.ActiveWindow.Selection.LinkToData 1, 3, True
    
        ActiveWindow.DeselectAll
        ActiveWindow.Select Application.ActiveWindow.Page.Shapes(4), visSelect
        Application.ActiveWindow.Selection.LinkToData 1, 4, True
    
        'Restore diagram services.
        ActiveDocument.DiagramServicesEnabled = DiagramServices
    
    End Sub
    
  6. Run each of the procedures in the previous code in the order in which they are listed.

  7. Save the file.

Enhancing Data Graphics in the Sample Visio .vdw File

At this point, your basic sample file is substantially complete. It contains shapes that are linked to XML data and that display the data, in the form of data graphics. However, you may want to customize the standard data graphics that Visio applies, which overlap the connectors and lack information about the status of the servers. You can easily enhance the appearance and functionality and improve the location of the data graphics relative to their associated shapes. To enhance the data graphics in the sample Visio .vdw file to look like those in Figure 1, follow these steps.

To enhance the data graphics in the sample Visio .vdw file

  1. Right-click any one of the three server shapes, point to Data, and then click Edit Data Graphic.

  2. Under Default position, in the Horizontal list, select Far Left, and then click Apply.

  3. Select the Name data field, and then click Edit Item.

  4. In the Style list, select Heading 3, click OK, and then click Apply to apply the change.

  5. Click New Item.

  6. In the Data field list, select Status, and in the Displayed as list, select Color by Value.

  7. For the Online status, in the Fill Color list, under Standard Colors, select Green, click OK, and then click Apply.

  8. Right-click the Webserver shape, point to Data, and then click Edit Data Graphic.

  9. Under Default position, in the Horizontal list, select Center, and in the Vertical list, select Below Shape.

  10. Under Apply changes to, select Only selected shapes, click Apply, and then click OK.

Specifying the Data Module to Use on the Server in the .vdw File

When you create the Visio .vdw file that you want to display on the SharePoint Server 2010 computer, you can specify the data module to be used on that computer, as follows. A data module is specified by a string that has the format "DataModule=ClassFullName,SimpleAssemblyName;". You can specify the data module by including that string in the DataRecordset.DataConnection.ConnectionString property value, which corresponds to the value of the ConnectionString property on the server. When the DataRecordset object does not have a DataConnection reference, you can specify the data module by including that string in the DataRecordset.CommandString property value, which corresponds to the QueryString property on the server. In this case, the string is also replicated in ConnectionString. The server parses out the data module string from the ConnectionString and uses it to load the module. The server removes the data module string from the ConnectionString value before running the module. Additional information about the data module is usually specified in the query string, in the form "Key1=Value1;Key2=Value2;..." and so forth, at the developer's discretion.

Deploy the sample files to the SharePoint Server Computer

Now that you have a finished Visio .vdw file that contains external data that you want to publish to a SharePoint page, post it and the XML file you created earlier to the SharePoint Server 2010 computer that is running Visio Services.

To deploy the sample files to the SharePoint Server computer

  1. Copy the source XML data file you created previously to the location on the SharePoint Server 2010 computer that you specified in the command string in the Visio drawing. In the sample in this article, that location is the root of the c:\ drive.

  2. Copy the sample Visio .vdw file that contains external XML data to a document library on the server.

Creating the Custom Data Provider and Deploying it to SharePoint Server

Follow these general steps to create a custom data provider and deploy it to a SharePoint Server 2010 computer that is running Visio Services.

To create a custom data provider and deploy it to SharePoint Server

  1. On the SharePoint Server 2010 computer, create the Microsoft Visual Studio 2010 solution presented in this article and then compile it.

    This will save a SharePoint solution package (.wsp file) to the location specified in the project. In the sample in this article, it is to the root of the c:\ drive.

  2. Create a Windows PowerShell script file from the text shown here to the location on the SharePoint Server 2010 computer that you specified in the command string in the Visio drawing. Once again, in the sample in this article, that location is the root of the c:\ drive.

  3. Run the Windows PowerShell script.

  4. Add a new trusted provider to the list of trusted providers in SharePoint Server 2010 Central Administration.

  5. Double-click the Visio .vdw file to render it in the Visio Web Access Web Part.

The following procedures explain in more detail how to perform the more complex steps.

Create and Compile the Visual Studio 2010 Solution

When compiled, the Visual Studio 2010 solution you create here produces a solution package at the root of the c:\ drive, where you have placed other important files for the sample. The Visual Studio 2010 solution references Visio Services and SharePoint.

To create and compile the Visual Studio 2010 solution

  1. On the SharePoint Server 2010 computer, in Visual Studio 2010, create a new Visual C# Class Library Project, and save the solution as CustomDataProvider.

  2. Add a reference to the System.Web namespace. In Solution Explorer, right-click References, click Add Reference, click .NET, select System.Web, and then click OK.

  3. Add a reference to Visio Services. In Solution Explorer, right-click References, click Add Reference, and click Browse. Navigate to the path to the windows folder on your computer\assembly\GAC_MSIL\Microsoft.Office.Visio.Server\ 14.0.0.0__71e9bce111e9429c, select Microsoft.Office.Visio.Server.dll, and then click OK.

  4. Rename the generic Class1.cs class file that Visual Studio 2010 creates to be VisioCustomDataProvider.cs.

  5. On the Project menu, click CustomDataProvider Properties. Change Assembly name to VisioCustomDataProvider, and change Default namespace to DataModules.

  6. Open the VisioCustomDataProvider.cs file, select the existing content, and then paste in the following code to overwrite the existing text in the file. The code comments provide documentation about what the code is doing.

    /* VisioCustomDataProviders.cs
     * <copyright>Copyright (c) Microsoft Corporation. All rights reserved.</copyright>
     * <summary>This class demonstrates how to add support for a custom
     * data source to Visio Services by creating a custom data provider. 
     * In this sample, the data source is an XML text file saved on the hard disk
     * of the computer running this custom data provider, typically a SharePoint Server
     * front-end Web server.</summary>
     * */
    using System;
    using System.Data;
    using System.Threading;
    using System.Web;
    using System.Xml;
    using Microsoft.Office.Visio.Server;
    
    namespace DataModules
    {
        /// <summary>
        /// This class demonstrates how to add support for a custom data source
        /// to Visio Services by creating a custom data provider. The class must 
        /// inherit from the AddonDataHandler abstract class, which includes the 
        /// following members:
        /// 
        /// this.Data:  The ADO.NET DataSet that describes the data required by the 
        ///             Visio Graphics Server. 
        ///             The custom data provider can fill this DataSet with updated 
        ///             data and return it to Visio Services. It is up to the 
        ///             implementation to specify the type of each DataColumn and 
        ///             to ensure data type compatibility with Visio Services.
        ///             
        /// this.ConnectionString:  The connection string associated with the Visio 
        ///                         DataRecordset being refreshed by this custom 
        ///                         data provider. This string is parsed out of the 
        ///                         Web drawing at refresh time and its value is then 
        ///                         assigned to this property. The format of this string 
        ///                         is a semicolon-delimited list of key/value pairs. 
        ///                         Each pair contains the key and value, separated by an 
        ///                         equals sign.
        ///                         
        /// this.QueryString:   The query string associated with the Visio
        ///                     DataRecordset being refreshed by this custom data 
        ///                     provider. This string is parsed out of the Web drawing
        ///                     at refresh time and its value is then assigned to this
        ///                     property. The format is a semicolon-delimited list of 
        ///                     key/value pairs. Each pair contains the key and value, 
        ///                     separated by an equal sign.
        ///                     
        /// this.Error: The exception object that describes an error that occurred if this 
        ///             custom data provider failed to retrieve data from its associated 
        ///             external data source. This property can be used to propagate error
        ///             information to the caller about a failure that occurred during the 
        ///             asynchronous processing. If the type of this exception is 
        ///             AddonDataHandlerException, the exception message is presented 
        ///             to the end user as is; otherwise, a generic message will be used.
        ///                     
        /// this.BeginGetData():    This method is called by Visio Services to 
        ///                         start data retrieval in this custom data 
        ///                         provider.
        ///                         
        /// this.EndGetData():      This method is called by Visio Services when
        ///                         the custom data provider finished retrieving data from
        ///                         the associated data source. This method must return 
        ///                         the data retrieved in the form of an ADO.NET DataSet.
        ///                         
        /// this.Cancel():      This method is called by Visio Services to stop the async
        ///                     processing when an error was detected or the maximum time
        ///                     allocated for retrieving data has passed and the custom data
        ///                     provider did not complete.
        ///                     
        /// This class also implements the IAsyncResult interface as described at
        /// https://msdn.microsoft.com/en-us/library/system.iasyncresult.aspx. 
        /// </summary>
        public class VisioCustomDataProvider : AddonDataHandler, IAsyncResult
        {
    
            // Fields used to support the implementation of the IAsyncResult interface.
            private object asyncState;  //Used to maintain a reference to this custom 
                                        //data provider.
            private bool completed;     //Used to notifiy Visio Services that the 
                                        //the custom data provider has finished 
                                        //retrieving data.
    
            #region Implementation of the IAsyncResult Interface
            /// <summary>
            /// This property implements the equivalent AsyncWaitHandle property of
            /// the IAsyncResult interface. More details on this member can 
            /// be found at https://msdn.microsoft.com/en-us/library/system.iasyncresult_properties.aspx
            /// Visio Services does not use this property.
            /// </summary>
            WaitHandle IAsyncResult.AsyncWaitHandle
            {
                get { return null; }
            }
    
            /// <summary>
            /// This property implements the equivalent AsyncState property of
            /// the IAsyncResult interface. More details on this member can 
            /// be found at https://msdn.microsoft.com/en-us/library/system.iasyncresult_properties.aspx
            /// Visio Services requires this property to return the asyncState object
            /// passed to the BeginGetData method by its caller.
            /// </summary>
            object IAsyncResult.AsyncState
            {
                get { return this.asyncState; }
            }
    
            /// <summary>
            /// This property implements the equivalent IsCompleted property of the
            /// IAsyncResult interface. This property gets a value that indicates whether
            /// the asynchronous operation has completed. More details on this member can 
            /// be found at https://msdn.microsoft.com/en-us/library/system.iasyncresult_properties.aspx
            /// </summary>
            bool IAsyncResult.IsCompleted
            {
                get { return this.completed; }
            }
    
            /// <summary>
            /// This property implements the equivalent CompleteSynchronously property
            /// of the IAsyncResult interface. This property gets a value that indicates
            /// whether the asyncrhonous operation has completed. More details on this member can 
            /// be found at https://msdn.microsoft.com/en-us/library/system.iasyncresult_properties.aspx
            /// </summary>
            bool IAsyncResult.CompletedSynchronously
            {
                get { return false; }
            }
            #endregion
    
            #region Implementation of the AddonDataHandler abstract class
            /// <summary>
            /// BeginGetData is called by Visio Services to start data retrieval in 
            /// this custom data provider. This method should return as quickly as possible
            /// because custom data providers are meant to be run asynchronously.
            /// </summary>
            /// <param name="context">The HTTP context of user viewing 
            /// the Web drawing.</param>
            /// <param name="callback">A reference to a Visio Services method that
            /// the custom data provider must call when it is finished retrieving 
            /// data from its associated external data source.</param>
            /// <param name="asyncState">Async state passed-in by the caller. Visio Services
            /// requires the implementation to store this state into the AsyncState member
            /// of the returned IAsyncResult without changes.
            /// </param>
            /// <returns>An IAsyncResult that contains information about the status of 
            /// the operation.</returns>
            public override IAsyncResult BeginGetData(
                System.Web.HttpContext context,         
                AsyncCallback callback,                 
                object asyncState)                      
            {
                //Store the async state.
                this.asyncState = asyncState;
    
                // Start data retrieval. This is done on a separate thread because
                // BeginGetData() should return as soon as possible. 
                // When the ThreadTask function finishes, the thread makes 
                // a call to the callback method, which indicates to Visio Services 
                // that the data retrieval step is complete.
                ThreadPool.QueueUserWorkItem(
                    new WaitCallback(ThreadTask),
                    callback);
    
                return this;
            }
    
            /// <summary>
            /// EndGetData is the method called by Visio Services when this 
            /// custom data provider has finished retrieving data. 
            /// </summary>
            /// <param name="result">An IAsyncResult that contains information 
            /// about the status of the operation.</param>
            /// <returns>This method must return the data retrieved by this
            /// custom data provider to Visio Services in the form of an ADO.NET
            /// DataSet.</returns>
            public override DataSet EndGetData(IAsyncResult result)
            {
                // Return an ADO.NET DataSet containing the data retrieved by this 
                // custom data provider to Visio Services. In this example, 
                // this.Data was updated in the ThreadTask method with the
                // appropriate data.
                return this.Data;
            }
    
            /// <summary>
            /// Cancel is the method called by Visio Services to stop the asynchronous
            /// processing when an error was detected or the maximum time
            /// allocated for retrieving data has passed and the custom data
            /// provider did not complete.
            /// </summary>
            public override void Cancel()
            {
                //This example does not require an implementation of this method.
            }
            #endregion 
    
            #region Data retrieval method
            /// <summary>
            /// This is the worker method which is lauched by BeginGetData(). 
            /// Typically this method should:
            /// (1) parse the the connection and query strings
            /// (2) implement authentication measures
            /// (3) connect to a custom data source, query, and retrieve data
            /// (4) format the retrieved data and update this.Data
            /// (5) in case of errors, set this.Error accordingly.
            /// (6) set this.completed and call the Visio Services callback method
            /// </summary>
            /// <param name="state">A reference to Visio Services callback 
            /// that must be called at the end of this task.</param>
            private void ThreadTask(object state)
            {
                // Get a reference to the Visio Services callback
                AsyncCallback callback = (AsyncCallback) state;
    
                // A string to hold the file name of the data source once 
                // it is parsed out of this.QueryString
                string filename = String.Empty;
    
                try
                {
                    // (1) Parse ConnectionString and QueryString.
                    //
                    // When configuring the Web drawing for custom data providers, the user 
                    // can choose whether to pass information in the ConnectionString, QueryString, 
                    // or both, depending on the data source and preferences.
                    //
                    // In this example, the significant content of ConnectionString
                    // and QueryString is the same and formatted as "File=<File>".
                    //
                    // Where:
                    // <File>" is the path to the xml file that contains the data. 
                    const string FileKey = "File=";
                    int fileNameStart = this.QueryString.IndexOf(FileKey) + FileKey.Length;
                    filename = this.QueryString.Substring(fileNameStart);
    
                    // (2) Authenticate
                    // This code is running in the security context of the end user.
                    // If the end user account does not have access to the disk where 
                    // the text data source is stored, implement the required authentication 
                    // mechanisms below.
    
                    // (3,4) Retrieve and format data 
                    // This custom data provider expects the file to contain an 
                    // ADO.NET DataSet XML description of the data to load; therefore it's 
                    // easy to load into this.Data, which is itself an ADO.NET DataSet.
                    // In this case, Reset must be called first to clear the DataSet.
                    this.Data.Reset();
                    this.Data.ReadXml(filename, XmlReadMode.Auto);
                }
                catch (Exception error)
                {
                    // (5) In case of errors when retrieving data, send feedback 
                    // to the user. This error will also force cancellation of
                    // all other external data refresh operations.
                    String message = String.Format(
                        "There was an error reading: {0}. Error details: {1}", 
                        filename, 
                        error.ToString());
                    this.Error = new AddonDataHandlerException(message);
                }
    
                // (6) Set this.completed to indicate that the async processing is complete
                // and invoke the Visio Services callback method passing a reference to this
                // custom data provider.
                this.completed = true;
                callback(this);
    
            }
            #endregion
        }
    }
    
  7. In Solution Explorer, right-click the solution name, and then click Build Solution.

  8. Add a CAB project to the solution. To do this, right-click the solution, point to Add, and then click New Project.

  9. Click Installed Templates, expand Other Project Types, expand Setup and Deployment, click Visual Studio Installer, and then click CAB Project.

  10. Name the project CustomDataProviderDeploymentPackage, and then click OK.

  11. Add a project output group to the deployment project: right-click the project, point to ADD, and then click Project Output.

  12. Select Primary Output, and then click OK.

  13. Add another project output group to the deployment project: right-click the project, point to ADD, and then click Project Output.

  14. Select Content Files, and then click OK.

  15. Add a public key (.snk) file to both projects to assign a strong name to the assembly. To do this, click Start, click All Programs, click Microsoft Visual Studio 2010, click Visual Studio Tools, and then click Visual Studio Command Prompt (2010).

  16. In the Command Prompt window, navigate to the project folder.

  17. At the command prompt, type sn /k VisioCustomDataProvider.snk, and then press ENTER.

  18. Right-click the CustomDataProvider project, point to Add, click Existing Item, select the VisioCustomDataProvider.snk file, and then click Add.

  19. Right-click the CustomDataProviderDeploymentPackage project, point to Add, click File, navigate to the project folder, select the VisioCustomDataProvider.snk file, and then click Open.

  20. Select the deployment project, and then in the Properties window, select PostBuildEvent and click the button that appears.

  21. In the Post-build Event Command Line window, paste the following code, and then click OK.

    copy "$(BuiltOuputPath)" "$(ProjectDir)\$(Configuration)\VisioCustomDataProvider.wsp"
    del "$(BuiltOuputPath)"
    
  22. Add a manifest file to the solution. To do this, right-click the CustomDataProvider project, point to Add, and then click New Item.

  23. Under Installed Templates, select Data, select XML File, name the file manifest.xml, and then click Add.

  24. Append the following code to the file.

    <Solution xmlns="https://schemas.microsoft.com/sharepoint/"
              SolutionId="DE30781F-2B54-4513-A921-4EEA58C10868" >
      <Assemblies>
        <Assembly DeploymentTarget="GlobalAssemblyCache" Location="VisioCustomDataProvider.dll"/>
      </Assemblies>
    </Solution>
    
  25. Open the AssemblyInfo.cs file, and append the following line to the file.

    [assembly: AssemblyKeyFile("VisioCustomDataProvider.snk")]
    
  26. Right-click the CustomDataProviderDeploymentPackage project, and then click Build to compile the project.

    Compiling the deployment project produces a .wsp file at the root of the c:\ drive.

Creating and Running the PowerShell Script

Creating and then running a Windows PowerShell script deploys the custom data provider (.wsp file) you created in Visual Studio 2010 to SharePoint Server 2010.

To create and run the Windows PowerShell script

  1. On the SharePoint Server 2010 computer, click Start, and then click SharePoint 2010 Management Shell.

  2. At the command prompt, type cd c:\ and then press ENTER to navigate to the root of the c:\ drive.

  3. At the command prompt, type the following, and then press ENTER.

    Add-SPSolution c:\visiocustomdataprovider.wsp
    
  4. At the command prompt, type the following, and then press ENTER.

    Install-SPSolution visiocustomdataprovider.wsp -GACDeployment
    
  5. After the script is finished running, close the management shell window.

If you need to uninstall the custom data provider later, use the following script.

Get-SPSolution  visiocustomdataprovider.wsp | Uninstall-SPSolution 
Remove-SPSolution visiocustomdataprovider.wsp

Adding a New Trusted Data Provider to Visio Graphics Service

In this step, you add a new trusted data provider to the list of trusted data providers for the Visio Graphics Service in SharePoint Server 2010. This enables you to refresh the Visio drawing from data stored in the data provider on the SharePoint Server 2010 computer. The provider ID that you enter should be of the following form:

Namespace.ClassSimpleName,AssemblySimpleName, Version=version, Culture=culture, PublicKeyToken= token

The following procedure explains how to add a new trusted data provider.

To add a new trusted data provider to Visio Graphics Service

  1. On the SharePoint Server 2010 computer, click Start, and then click SharePoint 2010 Central Administration.

  2. Under Application Management, click Manage service applications.

  3. Click Visio Graphics Service, and then click Trusted Data Providers.

  4. Click Add a new Trusted Data Provider.

  5. For Trusted Data Provider Id, type DataModules.VisioCustomDataProvider,VisioCustomDataProvider, Version=1.0.0.0, Culture=Neutral, PublicKeyToken= yourPublicKeyToken.

    You can find the value of the public key token by looking for the entry for your custom data provider in the c:\Windows\Assembly folder.

  6. For Trusted Data Provider Type, type 6.

  7. For the optional Trusted Data Provider Type Description, type Visio Web Services.

Testing the Sample Custom Data Provider

At this point, if you have not already uploaded the Visio .vdw file you created to a SharePoint Server 2010 document library, you should do so. And if you have not saved the XML file you created to the root folder of the c:\ drive, do that also.

After you upload the .vdw file and deploy the custom data provider and the XML data file to the server that is running Visio Services, you can test the sample. Use the following procedure.

To test the sample custom data provider

  1. In the document library where you uploaded the .vdw file, click the file to render it.

  2. Click Enable (this session) or Enable (always) to enable refresh.

  3. Open the XML file you saved to the server and change some of the data.

  4. Click Refresh in the rendered drawing, and observe how the diagram changes to reflect the changes you made in the XML data.

See Also

Reference

IAsyncResult

Concepts

Visio Services in SharePoint Server 2010

Customizing Visio Web Drawings in the Visio Web Access Web Part