ASP.NET MVC 5 - DocuSign - Send A Document For Signature From Web Application

Introduction
 
In this article, I will demonstrate how to send a document for signature from ASP.NET MVC5 web application using DocuSign. Please take a look at this DocuSign Part-1 article for basic account creation, integration, and validation with our application. Let's move forward to do a signing request.
 
Prerequisites 
  • Visual Studio
  • Basic Knowledge of ASP.NET MVC
  • Basic Knowledge of C#
  • Should have an account in DocuSign
Article Flow 
  • Create an ASP.NET MVC Empty project
  • Create a Controller and Design a View
  • Integrate DocuSign
  • Send the Document for a Sign
  • Validate in DocuSign and Email
Create an ASP.NET MVC Empty project 
  • To create an ASP.NET MVC empty project, follow the below steps one by one. Here, I have used Visual Studio 2017.
  • Select New Project -> Visual C# -> Web -> ASP.NET Web Application and enter your application name. Here, I named it "DocusignDemo".
  • Now, click OK.
  • Then, select Empty ASP.NET MVC template and click OK to create the project.
  • Once you click OK, the project will be created with the basic architecture of MVC. If you are not aware of how to create an Empty ASP.NET Web Application, please visit Step 1 and Step 2
Once you complete these steps, you will get the screen as below.
 
 
 
Create a Controller and Design a View
 
Now, create an empty Controller and View. Here, I have created a Controller with the name of "DocusignController". Whenever we create an empty Controller, it is created with an empty Index action method. And create an empty View of this action method "Index". Here we will create an action with the name of "SendDocumentforSign". And create a model to create a strongly typed view.
  1. public partial class Recipient {  
  2.     public string Name {  
  3.         get;  
  4.         set;  
  5.     }  
  6.     public string Email {  
  7.         get;  
  8.         set;  
  9.     }  
  10.     public string Description {  
  11.         get;  
  12.         set;  
  13.     }  
  14. }  
Now, create a strongly typed view with this model. I have created the view as below,
 
To get the same design and control paste the below code in your view.
  1. @model DocusignDemo.Models.Recipient  
  2. @{  
  3. /**/  
  4. ViewBag.Title = "SendDocumentforSign";  
  5. }  
  6. @using (Html.BeginForm("SendDocumentforSign""Docusign", FormMethod.Post, new { enctype = "multipart/form-data", id="SendForsign" }))  
  7. {  
  8. @Html.AntiForgeryToken()  
  9. <br />  
  10. <div class="panel panel-primary col-md-6">  
  11. <div class="panel-heading">Send For Sign</div>  
  12. <div class="panel-body" >  
  13. <div class="form-horizontal">  
  14. <hr />  
  15. @Html.ValidationSummary(true""new { @class = "text-danger" })  
  16. <div class="form-group">  
  17. @Html.LabelFor(model => model.Name, htmlAttributes: new { @class = "control-label col-md-2" })  
  18. <div class="col-md-10">  
  19. @Html.EditorFor(model => model.Name, new { htmlAttributes = new { @class = "form-control" } })  
  20. @Html.ValidationMessageFor(model => model.Name, ""new { @class = "text-danger" })  
  21. </div>  
  22. </div>  
  23. <div class="form-group">  
  24. @Html.LabelFor(model => model.Email, htmlAttributes: new { @class = "control-label col-md-2" })  
  25. <div class="col-md-10">  
  26. @Html.EditorFor(model => model.Email, new { htmlAttributes = new { @class = "form-control" } })  
  27. @Html.ValidationMessageFor(model => model.Email, ""new { @class = "text-danger" })  
  28. </div>  
  29. </div>  
  30. <div class="form-group">  
  31. @Html.Label("Document", htmlAttributes: new { @class = "control-label col-md-2" })  
  32. <div class="col-md-10">  
  33. <input id="UploadDocument" type="file" name="UploadDocument" class="form-control" />  
  34. </div>  
  35. </div>  
  36. <div class="form-group">  
  37. @Html.LabelFor(model => model.Description, htmlAttributes: new { @class = "control-label col-md-2" })  
  38. <div class="col-md-10">  
  39. @Html.EditorFor(model => model.Description, new { htmlAttributes = new { @class = "form-control" } })  
  40. @Html.ValidationMessageFor(model => model.Description, ""new { @class = "text-danger" })  
  41. </div>  
  42. </div>  
  43. <div class="form-group">  
  44. <div class="col-md-offset-2 col-md-10">  
  45. <input type="submit" value="Send For Sign" class="btn btn-primary" />  
  46. </div>  
  47. </div>  
  48. </div>  
  49. </div>  
  50. </div>  
  51. }  
  52. <script src="~/Scripts/jquery-1.10.2.min.js"></script>  
  53. <script src="~/Scripts/jquery.validate.min.js"></script>  
  54. <script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script>  
Integrate DocuSign
 
We have seen the DocuSign integration in my previous article with DocuSign.Integrations.Client.dll. But it's not comfortable for a beginner so I will go with another NuGet package for easier understanding, and there are no major changes in the code. Okay, let's take a look and install Docusign.eSign.dll from the NuGet.
 
 
 
Send the Document for a Sign
 
Now, create a post action in our controller as below to receive the data from view and to send the document to sign.
  1. [HttpPost]  
  2. public ActionResult SendDocumentforSign(DocusignDemo.Models.Recipient recipient, HttpPostedFileBase UploadDocument)  
  3. {  
  4. }   
Create a Folder Dynamically in our code to store the sending documents
  1. string directorypath = Server.MapPath("~/App_Data/" + "Files/");  
  2. if (!Directory.Exists(directorypath))  
  3. {  
  4. Directory.CreateDirectory(directorypath);  
  5. }  
Here, we will the namespace as below,
  1. using DocuSign.eSign.Api;  
  2. using DocuSign.eSign.Client;  
  3. using DocuSign.eSign.Model;  
  4. using Document = DocuSign.eSign.Model.Document;  
Now, save the sending document in our server. Here we are working with pdf files so we need to convert every file(s) to pdf format.
  1. byte[] data;  
  2. using(Stream inputStream = UploadDocument.InputStream) {  
  3.     MemoryStream memoryStream = inputStream as MemoryStream;  
  4.     if (memoryStream == null) {  
  5.         memoryStream = new MemoryStream();  
  6.         inputStream.CopyTo(memoryStream);  
  7.     }  
  8.     data = memoryStream.ToArray();  
  9. }  
  10. var serverpath = directorypath + recipient.Name.Trim() + ".pdf";  
  11. System.IO.File.WriteAllBytes(serverpath, data);  
Now, we need to send your document to the respective person, but before that we need to validate our DocuSign connection.
  1. public void docusign(string path, string recipientName, string recipientEmail) {  
  2.     ApiClient apiClient = new ApiClient("https://demo.docusign.net/restapi");  
  3.     Configuration.Default.ApiClient = apiClient;  
  4.     //Verify Account Details  
  5.     string accountId = loginApi(credential.UserName, credential.Password);  
  6. }  
  7. public string loginApi(string usr, string pwd) {  
  8.     // we set the api client in global config when we configured the client  
  9.     ApiClient apiClient = Configuration.Default.ApiClient;  
  10.     string authHeader = "{\"Username\":\"" + usr + "\", \"Password\":\"" + pwd + "\", \"IntegratorKey\":\"" + INTEGRATOR_KEY + "\"}";  
  11.     Configuration.Default.AddDefaultHeader("X-DocuSign-Authentication", authHeader);  
  12.     // we will retrieve this from the login() results  
  13.     string accountId = null;  
  14.     // the authentication api uses the apiClient (and X-DocuSign-Authentication header) that are set in Configuration object  
  15.     AuthenticationApi authApi = new AuthenticationApi();  
  16.     LoginInformation loginInfo = authApi.Login();  
  17.     // find the default account for this user  
  18.     foreach(DocuSign.eSign.Model.LoginAccount loginAcct in loginInfo.LoginAccounts) {  
  19.         if (loginAcct.IsDefault == "true") {  
  20.             accountId = loginAcct.AccountId;  
  21.             break;  
  22.         }  
  23.     }  
  24.     if (accountId == null) { // if no default found set to first account  
  25.         accountId = loginInfo.LoginAccounts[0].AccountId;  
  26.     }  
  27.     return accountId;  
  28. }  
  29. after validating connection, convert the document as a byte  
  30. byte[] fileBytes = System.IO.File.ReadAllBytes(path);  
Now, we will append this to docuSign document, and for that we will use the predefined EnvelopeDefinition class. We can send one or more document at a time.
  1. EnvelopeDefinition envDef = new EnvelopeDefinition();  
  2. envDef.EmailSubject = "Please sign this doc";  
  3. // Add a document to the envelope  
  4. Document doc = new Document();  
  5. doc.DocumentBase64 = System.Convert.ToBase64String(fileBytes);  
  6. doc.Name = Path.GetFileName(path);  
  7. doc.DocumentId = "1";  
  8. envDef.Documents = new List<Document>();  
  9. envDef.Documents.Add(doc);  
Now, add a recipient(s) to sign the document. Here, also we can define more than one signer. 
  1. // Add a recipient to sign the documeent  
  2. DocuSign.eSign.Model.Signer signer = new DocuSign.eSign.Model.Signer();  
  3. signer.Email = recipientEmail;  
  4. signer.Name = recipientName;  
  5. signer.RecipientId = "1";  
  6. envDef.Recipients = new DocuSign.eSign.Model.Recipients();  
  7. envDef.Recipients.Signers = new List<DocuSign.eSign.Model.Signer>();  
  8. envDef.Recipients.Signers.Add(signer);  
  9. set envelope status to "sent" to immediately send the signature request  
  10. envDef.Status = "sent";  
  11. EnvelopesApi contains methods related to creating and sending Envelopes (ask a signature requests)   
  12. EnvelopesApi envelopesApi = new EnvelopesApi();  
  13. EnvelopeSummary envelopeSummary = envelopesApi.CreateEnvelope(accountId, envDef);  
To Get an envelopeSummary we need to use a JsonConvert. So install it from the NuGet.
 
 
 
Now, use JsonConvert to seraializeObject.
  1. var result = JsonConvert.SerializeObject(envelopeSummary);   
Now, run your application.
 
 
In the above image, you can see that we successfully received the envelope summary and we might get a distinct envelope id for each DocuSign sign request.
 
Validate in DocuSign and Email
 
Now we shall check the DocuSign portal and email to see whether we have received any document. First, as an admin, we will check in DocuSign portal. In the below image, you can see the sent document with status, DateTime and recipient name.
 
 
 
 Now as a user, we will check the mailbox. In the below image, you can see that we have received the mail from DocuSign to sign.
 
 
Now, the user is able to sign/review the document by clicking the mailed link. In the next article we will see how to track whether the user signed or viewed in our web application.
 
Complete Controller 
  1. using DocuSign.eSign.Api;  
  2. using DocuSign.eSign.Client;  
  3. using DocuSign.eSign.Model;  
  4. using Newtonsoft.Json;  
  5. using System.Collections.Generic;  
  6. using System.IO;  
  7. using System.Web;  
  8. using System.Web.Mvc;  
  9. using Document = DocuSign.eSign.Model.Document;  
  10. namespace DocusignDemo.Controllers {  
  11.     public class DocusignController: Controller {  
  12.         MyCredential credential = new MyCredential();  
  13.         private string INTEGRATOR_KEY = "Enter Integrator Key";  
  14.         public ActionResult SendDocumentforSign() {  
  15.                 return View();  
  16.             }  
  17.             [HttpPost]  
  18.         public ActionResult SendDocumentforSign(DocusignDemo.Models.Recipient recipient, HttpPostedFileBase UploadDocument) {  
  19.             Models.Recipient recipientModel = new Models.Recipient();  
  20.             string directorypath = Server.MapPath("~/App_Data/" + "Files/");  
  21.             if (!Directory.Exists(directorypath)) {  
  22.                 Directory.CreateDirectory(directorypath);  
  23.             }  
  24.             byte[] data;  
  25.             using(Stream inputStream = UploadDocument.InputStream) {  
  26.                 MemoryStream memoryStream = inputStream as MemoryStream;  
  27.                 if (memoryStream == null) {  
  28.                     memoryStream = new MemoryStream();  
  29.                     inputStream.CopyTo(memoryStream);  
  30.                 }  
  31.                 data = memoryStream.ToArray();  
  32.             }  
  33.             var serverpath = directorypath + recipient.Name.Trim() + ".pdf";  
  34.             System.IO.File.WriteAllBytes(serverpath, data);  
  35.             docusign(serverpath, recipient.Name, recipient.Email);  
  36.             return View();  
  37.         }  
  38.         public string loginApi(string usr, string pwd) {  
  39.             // we set the api client in global config when we configured the client  
  40.             ApiClient apiClient = Configuration.Default.ApiClient;  
  41.             string authHeader = "{\"Username\":\"" + usr + "\", \"Password\":\"" + pwd + "\", \"IntegratorKey\":\"" + INTEGRATOR_KEY + "\"}";  
  42.             Configuration.Default.AddDefaultHeader("X-DocuSign-Authentication", authHeader);  
  43.             // we will retrieve this from the login() results  
  44.             string accountId = null;  
  45.             // the authentication api uses the apiClient (and X-DocuSign-Authentication header) that are set in Configuration object  
  46.             AuthenticationApi authApi = new AuthenticationApi();  
  47.             LoginInformation loginInfo = authApi.Login();  
  48.             // find the default account for this user  
  49.             foreach(DocuSign.eSign.Model.LoginAccount loginAcct in loginInfo.LoginAccounts) {  
  50.                 if (loginAcct.IsDefault == "true") {  
  51.                     accountId = loginAcct.AccountId;  
  52.                     break;  
  53.                 }  
  54.             }  
  55.             if (accountId == null) { // if no default found set to first account  
  56.                 accountId = loginInfo.LoginAccounts[0].AccountId;  
  57.             }  
  58.             return accountId;  
  59.         }  
  60.         public void docusign(string path, string recipientName, string recipientEmail) {  
  61.             ApiClient apiClient = new ApiClient("https://demo.docusign.net/restapi");  
  62.             Configuration.Default.ApiClient = apiClient;  
  63.             //Verify Account Details  
  64.             string accountId = loginApi(credential.UserName, credential.Password);  
  65.             // Read a file from disk to use as a document.  
  66.             byte[] fileBytes = System.IO.File.ReadAllBytes(path);  
  67.             EnvelopeDefinition envDef = new EnvelopeDefinition();  
  68.             envDef.EmailSubject = "Please sign this doc";  
  69.             // Add a document to the envelope  
  70.             Document doc = new Document();  
  71.             doc.DocumentBase64 = System.Convert.ToBase64String(fileBytes);  
  72.             doc.Name = Path.GetFileName(path);  
  73.             doc.DocumentId = "1";  
  74.             envDef.Documents = new List < Document > ();  
  75.             envDef.Documents.Add(doc);  
  76.             // Add a recipient to sign the documeent  
  77.             DocuSign.eSign.Model.Signer signer = new DocuSign.eSign.Model.Signer();  
  78.             signer.Email = recipientEmail;  
  79.             signer.Name = recipientName;  
  80.             signer.RecipientId = "1";  
  81.             envDef.Recipients = new DocuSign.eSign.Model.Recipients();  
  82.             envDef.Recipients.Signers = new List < DocuSign.eSign.Model.Signer > ();  
  83.             envDef.Recipients.Signers.Add(signer);  
  84.             //set envelope status to "sent" to immediately send the signature request  
  85.             envDef.Status = "sent";  
  86.             // |EnvelopesApi| contains methods related to creating and sending Envelopes (aka signature requests)  
  87.             EnvelopesApi envelopesApi = new EnvelopesApi();  
  88.             EnvelopeSummary envelopeSummary = envelopesApi.CreateEnvelope(accountId, envDef);  
  89.             // print the JSON response  
  90.             var result = JsonConvert.SerializeObject(envelopeSummary);  
  91.         }  
  92.     }  
  93.     public class MyCredential {  
  94.         public string UserName {  
  95.             get;  
  96.             set;  
  97.         } = "Enter UserName";  
  98.         public string Password {  
  99.             get;  
  100.             set;  
  101.         } = "Enter Password";  
  102.     }  
  103. }  
View 
  1. @model DocusignDemo.Models.Recipient  
  2. @{  
  3. /**/  
  4. ViewBag.Title = "SendDocumentforSign";  
  5. }  
  6. @using (Html.BeginForm("SendDocumentforSign""Docusign", FormMethod.Post, new { enctype = "multipart/form-data", id="SendForsign" }))  
  7. {  
  8. @Html.AntiForgeryToken()  
  9. <br />  
  10. <div class="panel panel-primary col-md-6">  
  11. <div class="panel-heading">Send For Sign</div>  
  12. <div class="panel-body" >  
  13. <div class="form-horizontal">  
  14. <hr />  
  15. @Html.ValidationSummary(true""new { @class = "text-danger" })  
  16. <div class="form-group">  
  17. @Html.LabelFor(model => model.Name, htmlAttributes: new { @class = "control-label col-md-2" })  
  18. <div class="col-md-10">  
  19. @Html.EditorFor(model => model.Name, new { htmlAttributes = new { @class = "form-control" } })  
  20. @Html.ValidationMessageFor(model => model.Name, ""new { @class = "text-danger" })  
  21. </div>  
  22. </div>  
  23. <div class="form-group">  
  24. @Html.LabelFor(model => model.Email, htmlAttributes: new { @class = "control-label col-md-2" })  
  25. <div class="col-md-10">  
  26. @Html.EditorFor(model => model.Email, new { htmlAttributes = new { @class = "form-control" } })  
  27. @Html.ValidationMessageFor(model => model.Email, ""new { @class = "text-danger" })  
  28. </div>  
  29. </div>  
  30. <div class="form-group">  
  31. @Html.Label("Document", htmlAttributes: new { @class = "control-label col-md-2" })  
  32. <div class="col-md-10">  
  33. <input id="UploadDocument" type="file" name="UploadDocument" class="form-control" />  
  34. </div>  
  35. </div>  
  36. <div class="form-group">  
  37. @Html.LabelFor(model => model.Description, htmlAttributes: new { @class = "control-label col-md-2" })  
  38. <div class="col-md-10">  
  39. @Html.EditorFor(model => model.Description, new { htmlAttributes = new { @class = "form-control" } })  
  40. @Html.ValidationMessageFor(model => model.Description, ""new { @class = "text-danger" })  
  41. </div>  
  42. </div>  
  43. <div class="form-group">  
  44. <div class="col-md-offset-2 col-md-10">  
  45. <input type="submit" value="Send For Sign" class="btn btn-primary" />  
  46. </div>  
  47. </div>  
  48. </div>  
  49. </div>  
  50. </div>  
  51. }  
  52. <script src="~/Scripts/jquery-1.10.2.min.js"></script>  
  53. <script src="~/Scripts/jquery.validate.min.js"></script>  
  54. <script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script>  
Model
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Web;  
  5. namespace DocusignDemo.Models {  
  6.     public partial class Recipient {  
  7.         public string Name {  
  8.             get;  
  9.             set;  
  10.         }  
  11.         public string Email {  
  12.             get;  
  13.             set;  
  14.         }  
  15.         public string Description {  
  16.             get;  
  17.             set;  
  18.         }  
  19.     }  
  20. }  
Refer to the attached project for reference, and I did attach the demonstrated project without package due to the size limit.
 
Summary 
 
In this article, we have discussed how to send a document for signature from ASP.NET MVC5 web application using DocuSign. I hope it will help you out. Your valuable feedback and comments about this article are always welcome.