1
+ using System ;
2
+ using System . Collections . Generic ;
3
+ using DocuSign . eSign . Api ;
4
+ using DocuSign . eSign . Model ;
5
+ using eg_03_csharp_auth_code_grant_core . Models ;
6
+ using Microsoft . AspNetCore . Mvc ;
7
+ using System . Text ;
8
+ using DocuSign . eSign . Client ;
9
+
10
+ namespace eg_03_csharp_auth_code_grant_core . Controllers
11
+ {
12
+ [ Route ( "eg016" ) ]
13
+ public class Eg016SetTabValuesController : EgController
14
+ {
15
+ // Set up the Ping Url, signer client ID, and the return (callback) URL for embedded signing
16
+ private string dsPingUrl ;
17
+ private readonly string signerClientId = "1000" ;
18
+ private string dsReturnUrl ;
19
+
20
+ public Eg016SetTabValuesController ( DSConfiguration config , IRequestItemsService requestItemsService )
21
+ : base ( config , requestItemsService )
22
+ {
23
+ ViewBag . title = "SetTabValues" ;
24
+ dsPingUrl = config . AppUrl + "/" ;
25
+ dsReturnUrl = config . AppUrl + "/dsReturn" ;
26
+ }
27
+ public override string EgName => "eg016" ;
28
+
29
+ [ HttpPost ]
30
+ public IActionResult Create ( string signerEmail , string signerName )
31
+ {
32
+ // Check the token with minimal buffer time
33
+ bool tokenOk = CheckToken ( 3 ) ;
34
+ if ( ! tokenOk )
35
+ {
36
+ // We could store the parameters of the requested operation so it could be
37
+ // restarted automatically. But since it should be rare to have a token issue
38
+ // here, we'll make the user re-enter the form data after authentication
39
+ RequestItemsService . EgName = EgName ;
40
+ return Redirect ( "/ds/mustAuthenticate" ) ;
41
+ }
42
+
43
+ // The envelope will be sent first to the signer; after it is signed,
44
+ // a copy is sent to the cc person
45
+ //
46
+ // Read files from a local directory
47
+ // The reads could raise an exception if the file is not available!
48
+ var basePath = RequestItemsService . Session . BasePath + "/restapi" ;
49
+
50
+ // Step 1: Obtain your OAuth token
51
+ var accessToken = RequestItemsService . User . AccessToken ; // Represents your {ACCESS_TOKEN}
52
+ var accountId = RequestItemsService . Session . AccountId ; // Represents your {ACCOUNT_ID}
53
+
54
+ // Step 2: Construct your API headers
55
+ var config = new Configuration ( new ApiClient ( basePath ) ) ;
56
+ config . AddDefaultHeader ( "Authorization" , "Bearer " + accessToken ) ;
57
+
58
+ // Step 3: Create Tabs and CustomFields
59
+ SignHere signHere = new SignHere
60
+ {
61
+ AnchorString = "/sn1/" ,
62
+ AnchorUnits = "pixels" ,
63
+ AnchorYOffset = "10" ,
64
+ AnchorXOffset = "20"
65
+ } ;
66
+
67
+ Text textLegal = new Text
68
+ {
69
+ AnchorString = "/legal/" ,
70
+ AnchorUnits = "pixels" ,
71
+ AnchorYOffset = "-9" ,
72
+ AnchorXOffset = "5" ,
73
+ Font = "helvetica" ,
74
+ FontSize = "size11" ,
75
+ Bold = "true" ,
76
+ Value = signerName ,
77
+ Locked = "false" ,
78
+ TabId = "legal_name" ,
79
+ TabLabel = "Legal name" ,
80
+ } ;
81
+
82
+ Text textFamiliar = new Text
83
+ {
84
+ AnchorString = "/familiar/" ,
85
+ AnchorUnits = "pixels" ,
86
+ AnchorYOffset = "-9" ,
87
+ AnchorXOffset = "5" ,
88
+ Font = "helvetica" ,
89
+ FontSize = "size11" ,
90
+ Bold = "true" ,
91
+ Value = signerName ,
92
+ Locked = "false" ,
93
+ TabId = "familiar_name" ,
94
+ TabLabel = "Familiar name"
95
+ } ;
96
+
97
+ // The salary is set both as a readable number in the /salary/ text field,
98
+ // and as a pure number in a custom field ('salary') in the envelope
99
+ int salary = 123000 ;
100
+
101
+ Text textSalary = new Text
102
+ {
103
+ AnchorString = "/salary/" ,
104
+ AnchorUnits = "pixels" ,
105
+ AnchorYOffset = "-9" ,
106
+ AnchorXOffset = "5" ,
107
+ Font = "helvetica" ,
108
+ FontSize = "size11" ,
109
+ Bold = "true" ,
110
+ Locked = "true" ,
111
+ // Convert number to String: 'C2' sets the string
112
+ // to currency format with two decimal places
113
+ Value = salary . ToString ( "C2" ) ,
114
+ TabId = "salary" ,
115
+ TabLabel = "Salary"
116
+ } ;
117
+
118
+ TextCustomField salaryCustomField = new TextCustomField
119
+ {
120
+ Name = "salary" ,
121
+ Required = "false" ,
122
+ Show = "true" , // Yes, include in the CoC
123
+ Value = salary . ToString ( )
124
+ } ;
125
+
126
+ CustomFields cf = new CustomFields
127
+ {
128
+ TextCustomFields = new List < TextCustomField > { salaryCustomField }
129
+ } ;
130
+
131
+ // Create a signer recipient to sign the document, identified by name and email
132
+ // We're setting the parameters via the object creation
133
+ Signer signer1 = new Signer
134
+ {
135
+ Email = signerEmail ,
136
+ Name = signerName ,
137
+ RecipientId = "1" ,
138
+ RoutingOrder = "1" ,
139
+ ClientUserId = signerClientId
140
+ } ;
141
+
142
+ // Add the tabs model (including the SignHere tab) to the signer.
143
+ // The Tabs object wants arrays of the different field/tab types
144
+ // Tabs are set per recipient/signer
145
+ Tabs signer1Tabs = new Tabs
146
+ {
147
+ SignHereTabs = new List < SignHere > { signHere } ,
148
+ TextTabs = new List < Text > { textLegal , textFamiliar , textSalary }
149
+ } ;
150
+ signer1 . Tabs = signer1Tabs ;
151
+ Recipients recipients = new Recipients
152
+ {
153
+ Signers = new List < Signer > { signer1 }
154
+ } ;
155
+
156
+ string doc1b64 = Convert . ToBase64String ( System . IO . File . ReadAllBytes ( Config . tabsDocx ) ) ;
157
+
158
+ // Create document objects, one per document
159
+ Document doc1 = new Document
160
+ {
161
+ DocumentBase64 = doc1b64 ,
162
+ Name = "Lorem Ipsum" , // Can be different from actual file name
163
+ FileExtension = "docx" ,
164
+ DocumentId = "1"
165
+ } ;
166
+
167
+ // Step 4: Create the envelope definition
168
+ EnvelopeDefinition envelopeAttributes = new EnvelopeDefinition ( )
169
+ {
170
+ EnvelopeIdStamping = "true" ,
171
+ EmailSubject = "Please Sign" ,
172
+ EmailBlurb = "Sample text for email body" ,
173
+ Status = "Sent" ,
174
+ Recipients = recipients ,
175
+ CustomFields = cf ,
176
+ Documents = new List < Document > { doc1 }
177
+ } ;
178
+
179
+ // Step 5: Call the eSignature REST API
180
+ EnvelopesApi envelopesApi = new EnvelopesApi ( config ) ;
181
+ EnvelopeSummary results = envelopesApi . CreateEnvelope ( accountId , envelopeAttributes ) ;
182
+ RequestItemsService . EnvelopeId = results . EnvelopeId ;
183
+
184
+ // Step 6: Create the View Request
185
+ RecipientViewRequest viewRequest = new RecipientViewRequest ( ) ;
186
+ // Set the URL where you want the recipient to go once they are done signing;
187
+ // this should typically be a callback route somewhere in your app.
188
+ // The query parameter is included as an example of how
189
+ // to save/recover state information during the redirect to
190
+ // the DocuSign signing ceremony. It's usually better to use
191
+ // the session mechanism of your web framework. Query parameters
192
+ // can be changed/spoofed very easily
193
+ viewRequest . ReturnUrl = dsReturnUrl + "?state=123" ;
194
+
195
+ // How has your app authenticated the user? In addition to your app's authentication,
196
+ // you can include authentication steps from DocuSign; e.g., SMS authentication
197
+ viewRequest . AuthenticationMethod = "none" ;
198
+
199
+ // Recipient information must match the embedded recipient info
200
+ // that we used to create the envelope
201
+ viewRequest . Email = signerEmail ;
202
+ viewRequest . UserName = signerName ;
203
+ viewRequest . ClientUserId = signerClientId ;
204
+
205
+ // DocuSign recommends that you redirect to DocuSign for the
206
+ // signing ceremony. There are multiple ways to save state.
207
+ // To maintain your application's session, use the PingUrl
208
+ // parameter. It causes the DocuSign Signing Ceremony web page
209
+ // (not the DocuSign server) to send pings via AJAX to your app
210
+ viewRequest . PingFrequency = "600" ; // seconds
211
+ // NOTE: The pings will only be sent if the pingUrl is an HTTPS address
212
+ viewRequest . PingUrl = dsPingUrl ; // Optional setting
213
+
214
+ ViewUrl results1 = envelopesApi . CreateRecipientView ( accountId , results . EnvelopeId , viewRequest ) ;
215
+ //***********
216
+ // Don't use an iframe with embedded signing requests!
217
+ //***********
218
+ // State can be stored/recovered using the framework's session or a
219
+ // query parameter on the return URL (see the makeRecipientViewRequest method)
220
+ string redirectUrl = results1 . Url ;
221
+ return Redirect ( redirectUrl ) ;
222
+ }
223
+ }
224
+ }
0 commit comments