Files
RevitSdkSamples/SDK/Samples/ExternalResourceServer/ExternalResourceDBServer/CS/SampleExternalResourceDBServer.cs
T

704 lines
32 KiB
C#

//
// (C) Copyright 2003-2019 by Autodesk, Inc.
//
// Permission to use, copy, modify, and distribute this software in
// object code form for any purpose and without fee is hereby granted,
// provided that the above copyright notice appears in all copies and
// that both that copyright notice and the limited warranty and
// restricted rights notice below appear in all supporting
// documentation.
//
// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS.
// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF
// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC.
// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE
// UNINTERRUPTED OR ERROR FREE.
//
// Use, duplication, or disclosure by the U.S. Government is subject to
// restrictions set forth in FAR 52.227-19 (Commercial Computer
// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii)
// (Rights in Technical Data and Computer Software), as applicable.
//
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using Autodesk.Revit;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.ExternalService;
namespace Revit.SDK.Samples.ExternalResourceDBServer.CS
{
/// <summary>
/// <para>Derive from the IExternalResourceServer interface to create a server class
/// for providing external resources (files or data) to Revit. This example server
/// provides both keynote data and Revit links.</para>
/// <para>The external resource framework has been designed so that the end user
/// loads external resources by browsing with an "open file" dialog. When the user
/// chooses an external resource server, the file dialog will display the contents
/// of the server's "root folder." From there, the user can navigate through a system
/// of folders and files specified by the IExternalResourceServer implementation. The
/// files and folders might be the actual contents of a directory tree only accessible
/// by the server, or might be some other logical structure relevant to the resource
/// that is being loaded.</para>
/// <para>To demonstrate the flexibility of the framework, this example server retrieves
/// keynote data from a fictitious database for users in France and Germany, and from
/// files for all other users. Revit link models are also obtained from files. To keep
/// the demonstration simple, the "root" folder for file-based resources is assumed to be
/// \SampleResourceServerRoot, located immediately under the directory where the DLL for
/// this project is placed. See the separate *.rtf file for additional documentation.</para>
/// </summary>
public class SampleExternalResourceDBServer : IExternalResourceServer
{
/// <summary>
/// Default constructor
/// </summary>
public SampleExternalResourceDBServer()
{ }
// Methods that must be implemented by a server for any of Revit's external services
#region IExternalServer Implementation
/// Indicate which of Revit's external services this server supports.
/// Servers derived from IExternalResourceServer *must* return
/// ExternalServices.BuiltInExternalServices.ExternalResourceService.
public ExternalServiceId GetServiceId()
{
return ExternalServices.BuiltInExternalServices.ExternalResourceService;
}
/// Uniquely identifies this server to Revit's ExternalService registry
public System.Guid GetServerId()
{
return new Guid("5F3CAA13-F073-4F93-BDC2-B7F4B806CDAF");
}
/// <summary>
/// Implement this method to return the name of the server.
/// </summary>
public System.String GetName()
{
return "SDK Sample ExtRes Server";
}
/// <summary>
/// # Implement this method to return the id of the vendor of the server.
/// </summary>
public System.String GetVendorId()
{
return "ADSK";
}
/// <summary>
/// Provide a short description of the server for display to the end user.
/// </summary>
public System.String GetDescription()
{
return "A Revit SDK sample external resource server which provides keynote data and Revit links.";
}
#endregion IExternalServer Implementation
/// Methods implemented specifically by servers for the ExternalResource service
#region IExternalResourceServer Implementation
public string GetShortName()
{
return GetName();
}
/// <summary>
/// Returns a URL address of the provider of this Revit add-in.
/// </summary>
public virtual String GetInformationLink()
{
return "http://www.autodesk.com";
}
/// <summary>
/// Specify an image to be displayed in browser dialogs when the end user is selecting a resource to load into Revit.
/// </summary>
/// <returns>A string containing the full path to an icon file containing 48x48, 32x32 and 16x16 pixel images.</returns>
public string GetIconPath()
{
return string.Empty;
}
/// <summary>
/// IExternalResourceServer classes can support more than one type of external resource.
/// This one supports keynotes and Revit links.
/// </summary>
public bool SupportsExternalResourceType(ExternalResourceType resourceType)
{
return (resourceType == ExternalResourceTypes.BuiltInExternalResourceTypes.KeynoteTable
||
resourceType == ExternalResourceTypes.BuiltInExternalResourceTypes.RevitLink);
}
/// <summary>
/// Return a list of resources and sub folders under a folder.
/// The Revit user always loads external resources by browsing with a file navigation
/// dialog, much like they would when selecting files on a locally-accessible drive.
/// The SetupBrowserData method allows the server implementer to simulate an organized
/// system of files and folders to support browsing for external resources.
/// Purely for demonstration purposes, this sample server obtains its keynote data from
/// a "database," and creates a "fake" directory structure for either German or French users
/// to browse keynote data. However, for all other users - and for Revit Links, file browsing
/// data is generated using actual files on in a folder location under the directory containing
/// this DLL.
/// </summary>
public void SetupBrowserData(ExternalResourceBrowserData browserData)
{
ExternalResourceMatchOptions matchOptions = browserData.GetMatchOptions();
ExternalResourceType resourceType = matchOptions.ResourceType;
CultureInfo currentCulture = CultureInfo.CurrentCulture;
String currentCultureName = currentCulture.ToString();
// Revit will call SupportsExternalResourceType() before calling this method, so we
// can assume that resourceType will be KeynoteTable or RevitLink.
if (resourceType == ExternalResourceTypes.BuiltInExternalResourceTypes.KeynoteTable
&&
(currentCultureName == "de-DE" || currentCultureName == "fr-FR"))
{
// French and German Keynote Data Are Obtained From a "Database"
SetupKeynoteDatabaseBrowserData(browserData, currentCultureName);
}
else
{
// Keynote Data in Other Languages, and Revit Links, are Obtained From File
SetupFileBasedBrowserData(browserData);
}
}
/// <summary>
/// Checks whether the given ExternalResourceReference is formatted correctly for this server.
/// The format should match one of the formats created in the SetupBrowserData method.
/// </summary>
public bool IsResourceWellFormed(ExternalResourceReference extRef)
{
if ( extRef.ServerId != GetServerId() )
return false;
if ( !extRef.HasValidDisplayPath() )
return false;
// Either the ExternalResourceReference has a valid database key (German/French keynote case) ...
IDictionary<string, string> refMap = extRef.GetReferenceInformation();
if (refMap.ContainsKey(RefMapDBKeyEntry))
{
return KeynotesDatabase.IsValidDBKey(refMap[RefMapDBKeyEntry]);
}
else if (refMap.ContainsKey(RefMapLinkPathEntry)) // ... OR it is a Revit link file
{
return File.Exists(GetFullServerLinkFilePath(extRef));
}
// ... OR it is a keynote file (non- French/German cases).
return File.Exists(GetFullServerKeynoteFilePath(extRef));
}
/// <summary>
/// Implement this method to compare two ExternalResourceReferences.
/// </summary>
/// <param name="referenceInformation_1">The string-string IDictionary of reference information stored in one ExternalResourceReference</param>
/// <param name="referenceInformation_2">The string-string IDictionary of reference information stored in a second ExternalResourceReference</param>
/// <returns></returns>
public virtual bool AreSameResources(IDictionary<string, string> referenceInformation_1, IDictionary<string, string> referenceInformation_2)
{
bool same = true;
if (referenceInformation_1.Count != referenceInformation_2.Count)
{
same = false;
}
else
{
foreach (string key in referenceInformation_1.Keys)
{
if (!referenceInformation_2.ContainsKey(key) || referenceInformation_1[key] != referenceInformation_2[key])
{
same = false;
break;
}
}
}
return same;
}
/// <summary>
/// Servers can override the name for UI purposes, but here we just return the names that we
/// used when we first created the Resources in SetupBrowserData().
/// </summary>
public String GetInSessionPath(ExternalResourceReference err, String savedPath)
{
return savedPath;
}
/// <summary>
/// Loads the resources.
/// </summary>
/// <param name="loadRequestId">A GUID that uniquely identifies this resource load request from Revit.</param>
/// <param name="resourceType">The type of external resource that Revit is asking the server to load.</param>
/// <param name="resourceReference">An ExternalResourceReference identifying which particular resource to load.</param>
/// <param name="loadContext">Context information, including the name of Revit document that is calling the server,
/// </param>the resource that is currently loaded and the type of load operation (automatic or user-driven).
/// <param name="loadContent">An ExternalResourceLoadContent object that will be populated with load data by the
/// server. There are different subclasses of ExternalResourceLoadContent for different ExternalResourceTypes.</param>
public void LoadResource(Guid loadRequestId, ExternalResourceType resourceType, ExternalResourceReference resourceReference, ExternalResourceLoadContext loadContext, ExternalResourceLoadContent loadContent)
{
loadContent.LoadStatus = ExternalResourceLoadStatus.Failure;
// The following checks can help with testing. However, they should not be necessary, since Revit checks all input paramters
// before calling this method.
if (loadRequestId == Guid.Empty)
throw new ArgumentNullException("loadRequestId");
if (resourceType == null)
throw new ArgumentNullException("resourceType");
if (resourceReference == null)
throw new ArgumentNullException("resourceReference");
if (loadContext == null)
throw new ArgumentNullException("loadContext");
if (loadContent == null)
throw new ArgumentNullException("loadContent");
if (!SupportsExternalResourceType(resourceType))
throw new ArgumentOutOfRangeException("resourceType", "The specified resource type is not supported by this server.");
// The server indicates what version of the resource is being loaded.
loadContent.Version = GetCurrentlyAvailableResourceVersion(resourceReference);
// resourceReference is for Keynote Data
if (resourceType == ExternalResourceTypes.BuiltInExternalResourceTypes.KeynoteTable)
{
LoadKeynoteDataResource(resourceReference, loadContent);
}
else // resourceReference is a Revit Link
{
LoadRevitLink(resourceReference, loadContent);
}
}
/// <summary>
/// Indicates whether the given version of a resource is the most current
/// version of the data.
/// </summary>
/// <param name="extRef">The ExternalResourceReference to check.</param>
/// <returns>An enum indicating whether the resource is current, out of date, or of unknown status</returns>
public ResourceVersionStatus GetResourceVersionStatus(ExternalResourceReference extRef)
{
// Determine whether currently loaded version is out of date, and return appropriate status.
String currentlyLoadedVersion = extRef.Version;
if (currentlyLoadedVersion == String.Empty)
return ResourceVersionStatus.Unknown;
return currentlyLoadedVersion == GetCurrentlyAvailableResourceVersion(extRef) ? ResourceVersionStatus.Current
: ResourceVersionStatus.OutOfDate;
}
/// <summary>
/// Implement this to extend the base IExternalResourceServer interface with additional methods
/// that are specific to particular types of external resource (for example, Revit Links).
/// NOTE: There are no extension methods required for keynote resources.
/// </summary>
/// <param name="extensions">An ExternalResourceServerExtensions object that can be populated with
/// sub-interface objects which can perform operations related to specific types of External Resource.</param>
public virtual void GetTypeSpecificServerOperations(ExternalResourceServerExtensions extensions)
{
RevitLinkOperations revitLinkOps = extensions.GetRevitLinkOperations();
//revitLinkOps.SetGetLocalPathForOpenCallback(new GetLinkPathForOpen()); // jeremy
//revitLinkOps.SetOnLocalLinkSharedCoordinatesSavedCallback(new LocalLinkSharedCoordinatesSaved()); // jeremy
}
#endregion IExternalResourceServer Implementation
#region SampleExternalResourceDBServer Implementation
/// <summary>
/// <para>Returns the path of the server's root folder. The contents of this folder will be displayed
/// when the user first selects this server while browsing to load keynote data or a Revit link
/// (unless the user loading keynote data is in France or Germany).</para>
/// <para>For this example server, the root folder is simply a directory immediately under the folder
/// where the DLL for this assembly is located.</para>
/// </summary>
private static String RootFolder
{
get
{
string assemblyFolder = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
string rootFolderName = assemblyFolder + "\\SampleResourceServerRoot";
DirectoryInfo rootFolder = new DirectoryInfo(rootFolderName);
if (!rootFolder.Exists)
rootFolder.Create();
return rootFolderName;
}
}
/// <summary>
/// Returns the string used to access the French and German keynotes database key that is
/// stored in an ExternalResourceReference's reference information string-string Dictionary.
/// See the SetupKeynoteDatabaseBrowserData method.
/// </summary>
private static String RefMapDBKeyEntry
{
get
{
return "DBKey";
}
}
/// <summary>
/// Returns the string used to access the server-based relative path to the Revit link file
/// that is stored in an ExternalResourceReference's reference information string-string Dictionary.
/// </summary>
private static String RefMapLinkPathEntry
{
get
{
return "Path";
}
}
/// <summary>
/// Returns a string specifying the version of an external resource available from the server.
/// </summary>
/// <param name="extResRef">The ExternalResourceReference of the resource whose version is requested.</param>
/// <returns>A string containing the version of the specified resource.</returns>
private String GetCurrentlyAvailableResourceVersion(ExternalResourceReference extResRef)
{
IDictionary<string, string> refMap = extResRef.GetReferenceInformation();
if (refMap.ContainsKey(RefMapDBKeyEntry))
{
return KeynotesDatabase.CurrentVersion;
}
else if (refMap.ContainsKey(RefMapLinkPathEntry)) // ... OR it is a Revit link file
{
String serverLinkPath = GetFullServerLinkFilePath(extResRef);
return GetFileVersion(serverLinkPath);
}
// ... OR it is a keynote file (non- French/German cases).
String serverKeynoteFilePath = GetFullServerKeynoteFilePath(extResRef);
return GetFileVersion(serverKeynoteFilePath);
}
/// <summary>
/// Provides Revit's file browser dialog with information for navigating the
/// fictitious database containing French and German keynotes data.
/// </summary>
private void SetupKeynoteDatabaseBrowserData(ExternalResourceBrowserData browserData, String currentCultureName)
{
string folderPath = browserData.FolderPath;
// To make this demonstration simple and clear, this code creates two sub-folders with names hard-coded
// in French and German, and one keynote data source (must have the extension *.txt) under each of
// these sub-folders.
// To make subsequent recognition of these resources easier (in the server's LoadResource method and
// elsewhere), a database "key" is stored in each resource's string-string Dictionary.
if (currentCultureName == "de-DE")
{
if (folderPath == "/") // Top-level
{
browserData.AddSubFolder("Unterordner1");
browserData.AddSubFolder("Unterordner2");
}
else if (folderPath.EndsWith("/Unterordner1"))
{
var refMap = new Dictionary<String, String>();
refMap[RefMapDBKeyEntry] = "1";
browserData.AddResource("Keynotes1_de-DE.txt", KeynotesDatabase.CurrentVersion, refMap);
}
else if (folderPath.EndsWith("/Unterordner2"))
{
var refMap = new Dictionary<String, String>();
refMap[RefMapDBKeyEntry] = "2";
browserData.AddResource("Keynotes2_de-DE.txt", KeynotesDatabase.CurrentVersion, refMap);
}
}
else if (currentCultureName == "fr-FR")
{
if (folderPath == "/") // Top-level
{
browserData.AddSubFolder("Sous-dossier1");
browserData.AddSubFolder("Sous-dossier2");
}
else if (folderPath.EndsWith("/Sous-dossier1"))
{
var refMap = new Dictionary<String, String>();
refMap[RefMapDBKeyEntry] = "3";
browserData.AddResource("Keynotes1_fr-FR.txt", KeynotesDatabase.CurrentVersion, refMap);
}
else if (folderPath.EndsWith("/Sous-dossier2"))
{
var refMap = new Dictionary<String, String>();
refMap[RefMapDBKeyEntry] = "4";
browserData.AddResource("Keynotes2_fr-FR.txt", KeynotesDatabase.CurrentVersion, refMap);
}
}
}
/// <summary>
/// A convenience utility method. For resources obtained from files on the server, we consider
/// the resource version to be the last-modified date of the file.
/// </summary>
/// <param name="filePath">The full path of a file on disk.</param>
/// <returns>The version (last-modified data) of the specified file.</returns>
private String GetFileVersion(String filePath)
{
FileInfo fileInfo = new FileInfo(filePath);
DateTime lastModifiedTime = fileInfo.LastWriteTimeUtc;
CultureInfo enUs = new CultureInfo("en-us");
return lastModifiedTime.ToString(enUs);
}
/// <summary>
/// Computes the full path of a ExternalResourceReference's keynote data file location on the server.
/// </summary>
/// <param name="extRef">An ExternalResourceReference for a keynote data file stored on this server.</param>
/// <returns>A string representing the full path to the Revit link resource on the server drive.</returns>
private String GetFullServerKeynoteFilePath(ExternalResourceReference extRef)
{
String inSessionPath = extRef.InSessionPath;
String serverName = GetName();
// As an alternative to using the inSessionPath to determine the actual file path, the
// preferred method is to store the relative server path of the file in the
// ExternalResourceReference's referenceInformation (as is done for links).
// This would be particularly true if you were overriding the default in-session path in
// the GetInSessionPath() method.
String serverKeynoteFilePath = inSessionPath.Replace(serverName + "://", RootFolder + "\\");
return serverKeynoteFilePath;
}
/// <summary>
/// <para>Provides Revit's file browser dialog with information for navigating a
/// directory stucture of files available from the server.</para>
/// <para>In this example implementation, the server simply echoes the directories
/// and files that it locates under its RootFolder (subject to the appropriate file
/// type filter pattern). </para>
/// </summary>
private void SetupFileBasedBrowserData(ExternalResourceBrowserData browserData)
{
ExternalResourceMatchOptions matchOptions = browserData.GetMatchOptions();
// filter some resources out by specified filter pattern
ExternalResourceType resourceType = matchOptions.ResourceType;
string filterPattern = resourceType == ExternalResourceTypes.BuiltInExternalResourceTypes.KeynoteTable
? "*.txt"
: "*.rvt";
// Expose a "real" directory structure for the user to browse.
// The server's root folder is specified in the RootFolder property.
string folderPath = browserData.FolderPath;
string path = RootFolder + folderPath.Replace('/', '\\');
if (Directory.Exists(path))
{
DirectoryInfo dir = new DirectoryInfo(path);
DirectoryInfo[] subDirs = dir.GetDirectories();
foreach (DirectoryInfo subDir in subDirs)
{
browserData.AddSubFolder(subDir.Name);
}
FileInfo[] subFiles = dir.GetFiles(filterPattern, SearchOption.TopDirectoryOnly);
foreach (FileInfo file in subFiles)
{
if (resourceType == ExternalResourceTypes.BuiltInExternalResourceTypes.KeynoteTable)
browserData.AddResource(file.Name, GetFileVersion(file.FullName));
else
{
var refMap = new Dictionary<String, String>();
// Relative Path of Link File is Stored in the ExternalResourceReference that
// Will Be Addded to the BrowserData.
refMap[RefMapLinkPathEntry] = folderPath.TrimEnd('/') + '/' + file.Name;
browserData.AddResource(file.Name, GetFileVersion(file.FullName), refMap);
}
}
}
else
{
throw new ArgumentException("Path is invalid");
}
}
/// <summary>
/// Loads the keynote data resources, either from the fictitious French/German database, or from a file.
/// </summary>
/// <param name="resourceReference">An ExternalResourceReference identifying which particular resource to load.</param>
/// <param name="loadContent">An ExternalResourceLoadContent object that will be populated with load data by the
/// server. There are different subclasses of ExternalResourceLoadContent for different ExternalResourceTypes.</param>
private void LoadKeynoteDataResource(ExternalResourceReference resourceReference, ExternalResourceLoadContent loadContent)
{
KeyBasedTreeEntriesLoadContent kdrlc = (KeyBasedTreeEntriesLoadContent)loadContent;
if (kdrlc == null)
throw new ArgumentException("Wrong type of ExternalResourceLoadContent (expecting a KeyBasedTreeEntriesLoadContent) for keynote data.", "loadContent");
kdrlc.Reset();
// Either the ExternalResourceReference has a valid database key (German/French case) ...
IDictionary<string, string> refMap = resourceReference.GetReferenceInformation();
if (refMap.ContainsKey(RefMapDBKeyEntry))
{
try
{
KeynotesDatabase.LoadKeynoteEntries(refMap[RefMapDBKeyEntry], ref kdrlc);
kdrlc.BuildEntries();
loadContent.LoadStatus = ExternalResourceLoadStatus.Success;
}
catch (ArgumentOutOfRangeException)
{
}
catch (ArgumentNullException)
{
}
}
else
{
// ... OR it is a real file (all other cases).
String serverKeynoteFilePath = GetFullServerKeynoteFilePath(resourceReference);
bool doesReadingSucceed = KeynoteEntries.LoadKeynoteEntriesFromFile(serverKeynoteFilePath, kdrlc);
if (doesReadingSucceed)
{
kdrlc.BuildEntries();
loadContent.LoadStatus = ExternalResourceLoadStatus.Success;
}
}
}
/// <summary>
/// Loads a specified Revit link external resource.
/// </summary>
/// <param name="resourceReference">An ExternalResourceReference identifying which particular resource to load.</param>
/// <param name="loadContent">An ExternalResourceLoadContent object that will be populated with load data by the
/// server. There are different subclasses of ExternalResourceLoadContent for different ExternalResourceTypes.</param>
private void LoadRevitLink(ExternalResourceReference resourceReference, ExternalResourceLoadContent loadContent)
{
LinkLoadContent linkLoadContent = (LinkLoadContent)loadContent;
if (linkLoadContent == null)
throw new ArgumentException("Wrong type of ExternalResourceLoadContent (expecting a LinkLoadContent) for Revit links.", "loadContent");
try
{
// Copy the file from the path under the server "root" folder to a secret "cache" folder on the users machine
String fullCachedPath = GetFullLinkCachedFilePath(resourceReference);
String cacheFolder = System.IO.Path.GetDirectoryName(fullCachedPath);
if (!System.IO.Directory.Exists(cacheFolder))
{
System.IO.Directory.CreateDirectory(cacheFolder);
}
String serverLinkPath = GetFullServerLinkFilePath(resourceReference);
System.IO.File.Copy(serverLinkPath, fullCachedPath, true); // Overwrite
ModelPath linksPath = ModelPathUtils.ConvertUserVisiblePathToModelPath(fullCachedPath);
linkLoadContent.SetLinkDataPath(linksPath);
loadContent.LoadStatus = ExternalResourceLoadStatus.Success;
}
catch (System.Exception)
{
}
}
/// <summary>
/// Computes the full path of a Revit link ExternalResourceReference's location on the server.
/// </summary>
/// <param name="resource">An ExternalResourceReference for a Revit link stored on this server.</param>
/// <returns>A string representing the full path to the Revit link resource on the server drive.</returns>
public static String GetFullServerLinkFilePath(ExternalResourceReference resource)
{
if (resource == null)
return "";
IDictionary<String, String> refMap = resource.GetReferenceInformation();
if (!refMap.ContainsKey(RefMapLinkPathEntry))
return "";
return RootFolder + resource.GetReferenceInformation()[RefMapLinkPathEntry].Replace("/", "\\");
}
/// <summary>
/// <para>Returns the path of the root folder of the cache where the server will make
/// local copies of Revit links. For this example server, the cache root folder is
/// simply a directory immediately under the folder where the DLL for this assembly is
/// located.</para>
/// </summary>
private static String LocalLinkCacheFolder
{
get
{
string assemblyFolder = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
string cacheRootFolderName = assemblyFolder + "\\SampleResourceServerLinkCache";
DirectoryInfo cacheRootFolder = new DirectoryInfo(cacheRootFolderName);
if (!cacheRootFolder.Exists)
cacheRootFolder.Create();
return cacheRootFolderName;
}
}
/// <summary>
/// <para>Computes the full path on the end user's local drive where an
/// ExternalResourceReference's link model will be copied when the user loads the
/// link from the server.</para>
///<para>The paths of the local copies relative to this cache root folder will be the
/// same as the paths of the original server copies relative to the Revit links
/// to the root folder on the (compare this method with the GetFullServerLinkFilePath method).</para>
/// </summary>
/// <param name="resource">An ExternalResourceReference for a Revit link stored on this server.</param>
/// <returns>A string representing the full path to the link model on the end user's local drive.</returns>
public static String GetFullLinkCachedFilePath(ExternalResourceReference resource)
{
if (resource == null)
return "";
IDictionary<String, String> refMap = resource.GetReferenceInformation();
if (!refMap.ContainsKey(RefMapLinkPathEntry))
return "";
return LocalLinkCacheFolder + resource.GetReferenceInformation()[RefMapLinkPathEntry].Replace("/", "\\");
}
#endregion SampleExternalResourceDBServer Implementation
#region SampleExternalResourceDBServer Member Variables
#endregion SampleExternalResourceDBServer Member Variables
}
}