I am using this code to upload some text directly to azure blob using rest api. I am getting an webexception 403 forbidden. Can someone plaese tell me where am i going wrong in my code
private String CreateAuthorizationHeader(String canonicalizedString, CloudBlob blob)
{
String signature = string.Empty;
using (HMACSHA256 hmacSha256 = new HMACSHA256())
{
Byte[] dataToHmac = System.Text.Encoding.UTF8.GetBytes(canonicalizedString);
signature = Convert.ToBase64String(hmacSha256.ComputeHash(dataToHmac));
}
String authorizationHeader = String.Format(CultureInfo.InvariantCulture, "{0} {1}:{2}", "SharedKeyLite", myaccount, signature);
return authorizationHeader;
}
private void PutBlob(String containerName, String blobName , CloudBlob blob)
{
String requestMethod = "PUT";
String urlPath = String.Format("{0}", blobName);
String storageServiceVersion = "2009-10-01";
String dateInRfc1123Format = DateTime.UtcNow.ToString("R", CultureInfo.InvariantCulture);
// if (uploadPST.HasFile)
// {
string content = "Sample file";
// Stream content = uploadPST.FileBytes;
UTF8Encoding utf8Encoding = new UTF8Encoding();
Byte[] blobContent = utf8Encoding.GetBytes(content);
Int32 blobLength = blobContent.Length;
const String blobType = "BlockBlob";
/* String canonicalizedHeaders = String.Format(
"x-ms-blob-type:{0}\nx-ms-date:{1}\nx-ms-version:{2}",
blobType,
dateInRfc1123Format,
storageServiceVersion);*/
String canonicalizedHeaders = String.Format(
"x-ms-date:{0}\nx-ms-meta-m1:{1}\nx-ms-meta-m1:{2}",
dateInRfc1123Format,
"v1",
"v2");
String canonicalizedResource = String.Format("/{0}/{1}", myaccount, urlPath);
String stringToSign = String.Format(
"{0}\n\n{1}\n\n{2}\n{3}",
requestMethod,
"text/plain; charset=UTF-8",
canonicalizedHeaders,
canonicalizedResource);
String authorizationHeader = CreateAuthorizationHeader(stringToSign, blob);
Uri uri = new Uri(CloudStorageAccount.FromConfigurationSetting("DataConnectionString").BlobEndpoint + "/" + urlPath);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
request.Method = requestMethod;
// request.Headers.Add("x-ms-blob-type", blobType);
request.Headers.Add("x-ms-date", dateInRfc1123Format);
// request.Headers.Add("x-ms-version", storageServiceVersion);
request.Headers.Add("Authorization", authorizationHeader);
request.ContentLength = blobLength;
using (Stream requestStream = request.GetRequestStream())
{
requestStream.Write(blobContent ,0 ,blobLength);
}
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
String ETag = response.Headers["ETag"];
}
// }
}
First, you construct an HMACSHA256 object using the default constructor -- this causes a random key to be generated and used for signing. What you want is the overload which accepts a string - and pass the azure account key.
Still, signing the request 'manually' can be tricky, as there are a lot of things to do and it's easy to mess up or forget something. Instead, I recommend you use the SignRequest method of StorageCredentialsAccountAndKey class (msdn doc) For instance;
// ...there exists a request object, and strings for the account name and key
var creds = new StorageCredentialsAccountAndKey(accountName, accountKey);
creds.SignRequest(request);
This will do everything needed to sign the request properly, including creating a canonicalized headers string, creating a date with the correct format, etc.
Related
I'm working with Azure Blob Storage and C#. I need to delete a blob using the API REST, but I get the 403 Forbidden error. I'm using the same function to generate the authentication header for create a new blob, but it works for put but doesn't it for delete. This is my code:
public bool DeleteBlob(string containerName, string fileName)
{
string blobName = fileName;
string method = "DELETE";
string requestUri = $"https://{_accountName}.blob.core.windows.net/{containerName}/{blobName}";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(requestUri);
string now = DateTime.UtcNow.ToString("R", CultureInfo.InvariantCulture);
request.Method = method;
request.Headers.Add("x-ms-version", "2020-10-02");
request.Headers.Add("x-ms-date", now);
request.Headers.Add("x-ms-delete-snapshots", "include");
request.Headers.Add("Authorization", AuthorizationHeader("DELETE", request, containerName, blobName));
bool result = false;
using (HttpWebResponse resp = (HttpWebResponse)request.GetResponse())
{
if (resp.StatusCode != HttpStatusCode.Accepted && resp.StatusCode != HttpStatusCode.OK)
{
throw new Exception(resp.StatusDescription);
}
result = true;
}
return result;
}
private string AuthorizationHeader(string method, HttpWebRequest request, string containerName, string blobName)
{
string urlResource = $"/{_accountName}/{containerName}/{blobName}";
string stringToSign = $"{method}\n\n\n{request.ContentLength}\n\n{request.ContentType}\n\n\n\n\n\n\n{GetCanonicalizedHeaders(request)}{GetCanonicalizedResource(request.RequestUri, _accountName)}";
HMACSHA256 hmac = new HMACSHA256(Convert.FromBase64String(_accountKey));
string signature = Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToSign)));
return string.Format("{0} {1}:{2}", "SharedKey", _accountName, signature);
}
private string GetAuthorizationHeader(string method, HttpWebRequest request, string now, string containerName, string blobName)
{
string urlResource = $"/{_accountName}/{containerName}/{blobName}";
var canonicalizedStringToBuild = string.Format("{0}\n{1}", now, $"/{_accountName}/" + urlResource);
string signature;
using (var hmac = new HMACSHA256(Convert.FromBase64String(_accountKey)))
{
byte[] dataToHmac = Encoding.UTF8.GetBytes(canonicalizedStringToBuild);
signature = Convert.ToBase64String(hmac.ComputeHash(dataToHmac));
}
return string.Format($"{_accountName}:" + signature);
}
private string GetCanonicalizedHeaders(HttpWebRequest request)
{
ArrayList headerNameList = new ArrayList();
StringBuilder sb = new StringBuilder();
foreach (string headerName in request.Headers.Keys)
{
if (headerName.ToLowerInvariant().StartsWith("x-ms-", StringComparison.Ordinal))
{
headerNameList.Add(headerName.ToLowerInvariant());
}
}
headerNameList.Sort();
foreach (string headerName in headerNameList)
{
StringBuilder builder = new StringBuilder(headerName);
string separator = ":";
foreach (string headerValue in GetHeaderValues(request.Headers, headerName))
{
string trimmedValue = headerValue.Replace("\r\n", String.Empty);
builder.Append(separator);
builder.Append(trimmedValue);
separator = ",";
}
sb.Append(builder.ToString());
sb.Append("\n");
}
return sb.ToString();
}
private string GetCanonicalizedResource(Uri address, string accountName)
{
StringBuilder str = new StringBuilder();
StringBuilder builder = new StringBuilder("/");
builder.Append(accountName);
builder.Append(address.AbsolutePath);
str.Append(builder.ToString());
NameValueCollection values2 = new NameValueCollection();
if (address.Query.Length > 0)
{
string query = address.Query.Remove(0, 1);
var queryParts = query.Split('&');
foreach (var queryPart in queryParts)
{
var parts = queryPart.Split('=');
values2.Add(parts[0], parts[1]);
}
ArrayList list2 = new ArrayList(values2.AllKeys);
list2.Sort();
foreach (string str3 in list2)
{
StringBuilder builder3 = new StringBuilder(string.Empty);
builder3.Append(str3);
builder3.Append(":");
builder3.Append(values2[str3]);
str.Append("\n");
str.Append(builder3.ToString());
}
}
return str.ToString();
}
Could anyone tell me what I'm doing wrong? As I commented for create a new blob working fine, but not for deletion. I don't know if the authentication header is different for delete (I know the method name is different) I have not found much information about that.
Thannks.
The reason your delete operation is failing with 403 error is because in your stringToSign you're assigning content length as 0 whereas it should be an empty string.
Please change your AuthorizationHeader method code to the code mentioned below and your delete blob operation should work just fine:
private string AuthorizationHeader(string method, HttpWebRequest request, string containerName, string blobName)
{
string urlResource = $"/{_accountName}/{containerName}/{blobName}";
var contentLength = request.ContentLength == 0 ? "" : request.ContentLength.ToString();
string stringToSign = $"{method}\n\n\n{contentLength}\n\n{request.ContentType}\n\n\n\n\n\n\n{GetCanonicalizedHeaders(request)}{GetCanonicalizedResource(request.RequestUri, _accountName)}";
HMACSHA256 hmac = new HMACSHA256(Convert.FromBase64String(_accountKey));
string signature = Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToSign)));
return string.Format("{0} {1}:{2}", "SharedKey", _accountName, signature);
}
What I have done above is set the content length value to an empty string if the content length is 0.
From this link (emphasis mine):
In the current version, the Content-Length field must be an empty
string if the content length of the request is zero. In version
2014-02-14 and earlier, the content length was included even if zero.
I'm trying to make a downloader attached to the service bus that is going to download the files from blob storage. But I'm having some problems with generating the SAS token manually, please se the error message below.
I'm getting error <AuthenticationErrorDetail>Signature fields not well formed.</AuthenticationErrorDetail>
private static string createToken(string resourceUri, string keyName, string key)
{
var now = DateTime.UtcNow;
TimeSpan sinceEpoch = now - new DateTime(1970, 1, 1);
var time = 60 * 2;
var expiry = Convert.ToString((int)sinceEpoch.TotalSeconds + time);
var expiryDateString = now.AddSeconds(time).ToUniversalTime().ToString("u");
string stringToSign = HttpUtility.UrlEncode(resourceUri) + "\n" + expiry;
HMACSHA256 hmac = new HMACSHA256(Encoding.UTF8.GetBytes(key));
var signature = Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToSign)));
var sasToken = String.Format(
CultureInfo.InvariantCulture,
"{0}?sp={1}&st={2}&se={3}&spr={4}&sv={5}&sr={6}&sig={7}",
resourceUri,
"r",
DateTime.UtcNow.ToUniversalTime().ToString("u"),
expiryDateString,
"https",
"2019-02-02",
"b",
HttpUtility.UrlEncode(signature));
return sasToken;
}
Is it the stringToSign? Or signature as a whole? I'm a but unusre, to maybe I need to use the HttpUtility.UrlEncoder on all fields?
Please try the code below, it generates a working sas token for me:
static void Main(string[] args)
{
string resourceUri = "https://xx.blob.core.windows.net/test1/1.txt";
string account_name= "storage account name";
string key = "storage account key";
string s1 = createToken(resourceUri,account_name,key);
Console.WriteLine(s1);
Console.ReadLine();
}
private static string createToken(string resourceUri, string account_name, string key)
{
var accountName = account_name;
var accountKey = key;
var start = DateTime.UtcNow.AddHours(-2).ToString("yyyy-MM-ddTHH:mm:ssZ");
var end = DateTime.UtcNow.AddHours(2).ToString("yyyy-MM-ddTHH:mm:ssZ");
var permission = "rwdlac";
var serviceType = "b";
var resourceTypes = "sco";
var protocol = "https";
var serviceVersion = "2019-02-02";
//here is the difference from your code.
var stringToSign = string.Format("{0}\n{1}\n{2}\n{3}\n{4}\n{5}\n{6}\n{7}\n{8}\n",accountName, permission,serviceType,resourceTypes,start,end,"",protocol,serviceVersion);
HMACSHA256 hmac = new HMACSHA256(Convert.FromBase64String(accountKey));
string signature = Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToSign)));
var sasToken = string.Format("?sv={0}&ss={1}&srt={2}&sp={3}&se={4}&st={5}&spr={6}&sig={7}", serviceVersion,
serviceType, resourceTypes, permission, end, start, protocol, HttpUtility.UrlEncode(signature));
var urlToListTables = resourceUri + sasToken;
return urlToListTables;
}
Please let me know if you still have any issues.
I would like to programatically get and create Web Apps under App Services in Windows Azure.
How to create it by using its REST API?
As far as I know, if you want to use REST API to get and create Web App, you need generate a access token. To generate access token we need talentID, clientId, clientSecret. We need to assign application to role, after that then we can use token in common. More information about how to assign application to role please refer to the article .This blog also has more detail steps to get AceessToken.
Notice: I use C# Codes to show a example.
Then you could send request as below:
Get webapp:
Url: https://management.azure.com/subscriptions/{subscriptionId}/resourceGroups/{resourceGroup}/Microsoft.Web/sites?api-version={api-version}
Method: PUT
Parameter:
subscriptionId The identifier of your subscription where the snapshot is being created.
resourceGroup The name of the resource group that will contain the snapshot.
api-version The version of the API to use.
The codes is as below:
// Display the file contents to the console. Variable text is a string.
string tenantId = "xxxxxxxxxxxxxxxxxxxxx";
string clientId = "xxxxxxxxxxxxxxxxxxxxx";
string clientSecret = "xxxxxxxxxxxxxxxxxxxxxxxxxxx";
string subscriptionid = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
string resourcegroup = "BrandoSecondTest";
string version = "2015-08-01";
string authContextURL = "https://login.windows.net/" + tenantId;
var authenticationContext = new AuthenticationContext(authContextURL);
var credential = new ClientCredential(clientId, clientSecret);
var result = authenticationContext.AcquireTokenAsync(resource: "https://management.azure.com/", clientCredential: credential).Result;
if (result == null)
{
throw new InvalidOperationException("Failed to obtain the JWT token");
}
string token = result.AccessToken;
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(string.Format("https://management.azure.com/subscriptions/{0}/resourceGroups/{1}/providers/Microsoft.Web/sites?api-version={2}", subscriptionid, resourcegroup, version));
request.Method = "GET";
request.Headers["Authorization"] = "Bearer " + token;
request.ContentType = "application/json";
var httpResponse = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
Console.WriteLine(streamReader.ReadToEnd());
}
Console.ReadLine();
Create WebApp:
You should send your webapp template in the request content.
Then you could send request as below:
Url: https://management.azure.com/subscriptions/{subscriptionId}/resourceGroups/{resourceGroup}/Microsoft.Web/sites/{appname}?api-version={api-version}
Method: PUT
Parameter:
subscriptionId The identifier of your subscription where the snapshot is being created.
resourceGroup The name of the resource group that will contain the snapshot.
appname: The name of your webapplicaiton you want to create
api-version The version of the API to use.
Request content:
{
"location": "East Asia",
"properties": {
"name": "YourWebpplcaitonName",
"serverFarmId": "Yourserviceplan"
}
}
Here is a C# example, hope it gives some tips:
string body = File.ReadAllText(#"D:\json.txt");
// Display the file contents to the console. Variable text is a string.
string tenantId = "xxxxxxxxxxxxxxxxxxxxxxxxx";
string clientId = "xxxxxxxxxxxxxxxxxxxxxxx";
string clientSecret = "xxxxxxxxxxxxxxxxxxxxxxxxx";
string subscriptionid = "xxxxxxxxxxxxxxxxxxxxxxxxxxxx";
string resourcegroup = "BrandoSecondTest";
string appname = "Brandosss";
string version = "2015-08-01";
string authContextURL = "https://login.windows.net/" + tenantId;
var authenticationContext = new AuthenticationContext(authContextURL);
var credential = new ClientCredential(clientId, clientSecret);
var result = authenticationContext.AcquireTokenAsync(resource: "https://management.azure.com/", clientCredential: credential).Result;
if (result == null)
{
throw new InvalidOperationException("Failed to obtain the JWT token");
}
string token = result.AccessToken;
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(string.Format("https://management.azure.com/subscriptions/{0}/resourceGroups/{1}/providers/Microsoft.Web/sites/{2}?api-version={3}", subscriptionid, resourcegroup,appname, version));
request.Method = "PUT";
request.Headers["Authorization"] = "Bearer " + token;
request.ContentLength = body.Length;
request.ContentType = "application/json";
try
{
using (var streamWriter = new StreamWriter(request.GetRequestStream()))
{
streamWriter.Write(body);
streamWriter.Flush();
streamWriter.Close();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
// Get the response
var httpResponse = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
Console.WriteLine(streamReader.ReadToEnd());
}
I am getting an error "Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature."
I followed the authorization tutorial provided by Microsoft, Delete Table, Authentication for the Azure Storage Services.
Am I missing anything?
It seems that you’d like to delete table via rest api.
DELETE https://myaccount.table.core.windows.net/Tables('mytable')
the following sample works fine on my side, please refer to the code to generate the signature.
string StorageAccount = "account name here";
string StorageKey = "account key here";
string tablename = "table name";
string requestMethod = "DELETE";
string mxdate = "";
string storageServiceVersion = "2015-12-11";
protected void Button1_Click(object sender, EventArgs e)
{
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(string.Format(CultureInfo.InvariantCulture,
"https://{0}.table.core.windows.net/Tables('{1}')",
StorageAccount, tablename));
req.Method = requestMethod;
//specify request header
string AuthorizationHeader = generateAuthorizationHeader();
req.Headers.Add("Authorization", AuthorizationHeader);
req.Headers.Add("x-ms-date", mxdate);
req.Headers.Add("x-ms-version", storageServiceVersion);
req.ContentType = "application/json";
req.Accept = "application/json;odata=minimalmetadata";
using (HttpWebResponse response = (HttpWebResponse)req.GetResponse())
{
}
}
public string generateAuthorizationHeader()
{
mxdate = DateTime.UtcNow.ToString("R");
string canonicalizedResource = $"/{StorageAccount}/Tables('{tablename}')";
string contentType = "application/json";
string stringToSign = $"{requestMethod}\n\n{contentType}\n{mxdate}\n{canonicalizedResource}";
HMACSHA256 hmac = new HMACSHA256(Convert.FromBase64String(StorageKey));
string signature = Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToSign)));
String authorization = String.Format("{0} {1}:{2}",
"SharedKey",
StorageAccount,
signature
);
return authorization;
}
I want to upload an image to docusign by c#, but it does not work. Below is my code that I wrote with mvc4.
Please help me,
Thanks!
public class UploadFileController : Controller
{
static string email = "***"; // your account email
static string password = "***"; // your account password
static string integratorKey = "***"; // your account Integrator Key (found on Preferences -> API page)
static string baseURL = ""; // - we will retrieve this
static string accountId = "***"; // - we will retrieve this
static string userId = "***";
static string signatureName = "signature";
#region FormUpload
public static class FormUpload
{
private static readonly Encoding encoding = Encoding.UTF8;
public static HttpWebResponse MultipartFormDataPost(string postUrl, string userAgent, Dictionary<string, object> postParameters)
{
string formDataBoundary = String.Format("----------{0:N}", Guid.NewGuid());
string contentType = "multipart/form-data; boundary=" + formDataBoundary;
byte[] formData = GetMultipartFormData(postParameters, formDataBoundary);
return PostForm(postUrl, userAgent, contentType, formData);
}
private static HttpWebResponse PostForm(string postUrl, string userAgent, string contentType, byte[] formData)
{
HttpWebRequest request = WebRequest.Create(postUrl) as HttpWebRequest;
if (request == null)
{
throw new NullReferenceException("request is not a http request");
}
// Set up the request properties.
request.Method = "PUT";
request.ContentType = contentType;
// request.UserAgent = userAgent;
request.CookieContainer = new CookieContainer();
request.ContentLength = formData.Length;
string authenticateStr =
"<DocuSignCredentials>" +
"<Username>" + email + "</Username>" +
"<Password>" + password + "</Password>" +
"<IntegratorKey>" + integratorKey + "</IntegratorKey>" + // global (not passed)
"</DocuSignCredentials>";
request.Headers.Add("X-DocuSign-Authentication", authenticateStr);
using (Stream requestStream = request.GetRequestStream())
{
requestStream.Write(formData, 0, formData.Length);
requestStream.Close();
}
return request.GetResponse() as HttpWebResponse;
}
private static byte[] GetMultipartFormData(Dictionary<string, object> postParameters, string boundary)
{
Stream formDataStream = new System.IO.MemoryStream();
bool needsCLRF = false;
foreach (var param in postParameters)
{
// Thanks to feedback from commenters, add a CRLF to allow multiple parameters to be added.
// Skip it on the first parameter, add it to subsequent parameters.
if (needsCLRF)
formDataStream.Write(encoding.GetBytes("\r\n"), 0, encoding.GetByteCount("\r\n"));
needsCLRF = true;
if (param.Value is FileParameter)
{
FileParameter fileToUpload = (FileParameter)param.Value;
// Add just the first part of this param, since we will write the file data directly to the Stream
StringBuilder headerbuilder = new StringBuilder();
String header1, header2, header3, header4, header5, header6, header7, header8, header9, header10, header11, header12, header13;
header1 = String.Format("--{0}\r\nContent-Disposition: form-data; name =\"HTTPMethod\"", boundary);
header2 = String.Format("\n--{0}\r\nContent-Disposition: form-data; name =\"MethodName\"", boundary);
header3 = String.Format("\n--{0}\r\nContent-Disposition: form-data; name =\"MethodURI\"", boundary);
header4 = String.Format("\n--{0}\r\nContent-Disposition: form-data; name =\"BaseURL\"", boundary);
header5 = String.Format("\n--{0}\r\nContent-Disposition: form-data; name =\"PublicPath\"", boundary);
header6 = String.Format("\n--{0}\r\nContent-Disposition: form-data; name =\"Protocol\"", boundary);
header7 = String.Format("\n--{0}\r\nContent-Disposition: form-data; name =\"Version\"", boundary);
header8 = String.Format("\n--{0}\r\nContent-Disposition: form-data; name =\"Username\"", boundary);
header9 = String.Format("\n--{0}\r\nContent-Disposition: form-data; name =\"Password\"", boundary);
header10 = String.Format("\n--{0}\r\nContent-Disposition: form-data; name =\"IntegratorKey\"", boundary);
header11 = String.Format("\n--{0}\r\nContent-Disposition: form-data; name =\"pram[accountId]\"", boundary);
header12 = String.Format("\n--{0}\r\nContent-Disposition: form-data; name =\"param[userId]\"", boundary);
header13 = String.Format("\n--{0}\r\nContent-Disposition: form-data; name =\"signatureName\"", boundary);
//headerbuilder.Append(
string header = string.Format("\n--{0}\r\nContent-Disposition: form-data; name=\"{1}\"; filename=\"{2}\";\r\nContent-Type: {3}\r\n\r\n",
boundary,
param.Key,
fileToUpload.FileName ?? param.Key,
fileToUpload.ContentType ?? "application/octet-stream");
headerbuilder.Append(header1);
headerbuilder.Append(header2);
headerbuilder.Append(header3);
headerbuilder.Append(header4);
headerbuilder.Append(header5);
headerbuilder.Append(header6);
headerbuilder.Append(header7);
headerbuilder.Append(header8);
headerbuilder.Append(header9);
headerbuilder.Append(header10);
headerbuilder.Append(header11);
headerbuilder.Append(header12);
headerbuilder.Append(header13);
headerbuilder.Append(header);
String a = headerbuilder.ToString();
formDataStream.Write(encoding.GetBytes(headerbuilder.ToString()), 0, encoding.GetByteCount(headerbuilder.ToString()));
// Write the file data directly to the Stream, rather than serializing it to a string.
formDataStream.Write(fileToUpload.File, 0, fileToUpload.File.Length);
}
else
{
string postData = string.Format("--{0}\r\nContent-Disposition: form-data; name=\"{1}\"\r\n\r\n{2}",
boundary,
param.Key,
param.Value);
formDataStream.Write(encoding.GetBytes(postData), 0, encoding.GetByteCount(postData));
}
}
// Add the end of the request. Start with a newline
string footer = "\r\n--" + boundary + "--\r\n";
formDataStream.Write(encoding.GetBytes(footer), 0, encoding.GetByteCount(footer));
// Dump the Stream into a byte[]
formDataStream.Position = 0;
byte[] formData = new byte[formDataStream.Length];
formDataStream.Read(formData, 0, formData.Length);
formDataStream.Close();
return formData;
}
public class FileParameter
{
public byte[] File { get; set; }
public string FileName { get; set; }
public string ContentType { get; set; }
public FileParameter(byte[] file) : this(file, null) { }
public FileParameter(byte[] file, string filename) : this(file, filename, null) { }
public FileParameter(byte[] file, string filename, string contenttype)
{
File = file;
FileName = filename;
ContentType = contenttype;
}
}
}
#endregion
public ActionResult Index()
{
// Read file data
FileStream fs = new FileStream("D:\\signature3.jpg", FileMode.Open, FileAccess.Read);
byte[] data = new byte[fs.Length];
fs.Read(data, 0, data.Length);
fs.Close();
// Generate post objects
Dictionary<string, object> postParameters = new Dictionary<string, object>();
postParameters.Add("filename", "signature3.jpg");
postParameters.Add("fileformat", "jpg");
postParameters.Add("file", new FormUpload.FileParameter(data, "signature3.jpg", "image/jpg"));
// Create request and receive response
string postURL = "https://demo.docusign.net/restapi/v2/accounts/"+accountId+"/users/"+userId+"/signatures/"+signatureName+"/signature_image";
string userAgent = "Someone";
HttpWebResponse webResponse = FormUpload.MultipartFormDataPost(postURL, userAgent, postParameters);
// Process response
StreamReader responseReader = new StreamReader(webResponse.GetResponseStream());
string fullResponse = responseReader.ReadToEnd();
webResponse.Close();
Response.Write(fullResponse);
return View();
}
}
DocuSign imposes a 200K limit on signature image files. See the DocuSign REST API guide for more info. Page 247 describes the set signature image call:
http://docusign.com/sites/default/files/REST_API_Guide_v2.pdf