Reputation: 5186
I have the following scenario that I'm not sure how it's best to handle.
On an ASP.NET MVC 4 system, I have a controller action that calls an external system (in the same network) that, within anywhere between 1 to 10 minutes, will generate 3 XML files and place them on a folder on the same server where the ASP.NET MVC app is hosted.
At first I thought of using a Windows Service with a FileSystemWatcher to monitor the folder for XML files, but I was asked to suggest an alternative solution, in case installing a Windows Service is not feasible.
I've done very little threading, so I'm not sure what the ideal way to do this is.
In theory, the controller action will call the external system (it's a web service (asmx) call) and then, I want to fire a short-lived thread that will execute for up to 10 minutes, and if it finds .xml files in the folder, it will process them.
Thanks
-- EDIT, Update
Brandon's solution works exactly the way I need it, but he says to get the Task.Delay method code from another stackoverflow question, from someone who decompiled the Async library. That did not work for me, so I had to get the Microsoft.CompilerServices.AsyncTargetingPack NuGet package.
Upvotes: 0
Views: 870
Reputation: 39212
A FileSystemWatcher
does not require a thread or a Windows service. Just create it, set up your event handlers, then set EnableRaisingEvents
to true. Then start a timer that expires after 10 minutes and disposes of the watcher. Something like:
private async void RunAfterDelay(TimeSpan delay, CancellationToken token, Action action)
{
await Task.Delay(delay, token);
if (!token.IsCancellationRequested)
{
action();
}
}
private void RunWatcher()
{
var cts = new CancellationTokenSource();
var watcher = new FileSystemWatcher();
watcher.Path = "...";
watcher.Created += (_, e) =>
{
if (e.FullPath == "file-you-are-interested-in")
{
// cancel the timer
cts.Cancel();
// do your stuff
// ...
// get rid of the watcher
watcher.Dispose();
}
};
watcher.EnableRaisingEvents = true;
// start the timer
RunAfterDelay(TimeSpan.FromMinutes(10), cts.Token, () =>
{
// get rid of the watcher
watcher.Dispose();
// do anything else you want to do, like send out failure notices.
});
}
This will start listening to the watcher and if you get what you want, it will dispose of the watcher. If the timer expires, it will stop the watcher.
The above is targetting .NET 4.5. If you are targetting 4.0, then first grab the implementation of Delay
shown here: https://stackoverflow.com/a/9068520/674326
Then change RunAfterDelay
to this:
private void RunAfterDelay(TimeSpan delay, CancellationToken token, Action action)
{
TaskEx.Delay(delay, token).ContinueWith(t => action(), TaskContinuationOptions.OnlyOnRanToCompletion);
}
Upvotes: 2