Google Drive API (v3) --- Download file as a service - c#

hope this question makes sense: Is there a way I can download files from a drive without reiterating the service account every time? So for example, I have a program that allows me to backup my Gapps organization drives. The program currently works like this:
Logs in to each account with the service I created in the Google developer console
Checks the token as a source for changed files from the last time the backup ran to the current execution
IF the token is different, executes a file list request and records the fileId and actual fileName for the files changed, then puts both values into a temporary text document as 2 columns ("fileId,fileName"). Here is what I'm using for the file resource list
Console.WriteLine("Changes detected. Making notes while we go through these.");
if (File.Exists(savelocation + ".deltalog.tok"))
File.Delete(savelocation + ".deltalog.tok");
using (StreamWriter deltalog = new StreamWriter(savelocation + ".deltalog.tok", true))
{
while (pageToken != null)
{
counter1++;
var request = CreateService.BuildService(user).Changes.List(pageToken);
//StreamWriter deltalog = new StreamWriter(savelocation + ".deltalog.tok", true);
request.Fields = "*";
request.Spaces = "drive";
var changes = request.Execute();
foreach (var change in changes.Changes)
{
try
{
string updatedfile = change.File.Name;
//string updatedfile = CreateService.BuildService(user).Files.Get(change.FileId).Execute().Name;
// Record the changed file
Console.WriteLine(user + ": New or changed file found: " + updatedfile + "\n");
logFile.WriteLine(user + ": New or changed file found: " + change.FileId + " --- " + updatedfile);
deltalog.Write(change.FileId + "," + updatedfile+"\n");
deltalog.Flush();
}
Start exporting the files out as documents to my server for backup. To do this, I log into the Gapps domain with my service account 3 different times for one file for each user. Right now, I'm reading the file created from step 3 and splitting the values so that I have the fileId and Filename on hand. The code looks like this:
FilesResource.ListRequest listRequest = CreateService.BuildService(user).Files.List();
listRequest.PageSize = 1000;
listRequest.Fields = "nextPageToken, files(id, name)";
string[] deltafiles = File.ReadAllLines(savelocation + ".deltalog.tok");
IList<Google.Apis.Drive.v3.Data.File> files = listRequest.Execute()
.Files;
Console.WriteLine("\nFiles to backup:\n");
if (deltafiles == null)
{
return;
}
else
{
foreach (var file in deltafiles)
{
try
{
// Our file is a CSV. Column 1 = file ID, Column 2 = File name
var values = file.Split(',');
string fileId = values[0];
string fileName = values[1];
fileName = fileName.Replace('\\', '_').Replace('/', '_').Replace(':', '_').Replace('!', '_').Replace('\'', '_').Replace('*', '_');
Console.WriteLine("Filename: " + values[1]);
logFile.WriteLine("ID: " + values[0] + " - Filename: " + values[1]);
var requestfileid = CreateService.BuildService(user).Files.Get(fileId);
var getfile = CreateService.BuildService(user).Files.Get(fileId).Execute();
var request = CreateService.BuildService(user).Files.Export(fileId, getfile.MimeType);
and so forth.
If I try to change the requestfileid to values[0] (which would be the fileId for that file in the loop), then the MediaDownloader doesn't work because it's no longer part of the Files.Get constructor.
Is there anything I can do, or overlooking, so that the service account only has to log in once to do everything it needs per account?
Hope that gibberish makes sense.
I've been using https://developers.google.com/drive/v3/web/quickstart/dotnet and the API documentation as my source for information, and I got everything working the way I want it to, Except for having to log in as the service multiple times for One file. Any help or point in the right direction would sure be appreciated. Thank you!

Related

Writing a report of cpp file in txt format with same name as file name

I am reading files from a directory and reading all text and generating reports separately for each file. I want report name same as file name.
I have tried to get file name but when I pass it to reporting module it gives exception error.
string path = "D:\\AssertCount\\";
foreach (string sFile in Directory.EnumerateFiles(path))
{
assertCount=0;
reportingCounter++;
string[] files = Directory.GetFiles(path);
string fileName = files[reportingCounter];
}
ReportWriting(totalWords, assertCount,fileName);
here is complete report writing module
public static void ReportWriting(int totalWords, int assertCount,string fileName)
{
StreamWriter file = new StreamWriter("D:\\AssertCount\\Reports\\"+fileName+".txt");
file.Write("TotalWords = " + totalWords);
file.Write("\nAasserts = " + assertCount);
file.Write("\nOccurence of assert keyword in code is " + assertPercentage + " % ");
file.Close();
}
followin exception occurs
System.IO.IOException: 'The filename, directory name, or volume label syntax is incorrect : 'D:\AssertCount\Reports\D:\AssertCount\testData2.cpp.txt''
The issue is that Directory.EnumerateFiles() and Directory.GetFiles() return full paths, not file names. You could try replacing
string fileName = files[reportingCounter];
with
string fileName = Path.GetFileNameWithoutExtension(files[reportingCounter]);
to turn the full path into just the file name, without the extension (since you add on ".txt" later).
Alternatively, you're already enumerating the files in the directory with the foreach, so why not just use sFile?
foreach (string sFile in Directory.EnumerateFiles(path))
{
assertCount=0;
string fileName = Path.GetFileNameWithoutExtension(sFile);
ReportWriting(totalWords, assertCount,fileName);
}
You're duplicating the path:
'D:\AssertCount\Reports\D:\AssertCount\testData2.cpp.txt' (It should be just 'D:\AssertCount\testData2.cpp.txt'
The variable fileName already includes the full path to the resource (not only the file name). So you could just delete "D:\AssertCount\Reports\" from the creation of the StreamWriter object. The code would be like this
public static void ReportWriting(int totalWords, int assertCount,string fileName)
{
StreamWriter file = new StreamWriter(fileName+".txt");
file.Write("TotalWords = " + totalWords);
file.Write("\nAasserts = " + assertCount);
file.Write("\nOccurence of assert keyword in code is " + assertPercentage + " % ");
file.Close();
}

Trying to get my SSIS to continue running if a file doesn't exist

So, I am running SSIS (through VS) and I have two segments that hang me up when my clients don't send in the exact files every day. I have a task that deletes old files, and then renames the current files to the filename with _OLD at the end of it.
The issue is: If the files that are in there aren't the exact same, it crashes, failing the entire thing.
An example:
A client sends in on Monday files: Names, Addresses, Grades, Schools
The same client, on Tuesday sends in: Names, Addresses, Schools
Since the Grades file doesn't exist, it still gets renamed to Grades_OLD but the SSIS fails.
The scripts are:
del Names_OLD.csv
bye
This will then go to the Rename Script:
ren Names.csv Names_OLD.csv
bye
and will then go on to Addresses, to do the same thing. It is super frustrating that these fail when a single file doesn't exist the next day, and there doesn't seem to be a need for it.
We have two scripts that generate the archive data to process:
public void Main()
{
Dts.Variables["ARCHIVEFILE"].Value = Path.GetFileNameWithoutExtension(Dts.Variables["FTPFILE"].Value.ToString()) + "_OLD" + Path.GetExtension(Dts.Variables["FTPFILE"].Value.ToString());
Dts.TaskResult = (int)ScriptResults.Success;
}
and
public void Main()
{
/*PSFTP_DEL_script.txt
del %1
bye
PSFTP_REN_script.txt
ren %1 %2
bye
*/
var lineOut = String.Empty;
var File1 = Dts.Variables["User::FTPWORKINGDIR"].Value.ToString() + "\\SSIS_PSFTP_DEL_script.txt";
var File2 = Dts.Variables["User::FTPWORKINGDIR"].Value.ToString() + "\\SSIS_PSFTP_REN_script.txt";
lineOut = "del " + Dts.Variables["User::ARCHIVEFILE"].Value.ToString() + Environment.NewLine + "bye";
System.IO.File.WriteAllText(File1, lineOut);
lineOut = "ren " + Dts.Variables["User::FTPFILE"].Value.ToString() + " " + Dts.Variables["User::ARCHIVEFILE"].Value.ToString() + Environment.NewLine + "bye";
System.IO.File.WriteAllText(File2, lineOut);
Dts.TaskResult = (int)ScriptResults.Success;
}
Researching it doesn't really give anything helpful, and kind of just leads me back to where I am right now.
Try using a foreach loop on files for each file that can be processed and put all the processing of the file inside it. And do not put any precendence constraints between the foreach loops.
This will process the files that are there an not fail when the others aren't there.
The foreach loop essentially works as a check if the file exists.
This assumes you do not need all the files to properly process them.
Why not checking if the file exists before writing the script:
if (System.IO.File.Exists(Dts.Variables["User::ARCHIVEFILE"].Value.ToString())){
lineOut = "del " + Dts.Variables["User::ARCHIVEFILE"].Value.ToString() + Environment.NewLine + "bye";
System.IO.File.WriteAllText(File1, lineOut);
}
if (Dts.Variables["User::FTPFILE"].Value.ToString())){
lineOut = "ren " + Dts.Variables["User::FTPFILE"].Value.ToString() + " " + Dts.Variables["User::ARCHIVEFILE"].Value.ToString() + Environment.NewLine + "bye";
System.IO.File.WriteAllText(File2, lineOut);
}

Increment the file name if the file already exists in c#

Tried the below logic in windows form for file name incremental, if the file already exists in the specified path. but the files are created with the names "New1.txt2","New1.txt2.txt3". how the files can be created as "New1.txt", "New2.txt", "New3.txt"...."Newn.txt" on every button Click?
String filename =#"C:\path";
if (File.Exists(filename))
{
count++;
filename = filename + count.ToString()+".txt";
There is one more problem in your code. Why do you have file names like "New1.txt2","New1.txt2.txt3", "New1.txt2.txt3.txt4"? Because you don't keep initial filename somewhere. So, I'd propose to keep two variables for filenames: for instance, filename_initial and filename_current.
Try something like this:
String filename_initial = #"C:\path\New.txt";
String filename_current = filename_initial;
count = 0;
while (File.Exists(filename_current))
{
count++;
filename_current = Path.GetDirectoryName(filename_initial)
+ Path.DirectorySeparatorChar
+ Path.GetFileNameWithoutExtension(filename_initial)
+ count.ToString()
+ Path.GetExtension(filename_initial);
}

C# Windows Service Not Compressing Folder Correctly

Im currently building a Windows service that will be used to create backups of logs. Currently, the logs are stored at the path E:\Logs and intent is to copy the contents, timestamp their new folder and compress it. After this, you should have E:\Logs and E:\Logs_[Timestamp].zip. The zip will be moved to C:\Backups\ for later processing. Currently, I am using the following to try and zip the log folder:
var logDirectory = "E://Logs";
var timeStamp = DateTime.Now.ToString("yyyyMMddHHmm");
var zippedFolder = logDirectory + "_" + timeStamp + ".zip";
System.IO.Compression.ZipFile.CreateFromDirectory(logDirectory, zippedFolder);
While this appears to create a zip folder, I get the error Windows cannot open the folder. The Compressed (zipped) Folder E:\Logs_201805161035.zip is invalid.
To address any troubleshooting issues, the service is running with an AD account that has a sufficient permission level to perform administrative tasks. Another thing to consider is that the service kicks off when its FileSystemWatcher detects a new zip folder in the path C:\Aggregate. Since there are many zip folders that are added to C:\Aggregate at once, the FileSystemWatcher creates a new Task for each zip found. You can see how this works in the following:
private void FileFoundInDrops(object sender, FileSystemEventArgs e)
{
var aggregatePath = new DirectoryInfo("C://Aggregate");
if (e.FullPath.Contains(".zip"))
{
Task task = Task.Factory.StartNew(() =>
{
try
{
var logDirectory = "E://Logs";
var timeStamp = DateTime.Now.ToString("yyyyMMddHHmm");
var zippedFolder = logDirectory + "_" + timeStamp + ".zip";
ZipFile.CreateFromDirectory(logDirectory, zippedFolder);
}
catch (Exception ex)
{
Log.WriteLine(System.DateTime.Now.ToString() + " - ERROR: " + ex);
}
});
task.Dispose();
}
}
How can I get around the error I am receiving? Any help would be appreciated!

Process.Start is not working after hosting asp.net web application in IIS

I have a return a c# code to save a file in the server folder and to retrieve the saved file from the location. But this code is working fine in local machine. But after hosting the application in IIS, I can save the file in the desired location. But I can't retrieve the file from that location using
Process.Start
What would be the problem? I have searched in google and i came to know it may be due to access rights. But I don't know what would be exact problem and how to solve this? Any one please help me about how to solve this problem?
To Save the file:
string hfBrowsePath = fuplGridDocs.PostedFile.FileName;
if (hfBrowsePath != string.Empty)
{
string destfile = string.Empty;
string FilePath = ConfigurationManager.AppSettings.Get("SharedPath") + ConfigurationManager.AppSettings.Get("PODocPath") + PONumber + "\\\\";
if (!Directory.Exists(FilePath.Substring(0, FilePath.LastIndexOf("\\") - 1)))
Directory.CreateDirectory(FilePath.Substring(0, FilePath.LastIndexOf("\\") - 1));
FileInfo FP = new FileInfo(hfBrowsePath);
if (hfFileNameAutoGen.Value != string.Empty)
{
string[] folderfiles = Directory.GetFiles(FilePath);
foreach (string fi in folderfiles)
File.Delete(fi);
//File.Delete(FilePath + hfFileNameAutoGen.Value);
}
hfFileNameAutoGen.Value = PONumber + FP.Extension;
destfile = FilePath + hfFileNameAutoGen.Value;
//File.Copy(hfBrowsePath, destfile, true);
fuplGridDocs.PostedFile.SaveAs(destfile);
}
To retrieve the file:
String filename = lnkFileName.Text;
string FilePath = ConfigurationManager.AppSettings.Get("SharedPath") + ConfigurationManager.AppSettings.Get("PODocPath") + PONumber + "\\";
FileInfo fileToDownload = new FileInfo(FilePath + "\\" + filename);
if (fileToDownload.Exists)
Process.Start(fileToDownload.FullName);
It looks like folder security issue. The folder in which you are storing the files, Users group must have Modify access. Basically there is user(not sure but it is IIS_WPG) under which IIS Process run, that user belongs to Users group, this user must have Modify access on the folder where you are doing read writes.
Suggestions
Use Path.Combine to create folder or file path.
You can use String.Format to create strings.
Create local variables if you have same expression repeating itself like FilePath.Substring(0, FilePath.LastIndexOf("\\") - 1)
Hope this works for you.
You may have to give permissions to the application pool that you are running. see this link http://learn.iis.net/page.aspx/624/application-pool-identities/
You can also use one of the built-in account's "LocalSystem" as application pool identity but it has some security issue's.

Categories