GPAL.OttoMagicClient gives you the same browser actions as IBrowser, but expressed as REST calls against the OttoMagic engine - useful when the thing driving the browser isn't your C# process. This tutorial opens tabs, waits for the network to settle, and walks through Execute() versus the typed Execute<T>().
Here's the whole workflow, start to finish. Each piece is broken down and explained below.
using GenerallyPositive;
using static GenerallyPositive.Enums;
using System.Threading;
GPAL
.WithUseOttoMagic(@"C:OttoMagic")
.WithPublishToConsole();
IRESTClient client = GPAL.OttoMagicClient
.WithName("OttoMagicClient")
.ToGPALObject();
// open a few tabs and let the network settle
client.GoTo("https://youtube.com").Execute();
client.CheckNetworkIdle().Execute();
client.NewTab("https://ebay.com").Execute();
client.CheckNetworkIdle().Execute();
// untyped Execute() - just confirms the call ran
client.Refresh().Execute();
// typed Execute<T>() - returns a strongly typed result
string currentUrl = client.GetCurrentUrl().Execute<string>();
bool atEndOfPage = client.IsEndOfPage().Execute<bool>();
// move between tabs and windows
client.GoToTab("https://example.com").Execute();
client.NextTab().Execute();
client.PreviousTab().Execute();
client.OpenWindow("https://deadmike.com").Execute();
Thread.Sleep(1_500);
client.NextWindow().Execute();
client.PreviousWindow().Execute();
client.CloseTab().Execute();
client.CloseWindow().Execute();
GPAL.OttoMagicClient.WithName(...).ToGPALObject() builds an IRESTClient configured to talk to the OttoMagic engine over REST instead of driving a local WebDriver directly. WithName labels the client in logs - useful once you have more than one client talking to the same engine. The result is the same fluent, chainable surface you've been using on IBrowser.
IRESTClient client = GPAL.OttoMagicClient
.WithName("OttoMagicClient")
.ToGPALObject();
GoTo navigates the active tab, and NewTab opens a fresh tab at a URL. Pages built with heavy client-side scripts keep making network requests after the initial load fires, so CheckNetworkIdle waits until the network has been quiet for a moment before the next step runs - which avoids acting on a half-loaded page.
client.GoTo("https://youtube.com").Execute();
client.CheckNetworkIdle().Execute();
client.NewTab("https://ebay.com").Execute();
client.CheckNetworkIdle().Execute();
Like WaitFor on IBrowser, CheckNetworkIdle is an ordinary chainable call - place it right after the navigation it should wait for, and again after any later step that triggers more network activity.
Every REST call ends with Execute(). For calls that don't return useful data - Refresh, NewTab, GoTo - the plain untyped Execute() is enough; it just confirms the call completed. For calls that return information about the page, use the generic Execute<T>() so you get back a properly typed value instead of a raw object.
// untyped Execute() - just confirms the call ran
client.Refresh().Execute();
// typed Execute<T>() - returns a strongly typed result
string currentUrl = client.GetCurrentUrl().Execute<string>();
bool atEndOfPage = client.IsEndOfPage().Execute<bool>();
Execute<T>() trusts you to ask for the right type - GetCurrentUrl returns a string, IsEndOfPage returns a bool. Asking for the wrong T won't be caught until the call runs.
GoToTab jumps to the tab whose URL matches, while NextTab and PreviousTab cycle through open tabs in order. OpenWindow creates a separate browser window, and NextWindow / PreviousWindow cycle through windows the same way tabs cycle - useful when a workflow needs to juggle more than one window at once. CloseTab and CloseWindow clean up when a tab or window is no longer needed.
client.GoToTab("https://example.com").Execute();
client.NextTab().Execute();
client.PreviousTab().Execute();
client.OpenWindow("https://deadmike.com").Execute();
Thread.Sleep(1_500);
client.NextWindow().Execute();
client.PreviousWindow().Execute();
client.CloseTab().Execute();
client.CloseWindow().Execute();
Every call so far has ended with Execute() or Execute<T>(), and the next call starts a new statement on client. AndThen() (or its generic AndThen<T>()) executes the call you just built, then hands back the same client so you continue setting up the next call in the same chain - this is what makes GPAL.OttoMagicClient a genuinely fluent client rather than a one-call-per-statement wrapper. WithResultName("name") labels the result of the call that follows it - set the name first, then call the endpoint method - and GetExecutionResults() returns a ResultCollection holding every named result produced by the chain so far, read back with results["name"]. AndThen<T>() can also be the last call in a chain - it still executes and stores the named result - but when nothing follows it, Execute<T>() is the cleaner choice: it ends the chain and hands you the result directly, where the <T> is the type of the result being retrieved.
// AndThen() executes the call before it and returns the same client,
// so the chain continues without starting a new statement
client
.GoTo("https://example.com")
.AndThen()
.CheckNetworkIdle()
.AndThen()
.WithResultName("url")
.GetCurrentUrl()
.Execute<string>(); // last call in the chain: Execute<T>() reads cleaner than AndThen<T>() here
// named results from anywhere in the chain are available afterward
var results = client.GetExecutionResults();
string currentUrl = (string)results["url"];
Showing off some plain text in these paragraphs eligendi laboriosam illo nostrum corporis at libero vel voluptas? Expedita, facere dolores voluptatem ad ab rem assumenda soluta!
Lorem ipsum dolor sit amet consectetur adipisicing elit. Obcaecati, iste distinctio veritatis eligendi laboriosam illo nostrum corporis at libero vel voluptas? Expedita, facere dolores voluptatem ad ab rem assumenda soluta!
Lorem ipsum dolor sit amet consectetur adipisicing elit. Obcaecati, iste distinctio veritatis eligendi laboriosam illo nostrum corporis at libero vel voluptas? Expedita, facere dolores voluptatem ad ab rem assumenda soluta!
Lorem ipsum dolor sit amet consectetur adipisicing elit. Quo veniam mollitia excepturi animi eum illum non libero sapiente provident assumenda, delectus voluptatum nobis sed dolorem adipisci laudantium incidunt. Error, ratione?
Lorem ipsum dolor sit amet consectetur adipisicing elit. Quo veniam mollitia excepturi animi eum illum non libero sapiente provident assumenda, delectus voluptatum nobis sed dolorem adipisci laudantium incidunt. Error, ratione?
Lorem ipsum dolor sit amet consectetur adipisicing elit. Quo veniam mollitia excepturi animi eum illum non libero sapiente provident assumenda, delectus voluptatum nobis sed dolorem adipisci laudantium incidunt. Error, ratione?
Lorem ipsum dolor sit amet consectetur adipisicing elit. Quo veniam mollitia excepturi animi eum illum non libero sapiente provident assumenda, delectus voluptatum nobis sed dolorem adipisci laudantium incidunt. Error, ratione?
Here you can find different accents and emphasis sit amet consectetur adipisicing elit. Obcaecati, iste distinctio veritatis eligendi laboriosam illo nostrum corporis at libero vel voluptas? Expedita, facere dolores voluptatem ad ab rem assumenda soluta!
This is a link and how it could look like bestlinkinthebeautifulworld. Obcaecati, iste distinctio veritatis eligendi laboriosam illo nostrum corporis at libero vel voluptas? Expedita, facere dolores voluptatem ad ab rem assumenda soluta!
Here's just some classic bold text adipisicing elit. Obcaecati, iste distinctio veritatis eligendi laboriosam notBoldSecondbestlinkinthebeautifulworld illo nostrum corporis at libero vel voluptas? Expedita, facere dolores voluptatem ad ab rem assumenda soluta!
Obcaecati, iste distinctio veritatis eligendi laboriosam adipisicing elit illo nostrum corporis at adipisicing elit libero vel voluptas? Expedita, adipisicing facere dolores voluptatem ad ab rem assumenda soluta!
Other cuple of colors in case we want to emphasize several ways adipisicing elit. Obcaecati, iste distinctio veritatis eligendi laboriosam adipisicing elit illo nostrum corporis at voluptatem libero vel voluptas? Expedita, facere dolores voluptatem ad ab rem assumenda soluta!
Lorem ipsum dolor sit amet consectetur adipisicing elit. Obcaecati, iste distinctio veritatis eligendi laboriosam illo nostrum corporis at libero vel voluptas? Expedita, facere dolores voluptatem ad ab rem assumenda soluta! Lorem ipsum dolor, sit amet consectetur adipisicing elit. Quod veniam, quam ad expedita laborum sed at voluptates culpa ipsam ut vel. Ullam temporibus a mollitia quod aliquam ratione exercitationem nesciunt.
Lorem ipsum dolor sit amet consectetur adipisicing elit. Obcaecati, iste distinctio veritatis eligendi laboriosam illo nostrum corporis at libero vel voluptas? Expedita, facere dolores voluptatem ad ab rem assumenda soluta! Lorem ipsum dolor, sit amet consectetur adipisicing elit. Quod veniam, quam ad expedita laborum sed at voluptates culpa ipsam ut vel. Ullam temporibus a mollitia quod aliquam ratione exercitationem nesciunt.
Lorem ipsum dolor sit amet consectetur adipisicing elit. Obcaecati, iste distinctio veritatis eligendi laboriosam illo nostrum corporis at libero vel voluptas? Expedita, facere dolores voluptatem ad ab rem assumenda soluta!
Lorem ipsum dolor sit amet consectetur adipisicing elit. Repudiandae quas consequuntur illo numquam assumenda autem exercitationem distinctio perspiciatis in natus. Eius dicta similique ipsam ipsa minima, nemo quae enim tempore.
GPAL
.CallIfNotFound(GenericCallIfNotFound)
.WithPublishToConsole();
//System.Drawing.Rectangle windowSize = new System.Drawing.Rectangle(10, 10, 1500, 1024);
// NOTE: we have to set browser = before we execute any steps
// this is due to the 'GenericCallIfNotFound' which might throw an exception, and BankScraper will not have the browser set when it calls scraper.Close()
// until the complete fluent line gets executed (meaning every step, meaning browser is not set until everything else succeeds)
browser = GPAL.Browser
.WithBrowserType(Enums.BrowserType.Chrome)
.WithProfileDataDirectory(ChromeProfileLocation)
.WithUseAutomationEngine(AutomationEngine.Selenium)
.WithWindowSize(new System.Drawing.Rectangle(0,0,1920,1080))
.ToGPALObject();