How to upload image signature in docusign by c#? - docusignapi

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

Related

Azure Blob Storage - Error trying to delete blob with API REST with C#

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.

POI not sending xls file as attachment , sending as string

one of my junior code is not sending excel file as attachment . It is sending file like
------=_Part_0_2066339629.1374147892060
Content-Type: text/plain; name="Service_Change_Alert_Thu Jul 18 17:14:50 IST 2013.xlsx"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="Service_Change_Alert_Thu Jul 18 17:14:50 IST 2013.xlsx"
UEsDBBQACAAIANqJ8kIAAAAAAAAAAAAAAAARAAAAZG9jUHJvcHMvY29yZS54bWytkV1LwzAUhu/7
K0Lu2yTr1BHaDlEGguLADsW7kB7bYvNBEu3892bdrCheennyPu/D4aRY79WA3sH53ugSs4xiBFqa
ptdtiXf1Jl3hdZUkhTQOts5YcKEHj2JL+xJ3IVhOiJcdKOGzGOuYvBinRIija4kV8lW0QBaUnhMF
QTQiCHKwpXbW4aOPS/vvykbOSvvmhknQSAIDKNDBE5Yx8s0GcMr/WZiSmdz7fqbGcczGfOLiRow8
3d0+TMunvfZBaAm4ShAqTnYuHYgADYoOHj4slPgrecyvrusNrhaU5Sm9SNmqZowvl/yMPhfkV//k
function is following
public void sendSeviceabilityMail(List<OctpinSaveBean> datalist)
throws MessagingException {
Session session = null;
Map<String, String> utilsMap = ApplicationBean.utilsProperties;
if (utilsMap == null || utilsMap.size() == 0)
utilsMap = ApplicationBean.getUtilsPropertyFileValues();
smtpHost = utilsMap.get("SMTPHost");
to = utilsMap.get("To");
try {
if (smtpHost != null && to != null) {
Date date = new Date();
XSSFWorkbook updateDataBook =
updatedServiceabilityExcel(datalist);
Properties props = System.getProperties();
props.put("mail.smtp.host", smtpHost);
props.put("To", to);
session = Session.getInstance(props, null);
String str = "strstr";
Multipart multipart = new MimeMultipart();
BodyPart messageBodyPart1 = new MimeBodyPart();
messageBodyPart1.setContent(str, "text/html");
BodyPart messageBodyPart = new MimeBodyPart();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
updateDataBook.write(baos);
byte[] bytes = baos.toByteArray();
DataSource ds = new ByteArrayDataSource(bytes,
"application/vnd.ms-excel");
DataHandler dh = new DataHandler(ds);
messageBodyPart.setDataHandler(dh);
String fileName = "Service_Change_Alert_" + date+".xlsx";
messageBodyPart.setFileName(fileName);
messageBodyPart.setHeader("Content-disposition", "attachment;
filename=\"" + fileName + "\"");
multipart.addBodyPart(messageBodyPart1);
multipart.addBodyPart(messageBodyPart);
if (to != null && to.length() > 0) {
MimeMessage msg = new MimeMessage(session);
msg.setFrom(new InternetAddress("tech_noida
<tech_noida#xyz.com>"));
String[] toArray = to.split(",");
InternetAddress[] address = new
InternetAddress[toArray.length];
for (int i = 0; i < toArray.length; i++) {
address[i] = new InternetAddress(toArray[i]);
}
msg.setRecipients(Message.RecipientType.TO, address);
msg.setSubject("Updated Serviceability Alert!!!");
msg.setContent(multipart);
msg.setSentDate(date);
try {
Transport.send(msg);
logger.info("Mail has been sent about the updated serviceability alert to :" + to);
} catch (Exception e1) {
e1.printStackTrace();
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
The problem is not related to POI, but with JavaMail (plus the way different email clients handles the specs and malformed emails). Try this:
Multipart multipart = new MimeMultipart();
MimeBodyPart html = new MimeBodyPart();
// Use actual html not "strstr"
html.setContent("<html><body><h1>Hi</h1></body></html>", "text/html");
multipart.addBodyPart(html);
// ...
// Joop Eggen suggestion to avoid spaces in the file name
String fileName = "Service_Change_Alert_"
+ new SimpleDateFormat("yyyy-MM-dd_HH:mm").format(date) + ".xlsx";
ByteArrayOutputStream baos = new ByteArrayOutputStream();
updateDataBook.write(baos);
byte[] poiBytes = baos.toByteArray();
// Can be followed by the DataSource / DataHandler stuff if you really need it
MimeBodyPart attachment = new MimeBodyPart();
attachment.setFileName(filename);
attachment.setContent(poiBytes, "application/vnd.ms-excel");
//attachment.setDataHandler(dh);
attachment.setDisposition(MimeBodyPart.ATTACHMENT);
multipart.addBodyPart(attachment);
Update:
Also don't forget to call saveChanges to update the headers before sending the message.
msg.saveChanges();
See this answer for further details.

How to create azure VM with Rest Api

Here is the code, but it prompts error:
The image o3lceiy3.ioa201305211013360129.vhd does not exist.
the subscriptionId and X509Certificate2 are valid
internal class Program
{
public static X509Certificate2 Certificate { get; set; }
private static void Main(string[] args)
{
const string subscriptionId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";
//#"https://management.core.windows.net/<subscription-id>/services/hostedservices/<cloudservice-name>/deployments";
var url = string.Format("https://management.core.windows.net/{0}/services/hostedservices/{1}/deployments",
subscriptionId, "edoc2cloudtest");
var myReq = (HttpWebRequest)WebRequest.Create(url);
myReq.Method = "POST";
myReq.Headers.Add("x-ms-version", "2012-03-01");
myReq.Proxy = null;
myReq.Timeout = 30000;
myReq.ContentType = "application/xml";
var postData = ReadConfig();
using (var reqStream = myReq.GetRequestStream())
{
var data = Encoding.UTF8.GetBytes(postData);
reqStream.Write(data, 0, data.Length);
reqStream.Flush();
}
Certificate = GetX509Certificate();
myReq.ClientCertificates.Add(Certificate);
try
{
var myRes = (HttpWebResponse) myReq.GetResponse();
}
catch (WebException exWeb)
{
// Parse the web response.
Stream responseStream = exWeb.Response.GetResponseStream();
StreamReader reader = new StreamReader(responseStream);
XmlDocument xDocResp = new XmlDocument();
xDocResp.Load(reader);
HttpWebResponse responseStatus = (HttpWebResponse)exWeb.Response;
responseStream.Close();
reader.Close();
var result = NiceFormatXml(xDocResp);
Console.WriteLine(result);
}
}
private static string NiceFormatXml(XmlDocument xDoc)
{
StringBuilder niceString = new StringBuilder();
StringWriter strWriter = new StringWriter(niceString);
XmlTextWriter xmlWriter = new XmlTextWriter(strWriter);
xmlWriter.Formatting = Formatting.Indented;
xDoc.WriteTo(xmlWriter);
xmlWriter.Close();
strWriter.Close();
return niceString.ToString();
}
private static X509Certificate2 GetX509Certificate()
{
X509Certificate2 certificate2 = null;
var store = new X509Store("MY", StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
var collection = store.Certificates;
var fcollection = collection.Find(X509FindType.FindByTimeValid, DateTime.Now, false);
const string certificateThumbprint = "‎‎‎‎7dfbc7369306ed096b7e5c7b4ba6e99f190240e9";
store.Close();
if (fcollection.Count > 0)
{
foreach (var variable in fcollection)
{
if (variable.Thumbprint != null &&
variable.Thumbprint.Equals(certificateThumbprint, StringComparison.InvariantCultureIgnoreCase))
{
certificate2 = variable;
}
}
}
return certificate2;
}
private static string ReadConfig()
{
string path = System.AppDomain.CurrentDomain.BaseDirectory + "Edoc2Cloud.xml";
//string path = System.AppDomain.CurrentDomain.BaseDirectory + "VM-CreateVM.xml";
string s;
using (var sr = new StreamReader(path, Encoding.GetEncoding("GB2312")))
{
s = sr.ReadToEnd();
}
return s;
}
}
Here is the XML:
<Deployment xmlns="http://schemas.microsoft.com/windowsazure" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Name>EDoc2Test</Name>
<DeploymentSlot>Staging</DeploymentSlot>
<Label>EDoc2Testlabe</Label>
<RoleList>
<Role>
<RoleName>EDoc2TestRoleName</RoleName>
<RoleType>PersistentVMRole</RoleType>
<ConfigurationSets>
<ConfigurationSet>
<ConfigurationSetType>WindowsProvisioningConfiguration</ConfigurationSetType>
<ComputerName>computer-name</ComputerName>
<AdminPassword>APasswor_324d</AdminPassword>
<EnableAutomaticUpdates>true</EnableAutomaticUpdates>
</ConfigurationSet>
</ConfigurationSets>
<AvailabilitySetName>EDoc2TestSetName</AvailabilitySetName>
<OSVirtualHardDisk>
<HostCaching>ReadWrite</HostCaching>
<DiskName>SomeName-0-20121007173943</DiskName>
<MediaLink>http://portalvhdsx4flx9dhmjyt1.blob.core.windows.net/vhds/o3lceiy3.ioa201305211013360129.vhd</MediaLink>
<SourceImageName>o3lceiy3.ioa201305211013360129.vhd</SourceImageName>
</OSVirtualHardDisk>
<RoleSize>Medium</RoleSize>
</Role>
Based on the error you're receiving and the XML you've specified, can you please check if there is an image by the name o3lceiy3.ioa201305211013360129.vhd in your custom images? You could find that information by logging into the portal and going to Virtual Machines --> Images.
Documentation regarding <SourceImageName> parameter states that it is needed when you want to create a virtual machine either by using system or custom images.
You can read the complete documentation here: http://msdn.microsoft.com/en-us/library/windowsazure/jj157186.aspx#OSVirtualHardDisk.

upload files over https

Can anyone give me a C# code snippet for this kind of file upload:
POST <BASE-URL>/documents
Content-Type: multipart/form-data; boundary=<BOUNDARY>
Transfer-Encoding: chunked
--<BOUNDARY>
Content-Disposition: form-data; name=“metadata”
Content-Type: application/json
{
“metadata” : {
“document” : {
“filename” : <filename>,
“size” : <filesize>,
“title” : <title>,
“author” : <author>
}
}
}
--<BOUNDARY>
Content-Disposition: form-data; name=“document”; filename=“<filename>”
Content-Type: <mime-type>
<File contents>
--<BOUNDARY>--
Currently I am using method shown below and I am getting status 400:Bad Request:
public static void HttpUploadFile(string url, string file, string paramName, string contentType, NameValueCollection nvc,string accessToken)
{
string boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x");
byte[] boundarybytes = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n");
HttpWebRequest wr = (HttpWebRequest)WebRequest.Create(url);
wr.ContentType = "multipart/form-data; boundary=" + boundary;
wr.Method = "POST";
wr.KeepAlive = false;
wr.SendChunked = true;
wr.Headers.Add("Authorization", "Bearer " + accessToken);
wr.Credentials = System.Net.CredentialCache.DefaultCredentials;
Stream rs = wr.GetRequestStream();
string formdataTemplate = "Content-Disposition: form-data; name=\"{0}\"\r\n\r\n{1}";
foreach (string key in nvc.Keys)
{
rs.Write(boundarybytes, 0, boundarybytes.Length);
string formitem = string.Format(formdataTemplate, key, nvc[key]);
byte[] formitembytes = System.Text.Encoding.UTF8.GetBytes(formitem);
rs.Write(formitembytes, 0, formitembytes.Length);
}
rs.Write(boundarybytes, 0, boundarybytes.Length);
string headerTemplate = "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\nContent-Type: {2}\r\n\r\n";
string header = string.Format(headerTemplate, paramName, file, contentType);
byte[] headerbytes = System.Text.Encoding.UTF8.GetBytes(header);
rs.Write(headerbytes, 0, headerbytes.Length);
FileStream fileStream = new FileStream(file, FileMode.Open, FileAccess.Read);
byte[] buffer = new byte[256000];
int bytesRead = 0;
while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
{
rs.Write(buffer, 0, bytesRead);
}
fileStream.Close();
byte[] trailer = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "--\r\n");
rs.Write(trailer, 0, trailer.Length);
rs.Close();
WebResponse wresp = null;
try
{
wresp = wr.GetResponse();
Stream stream2 = wresp.GetResponseStream();
StreamReader reader2 = new StreamReader(stream2);
//log.Debug(string.Format("File uploaded, server response is: {0}", reader2.ReadToEnd()));
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
if (wresp != null)
{
wresp.Close();
wresp = null;
}
}
finally
{
wr = null;
}
}
I guess it is the json string part of a post header form-data that gives me the trouble... here it uses namevaluecollection...
Thanx!

getting 403 forbidden webexception for azure blob put request

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.

Resources