Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How do I write this TryAsync chain? #956

Closed
MrYossu opened this issue Nov 22, 2021 · 4 comments
Closed

How do I write this TryAsync chain? #956

MrYossu opened this issue Nov 22, 2021 · 4 comments

Comments

@MrYossu
Copy link
Contributor

MrYossu commented Nov 22, 2021

I am writing some methods that work with the C# Google Drive API, and have most of them working. They return TryAsync<T>, and thanks to some great help from @Malgefor in another issue, I can chain them together.

However, one method is causing me problems. It is supposed to create a new folder. Although Google Drive allows multiple files and folders to have the same name, our code is not going to. Therefore, the CreateFolder method first needs to check if a folder of that name exists, and if so, just return the Id. If it doesn't exist, then we are to create it and return the Id.

I already have the following method working (implementation omitted as it's not relevant)...

TryAsync<List<File>> GetSubfolders(string folderId)

...where the (badly-named in my opinion) File type is in the Google.Apis.Drive.v3 namespace, and refers to either a file or a folder.

I also have a private method that checks the folders passed in to see if one by named folderName already exists, creates a new one where needed and returns the Id (again, implementation omitted)...

async Task<string> CreateNewFolder(string folderName, string parentFolderId, List<File> folders)

What I want to do is stick these together.

I tried the following...

public TryAsync<string> CreateFolder(string folderName, string parentFolderId) =>
  GetSubfolders(parentFolderId)
    .Bind(folders => CreateNewFolder(folderName, parentFolderId, folders));

...but this gives a compiler error on the call to Bind...

The type arguments for method 'TryAsyncExtensions.Bind<A, B>(TryAsync, Func<A, TryAsync>)' cannot be inferred from the usage

...as well as a confusing (to me at least) compiler error on the folders variable at the end of that same line...

Argument 3: cannot convert from 'int' to 'System.Collections.Generic.List<Google.Apis.Drive.v3.Data.File>'

That second error seems really weird, as if I hover over the folders variable, it clearly shows me that it is a List<File>, so why it thinks it's an int is beyond me. However, I suspect that if I can fix the first error, the second may go away.

Anyone any idea what I'm doing wrong? Please let me know if I need to supply anything else. I tried to show as much code as I can,. without confusing the matter with implementation details.

Thanks

@Malgefor
Copy link

In the Bind-call, you are combining a TryAsync with a Task. Those are not the same types and cannot be bound together like that.

If you look at the signature of the Bind call you see that the return type is a TryAsync and the function you have to provide has a signature of Func<T (List<File>), TryAsync<TResult (string)>> whereas you are doing: Func<T (List<File>), Task<TResult (string)>>

If you change the type of the CreateNewFolder method to TryAsync it works fine.

PS: the int-message is just Visual Studio not understanding what you are doing. Why it shows the parameter as int, no idea. Maybe Paul or someone else knows why that is the case.

@MrYossu
Copy link
Contributor Author

MrYossu commented Nov 22, 2021

@Malgefor Duh part 27!

As usual, you've hit the nail on the head.

I did actually think of that, and tried to convert CreateNewFolder to TryAsync but ran into problems. I tried again, and have it working. Please can you tell m if this can be improved, as it looks a little messy to me...

private TryAsync<string> CreateNewFolder(string folderName, string parentFolderId, List<DriveFile> folders) {
  if (folders.Any()) {
    // Is there a neater way to return the existing folder's Id?
    return TryAsync(() => Task.Run(() => folders.First().Id));
  }
  DriveFile newFolder = new() {
    Name = folderName,
    MimeType = "application/vnd.google-apps.folder",
    Parents = new[] { parentFolderId }
  };
  FilesResource.CreateRequest command = _service.Files.Create(newFolder);
  return TryAsync(async () => {
    DriveFile folder = await command.ExecuteAsync();
    return folder.Id;
  });
}

Thanks again for all the help.

@Malgefor
Copy link

You don't have to do that if-statement in the CreateNewFolder-method; only call that when you actually need to create a new folder.

Other than that maybe move the newFolder creation + command creation to a separate method.

@MrYossu
Copy link
Contributor Author

MrYossu commented Nov 22, 2021

You don't have to do that if-statement in the CreateNewFolder-method; only call that when you actually need to create a new folder.

Not sure what you mean. I need to check if a folder with the given name already exists. Otherwise I would end up creating another folder with the same name.

Thanks again.

Repository owner locked and limited conversation to collaborators Nov 23, 2021
@louthy louthy closed this as completed Nov 23, 2021

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants