Unable to view child elements from OneDrive C# SDK - c#

I am coding against the OneDrive C# SDK and I was shared a folder which contains multiple files. When accessing the shared folder from the onedrive.com, I am able to view the files -- however when trying to check the Item the children count is always at zero. I am assuming this may be some mix up on my end or permissions issue -- but I just wanted to run it past for a sanity check.
Code:
private async Task GetItem(string id = null)
{
List<string> idsToSearch = new List<string>();
var expandValue = this.clientType == ClientType.Consumer
? "thumbnails,children(expand=thumbnails)"
: "thumbnails,children";
try
{
Item folder;
if (id == null)
{
folder = await this.oneDriveClient.Drive.Root.Request()
.Expand(expandValue).GetAsync(); //root
}
else
{
folder = await this.oneDriveClient.Drive.Items[id].Request()
.Expand(expandValue).GetAsync(); //children of root
}
WriteToFile(new List<string>(new[] { #"Folder: " + folder.Name }));
if (folder.Children.Count == 0)
{
WriteToFile(new List<string>(new[] { #"NO Children" }));
}
else
{
foreach (var child in folder.Children)
{
WriteToFile(new List<string>(new[] {
#"Children of " + folder.Name + " : " + child.Name }));
}
foreach (var item in folder.Children)
{
GetItem(item.Id);
idsToSearch.Add(item.Id);
}
}
}
catch (Exception exception)
{
PresentServiceException(exception);
}
}
I also included a snapshot of the Item object when it reaches the Shared folder object:
Update
After looking through the folder object some more I found that there is RemoteItem which is returning the correct number of child counts -- however does not have any meta data to fetch the child elements.

From the comments on the question it was determined that this is a RemoteItem scenario. Remote items are different to local items - while there's some local metadata that's useful for rendering, the actual metadata for the item lives in another user's drive. Therefore, when such an item is encountered it may be necessary (e.g. if you need to enumerate children of a remote folder) for a subsequent request needs to be made directly for the item in question (using the driveId from the remoteItem.parentReference and the id from remoteItem.Id).
Have a look at this documentation for some more information.

Related

Delete Empty S3 Folder .Net SDK

I am using .Net Core along with Amazon's .net sdk to push and pull things from S3. I am using a folder structure in S3 that involves inserting an empty directory with several sub directories.
At a later time I insert files into those directories and move them around. Now I need to be able to remove the directory entirely.
I am able to delete all of the contents of the directory by using
await client.DeleteObjectAsync(bucketName, keyName, null).ConfigureAwait(false);
where I loop through all the files I want to delete in the given bucket. However, it always leaves me with the empty folder structure, in S3 I see that it has a content of 0 Bytes but I don't want to have to sort through thousands of empty folders to find the ones that actually have data.
Is there any way to remove an empty folder from S3 using AWS .NET SDK?
Update:
I am able to delete everything in the folder I want except for the folder itself.
using (IAmazonS3 client = new AmazonS3Client(awsCreds, Amazon.RegionEndpoint.USEast1))
{
try
{
DeleteObjectsRequest deleteRequest = new DeleteObjectsRequest();
ListObjectsRequest listRequest = new ListObjectsRequest
{
BucketName = bucketName,
Prefix = prefix,
//Marker = prefix,
};
ListObjectsResponse response = await client.ListObjectsAsync(listRequest).ConfigureAwait(false);
// Process response
foreach (S3Object entry in response.S3Objects)
{
deleteRequest.AddKey(entry.Key);
}
deleteRequest.BucketName = bucketName;
var response2 = await client.DeleteObjectsAsync(deleteRequest).ConfigureAwait(false);
return true;
}
catch (AmazonS3Exception amazonS3Exception)
{
if (amazonS3Exception.ErrorCode != null
&& (amazonS3Exception.ErrorCode.Equals("InvalidAccessKeyId", StringComparison.Ordinal)
|| amazonS3Exception.ErrorCode.Equals("InvalidSecurity", StringComparison.Ordinal)))
{
logger.LogError("AwsS3Service.DeleteFileFromBucket Error - Check the provided AWS Credentials.");
}
else
{
logger.LogError($"AwsS3Service.DeleteFileFromBucket Error - Message: {amazonS3Exception.Message}");
}
}
}
This deletes the entire contents of the directory I choose along with all sub directories. But the main directory remains, is there any way to remove that main directory.
Your code is 99% of the way there. The only thing you need to do is add the prefix variable to your keys to be deleted as well. Technically, it is a 0-byte object that needs to be 'deleted' as well.
For example, after your loop through all the objects in the response, go ahead and add the prefix variable that was added to find all those things.
foreach (S3Object entry in response.S3Objects)
{
deleteRequest.AddKey(entry.Key);
}
// Add the folder itself to be deleted as well
deleteRequest.AddKey(prefix);

Get folder hierarchy with Google Drive API [C# / .NET]

I am looking for an elegant way to get the folder hierarchy, beginning with my root folder, using the C# Google Drive API V3.
Currently, you can get the root folder and its parents by
var getRequest = driveService.Files.Get("root");
getRequest.Fields = "parents";
var file = getRequest.Execute();
but I am looking for a way to get the children, not the parents, so I can recursively go down the file structure.
Setting getRequest.Fields = 'children' is not a valid field option.
recursively fetching children is a very time consuming way to fetch the full hierarchy. Much better is to run a query to fetch all folders in a single GET (well it might take more than one if you have more than 1,000 folders) and then traverse their parent properties to build up the hierarchy in memory. Bear in mind that (afaik) there is nothing that prevents a folder hierarchy being cyclic, thus folder1 owns folder2 owns folder3 owns folder1, so whichever strategy you follow, check that you aren't in a loop.
If you're new to GDrive, it's important to realise early on that Folders are simply labels, rather than containers. So cyclic relationships and files with multiple parents is quite normal. They were originally called Collections, but got renamed to Folders to appease those members of the community that couldn't get their head around labels.
I hope this is the answer you were looking for. getHeirarchy Recursively digs Google Drive and stores the file titles into a text file.
public System.IO.StreamWriter w = new System.IO.StreamWriter("Hierarchy.txt", false);
string intend = " ";
private void getHierarchy(Google.Apis.Drive.v2.Data.File Res, DriveService driveService)
{
if (Res.MimeType == "application/vnd.google-apps.folder")
{
w.Write(intend + Res.Title + " :" + Environment.NewLine);
intend += " ";
foreach (var res in ResFromFolder(driveService, Res.Id).ToList())
getHierarchy(res, driveService);
intend = intend.Remove(intend.Length - 5);
}
else
{
w.Write(intend + Res.Title + Environment.NewLine);
}
}
You can call the function something like:
w.Write("My Drive:" + Environment.NewLine);
foreach (var Res in ResFromFolder(driveService, "root").ToList())
getHierarchy(Res, driveService);
w.Close();
Here, root can be replaced with the ID of any Directory to get it's structure. This will generate the entire Drive's structure.
The ResFromFolder method returns a list of Google.Apis.Drive.v2.Data.File metadata contained in a directory.
public List<Google.Apis.Drive.v2.Data.File> ResFromFolder(DriveService service, string folderId)
{
var request = service.Children.List(folderId);
request.MaxResults = 1000;
List<Google.Apis.Drive.v2.Data.File> TList = new List<Google.Apis.Drive.v2.Data.File>();
do
{
var children = request.Execute();
foreach (ChildReference child in children.Items)
{
TList.Add(service.Files.Get(child.Id).Execute());
}
request.PageToken = children.NextPageToken;
} while (!String.IsNullOrEmpty(request.PageToken));
return TList;
}
This code produces output something like
However as pinoyyid mentioned, it does consume a good deal of time if Drive contains a large number of files and folders.
Get folder hierarchy with Google Drive API [C# / .NET]
Google.Apis.Drive.v3.DriveService service = GetService();
List<GoogleDriveFile> folderList = new List<GoogleDriveFile>();
Google.Apis.Drive.v3.FilesResource.ListRequest request = service.Files.List();
//https://developers.google.com/drenter code hereive/api/v3/search-shareddrives
request.Q = string.Format("mimeType='application/vnd.google-apps.folder' and '{0}' in parents", folderId)`enter code here`;
request.Fields = "files(id, name)";
Google.Apis.Drive.v3.Data.FileList result = request.Execute();
foreach (var file in result.Files)
{
GoogleDriveFile googleDriveFile = new GoogleDriveFile
{
Id = file.Id,
Name = file.Name,
Size = file.Size,
Version = file.Version,
CreatedTime = file.CreatedTime,
Parents = file.Parents
};
folderList.Add(googleDriveFile);
}
return folderList;

C# File Permissions

I am currently writing a program in C# that will copy all user profile files to an external device (in this case, my home server).
When my code iterates through my files and folders, it throws an UnauthorizedAccessException.
I have Googled this and searched StackOverflow, but I am unable to find a clear solution that doesn't involve terminating my process. The idea is that it should copy the files and folders that have read permissions.
I had this when I first started, but I easily fixed it by limiting what directories I would backup (though I would prefer a full backup).
Here is my code:
FileInfo f = new FileInfo(_configuration.Destination);
if (!f.Directory.Exists)
{
f.Directory.Create();
}
string[] backupDirectories = new string[]
{
"Desktop",
"Documents",
"Downloads",
"Favorites",
"Links",
"Pictures",
"Saved Games",
"Searches",
"Videos",
".git",
".android",
".IdealC15",
".nuget",
".oracle_jre_usage",
".vs",
"Contacts"
};
foreach (string dirPath in backupDirectories)
{
DirectoryInfo dirInfo = new DirectoryInfo(_path + "\\" + dirPath);
if (dirInfo.Exists)
{
foreach (string dirP in Directory.GetDirectories(dirInfo.FullName, "*", SearchOption.AllDirectories))
{
DirectoryInfo dirI = new DirectoryInfo(dirP);
if (dirI.Exists)
{
string dir = dirP.Replace(_path, _configuration.Destination);
try
{
Directory.CreateDirectory(dir);
textBox2.Invoke((MethodInvoker) delegate
{
textBox2.AppendText("Create Directory: " + dir + Environment.NewLine);
});
} catch (Exception e)
{
textBox2.Invoke((MethodInvoker) delegate
{
textBox2.AppendText("Could NOT Create Directory: " + dir + Environment.NewLine);
});
continue;
}
foreach (FileInfo theFile in dirInfo.GetFiles("*", SearchOption.AllDirectories))
{
string newPath = theFile.FullName;
string file = newPath.Replace(_path, _configuration.Destination);
try
{
File.Copy(newPath, file, true);
textBox2.Invoke((MethodInvoker) delegate
{
textBox2.AppendText("Create File: " + file + Environment.NewLine);
});
} catch (Exception ex)
{
textBox2.Invoke((MethodInvoker) delegate
{
textBox2.AppendText("Could NOT Create File: " + file + Environment.NewLine);
});
}
}
}
}
}
}
I apologise if the code is messy, but I will describe sort of what it is doing. The first bit checks if the backup folder exists on the external drive.
The second part says what folders I need to backup (if you're able to fix this and make it backup all directories with permissions, please help me in doing so).
The first loop starts the iteration for each of the backupDirectories. The second loop starts the iteration for each of the directories in the backup directory. The third loop starts the iteration for each of the folders in the backup directory.
The exception is thrown at Directory.GetDirectories(dirInfo.FullName, "*", SearchOption.AllDirectories), and it is trying to access C:\Users\MyName\Documents\My Music. Attempting to access it in explorer does give me a permissions error, though it isn't listed in explorer when I try going to "Documents" (I am in Windows 10 Pro).
As I recommended, since the Operating System authority is higher than the application, it is likely that you cannot do more than what the Operating System would allow you to do (that is to access or not to access certain folder).
Thus, folders' accessibility is best solved in the Operating System level.
But you could still do two things in the program level to minimize the damage when you search for the items.
To use Directory.AccessControl to know the access level of a directory before you do any query on it. This is not so easy, and there are elaborated answers about this here and also here.
To minimize the damage made by unauthorized access issues by using SearchOption.TopDirectoryOnly instead of SearchOption.AllDirectories, combined with recursive search for all the accessible directories. This is how you can code it
public static List<string> GetAllAccessibleDirectories(string path, string searchPattern) {
List<string> dirPathList = new List<string>();
try {
List<string> childDirPathList = Directory.GetDirectories(path, searchPattern, SearchOption.TopDirectoryOnly).ToList(); //use TopDirectoryOnly
if (childDirPathList == null || childDirPathList.Count <= 0) //this directory has no child
return null;
foreach (string childDirPath in childDirPathList) { //foreach child directory, do recursive search
dirPathList.Add(childDirPath); //add the path
List<string> grandChildDirPath = GetAllAccessibleDirectories(childDirPath, searchPattern);
if (grandChildDirPath != null && grandChildDirPath.Count > 0) //this child directory has children and nothing has gone wrong
dirPathList.AddRange(grandChildDirPath.ToArray()); //add the grandchildren to the list
}
return dirPathList; //return the whole list found at this level
} catch {
return null; //something has gone wrong, return null
}
}
The function above minimize the damage caused by the unauthorized access only to the sub-directories which have the issue. All other accessible directories can be returned.

How to get all files in a StorageFolder in Windows Phone Runtime?

I want to get all files in a folder and its sub folders. but a flat query like this:
var allFiles = await myFolder.GetFilesAsync(Windows.Storage.Search.CommonFileQuery.OrderByName);
throws a ArgumentException exception:
A first chance exception of type 'System.ArgumentException' occurred
Additional information: Value does not fall within the expected range.
before I query subfolders one by one, isn't there any other way?
You want all the files and folder which are a descendent of the root folder, not just the shallow enummeration. For most folders the only way to enumerate all the contents and its subfolders content is:
Use StorageFolder.GetFilesAsync() for the files
Use StorageFolder.GetFoldersAsync() to retrieve the all the subfolders
Repeat recursively for all the subfolders you find in step 2.
There is a workaround for this if you are looking for a particular type of media. The instructions are here. These few combinations of locations and CommonFile/FolderQuery options will give a device deep search for media and return the ordered results.
Use CommonFileQuery.OrderByName This is a deep query too so the result will contain all of files from all of subfolders
AND IT WORKS! ;)
MSDN says that you get System.ArgumentException if:
You specified a value other than DefaultQuery from the CommonFileQuery enumeration for a folder that's not a library folder.
https://msdn.microsoft.com/en-us/library/windows/apps/BR211591.aspx
That is strange! Looks like a bug in GetFilesAsync method with all CommaonFileQuery options except DefaultQuery. It is working fine with DefaultQuery.
var allFiles = await myFolder.GetFilesAsync(CommonFileQuery.DefaultQuery);
Hope this helps!
I had the same problem, solved it by preloading file paths recursively:
private static List<string> mContentFilenames = new List<string>();
private static void preloadContentFilenamesRecursive(StorageFolder sf)
{
var files = sf.GetFilesAsync().AsTask().ConfigureAwait(false).GetAwaiter().GetResult();
if (files != null)
{
foreach (var f in files)
{
mContentFilenames.Add(f.Path.Replace('\\','/'));
}
}
var folders = sf.GetFoldersAsync().AsTask().ConfigureAwait(false).GetAwaiter().GetResult();
if (folders != null)
{
foreach (var f in folders)
{
preloadContentFilenamesRecursive(f);
}
}
}
private static void preloadContentFilenames()
{
if (mContentFilenames.Count > 0)
return;
var installed_loc = Windows.ApplicationModel.Package.Current.InstalledLocation;
var content_folder = installed_loc.GetFolderAsync("Content").AsTask().ConfigureAwait(false).GetAwaiter().GetResult();
if (content_folder != null)
preloadContentFilenamesRecursive(content_folder);
}
private static bool searchContentFilename(string name)
{
var v = from val in mContentFilenames where val.EndsWith(name.Replace('\\', '/')) select val;
return v.Any();
}
No idea why downvoted, there is no other way to get full filelist in WP8.1. MSFT for some strange reason corrupts its apis from version to version. Some of calls now returns "not implemented".

How to loop through all MailItems of certain Outlook subfolders

I'm working on an Outlook 2007 add-in. I found some code to loop through all the folders but I have not been able to figure out how to loop inside any given folder to examine the MailItem objects (ultimately, I want to save the emails elsewhere and modify the .Subject property).
Here is what I have so far:
private void btnFolderWalk_Click(object sender, EventArgs e)
{
// Retrieve the name of the top-level folder (Inbox) , for
// the purposes of this demonstration.
Outlook.Folder inbox = Application.Session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox)
as Outlook.Folder; // Cast the MAPI folder returned as an Outlook folder
// Retrieve a reference to the top-level folder.
if (inbox != null)
{
Outlook.Folder parent = inbox.Parent as Outlook.Folder; // the mailbox itself
if (parent != null)
{
RecurseThroughFolders(parent, 0);
}
}
}
private void RecurseThroughFolders(Outlook.Folder theRootFolder, int depth)
{
if (theRootFolder.DefaultItemType != Outlook.OlItemType.olMailItem)
{
return;
}
lbMail.Items.Add(theRootFolder.FolderPath);
foreach (Object item in theRootFolder.Items)
{
if (item.GetType() == typeof(Outlook.MailItem))
{
Outlook.MailItem mi = (Outlook.MailItem)item;
lbMail.Items.Add(mi.Subject);
//-------------------------------------------------------------------------
// mi.Subject is actually a folder name as it's full path.
// How to "open it" to get emails?
// need loop here to modify .Subject of MailItem(s) in certain subfolders
//-------------------------------------------------------------------------
}
}
foreach (Outlook.Folder folder in theRootFolder.Folders)
{
RecurseThroughFolders(folder, depth + 1);
}
}
I'm using a listbox at this stage of working things out and the output currently looks like this below. I want to "process" the email messages of the "Projectnnnnnn" folders.
\\Personal Folders
\\Personal Folders\Deleted Items
\\Personal Folders\Inbox
\\Personal Folders\Inbox\MySubFolder
\\Personal Folders\Inbox\MySubFolder\Project456212
\\Personal Folders\Inbox\MySubFolder\Project318188
\\Personal Folders\Inbox\Outbox
\\Personal Folders\Inbox\SentItems
EDIT:
I fixed this with a slight change in the loop above (i.e. removing the check that the current item is a mailitem):
foreach (Object item in theRootFolder.Items)
{
Outlook.MailItem mi = (Outlook.MailItem)item;
string modifiedSubject = "Modifed Subject: " + mi.Subject;
lbMail.Items.Add(modifiedSubject);
mi.Subject = modifiedSubject;
mi.Save();
// insert call webservice here to upload modified MailItem to new data store
}
While the above code may work it is likely that you will come across an unhandled InvalidCastException as not all items in the root folder will be mail items (e.g. meeting requests).
The following code worked for me:
foreach (object item in items)
{
if (item is Outlook.MailItem)
{
///The rest of your code
}
}
// iterating backwards is needed because of .move below
for (int i = theRootFolder.Items.Count; i > 0; i--)
{
Outlook.MailItem mi = (Outlook.MailItem)theRootFolder.Items[i];
if (mi != null)
{
if (!mi.Subject.StartsWith("M1"))
{
mi.Move(_TRIM_archiveFolder);
}
}
}

Categories

Resources