Watch me building the soon-to-be-famous (lol) my GoogleFormsToolkitLibrary for .NET C#, a nuget library that will help you easily access your Google Forms programmatically in dotnet, letting you load Field Question data, Submit Form data and so on! 😉
In my previous blog article, Programmatically access your complete Google Forms skeleton! where I shared about my adventure into working out a little hack to access your Google Forms page content programatically, I realized it was a solid implementation, and could be used with almost all kinds of openly accessible Google Forms.
So following up on that, this time I will be building a complete .NET library that will consist of all the awesome hacks and tricks that I built around playing with Google Forms myself, which I have also continuously written blog articles as well!
Backstory…
So far we have come across…
- Let’s auto fill Google Forms with URL parameters…
- You may RESTfully submit to your Google Forms…
- SCRIPTfully scrape off your Google Forms Field Ids…
And then in my previous blog article, Programmatically access your complete Google Forms skeleton! I shared how we retrieving the following data on a given Google Form extensively,
- Google Form Title, Description, Form ID
- List of Question Fields
And in each Question Field,
- Question Field Text
- Question Type
- If submitting Answer is mandatory or not
- Available answer list (Multiple answer selection)
- Question Field Identifier (Field Id) or Answer Submission ID
Then we analyzed the data structure of the FB_PUBLIC_LOAD_DATA_ script that we scraped out of the rendered HTML content, and even managed to parse it into a meaningful data structure which could be mapped to the data we are looking for.
So using that knowledge and expertise, let’s step up the game and build a solid library tool, which we can reuse easily in anywhere to access our Google Forms programmatically to perform all kinds of awesomeness as we wish! 😉
However if you haven’t gone through my previous blog articles in this Google Forms Hacks series, please do so before continuing to avoid any confusion, since I might not be diving into all the details.
Behold GoogleFormsToolkitLibrary v1!
So this library that I’m building will be on .NET Standards, which will allow you to use it in almost any kind of a .NET project. From Console apps, Desktop, Web and even to Mobile Apps in Xamarin!
It will provide you with the following awesome features!
- Load information on your Google Form
- Load Question Field data on your Google Form
- Submit Form data to your Google Form
At least for now, I will be adding more features as I go along my journey of hacking around Google Forms! 😉
I will be publishing this library to Nuget, so that you can easily grab it into your .NET projects, also let’s add some fancy Test Driven goodness to it, using xUnit Tests! 😀
Project Solution Set up…
So I created a .NET Stanard version 2.0 library in Visual Studio, naming it GoogleFormsToolkitLibrary of course! 😉 The I added a Test folder into the Solution which will hold the xUnit Unit Test project, which I named .Tests!
Then don’t forget to add the HTMLAgilityPack and Newtonsoft.Json nugets to the Library solution which will allow us to scrape out the HTML content in a Google Form and use the Json content parsing logic!
Now the basic set up is done, let’s move on to the code!
Let the coding begin…
We need to model the data objects that we’re going to handle when it comes to the perspective of a Google Form. Basically following are the main entities of a Google Form as far as we have recognized in our previous blog articles!
- A Google Form
- A Google Form Question Field
- The Google Form Field Type
Then as of the functionality I would be adding two public methods that we can call upon to execute.
- Load Google Form Structure, data, and form fields
- Submit form data to a given Google Form
Crafting the Models…
So we let’s start by building Model classes that will represent the entities we need.
GoogleFormsFieldTypeEnum
Let’s start with the simplest Model we could build that is the Google Form Field Type object, which will represent the type of a given Question Field. I basically described in detail about this entity and how I build the entity model myself through trial and error in my previous blog article:
Let’s create an enum model class giving it the name GoogleFormsFieldTypeEnum.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// using System.ComponentModel; | |
/// <summary> | |
/// Found the Field type representation values with trial | |
/// and error try out of blood sweat and tears lol! 😉 | |
/// </summary> | |
public enum GoogleFormsFieldTypeEnum | |
{ | |
[Description("Short Answer Field")] | |
ShortAnswerField = 0, | |
[Description("Paragraph Field")] | |
ParagraphField = 1, | |
[Description("Multiple Choice Field")] | |
MultipleChoiceField = 2, | |
[Description("Check Boxes Field")] | |
CheckBoxesField = 4, | |
[Description("Drop Down Field")] | |
DropDownField = 3, | |
// FileUpload – Not supported (needs user log in session) | |
[Description("File Upload Field")] | |
FileUploadField = 13, | |
[Description("Linear Scale Field")] | |
LinearScaleField = 5, | |
// represents both: Multiple Choice Grid | Checkbox Grid | |
[Description("Grid Choice Field")] | |
GridChoiceField = 7, | |
[Description("Date Field")] | |
DateField = 9, | |
[Description("Time Field")] | |
TimeField = 10, | |
} |
We’re adding the Description tags to hold the human readable value of each type.
GoogleFormField
Now this fella right here is a big deal, that is the Google Form Question Field object, which will represent a single Question Field in a given Google Form. A whole list of these fields comprises in every Google Form.
Let’s create a model class giving it the name GoogleFormField.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// using System.Collections.Generic; | |
/// <summary> | |
/// A Question Field in a Google Form | |
/// </summary> | |
public class GoogleFormField | |
{ | |
/// <summary> | |
/// Type of the Question Field | |
/// </summary> | |
public GoogleFormsFieldTypeEnum QuestionType { get; set; } | |
/// <summary> | |
/// Question text of the Field | |
/// </summary> | |
public string QuestionText { get; set; } | |
/// <summary> | |
/// The unique Id need to be used | |
/// when submitting the answer | |
/// I also refer to this as: Field Id | |
/// </summary> | |
public string AnswerSubmissionId { get; set; } | |
/// <summary> | |
/// Available Answer List for any kind of | |
/// multiple answer selection field | |
/// </summary> | |
public List<string> AnswerOptionList { get; set; } = new List<string>(); | |
/// <summary> | |
/// If the answer is required to Submit | |
/// </summary> | |
public bool IsAnswerRequired { get; set; } | |
} |
As you can see we have created properties inside this model that will hold all the values that we discussed previously, that could consist in a given Google Form Question Field.
GoogleForm
Now here’s the top entity, representing a whole Google Form page content. Let’s create a model class giving it the name GoogleForm.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// <summary> | |
/// A model representing a Google Form structure | |
/// consist of main the properties of a Google Form | |
/// </summary> | |
public class GoogleForm | |
{ | |
/// <summary> | |
/// Document Name of your Google Form | |
/// </summary> | |
public string FormDocName { get; set; } | |
/// <summary> | |
/// Form ID of your Google Form | |
/// </summary> | |
public string FormId { get; set; } | |
/// <summary> | |
/// Title of your Google Form | |
/// </summary> | |
public string Title { get; set; } | |
/// <summary> | |
/// Description of your Google Form | |
/// </summary> | |
public string Description { get; set; } | |
/// <summary> | |
/// List of Question Fields in your Google Form | |
/// </summary> | |
public List<GoogleFormField> QuestionFieldList { get; set; } | |
} |
Pretty straight forward set of properties that would usually contain in any Google Form as you can see above. Now make sure to add those Model classes to the Models directory in your project.
Alrighto, we got the model classes done, then let’s move on to the actual functional coding!
Implementing the core features…
We’re going add two main functionality to this library, for now as following! 😉
LoadGoogleFormStructureAsync
Now this method will intake a string parameter that will carry your Google Forms link, and it will return an object of type GoogleForm that we define above. Which obviously contains the given Google Form’s generic information and Question Field list data including Question Type, Answer Options, Submission Id, etc. Now that’s quite a handful eh! 😉
Task<GoogleForm> LoadGoogleFormStructureAsync(string yourGoogleFormsUrl)
So this fella will make Http Async call to load the rendered HTML of the Google Form into memory, run through my magical data scraping algorithm, build the GoogleForm object and return it! Sounds pretty simple but don’t let the implementation confuse you, take a look here! 😉
https://gist.github.com/UdaraAlwis/dcb473f9f07d5024376f1289c1b08ace
Please feel free to take a look at the full implementation on Gist link.
This method is more of an extension of the ScrapeOffFormSkeletonFromGoogleFormsAsync() method that I shared with you all in my last blog post, which I gotten into in depth details about explaining each step of the code.
So to reduce repetition I’m not going to repeat the same here, rather I would share the important bits to explain that are improvements on top of the previous implementation.
One of the differences I would say is that now we’re injecting the data that we scraped out into our model objects, as you can see we’re initializing out GoogleForm and GoogleFormField data objects here, and then loading the GoogleForm data object values.
Then inside the loop we’re loading the GoogleFormField object values as well, and then each object will then be added to the QuestionFormFieldList property of the GoogleForm. That’s pretty much it! 😉
SubmitToGoogleFormAsync
This method will intake a string parameter that will carry your Google Forms link, and a Dictionary object containing the Form field answer submission id and answer values mapping. As a result it will return a boolean value denoting the success or failure of the submission task.
Task<bool> SubmitToGoogleFormAsync (string yourGoogleFormsUrl, Dictionary<string, string> formData)
It will make a Http Async call the Google Forms REST API endpoint with the given data and await for the response code, upon receiving the response it will return true or false based on it.
https://gist.github.com/UdaraAlwis/8d547f68ae3f629d40b2184f51acd43e
Please feel free to take a look at the full implementation on Gist link.
This methods is actually an improvement of one of my previous posts, You may RESTfully submit to your Google Forms… where I explain in depth how I hacked around to figure this out and what each line of code is meant to handle. Please look into that article if you’re keep for more details.
We’re basically looking for the 200 StatusCode value that determines successful submission to the Google Forms REST API endpoint.
Now our Core Library is ready to go!
Unit Test it yo!
Yep but its not done until we implement a proper set of test cases isn’t it! So let’s add some Unit Tests that will test the functionalities that we built into our Library.
Like I mentioned in the Project set up, we have added a xUnit Unit Test project into the solution, and make sure to add a reference of our Library project GoogleFormsToolkitLibrary into it.
Let’s start by adding a Tests.cs class to it, which we will use to implement the tests. For now, I will add two test cases,
RetrieveGoogleFormStructure_Success
This will test for LoadGoogleFormStructureAsync() feature and make sure we get a valid response and the expected data of the given Google Form page.
SubmitDataToGoogleForm_Success
Now this case will test for the SubmitToGoogleFormAsync() feature and make sure we get a successful boolean response, with the given Google Form link, and the form data dictionary object.
Oh let’s not forget to make sure they’re passing in the Test Runner! 😀 lol
All good to go it seems! for now at least lol 😛
This is really a great practice because if I ever break anything in the code during any new implementation or existing modifications, I would be able to notice it here in the tests.
Nugetting it!
Let’s not forget to publish the beauty to Nuget eh! Let’s make sure all the nuget properties are added to the package before uploading…
And you may find it on nuget right now!
This whole project is open sourced and published to Github as well if you’re interested in looking at the code, or track the improvements I’m adding in the future!
So that’s done!
Let’s try it out!
Now the beauty of this is that you can easily add this to any of your .NET projects as the whole library is based on .NET Standard.
Go ahead and add it to your .NET project from Nuget using either the Package Manager Console or the Nuget Package Manager.
Install-Package GoogleFormsToolkitLibrary
Use of GoogleFormsToolkitLibrary is pretty simple, just instantiate it and call upon the method you wanna use.
// Retrieve the structure of my sample Google Forms page // https://docs.google.com/forms/d/e/1FAIpQLSeuZiyN-uQBbmmSLxT81xGUfgjMQpUFyJ4D7r-0zjegTy_0HA/viewform var googleFormLink = "https://docs.google.com/forms/d/e/" + "1FAIpQLSeuZiyN-uQBbmmSLxT81xGUfgjMQpUFyJ4D7r-0zjegTy_0HA" + "/viewform"; var googleFormsToolkitLibrary = new GoogleFormsToolkitLibrary(); var result = await googleFormsToolkitLibrary. LoadGoogleFormStructureAsync(googleFormLink);
That should work like a charm! Make sure to pass your Google Form’s link properly and make sure it is openly accessible, you should be able to see the magic pretty easily!
// Submit data to my sample Google Forms page // https://docs.google.com/forms/d/e/1FAIpQLSeuZiyN-uQBbmmSLxT81xGUfgjMQpUFyJ4D7r-0zjegTy_0HA/viewform var googleFormLink = "https://docs.google.com/forms/d/e/" + "1FAIpQLSeuZiyN-uQBbmmSLxT81xGUfgjMQpUFyJ4D7r-0zjegTy_0HA" + "/formResponse"; Dictionary<string,string> formData = new Dictionary<string, string> { // Question Field 1 {"entry.1277095329", "Moon Rockets Launching"}, // Question Field 2 {"entry.995005981","Banana Plums"}, // Question Field 3 {"entry.1155533672","Monkeys with hoodies"}, // Question Field 4 {"entry.1579749043","Jumping Apples"}, // Question Field 5 {"entry.815399500_year","2019"}, {"entry.815399500_month","11"}, {"entry.815399500_day","11"}, // Question Field 6 {"entry.940653577_hour","04"}, {"entry.940653577_minute","12"}, }; var googleFormsToolkitLibrary = new GoogleFormsToolkitLibrary(); var result = await googleFormsToolkitLibrary .SubmitToGoogleFormAsync(googleFormLink, formData);
The above should nicely respond with a successful true value! 😉
Something to keep in mind here is that you need to make sure you’re setting the correct Field Answer Submission ID properly, and when it comes to Multiple Answer selection fields, make sure the provided answers matches the available list of answers. Date Time fields should be carefully treated with their additional year,month,day suffixed fields and hour,minute respectively. Just go through my past few blog posts on Google Forms hacking, you’ll see for yourself!
What’s next?
Well building this and publishing it openly is just the first step, I’m going to continue building this further adding more features and performance improvements.
Then I will be building some demo Client apps which will use this library to implement some cool features… 😀
So keep an eye out!
There you have it, how I built a Google Forms Toolkit Library for .NET!
Share the love! 😀 Cheers!