Automate #Google login using C# and MasterDev ChromeDevTools

Automating a Chrome login in C# is difficult, because Google is clever enough to detect if you are using an embedded WebBrowser – either the embedded InternetExplorer Control, or CEFSharp, and probably others. It’s also a multi-step process, so you have to get the synchronisation right.

So, this is where ChromeDevTools by MasterDev comes in; The original repo is here:

https://github.com/MasterDevs/ChromeDevTools

I’ve forked this, and made my own changes and fixes here;

https://github.com/infiniteloopltd/ChromeDevTools/blob/master/source/Sample/Program.cs

How MasterDev ChromeDevTools differs from CEFSharp, is that chrome is spawned in a separate process, and it uses WebSockets (WebSocket4Net.WebSocket) to communicate between the host application in C# and Chrome. This also means you can run it in AnyCPU mode, and you don’t have to worry about x86 or x64 CPU types. Oh, and of course, Google can’t detect that you’re listening in to what Chrome is doing.

Some organisational changes I made to the sample code, so that it would run in a synchronous manner was this helper function WaitForEvent<T> which effectively does nothing until a given Event is received from the browser

private static void WaitForEvent<T>(IChromeSession chromeSession) where T : class
{
var waiter = new ManualResetEventSlim();
chromeSession.Subscribe<T>(eventFired =>
{
waiter.Set();
});
waiter.Wait();
}

This method will block indefinitely if the event is never received, but that’s another issue.

I also added this helper method to run Javascript on the page, since I would be calling it repeatedly;

private static async Task<string> ExecuteJavascript(IChromeSession chromeSession, string javaScriptToExecute)
{
var evalResponse = await chromeSession.SendAsync(new EvaluateCommand
{
Expression = javaScriptToExecute,
});
if (evalResponse.Result.ExceptionDetails != null)
{
return evalResponse.Result.ExceptionDetails.ToString();
}
return evalResponse.Result.Result.Value == null ? “” : evalResponse.Result.Result.Value.ToString();
}

Here, I am returning everything as a string, regardless of type – even errors. I’d leave it up to the client application to deal with unexpected values. In my case, I didn’t even need return values.

Everything else is quite straightforward. It’s a matter of navigating to the login page, wait for the page to load, enter the username, press next, wait for the next frame to load, then enter the password, press next, wait for a login, then I can process the page.

Of course, Anything unexpected will make the process hang indefinitely, so this is in no way robust, but it’s a proof of concept, that I hope it helps someone.

Flatlogic Admin Templates banner

Using OpenAPI Generator To Scaffold APIs And API Clients

A number of times in recent years, I’ve had the chance to work in companies that completely design out entire API’s using OpenAPI, before writing a single line of code. Essentially writing YAML to say which endpoints will be available, and what each API should accept and return.

There’s pros and cons to doing this of course. A big pro is that by putting in upfront time to really thinking about API structure, we can often uncover issues well before we get half way through a build. But a con is that after spending a bunch of time defining things like models and endpoints in YAML, we then need to spend days doing nothing but creating C# classes as clones of their YAML counterparts which can be tiresome and frankly, demoralizing at times.

That’s when I came across Open API Generator : https://openapi-generator.tech/

It’s a tool to take your API definitions, and scaffold out APIs and Clients without you having to lift a finger. It’s surprisingly configurable, but at the same time it isn’t too opinionated and allows you to do just the basics of turning your definition into controllers and models, and nothing more.

Let’s take a look at a few examples!

Installing Open API Generator

If you read the documentation here https://github.com/OpenAPITools/openapi-generator, it would look like installing is a huge ordeal of XML files, Maven and JAR files. But for me, using NPM seemed to be simple enough. Assuming you have NPM installed already (Which you should!), then you can simply run :

npm install @openapitools/openapi-generator-cli -g

And that’s it! Now from a command line you can run things like :

openapi-generator-cli version

Scaffolding An API

For this example, I actually took the PetStore API available here : https://editor.swagger.io/

It’s just a simple YAML definition that has CRUD operations on an example API for a pet store. I took this YAML and stored it as “petstore.yaml” locally. Then I ran the following command in the same folder  :

openapi-generator-cli generate -i petstore.yaml -g aspnetcore -o PetStore.Web –package-name PetStore.Web

Pretty self explanatory but one thing I do want to point out is the -g flag. I’m passing in aspnetcore here but in reality, Open API Generator has support to generate API’s for things like PHP, Ruby, Python etc. It’s not C# specific at all!

Our project is generated and overall, it looks just like any other API you would build in .NET

Notice that for each group of API’s in our definition, it’s generated a controller each and models as well.

The controllers themselves are well decorated, but are otherwise empty. For example here is the AddPet method :

/// <summary>
/// Add a new pet to the store
/// </summary>
/// <param name=”body”>Pet object that needs to be added to the store</param>
/// <response code=”405″>Invalid input</response>
[HttpPost]
[Route(“/v2/pet”)]
[Consumes(“application/json”, “application/xml”)]
[ValidateModelState]
[SwaggerOperation(“AddPet”)]
public virtual IActionResult AddPet([FromBody]Pet body)
{
//TODO: Uncomment the next line to return response 405 or use other options such as return this.NotFound(), return this.BadRequest(..), …
// return StatusCode(405);

throw new NotImplementedException();
}

I would note that this is obviously rather verbose (With the comments, Consumes attribute etc), but a lot of that is because that’s what we decorated our OpenAPI definition with, therefore it tries to generate a controller that should act and function identically.

But also notice that it hasn’t generated a service or data layer. It’s just the controller and the very basics of how data gets in and out of the API. It means you can basically scaffold things and away you go.

The models themselves also get generated, but they can be rather verbose. For example, each model gets an override of the ToString method that looks a bit like so :

/// <summary>
/// Returns the string presentation of the object
/// </summary>
/// <returns>String presentation of the object</returns>
public override string ToString()
{
var sb = new StringBuilder();
sb.Append(“class Pet {n”);
sb.Append(” Id: “).Append(Id).Append(“n”);
sb.Append(” Category: “).Append(Category).Append(“n”);
sb.Append(” Name: “).Append(Name).Append(“n”);
sb.Append(” PhotoUrls: “).Append(PhotoUrls).Append(“n”);
sb.Append(” Tags: “).Append(Tags).Append(“n”);
sb.Append(” Status: “).Append(Status).Append(“n”);
sb.Append(“}n”);
return sb.ToString();
}

It’s probably overkill, but you can always delete it if you don’t like it.

Obviously there isn’t much more to say about the process. One command and you’ve got yourself a great starting point for an API. I would like to say that you should definitely dig into the docs for the generator as there is actually a tonne of flags to use that likely solve a lot of hangups you might have about what it generates for you. For example there is a flag to use NewtonSoft.JSON instead of System.Text.Json if that is your preference!

I do want to touch on a few pros and cons on using a generator like this though…

The first con is that updates to the original Open API definition really can’t be “re-generated” into the API. There are ways to do it using the tool but in reality, I find it unlikely that you would do it like this. So for the most part, the generation of the API is going to be a one time thing.

Another con is as I’ve already pointed out, the generator has it’s own style which may or may not suit the way you like to develop software. On larger API’s fixing some of these quirks of the generator can be annoying. But I would say that for the most part, fixing any small style issues is still likely to take less time than writing the entire API from scratch by hand.

Overall however, the pro of this is that you have a very consistent style. For example, I was helping out a professional services company with some of their code practices recently. What I noticed is that they spun up new API’s every month for different customers. Each API was somewhat beholden to the tech leads style and preferences. By using an API generator as a starting point, it meant that everyone had a somewhat similar starting point for the style we wanted to go for, and the style that we should use going forward.

Generating API Clients

I want to quickly touch on another functionality of the Open API Generator, and that is generating clients for an API. For example, if you have a C# service that needs to call out to a web service, how can you quickly whip up a client to interact with that API?

We can use the following command to generate a Client library project :

openapi-generator-cli generate -i petstore.yaml -g csharp -o PetStore.Client –package-name PetStore.Client

This generates a very simple PetApi interface/class that has all of our methods to call the API.

For example, take a look at this simple code :

var petApi = new PetApi(“https://myapi.com”);
var myPet = petApi.GetPetById(123);
myPet.Name = “John Smith”;
petApi.UpdatePet(myPet);

Unlike the server code we generated, I find that the client itself is often able to be regenerated as many times as needed, and over long periods of time too.

As I mentioned, the client code is very handy when two services need to talk to each other, but I’ve also found it useful for writing large scale integration tests without having to copy and paste large models between projects or be mindful about what has changed in an API, and copy those changes over to my test project.

The post Using OpenAPI Generator To Scaffold APIs And API Clients appeared first on .NET Core Tutorials.

Flatlogic Admin Templates banner