How to convert chunck by chunck byte array into base64 string? - c#

We are reading byte array of a file and converting it into base64 string as follows
public static string ZipToBase64()
{
FileUpload fileCONTENT = FindControl("FileUploadControl") as FileUpload;
byte[] byteArr = fileCONTENT.FileBytes;
return Convert.ToBase64String(byteArr);
}
string attachmentBytes = ZipToBase64();
string json1 = "{ \"fileName\": \"Ch01.pdf\", \"data\": " + "\"" + attachmentBytes + "\"}";
When we try to convert large file upto 1 GB into base64 string, it is throwing out of memory exception. We are sending this json to restful wcf service. Following is my method in RESTful WCF Service.
[OperationContract]
[WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.WrappedRequest, RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
public void UploadFile1(Stream input)
{
string UserName = HttpContext.Current.Request.Headers["UserName"];
string Password = Sql.ToString(HttpContext.Current.Request.Headers["Password"]);
string sDevideID = Sql.ToString(HttpContext.Current.Request.Headers["DeviceID"]);
string Version = string.Empty;
if (validateUser(UserName, Password, Version, sDevideID) == Guid.Empty)
{
SplendidError.SystemWarning(new StackTrace(true).GetFrame(0), "Invalid username or password for " + UserName);
throw (new Exception("Invalid username or password for " + UserName));
}
string sRequest = String.Empty;
using (StreamReader stmRequest = new StreamReader(input, System.Text.Encoding.UTF8))
{
sRequest = stmRequest.ReadToEnd();
}
// http://weblogs.asp.net/hajan/archive/2010/07/23/javascriptserializer-dictionary-to-json-serialization-and-deserialization.aspx
JavaScriptSerializer json = new JavaScriptSerializer();
// 12/12/2014 Paul. No reason to limit the Json result.
json.MaxJsonLength = int.MaxValue;
Dictionary<string, string> dict = json.Deserialize<Dictionary<string, string>>(sRequest);
string base64String = dict["data"];
string fileName = dict["fileName"];
byte[] fileBytes = Convert.FromBase64String(base64String);
Stream stream = new MemoryStream(fileBytes);
//FileStream fs1 = stream as FileStream;
string networkPath = WebConfigurationManager.AppSettings["NetWorkPath"];
File.WriteAllBytes(networkPath + "/" + fileName, fileBytes); // Requires System.IO
}
Please provide solution for converting large byte array into base64 string

The fact you use Stream input in your wcf service does not really mean you pass anything in streamed manner. In fact in your case you do not, because:
You buffer whole file on client in memory to build json string.
You buffer whole file on server in memory via stmRequest.ReadToEnd().
So no streaming takes place. First you should realize that no json is needed here - you just need to pass file in your http request body. What you should do first is throw away all code below security checks in your UploadFile1 method and instead do this:
public void UploadFile1(string fileName, Stream input) {
// check your security headers here
string networkPath = WebConfigurationManager.AppSettings["NetWorkPath"];
using (var fs = File.Create(networkPath + "/" + fileName)) {
input.CopyTo(fs);
}
}
Here we just copy input stream to output stream (file) without any buffering (of course CopyTo will buffer chunks but they will be very small). Mark your service method with:
[WebInvoke(Method = "POST", UriTemplate = "/UploadFile1/{fileName}")]
To allow you pass filename in query string.
Now to client. Not sure which method you use to communicate with server, I'll show example with raw HttpWebRequest.
var filePath = "path to your zip file here";
var file = new FileInfo(filePath);
// pass file name in query string
var request = (HttpWebRequest)WebRequest.Create("http://YourServiceUrl/UploadFile1/" + file.Name);
request.Method = "POST";
// set content length
request.ContentLength = file.Length;
// stream file to server
using (var fs = File.OpenRead(file.FullName)) {
using (var body = request.GetRequestStream()) {
fs.CopyTo(body);
}
}
// ensure no errors
request.GetResponse().Dispose();

Related

Write content to a file on azure storage with using PUT request in C#

I am trying to make a put request to Azure storage file, where I want to add some simple contents. I change the URL and add ?comp=range at the end of the url but I get 403 error in response. I have created a basic console application in .net.
My Header is :
const string requestMethod = "PUT";
string urlPath = strShareName + "/" + "rahila.csv?comp=range";//+ "?comp=range HTTP/1.1";
String canonicalizedResource = String.Format("/{0}/{1}/{2}", StorageAccountName, strShareName, strFileName);
try
{
//GetWebRequest(requestMethod, urlPath, canonicalizedResource, "CreateFile");
HttpWebRequest request = null;
try
{
const string type = "file";
string MethodType = "CreateFile";
const string msVersion = "2015-04-05";
String dateInRfc1123Format = DateTime.UtcNow.ToString("R", CultureInfo.InvariantCulture);
String canonicalizedHeaders = "";
string data = "rahila sted";
canonicalizedHeaders = String.Format("x-ms-date:{0}\nx-ms-version:{1}", dateInRfc1123Format, msVersion);
if (MethodType == "CreateFile")
{
canonicalizedHeaders = String.Format("x-ms-content-length:65536\nx-ms-date:{0}\nx-ms-type:file\nx-ms-version:{1}", dateInRfc1123Format, msVersion);
}
String stringToSign = "";
stringToSign = String.Format("{0}\n\n\n\n\n\n\n\n\n\n\n\n{1}\n{2}", requestMethod, canonicalizedHeaders, canonicalizedResource);
if (String.IsNullOrEmpty(stringToSign))
{
throw new ArgumentNullException("canonicalizedString");
}
String signature;
if (String.IsNullOrEmpty(stringToSign))
{
throw new ArgumentNullException("unsignedString");
}
if (Convert.FromBase64String(StorageKey) == null)
{
throw new ArgumentNullException("key");
}
Byte[] dataToHmac = System.Text.Encoding.UTF8.GetBytes(stringToSign);
using (HMACSHA256 hmacSha256 = new HMACSHA256(Convert.FromBase64String(StorageKey)))
{
signature = Convert.ToBase64String(hmacSha256.ComputeHash(dataToHmac));
}
String authorizationHeader = String.Format(CultureInfo.InvariantCulture, "{0} {1}:{2}",
StorageScheme,
StorageAccountName, signature);
Uri uri = new Uri(FileEndPoint + urlPath);
request = (HttpWebRequest)WebRequest.Create(uri);
if (requestMethod != "Get")
{
request.ContentLength = data.Length;
}
// string data = "Hello testing";
//int a= ((data.Length) + 1);
request.Method = "PUT";//requestMethod;
request.Headers.Add("x-ms-write", "update");
request.Headers.Add("x-ms-date", dateInRfc1123Format);
request.Headers.Add("x-ms-version", msVersion);
request.Headers.Add("x-ms-range", "bytes=0-65535"); // + ((data.Length) - 1));
request.Headers.Add("Authorization", authorizationHeader);
the line where i get the exception is in the bold format.
HttpWebResponse response = null;
response = (HttpWebResponse)request.GetResponse();
string returnString = response.StatusCode.ToString();
Can anyone help me to resolve this issue or just guide me how to write content to a simple file on azure storage without using the azure client API.
update 12/19:
When using Put Range to upload content to azure file, you can follow the following code(I assume you have already created a file on the azure file share, and it's content length is larger than the content being uploaded):
static void UploadText()
{
string Account = "xxxx";
string Key = "xxxx";
string FileShare = "test1";
string FileName = "11.txt";
string apiversion = "2019-02-02";
//the string to be uploaded to azure file, note that the length of the uploaded string should less than the azure file length
string upload_text = "bbbbbbbbbbbbbbbbbbbbbbbb.";
Console.WriteLine("the string length: " + upload_text.Length);
DateTime dt = DateTime.UtcNow;
string StringToSign = String.Format("PUT\n"
+ "\n" // content encoding
+ "\n" // content language
+ upload_text.Length + "\n" // content length
+ "\n" // content md5
+ "\n" // content type
+ "\n" // date
+ "\n" // if modified since
+ "\n" // if match
+ "\n" // if none match
+ "\n" // if unmodified since
+ "\n"//+ "bytes=0-" + (upload_text.Length - 1) + "\n" // range
+"x-ms-date:" + dt.ToString("R") + "\nx-ms-range:bytes=0-"+(upload_text.Length-1) + "\nx-ms-version:" + apiversion + "\nx-ms-write:update\n" // headers
+ "/{0}/{1}/{2}\ncomp:range", Account, FileShare, FileName);
string auth = SignThis(StringToSign, Key, Account);
string method = "PUT";
string urlPath = string.Format("https://{0}.file.core.windows.net/{1}/{2}?comp=range", Account, FileShare,FileName);
Uri uri = new Uri(urlPath);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
request.Method = method;
request.ContentLength = upload_text.Length;
request.Headers.Add("x-ms-range", "bytes=0-"+(upload_text.Length-1));
request.Headers.Add("x-ms-write", "update");
request.Headers.Add("x-ms-date", dt.ToString("R"));
request.Headers.Add("x-ms-version", apiversion);
request.Headers.Add("Authorization", auth);
//request.Headers.Add("Content-Length", upload_text.Length.ToString());
var bytes = System.Text.Encoding.ASCII.GetBytes(upload_text);
using (var requestStream = request.GetRequestStream())
{
requestStream.Write(bytes, 0, bytes.Length);
}
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
//read the content
Console.WriteLine("the response is:" + response.StatusCode);
}
}
private static String SignThis(String StringToSign, string Key, string Account)
{
String signature = string.Empty;
byte[] unicodeKey = Convert.FromBase64String(Key);
using (HMACSHA256 hmacSha256 = new HMACSHA256(unicodeKey))
{
Byte[] dataToHmac = System.Text.Encoding.UTF8.GetBytes(StringToSign);
signature = Convert.ToBase64String(hmacSha256.ComputeHash(dataToHmac));
}
String authorizationHeader = String.Format(
CultureInfo.InvariantCulture,
"{0} {1}:{2}",
"SharedKey",
Account,
signature);
return authorizationHeader;
}
Then in the Main() method, you can call UploadText() method, it works at my side.
old:
guide me how to write content to a simple file on azure storage
without using the azure client API.
For this, you can directly use Azure File Storage SDK Microsoft.Azure.Storage.File, version 11.1.1. And we always recommend using SDK instead of using rest api, because the SDK is easy to use.
Here is an example of using this SDK.
First, create a console project of .NET framework in visual studio. Then install this nuget package Microsoft.Azure.Storage.File, version 11.1.1.
The code:
using Microsoft.Azure.Storage;
using Microsoft.Azure.Storage.Auth;
using Microsoft.Azure.Storage.File;
using System;
namespace AzureFileTest2
{
class Program
{
static void Main(string[] args)
{
string accountName = "xxx";
string accountKey = "xxx";
CloudStorageAccount storageAccount = new CloudStorageAccount(new StorageCredentials(accountName, accountKey), true);
CloudFileClient cloudFileClient = storageAccount.CreateCloudFileClient();
//make sure the file share named test1 exists.
CloudFileShare fileShare = cloudFileClient.GetShareReference("test1");
CloudFileDirectory fileDirectory = fileShare.GetRootDirectoryReference();
CloudFile myfile = fileDirectory.GetFileReference("test123.txt");
if (!myfile.Exists())
{
//if the file does not exists, then create the file and set the file max size to 100kb.
myfile.Create(100 * 1024 * 1024);
}
//upload text to the file
//Besides using UploadText() method to directly upload text, you can also use UploadFromFile() / UploadFromByteArray() / UploadFromStream() methods as per your need.
myfile.UploadText("hello, it is using azure storage SDK");
Console.WriteLine("**completed**");
Console.ReadLine();
}
}
}

Publish article for Apple news API using C# - (401) Unauthorized

I am working on posting article using Apple news API.
I created new account and also created new channel.
Below is the code snippet which I am using.
string channel_id = "{Channel_Id}";
string api_key_id = "{Key_Id}";
string api_key_secret = "{Secret}";
var path = "https://news-api.apple.com/channels/" + channel_id + "/articles";
var httpWebRequest = (HttpWebRequest)WebRequest.Create(path);
httpWebRequest.ContentType = "multipart/form-data";
httpWebRequest.Method = "POST";
httpWebRequest.Accept = "application/json";
httpWebRequest.Host = "news-api.apple.com";
httpWebRequest.UseDefaultCredentials = true;
httpWebRequest.PreAuthenticate = true;
httpWebRequest.ProtocolVersion = HttpVersion.Version11;
httpWebRequest.KeepAlive = true;
string appleDate = String.Format("{0}Z", DateTime.UtcNow.ToString("s"));
string credentials = String.Format("{0}:{1}", "Content-Disposition", "form-data; ");
credentials += String.Format("{0}:{1}", "filename", "article.json; ");
credentials += String.Format("{0}:{1}", "name", "article.json; ");
credentials += String.Format("{0}","HHMAC; ");
credentials += String.Format("{0}={1}", "key", api_key_id + "; ");
string decodedSecret = base64Decode(api_key_secret);
string canonical_request = path + "POST" + appleDate ;
string hash = Class1.HmacSha256Digest(canonical_request, decodedSecret);
string Encodedhash = Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(hash));
credentials += String.Format("{0}={1}", "signature", Encodedhash + "; ");
credentials += String.Format("{0}={1}", "date", appleDate + "; ");
httpWebRequest.Headers.Add("Authorization", credentials);
using (StreamReader r = new StreamReader(Directory.GetCurrentDirectory() + ("/article.json")))
{
string json = r.ReadToEnd();
dynamic jsonObj = JsonConvert.DeserializeObject(json);
ASCIIEncoding encoding = new ASCIIEncoding();
Byte[] bytes = encoding.GetBytes(json);
Stream newStream = httpWebRequest.GetRequestStream();
newStream.Write(bytes, 0, bytes.Length);
newStream.Close();
}
var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Here is base64Decode function
public static string base64Decode(string data)
{
var base64EncodedBytes = System.Convert.FromBase64String(data);
return System.Text.Encoding.UTF8.GetString(base64EncodedBytes);
}
Here is class to convert Sha256Digest
public static class Class1
{
public static string HmacSha256Digest(this string message, string secret)
{
ASCIIEncoding encoding = new ASCIIEncoding();
byte[] keyBytes = encoding.GetBytes(secret);
byte[] messageBytes = encoding.GetBytes(message);
System.Security.Cryptography.HMACSHA256 cryptographer = new System.Security.Cryptography.HMACSHA256(keyBytes);
byte[] bytes = cryptographer.ComputeHash(messageBytes);
return BitConverter.ToString(bytes).Replace("-", "").ToLower();
}
}
Whenever I am trying to post the API I am getting below error message:
"'The remote server returned an error: (401) Unauthorized".
When I am trying to post the API request using Postman then I am getting below error message:
{
"errors": [
{
"code": "WRONG_SIGNATURE"
}
]
}
Is there anything incorrect to generate Signature ?
I researched few articles but unable to find any solution.
Please guide me to find out the solution on this.
I don't have time to go through the entirety of your code and suggest you start with a simpler Channel Data request before attempting to POST json, but a potential couple of bits I noticed:
You use ASCII encoding where you should be using UTF8 throughout.
You strip hyphens from the Base64 but Apple only strips returns and
whitespace
The cannonical request should be written: "POST[url][date][contentType]" where url = "https://news-api.apple.com/channels/[channelID]/articles", date is in the format "yyyy-MM-dd'T'HH:mm:ss'Z'" and content-type = "multipart/form-data; boundary=[boundary]" where boundary is any string used to divide the content.
See also my tips on using Python, most importantly ensure you are using the path to a folder containing article.json (not the path to a file). And finally here is my own translation of the Python into Swift.

Convert API, new API version docx to PDF

I'm using Convert API to convert docx to PDF. With the old API version everything works good, but I'm trying to migrate to the new API version and when I open the PDF is not a valid document and it will not open. Not sure what I am doing wrong, maybe something about the encoding?
The response that I get from Convert API is a JSON with the File Name, File Size and File Data. Maybe this File Data needs to be processed to create a valid PDF file? if I just write that data in a file it does not work.
public string ConvertReportToPDF(string fileName)
{
string resultFileName = "";
key = "xxxxx";
var requestContent = new MultipartFormDataContent();
var fileStream = System.IO.File.OpenRead(fileName);
var stream = new StreamContent(fileStream);
requestContent.Add(stream, "File", fileStream.Name);
var response = new HttpClient().PostAsync("https://v2.convertapi.com/docx/to/pdf?Secret=" + key, requestContent).Result;
FileReportResponse responseDeserialized = JsonConvert.DeserializeObject<FileReportResponse>(response.Content.ReadAsStringAsync().Result);
var path = SERVER_TEMP_PATH + "\\" + responseDeserialized.Files.First().FileName;
System.IO.File.WriteAllText(path, responseDeserialized.Files.First().FileData);
return responseDeserialized.Files.First().FileName;
}
File data in JSON is Base64 encoded, decode it before writing to a file.
public string ConvertReportToPDF(string fileName)
{
string resultFileName = "";
key = "xxxxx";
var requestContent = new MultipartFormDataContent();
var fileStream = System.IO.File.OpenRead(fileName);
var stream = new StreamContent(fileStream);
requestContent.Add(stream, "File", fileStream.Name);
var response = new HttpClient().PostAsync("https://v2.convertapi.com/docx/to/pdf?Secret=" + key, requestContent).Result;
FileReportResponse responseDeserialized = JsonConvert.DeserializeObject<FileReportResponse>(response.Content.ReadAsStringAsync().Result);
var path = SERVER_TEMP_PATH + "\\" + responseDeserialized.Files.First().FileName;
System.IO.File.WriteAllText(path, Convert.FromBase64String(responseDeserialized.Files.First().FileData));
return responseDeserialized.Files.First().FileName;
}
Why to use JSON response in C# when you can use binary response instead. A response will be smaller, no need to decode. To change response type you need to add accept=application/octet-stream header to request to ask for binary response from server. The whole code will look like
using System;
using System.Net;
using System.IO;
class MainClass {
public static void Main (string[] args) {
const string fileToConvert = "test.docx";
const string fileToSave = "test.pdf";
const string Secret="";
if (string.IsNullOrEmpty(Secret))
Console.WriteLine("The secret is missing, get one for free at https://www.convertapi.com/a");
else
try
{
Console.WriteLine("Please wait, converting!");
using (var client = new WebClient())
{
client.Headers.Add("accept", "application/octet-stream");
var resultFile = client.UploadFile(new Uri("http://v2.convertapi.com/docx/to/pdf?Secret=" + Secret), fileToConvert);
File.WriteAllBytes(fileToSave, resultFile );
Console.WriteLine("File converted successfully");
}
}
catch (WebException e)
{
Console.WriteLine("Status Code : {0}", ((HttpWebResponse)e.Response).StatusCode);
Console.WriteLine("Status Description : {0}", ((HttpWebResponse)e.Response).StatusDescription);
Console.WriteLine("Body : {0}", new StreamReader(e.Response.GetResponseStream()).ReadToEnd());
}
}
}

Restful api + special characres

I have the following Rest interface:
[OperationContract(AsyncPattern = true)]
[WebInvoke(Method = "POST", UriTemplate = "/Save/servers/{serverName}/databases{databaseName}")]
Task Save(string subscriptionId, string serverName, string databaseName, Stream policyStream);
I invoke using that client`s method
private async Task<RestResponse> SendRequestWithPayloadAsync(string verbName, string methodName, string requestBody, IEnumerable<object> parameters = null)
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
string address = BuildAddress(methodName, parameters);
if (requestBody == null)
{
requestBody = String.Empty;
}
byte[] payload = Encoding.UTF8.GetBytes(requestBody);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(address);
SetCertificateSettings(request);
request.Method = verbName;
request.ContentType = "text/xml;charset=utf-8";
request.ContentLength = payload.Length;
// send request over the network
using (Stream dataStream = await request.GetRequestStreamAsync())
{
await dataStream.WriteAsync(payload, 0, payload.Length);
}
return await GetResponse(request, stopwatch, payload.Length);
}
When the databaseName ends with "#" I don`t get it in Save method
For example if I send
databases\hgは常#
I get hgは常 databases argument value.
Any ideas what causes that? and how to solve the issue?
The reason for that is because '#' character is a special character when being used in URLs (you can find more information here: http://en.wikipedia.org/wiki/Fragment_identifier - There are more reserved characters - see the section of RFC 3986)
You should escape URLs using Percent-Encoding (http://en.wikipedia.org/wiki/Percent-encoding)
So, if you want to include a hash-mark (#) in your parameters - pass '%23' instead.

How to get PDF back from a byte array

What I’m trying to do is…
Let the user select a PDF file and some other files using a WCF…once they select the file…those files need to be moved from there to a remote server (company hosted). I’m trying to deserialize the data (reading it as bytes) and transferring it over. I created a Form just as a testing purpose and to see how my client is going to work.
When I get the file....I can display the file but I want to get the actual PDF back and I’m not being able to do that. I can open the file in notepad (but its in the byte format) and when I try to open it in PDF it says that the file format is not supported. I’m really confused and don’t know what needs to be done.
Your help will be really appreciated.
Code Snippet:
Client Side:
private void btnUploadFile_Click(object sender, EventArgs e)
{
string pathServer = #"C:\Users\....\Desktop\Test.pdf";
RestClient newClient = new RestClient("http://localhost:...../Service1.svc/DisplayRawData");
var request = new RestRequest(Method.GET);
request.RequestFormat = DataFormat.Json;
request.OnBeforeDeserialization = resp => { resp.ContentType = "application/json"; };
IRestResponse<TempString> newResponse = newClient.Execute<TempString>(request);
//List<TempString> rtrn = (List<TempString>)newResponse.Data;
var responseData = newClient.DownloadData(request);
FileStream fStream = new FileStream(pathServer, FileMode.Create);
BinaryWriter bw = new BinaryWriter(fStream);
bw.Write(responseData);
bw.Close();
foreach (var xbyte in responseData)
{
// fStream.WriteByte(xbyte);
}
//fStream.Flush();
fStream.Close();
Server Side (Service)
public string DisplayRawData()
{
string path = #"C:\basketball.pdf";
byte[] fileToSend = File.ReadAllBytes(path);
string filetoSendB64 = Convert.ToBase64String(fileToSend);
// WebOperationContext.Current.OutgoingResponse.ContentType = "application/pdf";
return filetoSendB64;
}
Interface
//Getting Stream from a File
[OperationContract]
[WebInvoke(Method = "GET", UriTemplate = "DisplayRawData",
RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
// string DisplayRawData();
string DisplayRawData();
The code is a bit confusing, but I would say it looks like you need to decode the response string from Base64 back to a byte array before writing it to a file.

Categories