public void Log <TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func <TState, Exception, string> formatter) { if (IsEnabled(logLevel)) { Trace.TraceEvent(TraceMapping[logLevel], $"{_categoryName}: {formatter(state, exception)}"); } }
/// <inheritdoc /> public IEnumerable <IDocument> Execute(IReadOnlyList <IDocument> inputs, IExecutionContext context) { #pragma warning disable RCS1163 // Unused parameter. // Handle invalid HTTPS certificates and allow alternate security protocols (see http://stackoverflow.com/a/5670954/807064) ServicePointManager.ServerCertificateValidationCallback = (s, cert, chain, ssl) => true; #pragma warning restore RCS1163 // Unused parameter. // Key = link, Value = source, tag HTML ConcurrentDictionary <string, ConcurrentBag <(string documentSource, string outerHtml)> > links = new ConcurrentDictionary <string, ConcurrentBag <(string documentSource, string outerHtml)> >(); // Key = source, Value = tag HTML ConcurrentDictionary <string, ConcurrentBag <string> > failures = new ConcurrentDictionary <string, ConcurrentBag <string> >(); // Gather all links HtmlParser parser = new HtmlParser(); context.ParallelForEach(inputs, input => GatherLinks(input, parser, links)); // This policy will limit the number of executing link validations. // Limit the amount of concurrent link checks to avoid overwhelming servers. Task[] tasks = links.Select( async link => { // Attempt to parse the URI if (!Uri.TryCreate(link.Key, UriKind.RelativeOrAbsolute, out Uri uri)) { AddOrUpdateFailure(link.Value, failures); } // Adjustment for double-slash link prefix which means use http:// or https:// depending on current protocol // The Uri class treats these as relative, but they're really absolute if (uri.ToString().StartsWith("//") && !Uri.TryCreate($"http:{link.Key}", UriKind.Absolute, out uri)) { AddOrUpdateFailure(link.Value, failures); } // Relative if (!uri.IsAbsoluteUri && _validateRelativeLinks && !(await ValidateRelativeLink(uri, context).ConfigureAwait(false))) { AddOrUpdateFailure(link.Value, failures); } // Absolute if (uri.IsAbsoluteUri && _validateAbsoluteLinks && !(await ValidateAbsoluteLink(uri, context).ConfigureAwait(false))) { AddOrUpdateFailure(link.Value, failures); } }).ToArray(); Task.WaitAll(tasks); // Report failures if (failures.Count > 0) { int failureCount = failures.Sum(x => x.Value.Count); string failureMessage = string.Join( Environment.NewLine, failures.Select(x => $"{x.Key}{Environment.NewLine} - {string.Join(Environment.NewLine + " - ", x.Value)}")); Trace.TraceEvent( _asError ? TraceEventType.Error : TraceEventType.Warning, $"{failureCount} link validation failures:{Environment.NewLine}{failureMessage}"); } return(inputs); }
public IEnumerable <IDocument> Execute(IReadOnlyList <IDocument> inputs, IExecutionContext context) { // Handle invalid HTTPS certificates and allow alternate security protocols (see http://stackoverflow.com/a/5670954/807064) ServicePointManager.ServerCertificateValidationCallback = (s, cert, chain, ssl) => true; // Key = link, Value = source, tag HTML ConcurrentDictionary <string, ConcurrentBag <Tuple <FilePath, string> > > links = new ConcurrentDictionary <string, ConcurrentBag <Tuple <FilePath, string> > >(); // Key = source, Value = tag HTML ConcurrentDictionary <FilePath, ConcurrentBag <string> > failures = new ConcurrentDictionary <FilePath, ConcurrentBag <string> >(); // Gather all links HtmlParser parser = new HtmlParser(); context.ParallelForEach(inputs, input => { GatherLinks(input, parser, links); }); // Perform validation Parallel.ForEach(links, link => { // Attempt to parse the URI Uri uri; if (!Uri.TryCreate(link.Key, UriKind.RelativeOrAbsolute, out uri)) { AddOrUpdateFailure(link.Value, failures); } // Adjustment for double-slash link prefix which means use http:// or https:// depending on current protocol // The Uri class treats these as relative, but they're really absolute if (uri.ToString().StartsWith("//") && !Uri.TryCreate($"http:{link.Key}", UriKind.Absolute, out uri)) { AddOrUpdateFailure(link.Value, failures); } // Relative if (!uri.IsAbsoluteUri && _validateRelativeLinks && !ValidateRelativeLink(uri, context)) { AddOrUpdateFailure(link.Value, failures); } // Absolute if (uri.IsAbsoluteUri && _validateAbsoluteLinks && !ValidateAbsoluteLink(uri, context)) { AddOrUpdateFailure(link.Value, failures); } }); // Report failures if (failures.Count > 0) { int failureCount = failures.Sum(x => x.Value.Count); string failureMessage = string.Join(Environment.NewLine, failures.Select(x => $"{x.Key.FullPath}{Environment.NewLine} - {string.Join(Environment.NewLine + " - ", x.Value)}")); Trace.TraceEvent( _asError ? TraceEventType.Error : TraceEventType.Warning, $"{failureCount} link validation failures:{Environment.NewLine}{failureMessage}"); } return(inputs); }