Google Drive Async Upload Method - c#

I have a winforms application that uses Google Drive to manage files. My file upload method is fairly simple:
public static File UploadFile(string sourcefile, string description, string mimeType, int attempt)
{
try
{
string title = Path.GetFileName(sourcefile);
var file = new File {Title = title, Description = description, MimeType = mimeType};
byte[] bytearray = System.IO.File.ReadAllBytes(sourcefile);
var stream = new MemoryStream(bytearray);
FilesResource.InsertMediaUpload request = DriveService.Files.Insert(file, stream, "text/html");
request.Convert = false;
request.Upload();
File result = request.ResponseBody;
return result;
}
catch (Exception e)
{
if(attempt<10)
{
return UploadFile(sourcefile, description, mimeType, attempt + 1);
}
else
{
throw e;
}
}
}
This works, but prior to using Google Drive, I used an FTP solution, which allowed asynchronous upload operations. I would like to include a progress bar when files are uploading, but I can't figure out if there is a way to call InserMediaUpload asynchronously. Do such capabilities exist?
Thank you.

We just announced 1.4.0-beta version earlier today.
1.4.0-beta has a lot of great features including UploadAsync which optionally gets a cancellation token.
Take a look also in our new Media wiki page.

We still don't support an UpdateAsync method, but if you need to update your progress bar you can use the ProgressChanged event. Remember that the default ChunkSize is 10MB, so if you want to get updates after shorter periods, you should change the ChunkSize accordingly.
Be aware, that in the next release of the library, we will also going to support server errors (5xx)
UPDATE (June 2015):
We did add support for UploadAsync more than 2 years ago. Server errors are supported as well using an ExponentialBackoffPolicy.

I know it's late..but Adding a Progress Bar is fairly simple.
Following is a working piece of code for uploading:
public static File uploadFile(DriveService _service, string _uploadFile, string _parent, string _descrp = "Uploaded with .NET!")
{
if (System.IO.File.Exists(_uploadFile))
{
File body = new File();
body.Title = System.IO.Path.GetFileName(_uploadFile);
body.Description = _descrp;
body.MimeType = GetMimeType(_uploadFile);
body.Parents = new List<ParentReference>() { new ParentReference() { Id = _parent } };
byte[] byteArray = System.IO.File.ReadAllBytes(_uploadFile);
System.IO.MemoryStream stream = new System.IO.MemoryStream(byteArray);
try
{
FilesResource.InsertMediaUpload request = _service.Files.Insert(body, stream, GetMimeType(_uploadFile));
request.ProgressChanged += UploadProgessEvent;
request.ChunkSize = FilesResource.InsertMediaUpload.MinimumChunkSize; // Minimum ChunkSize allowed by Google is 256*1024 bytes. ie 256KB.
request.Upload();
return request.ResponseBody;
}
catch(Exception e)
{
MessageBox.Show(e.Message,"Error Occured");
}
}
else
{
MessageBox.Show("The file does not exist.","404");
}
}
And
private void UploadProgessEvent(Google.Apis.Upload.IUploadProgress obj)
{
label1.Text = ((obj.ByteSent*100)/TotalSize).ToString() + "%";
// update your ProgressBar here
}

Related

Validation for attribute in blazor

I'm learning C# with blazor, I wanted to know how I can validate an input of type file, so that it doesn't allow files larger than 3MB
This example explains how to upload files(in svg format) in Blazor with the InputFile component. Pay attention to the variable maxFileSize that set the maximum number of bytes that can be supplied by the Stream.
FileUpload.razor.cs
private bool fileUploading;
private string filePath = "C:\\fileFolder\\file.svg";
private const int maxFileSize= 3 * 1024 * 1024; //3MB max size
private async Task UploadSvgFileAsync(InputFileChangeEventArgs e)
{
fileUploading = true;
try
{
string fileExtension = Path.GetExtension(e.File.Name);
if (!fileExtension.Equals(".svg", StringComparison.OrdinalIgnoreCase))
throw new Exception("SVG file is required.");
var stream = e.File.OpenReadStream(maxFileSize);
await using FileStream fs = new(filePath, FileMode.Create);
await stream.CopyToAsync(fs);
}
catch (Exception ex)
{
//some error handling
}
fileUploading = false;
}
And in your FileUpload.razor component:
#if (fileUploading )
{
<span>- File Uploading...</span>
}
<InputFile OnChange="#UploadSvgFileAsync" />
I recommend reading the following articles to learn how to properly work with files in Blazor apps:
File Uploads
File Downloads
FileInfo file = new FileInfo(yourFile);
get the files byte size:
var fileBytes = file.Length;
turn bytes to MBs:
var fileMBs = fileBytes / (1024*1024);

Read large files - 2GB+ for Google Drive API Upload

I'm currently working on a small backup tool written in C# that is supposed to upload files contained within a specified folder to Google Drive via its API. The program largely functions as it's supposed to, the only problem that it is unable to handle files larger than 2GB.
The problem is caused by the upload function itself which is attached down below, it uses a byte array to read the file to subsequently create a Memory Stream. As far as I'm aware (I'm still a beginner when it comes to c#), a byte array can only contain 2GB of information before returning an overflow exception. To combat this I've tried to utilize FileStream.Read (second bit of code attached below) instead of System.IO.File.ReadAllBytes, though this again lead to an overflow exception of the byte Array. I know that at this point I'd have to split the file up, however, due to the rather limited documentation of the GDrive API for C# - at least from what I've seen - and my limited knowledge of C# I've got little to no clue on how to tackle this problem.
I'm sorry for the long read, all help on this matter is highly appreciated.
Upload Function V1 (System.IO.File.ReadAllBytes):
private static Google.Apis.Drive.v3.Data.File UploadFile(Boolean useFolder, String mime, DriveService _service, string _uploadFile, string _parent, string _descrp = "")
{
if (System.IO.File.Exists(_uploadFile))
{
Google.Apis.Drive.v3.Data.File body = new Google.Apis.Drive.v3.Data.File
{
Name = System.IO.Path.GetFileName(_uploadFile),
Description = _descrp,
MimeType = mime
};
if (useFolder)
{
body.Parents = new List<string> { _parent };
}
byte[] byteArray = System.IO.File.ReadAllBytes(_uploadFile);
MemoryStream stream = new System.IO.MemoryStream(byteArray);
try
{
FilesResource.CreateMediaUpload request = _service.Files.Create(body, stream, mime);
request.SupportsTeamDrives = true;
request.Upload();
return request.ResponseBody;
}
catch (Exception e)
{
Console.WriteLine("Error Occured: " + e);
return null;
}
}
else
{
Console.WriteLine("The file does not exist. 404");
return null;
}
}
Upload Method V2 (FileStream):
private static Google.Apis.Drive.v3.Data.File UploadFile(Boolean useFolder, String mime, DriveService _service, string _uploadFile, string _parent, string _descrp = "")
{
if (System.IO.File.Exists(_uploadFile))
{
Google.Apis.Drive.v3.Data.File body = new Google.Apis.Drive.v3.Data.File
{
Name = System.IO.Path.GetFileName(_uploadFile),
Description = _descrp,
MimeType = mime
};
if (useFolder)
{
body.Parents = new List<string> { _parent };
}
//byte[] byteArray = System.IO.File.ReadAllBytes(_uploadFile);
using (FileStream fileStream = new FileStream(_uploadFile, FileMode.Open, FileAccess.Read))
{
Console.WriteLine("ByteArrayStart");
byte[] byteArray = new byte[fileStream.Length];
int bytesToRead = (int)fileStream.Length;
int bytesRead = 0;
while (bytesRead > 0)
{
int n = fileStream.Read(byteArray, bytesRead, bytesToRead);
if (n == 0)
{
break;
}
bytesRead += n;
Console.WriteLine("Bytes Read: " + bytesRead);
bytesToRead -= n;
Console.WriteLine("Bytes to Read: " + bytesToRead);
}
bytesToRead = byteArray.Length;
MemoryStream stream = new System.IO.MemoryStream(byteArray);
try
{
FilesResource.CreateMediaUpload request = _service.Files.Create(body, stream, mime);
request.SupportsTeamDrives = true;
request.Upload();
return request.ResponseBody;
}
catch (Exception e)
{
Console.WriteLine("Error Occured: " + e);
return null;
}
}
}
else
{
Console.WriteLine("The file does not exist. 404");
return null;
}
}
MemoryStream's constructors only work with byte arrays that are limited to Int32.MaxValue bytes. Why not just use your FileStream object directly?
var fileMetadata = new Google.Apis.Drive.v3.Data.File()
{
Name = "flag.jpg"
};
FilesResource.CreateMediaUpload request;
using (var stream = new System.IO.FileStream(#"C:\temp\flag.jpg", System.IO.FileMode.Open))
{
request = service.Files.Create(fileMetadata, stream, "image/jpeg");
request.Fields = "id";
request.Upload();
}
var file = request.ResponseBody;
Really a file that big you should be using resumable upload but im going to have to dig around for some sample code for that.

How to save as Image From Stream which is send in retrofit2 to wcf web service

I am sending a image file to wcf web service using retrofit, on saving side of wcf web service i am unable to save the stream file.
In android i creating like
//ApiInterface.class
#Multipart
#POST("RestService/json/PostUploadFile/")
Call<UploadFileResponse> uploadFile(#Part MultipartBody.Part file);
service call be like
File file = new File(assets.get(0).getPath());
RequestBody requestFile = RequestBody.create(MediaType.parse("multipart/form-data"), file);
// MultipartBody.Part is used to send also the actual file name
MultipartBody.Part part = MultipartBody.Part.createFormData("imageData", file.getName(), requestFile);
//api call method
callUploadFile(part, this);
private void callUploadFile(MultipartBody.Part part,
MainInteractor.OnFinishedListener listenerP) {
final MainInteractor.OnFinishedListener listener = listenerP;
HashMap<String, String> headerMap = new HashMap<>();
headerMap.put("SessionID", "");
headerMap.put("UserName", "");
OkHttpClient httpClient = ConnectToService.newInstance().addHeaders(getContext(), headerMap);
ApiInterface apiService =
ConnectToService.newInstance()
.getClient(httpClient).create(ApiInterface.class);
Call<UploadFileResponse> call = apiService.uploadFile(part);
call.enqueue(new Callback<UploadFileResponse>() {
#Override
public void onResponse(Call<UploadFileResponse> call, Response<UploadFileResponse> response) {
onFinished(response.body().getResult());
}
#Override
public void onFailure(Call<UploadFileResponse> call, Throwable t) {
if (t.getLocalizedMessage() != null) {
onFinishedFailure(t.getLocalizedMessage());
}
}
});
}
In wcf webservice i am getting data in message but when i save i get argument exception error.
EDITED: Below code works
Bitmap bm = BitmapFactory.decodeFile(assets.get(finalX).getPath());
Bitmap bitmap = Bitmap.createScaledBitmap(bm, 480, 480, true);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 80, baos); //bm is the bitmap object
byte[] byteArray = baos.toByteArray();
RequestBody body = RequestBody.create(MediaType.parse("application/octet-stream"), byteArray);
callUploadFile(body, "File_" + finalX, MainFragment.this);
calling service method
private void callUploadFile(RequestBody body, String fileName,
MainInteractor.OnFinishedListener listenerP) {
final MainInteractor.OnFinishedListener listener = listenerP;
HashMap<String, String> headerMap = new HashMap<>();
headerMap.put("SessionID", "");
headerMap.put("UserName", "");
headerMap.put("FileName", fileName);
OkHttpClient httpClient = ConnectToService.newInstance().addHeaders(getContext(), headerMap);
ApiInterface apiService =
ConnectToService.newInstance()
.getClient(httpClient).create(ApiInterface.class);
Call<UploadFileResponse> call = apiService.uploadFile(body);
call.enqueue(new Callback<UploadFileResponse>() {
#Override
public void onResponse(Call<UploadFileResponse> call, Response<UploadFileResponse> response) {
if (response != null && response.body() != null) {
onFinished(response.body().getResult());
} else {
if (response.message() != null) {
onFinishedFailure(response.message());
}
}
}
#Override
public void onFailure(Call<UploadFileResponse> call, Throwable t) {
if (t.getLocalizedMessage() != null) {
onFinishedFailure(t.getLocalizedMessage());
}
}
});
}
In wcf service
public string uploadFile(Stream imageData)
{
string fileName = WebOperationContext.Current.IncomingRequest.Headers.Get("fileName");
string fileFullPath = "D:\\Share\\srinidhi\\Temp_" + fileName + ".Jpeg";
Image img = System.Drawing.Image.FromStream(imageData);
img.Save(fileFullPath, ImageFormat.Jpeg);
return "success";
}
In api call
#POST("RestService/json/PostUploadFile/")
Call<UploadFileResponse> uploadFile(#Body RequestBody bytes);
It seems that your stream is submitted by the form-data, which means that the stream contains some unnecessary data, such as the other data in the submitted form-data. One thing must be noted that WCF doesn’t support the form-data by default, we generally convert the data to the complete file data by using the third-party library, MultipartParser.
Here is the download page.
http://antscode.blogspot.com/2009/11/parsing-multipart-form-data-in-wcf.html
Under this circumstance, please use the below code segments to save the image.
public async Task UploadStream(Stream stream)
{
//the third-party library.
MultipartParser parser = new MultipartParser(stream);
if (parser.Success)
{
//absolute filename, extension included.
var filename = parser.Filename;
var filetype = parser.ContentType;
var ext = Path.GetExtension(filename);
using (var file = File.Create(Path.Combine(HostingEnvironment.MapPath("~/Uploads"), Guid.NewGuid().ToString() +ext)))
{
await file.WriteAsync(parser.FileContents, 0, parser.FileContents.Length);
}
}
}
If the stream is the complete binary file, please consider the below code (we use the HTTP header to save the file extension since WCF doesn’t allow to contain another parameter in the method signature).
public async Task UploadStream(Stream stream)
{
var context = WebOperationContext.Current;
string filename = context.IncomingRequest.Headers["filename"].ToString();
string ext = Path.GetExtension(filename);
using (stream)
{
//save the image under the Uploads folder on the server-side(root directory).
using (var file = File.Create(Path.Combine(HostingEnvironment.MapPath("~/Uploads"), Guid.NewGuid().ToString() + ext)))
{
await stream.CopyToAsync(file);
}
}
}
Feel free to let me know if the problem still exists.

How to convert office files (docx, xlsx) to google format in c#

Anyone share the way to convert docx, xlsx, pptx to google format in programmatic. I am uploading through Google Drive API and sharing to users using c#. every time creating a duplicate document when someone edit the file.
I want to convert the file while upload. So i can share the converted file to everyone.
I am using Google Drive v3 api.
Download Code:
private static System.IO.MemoryStream DownloadFile(DriveService service, string fileID)
{
var request = service.Files.Get(fileID);
var stream = new System.IO.MemoryStream();
// Add a handler which will be notified on progress changes.
// It will notify on each chunk download and when the
// download is completed or failed.
request.MediaDownloader.ProgressChanged += (Google.Apis.Download.IDownloadProgress progress) =>
{
switch (progress.Status)
{
case Google.Apis.Download.DownloadStatus.Downloading:
{
Console.WriteLine(progress.BytesDownloaded);
break;
}
case Google.Apis.Download.DownloadStatus.Completed:
{
Console.WriteLine("Download complete.");
//SaveStream(stream, saveTo);
break;
}
case Google.Apis.Download.DownloadStatus.Failed:
{
Console.WriteLine("Download failed.");
break;
}
}
};
request.Download(stream);
return stream;
}
private static void SaveStream(System.IO.MemoryStream stream, string saveTo)
{
using (System.IO.FileStream file = new System.IO.FileStream(saveTo, System.IO.FileMode.Create, System.IO.FileAccess.Write))
{
stream.WriteTo(file);
}
}
Here's something to get you started my friend. Check the Basic uploads and Importing to Google Docs types as it shows you how to upload and convert some file types to Google formats.
var fileMetadata = new File()
{
Name = "My Report",
MimeType = "application/vnd.google-apps.spreadsheet"
};
FilesResource.CreateMediaUpload request;
using (var stream = new System.IO.FileStream("files/report.csv",
System.IO.FileMode.Open))
{
request = driveService.Files.Create(
fileMetadata, stream, "text/csv");
request.Fields = "id";
request.Upload();
}
var file = request.ResponseBody;
Console.WriteLine("File ID: " + file.Id);

Upload thumbnail image to vimeo via api call c#

I am trying to set the thumbnail for a pull video upload done through the vimeo api. I am developing this for a c# windows service and please note that there are no official libraries for this. For the moment I use this library. I am able to successfully upload the video by following the vimeo documentation, however, when I try to upload an image to be the thumbnail of a video I get an issue. According to the vimeo picutre upload documentation, in step 2, i need to upload my thumbnail image via a PUT request. It says, that I need to do the following:
PUT https://i.cloud.vimeo.com/video/518016424
.... binary data of your file in the body ....
I can't figure out how to do this. I can get the binary data of the image by using
byte[] byte_array_of_image = File.ReadAllBytes(file);
but how can I send this data to the api and get a response (with or without using the library)? If it would help, here is my code to upload the video and thumbnail done so far.
var vc = VimeoClient.ReAuthorize(
accessToken: ConfigurationManager.AppSettings["ACCESS_TOKEN"],
cid: ConfigurationManager.AppSettings["API_KEY"],
secret: ConfigurationManager.AppSettings["API_SECRET"]
);
string temporary_video_dir = ConfigurationManager.AppSettings["TEMP_VIDEO_URL"];
Dictionary<string,string> automatic_pull_parameters = new Dictionary<string, string>();
automatic_pull_parameters.Add("type", "pull");
automatic_pull_parameters.Add("link", temporary_video_dir);
var video_upload_request = vc.Request("/me/videos", automatic_pull_parameters, "POST");
string uploaded_URI = video_upload_request["uri"].ToString();
string video_id = uploaded_URI.Split('/')[2];
Library.WriteErrorLog("Succesfully uploaded Video in test folder. Returned Vimeo ID for video: "+ video_id);
var picture_resource_request = vc.Request("/videos/" + video_id + "/pictures", null, "POST");
string picture_resource_link = picture_resource_request["uri"].ToString();
//Library.WriteErrorLog("uri: " + picture_resource_link);
byte[] binary_image_data = File.ReadAllBytes("http://testclient.xitech.com.au/Videos/Images/Closing_2051.jpg");
string thumbnail_upload_link = picture_resource_link.Split('/')[4];
Please help! Stuck for hours now.
WebClient has a method called UploadData that fits like a glove. Below there is an example that what you can do.
WebClient wb = new WebClient();
wb.Headers.Add("Authorization","Bearer" +AccessToken);
var file = wb.DownloadData(new Uri("http://testclient.xitech.com.au/Videos/Images/Closing_2051.jpg"));
var asByteArrayContent = wb.UploadData(new Uri(picture_resource_request ), "PUT", file);
var asStringContent = Encoding.UTF8.GetString(asByteArrayContent);
reference post:- Vimeo API C# - Uploading a video
the answer is not upvoted but it could be tried worked well in my case.
see the code below:-
public ActionResult UploadChapterVideoVimeo(HttpPostedFileBase file, string productID = "")
{
if (file != null){
var authCheck = Task.Run(async () => await vimeoClient.GetAccountInformationAsync()).Result;
if (authCheck.Name != null)
{
BinaryContent binaryContent = new BinaryContent(file.InputStream, file.ContentType);
int chunkSize = 0;
int contenetLength = file.ContentLength;
int temp1 = contenetLength / 1024;
if (temp1 > 1)
{
chunkSize = temp1 / 1024;
chunkSize = chunkSize * 1048576;
}
else
{ chunkSize = chunkSize * 1048576; }
binaryContent.OriginalFileName = file.FileName;
var d = Task.Run(async () => await vimeoClient.UploadEntireFileAsync(binaryContent, chunkSize, null)).Result;
vmodel.chapter_vimeo_url = "VIMEO-" + d.ClipUri;
}
return RedirectToAction("ProductBuilder", "Products", new { productId = EncryptedProductID, message = "Successfully Uploaded video", type = 1 });
}
}
catch (Exception exc)
{
return RedirectToAction("ProductBuilder", "Products", new { productId = EncryptedProductID, message = "Failed to Uploaded video " + exc.Message, type = 0 });
}
}
return null; }

Categories

Resources