It seems my DI container makes a new instance for ChromeDriver (IWebDriver) each time I try and get it from the container? All of this happened after refactoring my code. I suddenly needed Selenium by reference for the methods below, otherwise, it wouldn't update the DOM throughout new page loads as I was passing it by value.
Here are the original methods before refactoring,
public static bool ElementExists(IWebDriver selenium, By selector)
{
try
{
selenium.FindElement(selector);
return true;
}
catch (NoSuchElementException)
{
return false;
}
}
public static void WaitForElements(IWebDriver selenium, List<By> selectors, string name = "")
{
new ConsoleLogger().Trace("Waiting for " + (string.IsNullOrEmpty(name) ? selectors.Count + " items" : name) + ", give us a second.");
while (selectors.Where(x => ElementExists(selenium, x)).Count() < selectors.Count)
{
Thread.Sleep(100);
}
}
I thought hmm, this is going to be a tricky one. I needed some sort of static instance that I could always pass by reference, I refactored it to this.
public static bool ElementExists(By selector)
{
var selenium = Reusables.GetServiceProvider().GetService<IWebDriver>();
try
{
selenium.FindElement(selector);
return true;
}
catch (NoSuchElementException)
{
return false;
}
}
Reusables class:
public static class Reusables
{
public static IDependencyProvider DependencyProvider;
public static IServiceProvider GetServiceProvider()
{
return DependencyProvider.BuildServiceProvider();
}
}
Program:
private static void Main(string[] args)
{
var diProvider = new DependencyProvider();
Reusables.DependencyProvider = diProvider;
Console.ForegroundColor = ConsoleColor.White;
Console.CancelKeyPress += (sender, eArgs) => {
QuitEvent.Set();
eArgs.Cancel = true;
};
Console.WriteLine();
Console.CursorVisible = false;
/*var config = serviceProvider.GetService<IConfigProvider>();
config.Load("https://kskdkskd.kdskdkk", new WebClient());*/
var scraper = Reusables.GetServiceProvider().GetService<IScraperHandler>();
scraper.Start();
QuitEvent.WaitOne();
}
Not sure if its needed, but here's how I register my dependencies:
public class DependencyProvider : ServiceCollection, IDependencyProvider
{
public DependencyProvider()
{
Register();
}
public void Register()
{
this.AddSingleton<IAuthProvider, AuthProvider>();
var options = new ChromeOptions();
options.AddArguments("--disable-notifications");
options.SetLoggingPreference(LogType.Browser, LogLevel.Off);
this.AddSingleton<IWebDriver>(provider =>
new ChromeDriver(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), options)
);
var links = File.ReadAllLines("***");
this.AddSingleton<IHttpHandler, HttpHandler>();
this.AddSingleton<IEnumerable>(stack => new Stack<string>(links.ToList()));
this.AddSingleton<IScraperHandler, ScraperHandler>();
this.AddSingleton<IConfigProvider, JsonConfigProvider>();
}
}