5
\$\begingroup\$

I have a piece of code that I am not feeling comfortable.

  • I don't want to block the UI
  • Read operation works synchronously (reading may broke 50 ms rule)
  • Save operation supports async (returns Task)
  • I have to await SaveChanges (so operation could be completed before Dispose)

public Task AddToMyProject(string directory) {
    return Task.Run(async () => {
        if (!Directory.Exists(directory)) return;

        using (var context = _contextFactory.CreateContext()) {
            var existing = context.WatchDirectories.FirstOrDefault(wd => wd.Directory == directory);
            if (existing == null) {
                var childWatchers = context.WatchDirectories.Where(wd => wd.Directory.StartsWith(directory));
                foreach (var watchDirectory in childWatchers) {
                    context.Delete(watchDirectory);
                    RemoveDirectoryWatcher(watchDirectory.Directory);
                }

                context.Insert(new WatchDirectory { Directory = directory });
                await context.SaveChanges()
                    .ContinueWith(t => AddDirectoryWatcher(directory));
            }
        }
    });
}

I just want to know if there is a better approach for this.

\$\endgroup\$
1

2 Answers 2

2
\$\begingroup\$

Instead of WatchDirectories.FirstOrDefault you can make use of Any() which is more meaningful.

Also if you are checking Any() you can return early and save horizontal spacing.

public Task AddDirectoryWatcher(string directory) {
    return Task.Run(async () => {
        if (!Directory.Exists(directory)) return;

        using (var context = _contextFactory.CreateContext()) {
            if (context.WatchDirectories.Any(wd => wd.Directory == directory)) { return; };

            var childWatchers = context.WatchDirectories.Where(wd => wd.Directory.StartsWith(directory));

This AddDirectoryWatcher() is using a context to delete and insert items. Doesn't the RemoveDirectoryWatcher() method already uses a context too ? If yes, the call to context.Delete(watchDirectory); is redundant.


Instead of checking if the passed directory exists and silently returning , I would check this before calling the method and throw a DirectoryNotFoundException.

\$\endgroup\$
4
  • \$\begingroup\$ My real concerns were pitfalls of async lambda and Task.Run Etiquette and Proper Usage. But you are right about .Any usage, there used to be an UpdateTime property which is updated every time an object saved, I removed it but forgot to change the code, thanks. By the way, AddDirectoryWatcher and RemoveDirectoryWatcher are not using context, they just create/remove FileSystemWatcher objects. \$\endgroup\$
    – Umut Özel
    Feb 9, 2015 at 11:54
  • \$\begingroup\$ I realized my code looks recursive, my mistake. I changed the method's name in the post, because it contained top secret information :) I fixed it now. \$\endgroup\$
    – Umut Özel
    Feb 9, 2015 at 12:13
  • \$\begingroup\$ Hi @UmutOzel, if you liked this answer then maybe you can reward the poster with an upvote + accept \$\endgroup\$
    – janos
    Feb 15, 2015 at 11:52
  • \$\begingroup\$ Hi @janos, sorry but this answer does not answer my questions about async/await usage. \$\endgroup\$
    – Umut Özel
    Feb 15, 2015 at 12:43
0
\$\begingroup\$
await context.SaveChanges()
    .ContinueWith(t => AddDirectoryWatcher(directory));

This means that when SaveChanges() throws an exception, you're going to silently ignore it. Generally speaking, you shouldn't use ContinueWith() when you can use await:

await context.SaveChanges();
AddDirectoryWatcher(directory);
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.