Asynchronous website monitor I have a class which is responsible for checking whether a website is up or down. I've made it to run asynchronously, but I would like critique if this is a good/bad way or if there is another better way to do it.

class UrlChecker {
    private readonly IValidationCondition _condition;
    private readonly Dictionary&lt;string, UrlStatus&gt; _status = new Dictionary&lt;string, UrlStatus&gt;();
    private readonly object _lock = new object();

    public UrlChecker(IValidationCondition condition) {
        _condition = condition;
    }

    public void CheckRange(IEnumerable&lt;string&gt; urls, Action&lt;Dictionary&lt;string, UrlStatus&gt;&gt; callback) {
        var options = new ParallelOptions {MaxDegreeOfParallelism = 5};
        Parallel.ForEach(urls, options, Check);

        callback(_status);
    }

    private void Check(string url) {
        Console.WriteLine("Checking " + url);

        var req = (HttpWebRequest) WebRequest.Create(url);
        req.Timeout = 10 * 10000; // 10 seconds

        HttpWebResponse resp;

        try {
            resp = (HttpWebResponse)req.GetResponse();    
        }
        catch(WebException ex) {
            // We got an exception, consider it as down
            lock (_lock)
                _status.Add(url, UrlStatus.Down);
            return;
        }

        if(resp.StatusCode != HttpStatusCode.OK) {
            lock (_lock)
                _status.Add(url, UrlStatus.Down);
            return;
        }

        using(var reader = new StreamReader(resp.GetResponseStream())) {
            // Check for empty response
            var html = reader.ReadToEnd();
            if(string.IsNullOrEmpty(html)) {
                lock(_lock) {
                    _status.Add(url, UrlStatus.Down);
                }
            }

            // Validate against condition
            if(!_condition.IsValid(html)) {
                lock(_lock) {
                    _status.Add(url, UrlStatus.Down);
                }
                return;
            }
        }

        // We reached the end without problems, it's a valid url
        lock(_lock) {
            _status.Add(url, UrlStatus.OK);
        }
    }
}


It's called like so:

checker.CheckRange(urls, status =&gt; {
    if(status.Any(x =&gt; x.Value == UrlStatus.Down))
        EmailFailing(message);
});


The second parameter is obviously a callback that's invoked when all checks are done.

Am I locking correctly?

Is this an acceptable way of doing it? Checking with Fiddler proves that it's working correctly, but is there a better way?
I don't see how this runs asynchronously. callback(_status); will still only be called after all processing is finished, parallel or not. In this case this makes the callback rather redundant, as it does the same as a simple return value.

If you want to make it asynchronous you'll need to store the callback as a member variable, but return immediately in CheckRange. Start the actual processing on a separate thread by e.g. using a BackgroundWorker. Once this execution completes, you can call the stored callback with the result.