C# Google Drive API - Prevent duplicate folder creation when checking if directory exists

I need help with Google Drive folder management in C#

I’m working on a C# application that uploads CSV files to Google Drive. My goal is to create a specific directory for storing these files, but I want to avoid making duplicate folders each time the program runs.

Right now my code creates a new folder every time instead of checking properly if one already exists. I think there might be an issue with my folder detection logic.

Here’s what I have so far:

class DriveManager
{
    private string[] permissions = { DriveService.Scope.Drive };
    private string appName;
    private string directoryId;
    private string documentName;
    private string documentPath;
    private string fileType;

    public DriveManager(string docName, string docPath)
    {
        appName = "DataUploader";
        fileType = "text/csv";
        documentName = docName;
        documentPath = docPath;
    }

    public void ProcessUpload()
    {
        UserCredential creds = AuthenticateUser();
        DriveService driveClient = InitializeDriveService(creds);
        directoryId = BuildDirectory(driveClient, "ReportsFolder");
        SendFile(driveClient, documentName, documentPath, fileType);
    }

    private DriveService InitializeDriveService(UserCredential creds)
    {
        return new DriveService(new BaseClientService.Initializer()
        {
            HttpClientInitializer = creds,
            ApplicationName = appName,
        });
    }

    private UserCredential AuthenticateUser()
    {
        UserCredential userCreds;
        using (var fileStream = new FileStream("credentials.json", FileMode.Open, FileAccess.Read))
        {
            string credsPath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);
            credsPath = Path.Combine(credsPath, ".auth/drive-app-tokens.json");

            userCreds = GoogleWebAuthorizationBroker.AuthorizeAsync(
                GoogleClientSecrets.Load(fileStream).Secrets,
                permissions,
                "user",
                CancellationToken.None,
                new FileDataStore(credsPath, true)).Result;
        }
        return userCreds;
    }

    private string SendFile(DriveService driveClient, string docName, string docPath, string mimeType)
    {
        var fileInfo = new Google.Apis.Drive.v3.Data.File();
        fileInfo.Name = docName;
        fileInfo.Parents = new List<string> { directoryId };

        FilesResource.CreateMediaUpload uploadRequest;
        using (var fileStream = new FileStream(docPath, FileMode.Open))
        {
            uploadRequest = driveClient.Files.Create(fileInfo, fileStream, mimeType);
            uploadRequest.Upload();
        }
        var uploadedFile = uploadRequest.ResponseBody;
        return uploadedFile.Id;
    }

    public static string BuildDirectory(DriveService driveClient, string dirName)
    {
        bool folderExists = CheckDirectoryExists(driveClient, dirName);
        if (folderExists)
            return $"Directory {dirName} is already present!";

        var newFolder = new Google.Apis.Drive.v3.Data.File();
        newFolder.Name = dirName;
        newFolder.MimeType = "application/vnd.google-apps.folder";
        var createRequest = driveClient.Files.Create(newFolder);
        createRequest.Fields = "id";
        var response = createRequest.Execute();
        return response.Id;
    }

    private static bool CheckDirectoryExists(DriveService driveClient, string folderName)
    {
        var searchRequest = driveClient.Files.List();
        searchRequest.PageSize = 50;
        searchRequest.Q = $"trashed = false and name contains '{folderName}' and 'root' in parents";
        searchRequest.Fields = "files(name)";
        var results = searchRequest.Execute().Files;

        foreach (var item in results)
        {
            if (folderName == item.Name)
                return true;
        }
        return false;
    }
}

What am I doing wrong with the duplicate detection? Any suggestions would be really helpful!

The issue lies in your BuildDirectory method, which currently returns a string message when the directory exists instead of returning the actual folder ID. This breaks the functionality of the SendFile method, as it expects directoryId to contain an ID rather than a message. You should modify CheckDirectoryExists to return the folder ID instead of just a boolean. Additionally, enhance your search query by including the MIME type to avoid false positives. Here’s the revised code:

private static string CheckDirectoryExists(DriveService driveClient, string folderName)
{
    var searchRequest = driveClient.Files.List();
    searchRequest.Q = $"trashed = false and name = '{folderName}' and mimeType = 'application/vnd.google-apps.folder' and 'root' in parents";
    searchRequest.Fields = "files(id, name)";
    var results = searchRequest.Execute().Files;
    
    return results.FirstOrDefault()?.Id;
}

public static string BuildDirectory(DriveService driveClient, string dirName)
{
    string existingFolderId = CheckDirectoryExists(driveClient, dirName);
    if (!string.IsNullOrEmpty(existingFolderId))
        return existingFolderId;
    
    var newFolder = new Google.Apis.Drive.v3.Data.File();
    newFolder.Name = dirName;
    newFolder.MimeType = "application/vnd.google-apps.folder";
    var createRequest = driveClient.Files.Create(newFolder);
    createRequest.Fields = "id";
    return createRequest.Execute().Id;
}

Note that I also updated the matching condition from name contains to name = for more accurate results.

I hit the same issue. Your method returns different types depending on what happens - that’s the problem. When CheckDirectoryExists finds a folder, BuildDirectory returns a string message. But when it creates a new folder, it returns the folder ID. So directoryId gets set to “Directory ReportsFolder is already present!” instead of an actual ID, and your file upload fails. Fix CheckDirectoryExists to return the folder ID when it finds one, then update BuildDirectory to match. Also, your current search might grab folders with similar names - I’d use exact matching instead. And throw in the folder mime type filter to avoid weird edge cases where files have the same name.

hey! ur query logic’s a bit off - ‘name contains’ can match partial names, which can cause issues. also, BuildDirectory should return the folder ID instead of a string msg when it finds existing folders. use exact matching and always return the folder ID.