Developer Tutorial This developer tutorial will guide you through the steps of: 1. Using the client API to build user interfaces that benefit from the transfer controller and its plug-in architecture; 2. Developing new plug-ins for the client API and Memba Velodoc Outlook Add-In. We highly recommend you read the “Design and Architecture” document first. The “Installation Guide” also describes how to install the source code in a development environment. Client API The client API is a good fit to pilot file transfers from a rich client user interface. We use it in the Memba Velodoc Outlook Add-In. It is not a good fit to transfer files from a web interface. In this case, consider Velodoc XP Edition and its Ajax components. IMPORTANT: The client API has not been designed to work as a server API. It is the client component of a client-server architecture. The client API contains 4 main object types: TransferAgent, ITransferAccount, ITransferPackage and ITransferFIle. Although they are split across two assemblies, Memba.Transfer.ClientAPI.dll and Memba.Transfer.dll, which you need to reference in your projects... 1 Copyright © 2007-2008 Memba SA. All rights reserved. ... they are all part of the Memba.Transfer.ClientAPI namespace and you only need one directive for resolving class names in your code: using Memba.Transfer.ClientAPI; These 4 classes and interfaces have the following responsibilities: A TransferFile object (implementing ITransferFile) represents a file to be transferred; It is the equivalent of an email attachment; A TransferPackage object (implementing ITransferPackage) represents a message to be sent which possibly contains several ITransferFile objects ; A TransferAccount object (implementing ITransferAccount) represents an account to access a file transfer server platform, including Velodoc Enterprise Edition, Velodoc XP Edition, FTP Servers, Microsoft BITS Servers, UNC File Shares and Amazon S3. The TransferAgent object has two functions: o It is a static factory which you will use to create TransferFile, TransferPackage and TransferAccount objects; o It implements the 3 main methods of the API, which are Send, Upload and Download. This is described in the “Architecture and Design” document. Uploading a file Depending on the remote server and the plug-in, uploading a file would generally require credentials. In this example, we have chosen to demonstrate how to get a named account from the persistence store. It is assumed that you have created this account from the account settings dialog box. //Create transfer file string sLocalFile = "C:\\img1.jpg"; ITransferFile objTransferFile = TransferAgent.CreateFile(sLocalFile); //Get upload account ITransferAccount objTransferAccount = TransferAgent.GetAccount("My Account Name"); //Upload TransferAgent objTransferAgent = new TransferAgent(objTransferAccount); objTransferAgent.Upload(ref objTransferFile); //Confirm MessageBox.Show("File uploaded to " + objTransferFile.RemoteFile.AbsoluteUri); You can find a sample implementation of this code in the TestAPI project and in the unit tests. Downloading a file Downloading a file only requires that you now the Uri of the remote file and that you know which plug-in (protocol) to use to download the file. You do not even need an account saved in registry; i.e. the account can be created on the fly, especially with anonymous downloads. 2 Copyright © 2007-2008 Memba SA. All rights reserved. //Create transfer file Uri objRemoteFile = new Uri(("ftp://10.0.0.12/Download/fd033773749946a59926ba18bb8ced23/img1.jpg"); string sFileName = objRemoteFile.Segments[objRemoteFile.Segments.Length - 1]; string sLocalFile = System.IO.Path.Combine("C:\\", sFileName); ITransferFile objTransferFile = TransferAgent.CreateFile(sLocalFile,objRemoteFile); //Create download account ITransferAccount objTransferAccount = TransferAgent.CreateAccount("temp", FTPPlugIn.PLUGINNAME); //Download TransferAgent objTransferAgent = new TransferAgent(objTransferAccount); objTransferAgent.Download(ref objTransferFile); //Confirm MessageBox.Show("File downloaded to " + objTransferFile.LocalFile); You can find a sample implementation of this code in the TestAPI project and in the unit tests. Sending a package Depending on the remote server and the plug-in, sending a package would generally require credentials. You can build your account on the fly, like in the following example, but in this case we get a named account from the persistence store. You should have created this account from the account settings dialog box. //Create package ITransferPackage objTransferPackage = TransferAgent.CreatePackage( "New Package", //Name "joe.bloggs@acme.com", //From "john.smith@world.com", //To "paul.smith@world.com", //Cc "peter.smith@world.com", //Bcc "Hello World!", //Subject "Please find some files attached"); //Body objTransferPackage.IsCompressed = true; objTransferPackage.EncryptionPassword = "my secret"; //Add ‘attachments’ ITransferFile objTransferFile = TransferAgent.CreateFile("C:\\img1.jpg"); objTransferPackage.AddFile(objTransferFile); ITransferFile objTransferFile = TransferAgent.CreateFile("C:\\img2.jpg"); objTransferPackage.AddFile(objTransferFile); //Create sender account ITransferAccount objTransferAccount = TransferAgent.GetAccount("My Account Name"); //Send TransferAgent objTransferAgent = new TransferAgent(objTransferAccount); objTransferAgent.Send(ref objTransferPackage); You can find a sample implementation of this code in the TestAPI project and in the unit tests. Note that you still have to send the email with the links to download the files using an API like System.Net.Mail unless the remote server emits the notification based on the XML manifest received. The manifest is an XML representation of the transfer which can be transferred by the plug-in for the remote server to create records and/or send email notifications. 3 Copyright © 2007-2008 Memba SA. All rights reserved. Testing/debugging with the Mockup Service plug-in If you develop a client interface with the client API, it is easier to test with the Mockup Service plugin implemented in Memba.Transfer.PlugIns.DummyPlugIn.cs (only available in debug mode). The mockup service plug-in simulates a transfer but does not transfer anything. Accordingly it does not require any specific account settings. Developing transfer plug-ins Memba Velodoc transfer plug-ins constitute an abstraction layer which handles the specificities of each file transfer server platform: Velodoc servers, FTP servers, Microsoft BITS servers, Amazon S3 and others. A transfer plug-in for Memba Velodoc Outlook Add-In is a class which inherits from Memba.Transfer.PlugIns.TransferPlugInBase (in assembly Memba.Transfer.dll): public sealed class FTPPlugIn : Memba.Transfer.PlugIns.TransferPlugInBase TransferPlugInBase is an abstract class which implements the ITransferPlugIn interface which has the following Members divided into: Plug-in properties Plug-in capabilities Account settings Remote file information Transfer commands Plug-in properties Plug-in properties describe the parameters required to run the plug-in: string Name { get; } string[] SettingsParams { get; } string[] EncryptedParams { get; } Gets the plug-in name (read-only) Gets an array of settings parameter names. For example, the FTP plug-in returns { “host”, “passivemode”, “uploadvdir”, “username”, “password”, “downloadvdir”, “proxyconfig”, “proxyuri”, “proxyport” } Gets an array of settings parameter names that need to be encrypted in the persistence store. For example, the FTP plug-in return {“password”} The persistence store is the registry. When saving an account created for the FTP plug-in, the following registry names and values will be created under the account key: 4 Copyright © 2007-2008 Memba SA. All rights reserved. There is one specific parameter which is “email”, which when added to SettingsParams will override the sender’s email in the transfer package. This is important in the Outlook plug-in because you may have several Outlook accounts, but only one account on the file transfer server which uses the email as the user identifier. This allows you to send packages from any of your Outlook accounts using always the same account on the file transfer server platform. Plug-in capabilities Plug-in capabilities describe what the plug-in can and cannot do. All these capabilities have a default implementation in TransferPlugInBase and you only need to override the ones which change. bool CanUpload { get; } bool CanDownload { get; } bool IsTransferDelegated { get; } bool CanProcessManifest { get; } 5 Checks whether the current plug-in can upload files. The default implementation in the TransferPlugInBase abstract class returns true. Checks whether the current plug-in can download files. The default implementation in the TransferPlugInBase abstract class returns true. Checks whether the plug-in executes the transfer or delegates the transfer to another process, for example the BITS windows service. This is essentially used not to pause/resume transfers when exiting the controller since the transfers do not execute in the controller process. The default implementation in the TransferPlugInBase abstract class returns false. Checks whether the plug-in (or more exactly the remote service) can process manifests. A manifest is an XML blueprint of the transfer which can be passed to the remote service to create database records or else. This is only used with the Velodoc server platforms. The default implementation in the TransferPlugInBase abstract class returns false. Copyright © 2007-2008 Memba SA. All rights reserved. string HashAlgorithmName { get; } bool UseRegisteredProtocolHandlerForDo wnloads { get; } Gets the hash algorithm used for hashing transferred files (read-only). This name should follow the conventions used by System.Security.Cryptography.CryptoConfig. CreateFromName. The default implementation in the TransferPlugInBase abstract class returns “SHA1”. Checks whether downloads should be handled by a registered protocol handler. For example the browser is the default protocol handler for http: and ftp: (see http://msdn.microsoft.com/enus/library/aa767914(VS.85).aspx). In this case, the controller would launch the browser to execute the download. This capability only applies if CanDownload returns false. The default implementation in the TransferPlugInBase abstract class returns false. Account settings The plug-in members related to account settings are the following and need to be implemented in every plug-in. bool AreSettingsOK(NameValueCollection plugInSettings, out string message); object GetSettingsControl(); Checks plug-in settings and returns an error message if plug-in settings are invalid (returning false). Returns the user control used to display/modify settings in the account settings dialog. The object returned must inherit from UserControl and implement the ITransferPlugInSettings interface.. The method skeletons are created by right-clicking TransferPlugInBase in the class declaration statement and selecting contextual menu “Implement Abstract Class”: 6 Copyright © 2007-2008 Memba SA. All rights reserved. Remote file information The following members represent information about a remote file hosted on a file transfer server platform. GetRemoteFIle and GetRemoteSize need to be implemented by your plug-in. Uri GetRemoteFile(ITransferInfo transferInfo, string localFile, Nullable<Guid> itemId, bool isManifest); long GetRemoteSize(ITransferInfo transferInfo, Uri remoteFile); string GetRemoteContentType(ITransferInfo transferInfo, Uri remoteFile); Computes the remote file uri used for downloads (this method is only used in the context of uploads). This should return the uri required to download the file which may be different from the uri used to upload the file. Gets the size of a remote file (this method is only used in the context of downloads). The size is returned as a number of bytes. Gets the content type of a remote file (this method is only used in the context of downloads). There is a default implementation in TransferPlugInBase which returns the mime type recorded in the registry for the file extension, so you generally do not have to implement this member. Transfer commands The following members execute the transfer commands: start, pause, resume and cancel. They have default implementations in TransferPlugInBase which you do not need to change. void Start(ITransferInfo transferInfo); 7 Starts a new transfer including several files. The default implementation in TransferPlugInBase looks at transferInfo.Direction and if it is an upload, it passes a call to the Upload override (see next table below) to the thread pool and if it Copyright © 2007-2008 Memba SA. All rights reserved. void Pause(ITransferInfo transferInfo); void Resume(ITransferInfo transferInfo); void Cancel(ITransferInfo transferInfo); is a download, it passes a call to the Download override (see below too) to the thread pool. So you only really have to implement upload and download below. Pauses a transfer. The default implementation in TransferPluginBase only changes the status of the TransferInfo to PauseRequested. Your code in the upload and download overrides should periodically query this status to pause the transfer. Resumes a transfer. The default implementation in TransferPluginBase only restarts the transfer by passing an upload or a download to the thread pool. So your upload and download overrides need to be re-entrant and check for the completed status of a TransferItem before uploading or downloading it. Cancels a transfer. The default implementation in TransferPluginBase only changes the status of the TransferInfo to Cancelled. Your code in the upload and download overrides should periodically query this status to cancel the transfer. You only need to override these two virtual members of TransferPlugInBase: protected override void Executes the upload defined in a TransferInfo Upload(object state) object. protected override void Executes the download defined in a TransferInfo Download(object state) object. These two methods are obviously the most important part of your plug-in. We have completed 6 implementations which are open-source and which constitute sample code to learn from: The FTP plug-in, The UNC file share plug-in, The BITS plug-in, The Amazon S3 plug-in, The Velodoc XP plug-in (based on WCF web services), The Velodoc Enterprise Edition plug-in (based on BITS too). Building and testing your plug-in You may find easier to test your plug-in with the TestAPI winforms application than with the Outlook add-in and I strongly encourage you to build unit tests for your plug-in using the existing unit tests as a blueprint. Installing your plug-in In order for your plug-in to run flawlessly, it is necessary to sign the assembly with a strong name and to add a membership condition to the Memba.Transfer.1 code group: 8 Copyright © 2007-2008 Memba SA. All rights reserved. This can easily be done by executing Memba.Transfer.AddIns.AddInInstaller with the InstallUtil installer tool. Building the Visual Studio solution Building the Memba Velodoc Outlook Add-In is a standard Visual Studio 2008 build process. There are a few known issues: Known issue 1 If you are using source control, the Release version will not build if you do not check out the following two files from the setup project: Memba.Transfer.AddIns.Outlook2007.dll.manifest Memba.Transfer.AddIns.Outlook2007.vsto 9 Copyright © 2007-2008 Memba SA. All rights reserved. Known issue 2 Apparently you cannot exclude permanently the following files from the setup project: Microsoft.Office.Interop.Outlook.dll (v.11) Microsoft.Office.Interop.Outlook.dll (v.12) Microsoft.Office.Interop.SmartTag.dll (v.11) Microsoft.Office.Interop. SmartTag.dll (v.12) Microsoft.Office.Interop.Word.dll (v.11) Microsoft.Office.Interop. Word.dll (v.12) Microsoft.Vbe.Interop.dll (v.11) Microsoft.Vbe.Interop.dll (v.12) Office.dll (v.11) Office.dll (v.12) Each time you reload your solution, they get reloaded so you need to select them all as shown below, right-click to display the contextual menu and select Exclude before you build your setup. 10 Copyright © 2007-2008 Memba SA. All rights reserved. Known issue 3 Sometimes the setup you generate will fail to load properly in Outlook 2007 with the following error: “File ... has a different computed hash than specified in the manifest”: 11 Copyright © 2007-2008 Memba SA. All rights reserved. If this occurs, you need to: 1. 2. 3. 4. Close Visual Studio; Re-open the solution; Execute the steps described in Known Issue 1 and Known Issue 2 above Rebuild your setup This works all the time for us. I hope this will work for you too. 12 Copyright © 2007-2008 Memba SA. All rights reserved.