How to generate stream to save Word document at remote location? - c#

I am working on Word AddIn project. I am trying to generate a MmoryStream to save that stream to remote location. Basically What I am supposed to do is take the content of ActiveDocument by using Globals.ThisAddIn.Application.ActiveDocument.WordOpenXML and save it at remote location.
Now for that I am converting this entire string which I am getting with WordOpenXML property to MemoryStream by this code.
After that, I am passing this MemoryStream to HttpContent and for that I have written below code.
public async Task<HttpResponseMessage> PostDocumentAsync(SendAttachement sendAttachement)
{
if (sendAttachement == null)
{
throw new ArgumentNullException(nameof(sendAttachement));
}
using (var _client = new HttpClient(clientHandler, false))
{
_client.Timeout = new TimeSpan(0, 30, 0);
_client.BaseAddress = _URLParams.HostName;
_client.DefaultRequestHeaders.Accept.Clear();
_client.DefaultRequestHeaders.Add("UserNameOrEmail", Settings.Default.UserName);
_client.DefaultRequestHeaders.Add("Password", Settings.Default.Password);
_client.DefaultRequestHeaders.Add("User-Agent", "Word-Addins");
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
MultipartFormDataContent form = new MultipartFormDataContent();
foreach (var contentItem in sendAttachement.Contents)
{
HttpContent content = contentItem.streamContent;
content.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{
FileName = contentItem.FileName
};
form.Add(content);
}
var uri = _URLParams.APIPath + "/" + _URLParams.AbsolutePath + "?ClientId=" + sendAttachement.ClientId + "&RoomId=" + sendAttachement.RoomId + "&FolderId=" + sendAttachement.FolderId + "&ConflictStatus=" + sendAttachement.ConflictStatus;
return await _client.PostAsync(uri, form);
}
}
Above code gives me 200 OK but as I download the uploaded file, It gives me error that Microsoft Word cannot open this document because some part of this file is missing is invalid.
Now I am unable to figure out that Whether am I creating wrong/corrupted stream or anything else.
Sorry for this silly question but I have tried as much as possible solutions I could have done it.

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

Xamarin forms unable to send file(image) from mobile to http post server [duplicate]

I want to upload a file using HttpClient to a php script to save it on a server in a Windows Phone 8.1 application.
Here is my C# code I got from this post.
private async Task<string> GetRawDataFromServer(byte[] data)
{
//Debug.WriteLine("byte[] data length:" + Convert.ToBase64String(data).Length);
var requestContent = new MultipartFormDataContent();
// here you can specify boundary if you need---^
var imageContent = new ByteArrayContent(data);
imageContent.Headers.ContentType =
MediaTypeHeaderValue.Parse("image/jpeg");
requestContent.Add(imageContent, "image", "image.jpg");
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://www.x.net/");
var result = client.PostAsync("test/fileupload.php", requestContent).Result;
return result.Content.ReadAsStringAsync().Result;
}
}
And with this code I retrieve the data in the php script
<?
function base64_to_image( $imageData, $outputfile ) {
/* encode & write data (binary) */
$ifp = fopen( $outputfile, "wb" );
fwrite( $ifp, base64_decode( $imageData ) );
fclose( $ifp );
/* return output filename */
return( $outputfile );
}
if (isset($_POST['image'])) {
base64_to_jpeg($_POST['image'], "image.jpg");
}
else
die("no image data found");
?>
But the result I always get is "No Data found" although there IS an image file. Am I doing something wrong passing it as a POST parameter?
Okay after hours of researching I came to the point that I should restart from draft.
I simulate a Html form upload with following C# code:
private async Task<string> UploadImage(StorageFile file)
{
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://your.url.com/");
MultipartFormDataContent form = new MultipartFormDataContent();
HttpContent content = new StringContent("fileToUpload");
form.Add(content, "fileToUpload");
var stream = await file.OpenStreamForReadAsync();
content = new StreamContent(stream);
content.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{
Name = "fileToUpload",
FileName = file.Name
};
form.Add(content);
var response = await client.PostAsync("upload.php", form);
return response.Content.ReadAsStringAsync().Result;
}
And my php file to receive the data looks as the follwing:
<?php
$uploaddir = 'uploads/';
$uploadfile = $uploaddir . basename($_FILES['fileToUpload']['name']);
echo '<pre>';
if (move_uploaded_file($_FILES['fileToUpload']['tmp_name'], $uploadfile)) {
echo "File is valid, and was successfully uploaded.\n";
} else {
echo "Possible file upload attack!\n";
}
echo 'Here is some more debugging info:';
print_r($_FILES);
?>
Now it works as it should and I hope somebody can reuse my code.

Firefox not downloading properly displayed blob PDF

My clients are unable to download PDF document when trying to save (CTRL+S) a properly displayed PDF document in Firefox (v. 49.0.2) browser.
I dont know if this is my programming problem or a browser problem.
Only way I can download is to click on "Download" button of the PDF plugin, but my clients want to save a file with (CTRL+S) option.
Please take a look at this picture:
And there is a angular code where I try to open a file in browser: it works on Chrome and Edge, it also opens a PDF in Firefox. Response object is a $http response.
function openFile(response) {
var responseHeaders = response.headers();
var contentType = responseHeaders['content-type'];
var contentDisposition = responseHeaders['content-disposition'];
var fileName = contentDisposition.match(/filename="(.+)"/)[1];
fileName = fileName.substring(0, fileName.indexOf(';')-1);
var file = new Blob([response.data], { type: contentType });
if(contentType==='application/pdf') //YES content-type is PDF
{
try
{
var fileURL = URL.createObjectURL(file);
window.open(fileURL);
}
catch(err) //For Edge, just save a file
{
FileSaver.saveAs(file, fileName);
}
}
else //for other content types, just save a file
{
FileSaver.saveAs(file, fileName);
}
}
And this is my C# backend code:
byte[] report = service.GetReportCustomerCreditRatesCard();//render report
RenderFormatResolver renderResolver = new RenderFormatResolver(request.renderFormat);
HttpContent content = new ByteArrayContent(report);
var response = new HttpResponseMessage(HttpStatusCode.OK);
response.Content = content;
response.Content.Headers.ContentType = new MediaTypeHeaderValue(renderResolver.MIMEType);
response.Content.Headers.ContentLength = report.Length;
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") //"attachment", "inline"
{
FileName = String.Format("{0}." + renderResolver.FileNameExtension,
Translations.REPORT_FILENAME_CUSTOMER_CARD),
Name = Translations.REPORT_FILENAME_CUSTOMER_CARD
};
return response;
Try once to change the content disposition header in your response object to hold also the file name:
Content-Disposition: attachment; filename="document.pdf"
So something like:
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue( 'attachment; filename="document.pdf"' );
That might help. Not sure, but worth a try...

Serve the image - Close the image resource

The below code is working perfect. It serves the specified image.
public HttpResponseMessage Get(string id)
{
string fileName = string.Format("{0}.png", id);
FileStream fileStream = File.Open(System.Web.Hosting.HostingEnvironment.MapPath("~/Images/" + fileName), FileMode.Open);
HttpResponseMessage response = new HttpResponseMessage { Content = new StreamContent(fileStream) };
response.Content.Headers.ContentType = new MediaTypeHeaderValue("image/jpg");
response.Content.Headers.ContentLength = fileStream.Length;
return response;
}
Just to release the resource that I acquired to read the image file I have modified the code as follows.
public HttpResponseMessage Get(string id)
{
string fileName = string.Format("{0}.png", id);
using (FileStream fileStream = File.Open(System.Web.Hosting.HostingEnvironment.MapPath("~/Images/" + fileName), FileMode.Open))
{
HttpResponseMessage response = new HttpResponseMessage { Content = new StreamContent(fileStream) };
response.Content.Headers.ContentType = new MediaTypeHeaderValue("image/jpg");
response.Content.Headers.ContentLength = fileStream.Length;
return response;
}
}
I am getting the error "Error while copying content to a stream". Yes. I am closing the resource before it is streamed.
But the question is how to serve the image and still close the unhandled resource?
Asp.Net Web API 2 and above.
Thank you for your thoughts.
You don't need to worry about releasing FileStream object. It will closed by lower layers of Web API once response is complete. Code mentioned in your first snippet is fine.

Google Drive upload fails

I have a method that checks if my file exists on the drive and if not, it uploads one and adds permission.
This method worked while testing the first time and Update requests worked on the file to.
After deleting all existing files in my drive the upload stopped working, the responsebody is null and if I look at it in viddler the requestbody is also empty.
(the file is a valid docx)
I am using the following code:
DriveService service = Google_SDK.Authentication.AppFlowMetadata.BuildServerDriveService();
Google.Apis.Drive.v2.Data.File file;
var items = service.Files.List().Execute().Items.ToLookup(a => a.OriginalFilename = doc.Name + " (" + doc.Id + ".docx)");
if (items.Count > 0)
{
// This worked while testing:
//string fileId = items.FirstOrDefault().FirstOrDefault().Id;
//FilesResource.UpdateRequest uploadRequest = service.Files.(body, fileId, stream, "application/vnd.google-apps.document");
//uploadRequest.Convert = true;
//uploadRequest.Upload();
file = items.FirstOrDefault().FirstOrDefault();
}
else
{
Google.Apis.Drive.v2.Data.File body = new Google.Apis.Drive.v2.Data.File();
body.Title = doc.Name + " (" + doc.Id + ".docx)";
body.OriginalFilename = doc.Name + " (" + doc.Id + ".docx)";
body.Editable = true;
body.Shared = false;
body.WritersCanShare = false;
body.Copyable = false;
body.Description = doc.Notes;
body.MimeType = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
byte[] byteArray = doc.DocxContent; // valid byteArray
System.IO.MemoryStream stream = new System.IO.MemoryStream(byteArray);
FilesResource.InsertMediaUpload uploadRequest = service.Files.Insert(body, stream, "application/vnd.google-apps.document");
uploadRequest.Convert = true;
uploadRequest.Upload();
file = uploadRequest.ResponseBody; // No errors or exceptions but returns null
PermissionsResource.InsertRequest permissionRequest = service.Permissions.Insert(new Permission()
{
Role = "writer",
Type = "user",
EmailAddress = "user#domain.com",
Value = "user#domain.com"
}, file.Id); // file.Id fails becase file equals null
permissionRequest.Execute();
}
I really do not see what I am doing wrong and why this worked the first time.
Thank you in advance.
Edit:
I've been debugging some other parts of my project and I found out that the changes still exist, this seems logical that any deletion is saved as a change for version controll.
Maybe that has something to do with my problems?
Also I forgot to mention that the deletion of all the files is done by code and the drive used is not a gmail account but an *.apps.googleusercontent.com account.
The code I used to remove all the files:
DriveService service = Google_SDK.Authentication.DriveServiceProvider.Service;
FilesResource.ListRequest listRequest = service.Files.List();
FileList listResponse = listRequest.Execute();
int amount = listResponse.Items.Count();
foreach(Google.Apis.Drive.v2.Data.File f in listResponse.Items.AsQueryable()){
FilesResource.DeleteRequest deleteRequest = service.Files.Delete(f.Id);
deleteRequest.Execute();
}
HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
response.Content = new StringContent(String.Format("Removed {0} items.",amount));
return response;
Edit 2:
I've created a completely new document in my system and tried uploading it to the google drive. This was succesfull! After deleting the new document from the drive I got the same behavior as described above, an empty responsebody while uploading.
So even though I removed the old document it still recognizes that it is the same document that used to be on the drive.
Does somebody know a way to prevent this?

Categories

Resources