In Focus

ASP.NET MVC 5 - DocuSign - Getting, Storing, Listing And Downloading The Document(s) In Our Web Application

In this article, we will see how to get documents from DocuSign and store them in our local directory as the file and list in our web application.

Introduction
 
In this article, we will see how to get the document(s) from DocuSign using envelope id, store it to a local directory, and list and download in the web application view. Please take a look at my previous articles for basic account creation, integration, validation, and creation of a signature request on a document, storing the envelope information, sign on a document and track envelopes within our application.
Let's move forward to get and download the document(s) for respective envelopes.
 
Prerequisites
  • Visual Studio
  • Basic knowledge of ASP.NET MVC
  • Basic knowledge of C#
  • Should have an account on DocuSign
Article Flow 
  • Get document(s) using Envelop id and Store document(s) to Local Directory
  • List document(s) in view
  • Download document(s)
Get document(s) using Envelope id and Store document(s) to Local Directory
 
In the last article, we have seen how to view the document using mailbox or DocuSign portal. Now, let's try to get the document from DocuSign to our application. We can get the documents using a DocuSign account and recipient envelope id. In the below code, we are getting an account id by passing the DocuSign credentials.
  1. public string loginApi(string usr, string pwd) {  
  2.     // we set the api client in global config when we configured the client  
  3.     ApiClient apiClient = Configuration.Default.ApiClient;  
  4.     string authHeader = "{\"Username\":\"" + usr + "\", \"Password\":\"" + pwd + "\", \"IntegratorKey\":\"" + INTEGRATOR_KEY + "\"}";  
  5.     Configuration.Default.AddDefaultHeader("X-DocuSign-Authentication", authHeader);  
  6.     // we will retrieve this from the login() results  
  7.     string accountId = null;  
  8.     // the authentication api uses the apiClient (and X-DocuSign-Authentication header) that are set in Configuration object  
  9.     AuthenticationApi authApi = new AuthenticationApi();  
  10.     LoginInformation loginInfo = authApi.Login();  
  11.     // find the default account for this user  
  12.     foreach(DocuSign.eSign.Model.LoginAccount loginAcct in loginInfo.LoginAccounts) {  
  13.         if (loginAcct.IsDefault == "true") {  
  14.             accountId = loginAcct.AccountId;  
  15.             break;  
  16.         }  
  17.     }  
  18.     if (accountId == null) { // if no default found set to first account  
  19.         accountId = loginInfo.LoginAccounts[0].AccountId;  
  20.     }  
  21.     return accountId;  
  22. }  
And, we have stored the recipient's envelope information in our local database. So, we can get the envelope information by calling the recipient table. Now, let's loop the table values. 
  1. List < DocusignDemo.Models.Recipient > recipientsDocs = new List < DocusignDemo.Models.Recipient > ();  
  2. public ActionResult ListDocuments() {  
  3.     ApiClient apiClient = new ApiClient("https://demo.docusign.net/restapi");  
  4.     Configuration.Default.ApiClient = apiClient;  
  5.     MyCredential myCredential = new MyCredential();  
  6.     // call the Login() API which sets the user's baseUrl and returns their accountId  
  7.     string accountId = loginApi(myCredential.UserName, myCredential.Password);  
  8.     DocusignDemo.Models.CSharpCornerEntities cSharpCornerEntities = new DocusignDemo.Models.CSharpCornerEntities();  
  9.     var recipients = cSharpCornerEntities.Recipients.ToList();  
  10.     string serverDirectory = Server.MapPath("~/Uploadfiles/");  
  11.     if (!Directory.Exists(serverDirectory)) {  
  12.         Directory.CreateDirectory(serverDirectory);  
  13.     }  
  14.     foreach(var recipient in recipients) {  
  15.         if (recipient.Name == "GnanavelSekar") {  
  16.             string recipientDirectory = Server.MapPath("~/Uploadfiles/" + recipient.EnvelopeID);  
  17.             if (!Directory.Exists(recipientDirectory)) {  
  18.                 Directory.CreateDirectory(recipientDirectory);  
  19.             }  
  20.             EnvelopeDocumentsResult documentList = ListEnvelopeDocuments(accountId, recipient.EnvelopeID);  
  21.             int i = 0;  
  22.             string SignedPDF = string.Empty;  
  23.             EnvelopesApi envelopesApi = new EnvelopesApi();  
  24.             foreach(var document in documentList.EnvelopeDocuments) {  
  25.                 string signingStatus = recipient.Status == "completed" ? "Signed" : "Yet to Sign";  
  26.                 MemoryStream docStream = (MemoryStream) envelopesApi.GetDocument(accountId, recipient.EnvelopeID, documentList.EnvelopeDocuments[i].DocumentId);  
  27.                 string documentName = document.Name != "Summary" ? document.Name : "Summary";  
  28.                 SignedPDF = Server.MapPath("~/Uploadfiles/" + recipient.EnvelopeID + "/" + recipient.EnvelopeID + "_" + documentName + ".pdf");  
  29.                 using(var fileStream = System.IO.File.Create(SignedPDF)) {  
  30.                     docStream.Seek(0, SeekOrigin.Begin);  
  31.                     docStream.CopyTo(fileStream);  
  32.                 }  
  33.                 recipientsDocs.Add(new DocusignDemo.Models.Recipient {  
  34.                     EnvelopeID = recipient.EnvelopeID, Name = recipient.Name, Email = recipient.Email, Status = signingStatus, documentURL = SignedPDF, SentOn = recipient.SentOn, UpdatedOn = recipient.UpdatedOn  
  35.                 });  
  36.                 i++;  
  37.             }  
  38.         }  
  39.     }  
  40.     return View(recipientsDocs);  
  41. }  
In the above code, we are getting the list of recipients. For that, I have created the list object to hold it. Then, we have created the local directory to store the recipient documents. Now, let's loop the recipient to get the list of documents. And we have created a directory for each recipient envelope. 
  1. public EnvelopeDocumentsResult ListEnvelopeDocuments(string accountId, string envelopeId) {  
  2.     EnvelopesApi envelopesApi = new EnvelopesApi();  
  3.     EnvelopeDocumentsResult docsList = envelopesApi.ListDocuments(accountId, envelopeId);  
  4.     return docsList;  
  5. }  
Every time, we will get the two documents for each envelop.
  • Sent document with/without Signature 
  • Certified document - It represents the Summary document; it contains the information, such as sender details, recipient details, etc.
List document(s) in View
 
We have got the list of the documents in "recipientsDocs" object. Now, let's create a strongly typed view to list these documents.
  1. @model IEnumerable<DocusignDemo.Models.Recipient>    
  2. @{    
  3. /**/    
  4. ViewBag.Title = "ListDocuments";    
  5. Layout = "~/Views/Shared/_Layout.cshtml";    
  6. }    
  7. <head>  
  8.     <meta charset="utf-8">  
  9.     <meta name="viewport" content="width=device-width, initial-scale=1">  
  10.     <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">  
  11.     <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>  
  12.     <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>  
  13. </head>  
  14.   
  15. <body style="margin-top:20px">  
  16.     <div class="container">  
  17.         <div class="table-responsive">  
  18.             <table class="table table-bordered">  
  19.                 <thead class="btn-primary">  
  20.                     <tr>  
  21.                         <th> @Html.DisplayNameFor(model => model.Name) </th>  
  22.                         <th> @Html.DisplayNameFor(model => model.Email) </th>  
  23.                         <th> @Html.DisplayNameFor(model => model.EnvelopeID) </th>  
  24.                         <th> @Html.DisplayNameFor(model => model.Status) </th>  
  25.                         <th> @Html.DisplayNameFor(model => model.SentOn) </th>  
  26.                         <th> @Html.DisplayNameFor(model => model.UpdatedOn) </th>  
  27.                         <th> @Html.DisplayNameFor(model => model.documentURL) </th>  
  28.                     </tr>  
  29.                 </thead>  
  30.                 <tbody>  
  31.                   @foreach (var item in Model)    
  32.                   {    
  33.                      <tr>  
  34.                          <td> @Html.DisplayFor(modelItem => item.Name) </td>  
  35.                          <td> @Html.DisplayFor(modelItem => item.Email) </td>  
  36.                          <td> @Html.DisplayFor(modelItem => item.EnvelopeID) </td>  
  37.                          <td> @Html.DisplayFor(modelItem => item.Status) </td>  
  38.                          <td> @Html.DisplayFor(modelItem => item.SentOn) </td>  
  39.                          <td> @Html.DisplayFor(modelItem => item.UpdatedOn) </td>  
  40.                          <td> @Html.DisplayFor(modelItem => item.documentURL) </td>  
  41.                      </tr>  
  42.                     }   
  43.                 </tbody>  
  44.             </table>  
  45.         </div>  
  46.     </div>  
  47. </body>   
Now, run your application.
 
Output 
 
I made a few more signature requests to the below recipients.
 
 
 
Now, you can see the "Yet to Sign" status which is recently sent.
 
 
 
Download document(s)
 
Still, we have shown the local directory path in documentUrl so, let's change that into the link to download the respective document
@Html.ActionLink(item.Status, "Download", "Docusign", new { filePath = item.documentURL }, null) 
Now, create a download action DocuSign controller to download the file from the respective path. I am passing the input parameter "filePath " value while calling the Download action.
  1. public FileResult Download(string filePath) {  
  2.     string fileName = Path.GetFileName(filePath);  
  3.     string contentType = "application/pdf";  
  4.     return File(filePath, contentType, fileName);  
  5. }  
Now, run your application.
 
 
 
Complete View
  1. @model IEnumerable<DocusignDemo.Models.Recipient>    
  2. @{    
  3. /**/    
  4. ViewBag.Title = "ListDocuments";    
  5. Layout = "~/Views/Shared/_Layout.cshtml";    
  6. }    
  7. <head>  
  8.     <meta charset="utf-8">  
  9.     <meta name="viewport" content="width=device-width, initial-scale=1">  
  10.     <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">  
  11.     <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>  
  12.     <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>  
  13. </head>  
  14.   
  15. <body style="margin-top:20px">  
  16.     <div class="container">  
  17.         <div class="table-responsive">  
  18.             <table class="table table-bordered">  
  19.                 <thead class="btn-primary">  
  20.                     <tr>  
  21.                         <th> @Html.DisplayNameFor(model => model.Name) </th>  
  22.                         <th> @Html.DisplayNameFor(model => model.Email) </th>  
  23.                         <th> @Html.DisplayNameFor(model => model.EnvelopeID) </th> @*<th> @Html.DisplayNameFor(model => model.Status) </th>*@ <th> @Html.DisplayNameFor(model => model.SentOn) </th>  
  24.                         <th> @Html.DisplayNameFor(model => model.UpdatedOn) </th>  
  25.                         <th> Document </th>  
  26.                     </tr>  
  27.                 </thead>  
  28.                 <tbody> @foreach (var item in Model) { <tr>  
  29.                         <td> @Html.DisplayFor(modelItem => item.Name) </td>  
  30.                         <td> @Html.DisplayFor(modelItem => item.Email) </td>  
  31.                         <td> @Html.DisplayFor(modelItem => item.EnvelopeID) </td> @*<td> @Html.DisplayFor(modelItem => item.Status) </td>*@ <td> @Html.DisplayFor(modelItem => item.SentOn) </td>  
  32.                         <td> @Html.DisplayFor(modelItem => item.UpdatedOn) </td>  
  33.                         <td> @*@Html.DisplayFor(modelItem => item.documentURL)*@ @Html.ActionLink(item.Status, "Download""Docusign"new { filePath = item.documentURL }, null) </td>  
  34.                     </tr> } </tbody>  
  35.             </table>  
  36.         </div>  
  37.     </div>  
  38. </body>  
Complete Controller 
  1. using DocuSign.eSign.Api;  
  2. using DocuSign.eSign.Client;  
  3. using DocuSign.eSign.Model;  
  4. using DocusignDemo.Models;  
  5. using Newtonsoft.Json;  
  6. using System.Collections.Generic;  
  7. using System.Data.Entity;  
  8. using System.IO;  
  9. using System.Linq;  
  10. using System.Web;  
  11. using System.Web.Mvc;  
  12. using Document = DocuSign.eSign.Model.Document;  
  13. namespace DocusignDemo.Controllers {  
  14.     public class DocusignController: Controller {  
  15.         public string loginApi(string usr, string pwd) {  
  16.             // we set the api client in global config when we configured the client  
  17.             ApiClient apiClient = Configuration.Default.ApiClient;  
  18.             string authHeader = "{\"Username\":\"" + usr + "\", \"Password\":\"" + pwd + "\", \"IntegratorKey\":\"" + INTEGRATOR_KEY + "\"}";  
  19.             Configuration.Default.AddDefaultHeader("X-DocuSign-Authentication", authHeader);  
  20.             // we will retrieve this from the login() results  
  21.             string accountId = null;  
  22.             // the authentication api uses the apiClient (and X-DocuSign-Authentication header) that are set in Configuration object  
  23.             AuthenticationApi authApi = new AuthenticationApi();  
  24.             LoginInformation loginInfo = authApi.Login();  
  25.             // find the default account for this user  
  26.             foreach(DocuSign.eSign.Model.LoginAccount loginAcct in loginInfo.LoginAccounts) {  
  27.                 if (loginAcct.IsDefault == "true") {  
  28.                     accountId = loginAcct.AccountId;  
  29.                     break;  
  30.                 }  
  31.             }  
  32.             if (accountId == null) { // if no default found set to first account  
  33.                 accountId = loginInfo.LoginAccounts[0].AccountId;  
  34.             }  
  35.             return accountId;  
  36.         }  
  37.         List < DocusignDemo.Models.Recipient > recipientsDocs = new List < DocusignDemo.Models.Recipient > ();  
  38.         public ActionResult ListDocuments() {  
  39.             ApiClient apiClient = new ApiClient("https://demo.docusign.net/restapi");  
  40.             Configuration.Default.ApiClient = apiClient;  
  41.             MyCredential myCredential = new MyCredential();  
  42.             // call the Login() API which sets the user's baseUrl and returns their accountId  
  43.             string accountId = loginApi(myCredential.UserName, myCredential.Password);  
  44.             DocusignDemo.Models.CSharpCornerEntities cSharpCornerEntities = new DocusignDemo.Models.CSharpCornerEntities();  
  45.             var recipients = cSharpCornerEntities.Recipients.ToList();  
  46.             string serverDirectory = Server.MapPath("~/Uploadfiles/");  
  47.             if (!Directory.Exists(serverDirectory)) {  
  48.                 Directory.CreateDirectory(serverDirectory);  
  49.             }  
  50.             foreach(var recipient in recipients) {  
  51.                 string recipientDirectory = Server.MapPath("~/Uploadfiles/" + recipient.EnvelopeID);  
  52.                 if (!Directory.Exists(recipientDirectory)) {  
  53.                     Directory.CreateDirectory(recipientDirectory);  
  54.                 }  
  55.                 EnvelopeDocumentsResult documentList = ListEnvelopeDocuments(accountId, recipient.EnvelopeID);  
  56.                 int i = 0;  
  57.                 string SignedPDF = string.Empty;  
  58.                 EnvelopesApi envelopesApi = new EnvelopesApi();  
  59.                 foreach(var document in documentList.EnvelopeDocuments) {  
  60.                     string signingStatus = recipient.Status == "completed" ? "Signed" : "Yet to Sign";  
  61.                     MemoryStream docStream = (MemoryStream) envelopesApi.GetDocument(accountId, recipient.EnvelopeID, documentList.EnvelopeDocuments[i].DocumentId);  
  62.                     string documentName = document.Name != "Summary" ? document.Name : "Summary";  
  63.                     SignedPDF = Server.MapPath("~/Uploadfiles/" + recipient.EnvelopeID + "/" + recipient.EnvelopeID + "_" + documentName + ".pdf");  
  64.                     using(var fileStream = System.IO.File.Create(SignedPDF)) {  
  65.                         docStream.Seek(0, SeekOrigin.Begin);  
  66.                         docStream.CopyTo(fileStream);  
  67.                     }  
  68.                     recipientsDocs.Add(new DocusignDemo.Models.Recipient {  
  69.                         EnvelopeID = recipient.EnvelopeID, Name = recipient.Name, Email = recipient.Email, Status = signingStatus, documentURL = SignedPDF, SentOn = recipient.SentOn, UpdatedOn = recipient.UpdatedOn  
  70.                     });  
  71.                     i++;  
  72.                 }  
  73.             }  
  74.             return View(recipientsDocs);  
  75.         }  
  76.         public EnvelopeDocumentsResult ListEnvelopeDocuments(string accountId, string envelopeId) {  
  77.             EnvelopesApi envelopesApi = new EnvelopesApi();  
  78.             EnvelopeDocumentsResult docsList = envelopesApi.ListDocuments(accountId, envelopeId);  
  79.             return docsList;  
  80.         }  
  81.         public FileResult Download(string filePath) {  
  82.             string fileName = Path.GetFileName(filePath);  
  83.             string contentType = "application/pdf";  
  84.             return File(filePath, contentType, fileName);  
  85.         }  
  86.     }  
  87.     public class MyCredential {  
  88.         public string UserName {  
  89.             get;  
  90.             set;  
  91.         } = ""//Enter Docusign Username  
  92.         public string Password {  
  93.             get;  
  94.             set;  
  95.         } = ""//Enter Docusign Password  
  96.     }  
  97. }  
Model 
  1. namespace DocusignDemo.Models {  
  2.     using System;  
  3.     using System.Collections.Generic;  
  4.     public partial class Recipient {  
  5.         public long Id {  
  6.             get;  
  7.             set;  
  8.         }  
  9.         public string Name {  
  10.             get;  
  11.             set;  
  12.         }  
  13.         public string Email {  
  14.             get;  
  15.             set;  
  16.         }  
  17.         public string EnvelopeID {  
  18.             get;  
  19.             set;  
  20.         }  
  21.         public byte[] Documents {  
  22.             get;  
  23.             set;  
  24.         }  
  25.         public string Description {  
  26.             get;  
  27.             set;  
  28.         }  
  29.         public string Status {  
  30.             get;  
  31.             set;  
  32.         }  
  33.         public Nullable < System.DateTime > SentOn {  
  34.             get;  
  35.             set;  
  36.         }  
  37.         public Nullable < System.DateTime > UpdatedOn {  
  38.             get;  
  39.             set;  
  40.         }  
  41.         public string documentURL {  
  42.             get;  
  43.             set;  
  44.         }  
  45.     }  
  46. }  
Refer to the attached project for reference. I have attached the demonstrated project without package due to the size limit.
 
Summary
 
In this article, we discussed how to get the document(s) from DocuSign using envelope id, store them to a local directory, and list and download those into our web application view. I hope it will help you. Your valuable feedback and comments about this article are always welcome.