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 beforeDispose
)
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.
-
\$\begingroup\$ Welcome to Code Review! I have rolled back the last edit. Please see what you may and may not do after receiving answers . \$\endgroup\$Heslacher– Heslacher2015年02月09日 15:28:49 +00:00Commented Feb 9, 2015 at 15:28
2 Answers 2
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
.
-
\$\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– Umut Özel2015年02月09日 11:54:35 +00:00Commented 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– Umut Özel2015年02月09日 12:13:12 +00:00Commented 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– janos2015年02月15日 11:52:40 +00:00Commented 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– Umut Özel2015年02月15日 12:43:39 +00:00Commented Feb 15, 2015 at 12:43
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);
Explore related questions
See similar questions with these tags.