How to upload "Binary" data through "oneNote API" - c#

I need to upload multiple images to oneNote through "oneNote API", but I don't know how to write binary to code.
Here's the code in my code:
var client = new HttpClient();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", await Auth.GetAuthToken(provider));
string imagePartName = "imageBlock1";
StringBuilder simpleHtml = new StringBuilder();
simpleHtml.Append("<html lang=\"zh-CN\">\n");
simpleHtml.Append("<head>\n");
simpleHtml.Append("<title>" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "</title>\n");
simpleHtml.Append("<meta name=\"created\" content=\"" + DateTime.Now.ToString("o") + "\" />\n");
simpleHtml.Append("<meta http-equiv=\"Content-Type\" content=\"text/html;charset=utf-8\" />\n");
simpleHtml.Append("</head>\n");
simpleHtml.Append("<body data-absolute-enabled=\"true\" style=\"font-family:Microsoft YaHei;font-size:11pt\">\n");
simpleHtml.Append("<img src=\"name:"+ imagePartName + "\" alt=\"a cool image\" width=\"500\"/>");
simpleHtml.Append("</body>\n");
simpleHtml.Append("</html>");
var createMessage = new HttpRequestMessage(HttpMethod.Post, apiRoute + "/pages")
{
Content = new MultipartFormDataContent
{
{
new StringContent(simpleHtml.ToString(), Encoding.UTF8, "text/html"), "Presentation"
}, //Here is the HTML data
//How to add "binary" data here
}
};
response = await client.SendAsync(createMessage);
Looking forward to everyone's reply!

If you want to use MultipartFormDataContent you can convert your binary data to Base64 string (example).
Drawback of this is the amount of characters you need to transfer.
There're several methods in MultipartFormDataContent that concerns 'stream'. It would be worth to look into those.

Related

Reading Multipart Data from Xamarin

We have a requirement of sending the jpeg files of a given directory to a Xamarin App.
Following is the code in the Web API.
public HttpResponseMessage DownloadMutipleFiles()
{
name = "DirectoryName";
var content = new MultipartContent();
var ids = new List<int> { 1,2};
var objectContent = new ObjectContent<List<int>>(ids, new System.Net.Http.Formatting.JsonMediaTypeFormatter());
content.Add(objectContent);
var file1Content = new StreamContent(new FileStream(#"D:\Photos\" + name+"\\"+ "BL1408037_20191031124058_0.jpg", FileMode.Open));
file1Content.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("image/jpeg");
content.Add(file1Content);
var file2Content = new StreamContent(new FileStream(#"D:\Photos\" + name + "\\" + "BL1408037_20191031124058_1.jpg", FileMode.Open));
file2Content.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("image/jpeg");
content.Add(file2Content);
var response = new HttpResponseMessage(HttpStatusCode.OK);
response.Content = content;
return response;
}
Can some one help out with how to read from Xamarin app? Thanks in advance
This is the function I was able to use to send an image as a multi part data file! I just took the byte array given to me by the Xamarin Essentials image picker and passed it into this function:
public async Task SubmitImage(byte[] image, string imageName)
{
using (var client = new HttpClient())
{
string url = $"..."; // URL goes here
var token = Preferences.Get("AccessToken", "");
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
var stream = new MemoryStream(image);
var content = new StreamContent(stream);
//Without a name we can't actually put the file in IFormFile. We need the equivalent
//"name" value to be "file" (used if you upload via an <input> tag). We could call it
//anything but file is simple
content.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{
FileName = imageName,
Name = "file"
};
content.Headers.ContentType = new MediaTypeHeaderValue("image/jpeg");
var multipartContent = new MultipartFormDataContent();
multipartContent.Add(content);
var result = await client.PostAsync(url, multipartContent);
}
}
You can test this using a console application as well and just send over a picture from your computer, instead of doing this through the app

Upload file to OneDrive using RestAPI

I am trying to upload an image to OneDrive using below code. The file was successfully uploaded to the OneDrive folder but when I download the file manually from OneDrive, it opens in black color and shows Invalid Image.
var client = new RestClient("https://graph.microsoft.com/v1.0" + $"/drives/{driveID}/items/{folderId}:/{originalFileName}:/content");
var request = new RestRequest(Method.PUT);
request.AddHeader("cache-control", "no-cache");
request.AddHeader("Content-Type", Path.GetExtension(originalFileName).GetMimeType());
request.AddHeader("Authorization", "Bearer " + GetAccessToken());
request.AddFile("content", System.IO.File.ReadAllBytes(filePath), originalFileName);
var response = client.Execute(request);
I really do not know what mistake I am making in here. May you please help me?
Inspired from this SO answer
I need to change it to HttpClient from RestClient. After change the code will like:
using (var client = new HttpClient())
{
var url = "https://graph.microsoft.com/v1.0" + $"/drives/{driveID}/items/{folderId}:/{originalFileName}:/content";
client.DefaultRequestHeaders.Add("Authorization", "Bearer " + GetAccessToken());
byte[] sContents = System.IO.File.ReadAllBytes(filePath);
var content = new ByteArrayContent(sContents);
var response = client.PutAsync(url, content).Result.Content.ReadAsStringAsync().Result;
}

C# RESTful POST with image and body

I am currently trying to POST some data to server to create user profile. The body of RESTful POST has selected image and also other fields.
I managed to POST it using Postman. However, I am trying to figure out how to do it using C#. I attempted but it seems that server returns status 500 without much useful message.
Please refer attachments on how i POST to server and some C# code on how I attempted to POST it. Appreciate help on how to fix my C# code to make it work.
C# code:
if (!string.IsNullOrEmpty(baseUrl) && !string.IsNullOrEmpty(apiKey))
{
var fullUrl = baseUrl + "/user_profiles";
using (var httpClient = new HttpClient())
{
//httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", apiKey);
httpClient.DefaultRequestHeaders.Add("Authorization", "Bearer " + apiKey);
var boundary = "Upload----" + DateTime.Now.Ticks.ToString();
using (var content = new MultipartFormDataContent(boundary))
{
try
{
var name = string.IsNullOrEmpty(userRegistration.Name) ? "" : userRegistration.Name;
var city = string.IsNullOrEmpty(userRegistration.City) ? "" : userRegistration.City.ToUpper();
var phone = string.IsNullOrEmpty(userRegistration.Mobile) ? "" : userRegistration.Mobile;
phone = phone.Replace(" ", ""); //remove empty string in between and at edges
phone = phone.StartsWith("+") ? phone : "+" + phone;
var address = string.IsNullOrEmpty(userRegistration.CompanyAddress) ? "Unspecified" : userRegistration.CompanyAddress;
var country = string.IsNullOrEmpty(userRegistration.Country) ? "" : userRegistration.Country.ToUpper();
var email = string.IsNullOrEmpty(userRegistration.Email) ? "" : userRegistration.Email;
var isContractor = userRegistration.IsRegisteredAsContractor.ToString();
var category = string.IsNullOrEmpty(userRegistration.Category) ? "" : userRegistration.Category;
var companyName = string.IsNullOrEmpty(userRegistration.CompanyName) ? "" : userRegistration.CompanyName;
var companyAddress = string.IsNullOrEmpty(userRegistration.CompanyAddress) ? "" : userRegistration.CompanyAddress;
//TEST
//var body = new
//{
// city,
// phone,
// address,
// country,
// email,
// name,
// identifier_for_vendor = localId,
// is_contractor = isContractor,
// work_categories = category,
// company_name = companyName,
// company_address = companyAddress
//};
//var bodyStr = JsonConvert.SerializeObject(body);
//var stringContent = new StringContent(bodyStr, Encoding.UTF8, "application/json");
//content.Add(stringContent);
//response = await httpClient.PostAsync(fullUrl, content).ConfigureAwait(false);
//TEST
content.Add(new StringContent(name, Encoding.UTF8, "text/plain"), "name");
content.Add(new StringContent(city, Encoding.UTF8, "text/plain"), "city");
content.Add(new StringContent(phone, Encoding.UTF8, "text/plain"), "phone");
content.Add(new StringContent(companyAddress, Encoding.UTF8, "text/plain"), "address");
content.Add(new StringContent(country, Encoding.UTF8, "text/plain"), "country");
content.Add(new StringContent(email, Encoding.UTF8, "text/plain"), "email");
content.Add(new StringContent(localId, Encoding.UTF8, "text/plain"), "identifier_for_vendor");
content.Add(new StringContent(isContractor, Encoding.UTF8, "text/plain"), "is_contractor");
content.Add(new StringContent(category, Encoding.UTF8, "text/plain"), "work_categories");
content.Add(new StringContent(companyName, Encoding.UTF8, "text/plain"), "company_name");
content.Add(new StringContent(companyAddress, Encoding.UTF8, "text/plain"), "company_address");
if (!string.IsNullOrEmpty(userRegistration.ProfileImagePath) && File.Exists(userRegistration.ProfileImagePath))
{
using (var stream = File.OpenRead(userRegistration.ProfileImagePath))
{
//stream.Seek(0, SeekOrigin.Begin);
var fileName = Guid.NewGuid().ToString() + ".jpg";
content.Add(new StreamContent(stream), "image", fileName);
response = await httpClient.PostAsync(fullUrl, content).ConfigureAwait(false);
}
}
else
{
response = await httpClient.PostAsync(fullUrl, content).ConfigureAwait(false);
}
}
catch (Exception ex)
{
}
}
}
}
When you use File.OpenRead, It will return a File Stream (Bytes)
You need to convert it to Base64 which is the preferred way of sending images over REST.
base64Image = System.Convert.ToBase64String(stream);
After that, you will need to convert it back on your backend and store it where ever you want.
Also, I wouldn't recommend using FormDataContent to send the data since it has some size limitations.
I recommend using JObjectand adding what you want to send as JProperty.
Uri postURL = new Uri(Constants.RestUrl + "/NewReservation");
HttpClient client = new HttpClient();
TimeSpan timeout = new TimeSpan(0, 0, 20);
client.Timeout = timeout;
var UserData = AccountCheck.CurrentUserData();
JObject RequestData = new JObject(
new JProperty("apiKey", UserData.ApiKey),
new JProperty("customerID", UserData.CustomerId.ToString()),
new JProperty("containerIDs", NewReservationRequest.ContainerIDs),
new JProperty("containersQuantities", NewReservationRequest.ContainerQuantities),
new JProperty("location", NewReservationRequest.Location),
new JProperty("image", NewReservationRequest.ImageBlob),
new JProperty("dateFrom", NewReservationRequest.StartDate.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture)),
new JProperty("dateTo", NewReservationRequest.StartDate.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture)),
new JProperty("expectedTime",NewReservationRequest.ExpectedTime),
new JProperty("remarks", UserRemarks)
);
var RequestDataString = new StringContent(RequestData.ToString(), Encoding.UTF8, "application/json");
HttpResponseMessage responsePost = await client.PostAsync(postURL, RequestDataString);
string response = await responsePost.Content.ReadAsStringAsync();
After that , you will need to parse the json response.
reply to this answer if you need more help

PATCH existing OneNote Page by appending binary image content

Using the Microsoft Graph v1.0 api and C#, I am able to update (patch) existing OneNote pages however after writing image data to the multipart/form-data section, the resulting image height and width are correct, but, the image is not rendered on the page -- other than an empty image place-holder.
So the question is, what is the correct image format expected by OneNote for a PATCH command? The docs state that it must be 'binary image data'. Shouldn't File.ReadAllBytes be sufficient?
Here are the formats attempted so far:
string file = #"c:\images\file1.jpg";
var rawData = System.IO.File.ReadAllText(file); //attempt1
byte[] bytes = System.IO.File.ReadAllBytes(file); //attempt2
var byteArray = BitConverter.ToString(bytes); //attempt3
var byteString = Encoding.ASCII.GetString(bytes); //attempt4
string base64String = Convert.ToBase64String(bytes, 0, bytes.Length); //attempt5
string imageDataURL = string.Format("data:image/jpeg;base64,{0}", base64String); //attempt6
...
/* Construct message content */
StringBuilder sb = new StringBuilder();
sb.Append("--MyPartBoundary198374" + "\r\n");
sb.Append(#"Content-Disposition: form-data; name=""Commands""" + "\r\n");
sb.Append("Content-Type: application/json" + "\r\n" + "\r\n");
sb.Append(
#"[{
'target':'body',
'action':'append',
'position':'before',
'content':'<img src=""name:image1"" width=""400"" height=""500""/>'
}]"
+ "\r\n" + "\r\n");
sb.Append("--MyPartBoundary198374" + "\r\n");
sb.Append(#"Content-Disposition: form-data; name=""image1""" + "\r\n");
sb.Append("Content-Type: image/jpeg" + "\r\n\r\n" );
sb.Append([see formats above] + "\r\n");
sb.Append("--MyPartBoundary198374--" );
string content = sb.ToString();
string contentType = "multipart/form-data; boundary=MyPartBoundary198374";
var result = await OneNoteService.UpdatePageAsync(client, page, contentType, content);
...
internal static async Task <HttpResponseMessage> UpdatePageAsync(GraphServiceClient client, OnenotePage page, string contentType, string content)
{
HttpResponseMessage response = null;
try
{
string requestUri = client.Users[ME].Onenote.Pages[page.Id].Content.Request().RequestUrl;
List<OnenotePatchContentCommand> patchCommands = new List<OnenotePatchContentCommand>();
HttpRequestMessage request = new HttpRequestMessage()
{
Method = new HttpMethod("PATCH"),
RequestUri = new Uri(requestUri),
Content = new StringContent(content, Encoding.UTF8, "application/json"),
};
request.Content.Headers.Remove("Content-Type");
request.Content.Headers.TryAddWithoutValidation("Content-Type", contentType);
// Adds the user's access token from the GraphServiceClient to the request.
await client.AuthenticationProvider.AuthenticateRequestAsync(request);
response = await client.HttpProvider.SendAsync(request);
if (!response.IsSuccessStatusCode)
{
throw new Microsoft.Graph.ServiceException(
new Error
{
Code = response.StatusCode.ToString(),
Message = await response.Content.ReadAsStringAsync()
});
}
}
catch (Exception ex)
{
//TODO: Error handling
Console.WriteLine(ex.ToString());
}
return response;
}
The suggestions listed in this post did not resolve the issue:
Inserting image into existing OneNote page via REST api not working
Been trying to resolve this for more than a day. Can someone provide the proper image data format expected by the PATCH command.
Thanks,
Roland
Moving previous comment to an answer in case others run into this.
Rather than sending multiple parts, combine attempts 5 & 6 and include the result directly in the src attribute:
string base64String = Convert.ToBase64String(bytes, 0, bytes.Length); //attempt5
string imageDataURL = string.Format("data:image/jpeg;base64,{0}", base64String); //attempt6
/* Construct message content */
StringBuilder sb = new StringBuilder();
sb.Append("--MyPartBoundary198374" + "\r\n");
sb.Append(#"Content-Disposition: form-data; name=""Commands""" + "\r\n");
sb.Append("Content-Type: application/json" + "\r\n" + "\r\n");
sb.Append(
#"[{
'target':'body',
'action':'append',
'position':'before',
'content':'<img src=" + imageDataURL + " width=""400"" height=""500""/>'
}]"
+ "\r\n" + "\r\n");
This will include the image directly in the HTML you're inserting.

HttpClient: The uri string is too long

Given the following attempt to post data to a web service that generates PDF files, PDF rocket (which is awesome by the way).
I get the error Invalid URI: The uri string is too long
Why would anyone impose an arbitrary limit on POSTed data?
using (var client = new HttpClient())
{
// Build the conversion options
var options = new Dictionary<string, string>
{
{ "value", html },
{ "apikey", ConfigurationManager.AppSettings["pdf:key"] },
{ "MarginLeft", "10" },
{ "MarginRight", "10" }
};
// THIS LINE RAISES THE EXCEPTION
var content = new FormUrlEncodedContent(options);
var response = await client.PostAsync("https://api.html2pdfrocket.com/pdf", content);
var result = await response.Content.ReadAsByteArrayAsync();
return result;
}
I receive this rediculous error.
{System.UriFormatException: Invalid URI: The Uri string is too long.
at System.UriHelper.EscapeString
at System.Uri.EscapeDataString
at System.Net.Http.FormUrlEncodedContent.Encode
at System.Net.Http.FormUrlEncodedContent.GetContentByteArray
This reminds me of 640k ought to be enough... I mean really?
If, like me, you're faced with some wonky 3rd party web service that will only accept form content, you can work around the problem like this:
// Let's assume you've got your key-value pairs organised into a nice Dictionary<string, string> called formData
var encodedItems = formData.Select(i => WebUtility.UrlEncode(i.Key) + "=" + WebUtility.UrlEncode(i.Value));
var encodedContent = new StringContent(String.Join("&", encodedItems), null, "application/x-www-form-urlencoded");
// Post away!
var response = await client.PostAsync(url, encodedContent);
With a post can include the content in the http message instead of the URI. A uri has a max length of 2083 characters. You could send it as JSON in the http message instead of the URI which is the recommended way to send larger chunks of data in an HttpPost/HttpPut. I altered your code to make use of it. This assumes that your service you are contacting can work with JSON (.net Web Api out of the box should have no problem with this).
using (var client = new HttpClient())
{
// Build the conversion options
var options = new
{
value = html,
apikey = ConfigurationManager.AppSettings["pdf:key"],
MarginLeft = "10",
MarginRight = "10"
};
// Serialize our concrete class into a JSON String
var stringPayload = JsonConvert.SerializeObject(options);
var content = new StringContent(stringPayload, Encoding.UTF8, "application/json");
var response = await client.PostAsync("https://api.html2pdfrocket.com/pdf", content);
var result = await response.Content.ReadAsByteArrayAsync();
return result;
}
Make sure to install newtonsoft json.
I just solved a similar problem. For me I was integrating with a backend I didn't control and had to POST file along with form data (eg customerID) as form variables. So switching to JSON or Multipart would break the backend I didn't control. The problem was that large files would cause the FormUrlEncodedContent to throw an error saying "The uri string is too long".
This is the code that solved it for me after two days of effort (note still needs to be tweaked to be ASYNC).
private string UploadFile(string filename, int CustomerID, byte[] ImageData) {
string Base64String = "data:image/jpeg;base64," + Convert.ToBase64String(ImageData, 0, ImageData.Length);
var baseAddress = new Uri("[PUT URL HERE]");
var cookieContainer = new CookieContainer();
using (var handler = new HttpClientHandler() { AllowAutoRedirect = true, UseCookies = true, CookieContainer = cookieContainer })
using (var client = new HttpClient(handler) { BaseAddress = baseAddress })
{
try {
//ENCODE THE FORM VARIABLES DIRECTLY INTO A STRING rather than using a FormUrlEncodedContent type which has a limit on its size.
string FormStuff = string.Format("name={0}&file={1}&id={2}", filename, HttpUtility.UrlEncode(Base64String), CustomerID.ToString());
//THEN USE THIS STRING TO CREATE A NEW STRINGCONTENT WHICH TAKES A PARAMETER WHICH WILL FormURLEncode IT AND DOES NOT SEEM TO THROW THE SIZE ERROR
StringContent content = new StringContent(FormStuff, Encoding.UTF8, "application/x-www-form-urlencoded");
//UPLOAD
string url = string.Format("/ajax/customer_image_upload.php");
response = client.PostAsync(url, content).Result;
return response.Content.ToString();
}
catch (Exception ex) {
return ex.ToString();
}
}
}
#Mick Byrne :
Thanks - your solution worked like a charme!
Here is my complete code:
public async Task DateienSendenAsync (string PfadUndDatei, string Dateiname, String VRPinGUID, String ProjektGUID, String VRPinX, String VRPinY, String VRPinZ)
{
var client = new HttpClient();
// Create the HttpContent for the form to be posted.
var requestContent = new[] {
new KeyValuePair<string, string>("dateiname", Dateiname),
new KeyValuePair<string, string>("bild", Convert.ToBase64String(File.ReadAllBytes(PfadUndDatei))),
new KeyValuePair<string, string>("VRPinGUID", VRPinGUID),
new KeyValuePair<string, string>("ProjektGUID", ProjektGUID),
new KeyValuePair<string, string>("ebene", "ebene"),
new KeyValuePair<string, string>("raumnummer", "raumnummer"),
new KeyValuePair<string, string>("ansichtsname", "ansichtsname"),
new KeyValuePair<string, string>("VRPinX", VRPinX),
new KeyValuePair<string, string>("VRPinY", VRPinY),
new KeyValuePair<string, string>("VRPinZ", VRPinZ),
};
String url = "http://yourhomepage/path/upload.php";
var encodedItems = requestContent.Select(i => WebUtility.UrlEncode(i.Key) + "=" + WebUtility.UrlEncode(i.Value));
var encodedContent = new StringContent(String.Join("&", encodedItems), null, "application/x-www-form-urlencoded");
// Post away!
var response = await client.PostAsync(url, encodedContent);
}

Categories

Resources