Writing a Download Handler for KTA

As much as I like KTA’s Forms and especially the WebCapture control, there’s no out-of-the box solution for downloading files. Just imagine: while the control can display (most) files including PDF and office formats, you can never just simply download them. Well, it’s time to change that.

Above GIF shows you everything in action: I just select a document form a folder, click on my download button, and et voilà: here’s my PDF. All you need is KTA’s API, and a small Generic Handler written in .NET. In this tutorial, I’m going to use C#, as always.

We’ll be making use of the GetDocument method  from the CaptureDocumentService class – this method allows us to retrieve any document stored in KTA’s document repository. That’s ideal for most scenarios where you use capture activities, or just the WebCapture control itself – all we need is the document id (and of course, a session id). But how are we to call the GetDocument method? I decided to go for a small generic (web) handler. You can think of it as a simple web page that is hosted in the Internet Information Server (IIS) that we can call from within our KTA forms – or even outside of them, if that’s what you want. The good thing here: a web handler can be written in minutes with Visual Studio as there’s a template for it, and the infrastructure (the IIS) already exists.

Writing the ASP.NET ASHX Handler

First, let’s select ASP.NET Web Application. We will be starting with an empty template.

Selecting a new ASP.NET Web Application
Starting with an empty template

After the solution is created, we add a new Generic Handler named and FileHandler.ashx  to our project:

Note that there is a single method that’s relevant to us right now:

public void ProcessRequest(HttpContext context)
{
  context.Response.ContentType = "text/plain";
  context.Response.Write("Hello World");
}

This is what the template provided us with. If we were to call our handler right now, we’d see a simple web page containing “Hello World” (in fact, we don’t even return HTML but plain text as stated in the headers, however almost any browsers can display plain text).

Now, here comes the part were we connect our handler with TotalAgility. As we want to make use of KTA’s API, we have to add the correct references. I won’t go into too much detail here as this is already covered in KTA’s API documentation. I also decided to add the session id into the web.config section:

<appSettings>
 <add key="IsMultitenantDeployment" value="false" />
 <add key="SdkServicesLocation" value="http://localhost/TotalAgility/Services/SDK" />
 <add key="ClientSettingsProvider.ServiceUri" value="" />
 <add key="SessionId" value="3F80668AE02E314E860D648BE4CF42A3" />
</appSettings>

In addition, we need to get a document by id from KTA’s repository. That’s simple enough using the API. In addition, I created a small class to represent the file that we are about to return:


private ResponseFile GetDocumentUsingAPI(string SessionId, string DocId)
{
    // gets a doc from the repository using KTA's API            
    ResponseFile f = new ResponseFile();
    CaptureDocumentService cds = new CaptureDocumentService();
    Document d = cds.GetDocument(SessionId, null, DocId);
    f.FileName = d.FileName;
    f.MimeType = d.MimeType;
            
    Stream s = cds.GetDocumentFile(SessionId, null, DocId, f.Extension);        
    using (MemoryStream ms = new MemoryStream())
    {
        s.CopyTo(ms);
        f.Content = ms.ToArray();
    }
    return f;
}
public class ResponseFile
{
    public byte[] Content { get; set; }
    public string MimeType { get; set; }        
    public string Extension { get; private set; }
    private string fileName;
    public string FileName
    {
        get
        {
            return fileName;
        }

        set
        {
            Extension = Path.GetExtension(value);
            fileName = value;
        }
    }
}

Almost done! Calling our GetDocumentUsingAPI method with a valid document id returns a ResponseFile object – i.e. our file containing all relevant data and metadata (such as the extension, the mime type and the filename). Now, we just call said method from the handler’s ProcessRequest method:


public void ProcessRequest(HttpContext context)
{
    string sessionId = ConfigurationManager.AppSettings["SessionId"];
                       
    // get the parameters from the request
    string docId = context.Request.Params.Get("docId"); // anyone could get any document

    ResponseFile file = GetDocumentUsingAPI(sessionId, docId);
    HttpResponse response = HttpContext.Current.Response;
    response.ClearContent();
    response.Clear();
    response.ContentType = file.MimeType;
    response.AddHeader("Content-Disposition",
                        "inline; filename=" + file.FileName + ";");
    response.BinaryWrite(file.Content);
    response.Flush();
    response.End();
}

Note that I decided to provide the document’s guid in an URL parameter called “docId”. So, a sample request would look like this:

http://localhost/AgilityHelper/FileHandler.ashx?docId=bf0adbbd-dda3-44b5-b081-a7b5014300a3

You guessed it: the URL above would return the document with the GUID bf0adbbd-dda3-44b5-b081-a7b5014300a3. In addition, I decided to add a header telling the browser to use inline as Content-Disposition. Essentially, that translates to: if you can display it directly in the browser, do so. Otherwise, download it. In my case images such as PNG files or PDFs are thus rendered directly in the browser – other files are downloaded immediately (such as office files).

Let’s give it a test drive:

From this point on, everything is straight-forward: Visual Studio allows you to publish your application to the local IIS with the click of a button.

Calling the Handler from a KTA Form

The rest is simple: in a KTA form, just create a redirect action. You can call the action from any event, such as a button click:

Additional Notes

A head’s up first: we make use of KTA’s CaptureDocumentService, in particular the GetDocument method. While this method works just fine for any document type KTA supports (i.e. most images, office files, PDFs), it will fail with any other type (e.g. MP3 files or videos). I raised an Enhancement Request at Kofax many months ago, for the time being it might we smarter to directly get the BLOBs from KTA’s database if you your file handler to support additional (any) formats.

In addition, please keep in mind that there is no security provided in this sample: anyone with the link or even the document GUID could just download the file. In a real-world scenario you might want to authenticate the users first – thankfully KTAs API offers a solution for that, too.

And a special thanks to Christoph who helped me with the Handler part!