Skip to content

Instantly share code, notes, and snippets.

@ZodmanPerth
Last active February 22, 2024 01:19
Show Gist options
  • Save ZodmanPerth/be313b8989c7ef191e66b1b0292c2e71 to your computer and use it in GitHub Desktop.
Save ZodmanPerth/be313b8989c7ef191e66b1b0292c2e71 to your computer and use it in GitHub Desktop.
Google Forms Data Submission in C#
/// <summary>Submit form data to a Google form</summary>
/// <remarks>Kudos: https://stackoverflow.com/questions/52398172/how-to-fill-google-form-with-c-sharp </remarks>
public class GoogleFormsSubmissionService
{
private string _baseUrl;
private Dictionary<string, string> _field;
private Dictionary<string, string[]> _checkbox;
private HttpClient _client;
public GoogleFormsSubmissionService(string formUrl)
{
if (string.IsNullOrEmpty(formUrl)) throw new ArgumentNullException(nameof(formUrl));
_baseUrl = formUrl;
_field = new Dictionary<string, string>();
_checkbox = new Dictionary<string, string[]>();
_client = new HttpClient();
}
/// <summary>Set multiple fields with individual values. Fields with empty values will be ignored.</summary>
/// <remarks>All keys must be valid or exceptions will be thrown.</remarks>
public void SetFieldValues(Dictionary<string, string> data)
{
if (data == null) throw new ArgumentNullException(nameof(data));
if (data.Keys.Any(value => string.IsNullOrWhiteSpace(value))) throw new ArgumentNullException(nameof(data), "Empty keys are invalid");
var fieldsWithData = data.Where(kvp => !string.IsNullOrWhiteSpace(kvp.Value));
foreach (var kvp in fieldsWithData)
_field[kvp.Key] = kvp.Value;
}
/// <summary>Set one or more values for a single checkbox field. Values must match the text on the form Checkboxes. Empty values will be ignored.</summary>
public void SetCheckboxValues(string key, params string[] values)
{
if (string.IsNullOrWhiteSpace(key)) throw new ArgumentNullException(nameof(key));
var valuesWithData = values.Where(value => !string.IsNullOrWhiteSpace(value)).ToArray();
_checkbox[key] = valuesWithData;
}
/// <summary>Submits the previously set data asynchronously and returns the response.</summary>
/// <remarks>See https://stackoverflow.com/a/52404185/117797 for queryParams formatting details</remarks>
public async Task<HttpResponseMessage> SubmitAsync()
{
if (!_field.Any() && !_checkbox.Any())
{
throw new InvalidOperationException("No data has been set to submit");
}
var content = new FormUrlEncodedContent(_field);
var url = _baseUrl;
if (_checkbox.Any())
{
var queryParams = string.Join("&", _checkbox.Keys.SelectMany(key => _checkbox[key].Select(value => $"{key}={value.Replace(' ', '+')}")));
url += $"?{queryParams}";
}
var response = await _client.PostAsync(url, content);
if (response.IsSuccessStatusCode)
{
Console.Write("Google form data was submitted sucessfully");
}
else
{
var fieldText = string.Join(Environment.NewLine, _field.Keys.Select(key => $"{key}={string.Join(",", _field[key])}"));
Console.Write($"Failed to submit Google form\n{response.StatusCode}: {response.ReasonPhrase}\n{url}\n{fieldText}");
}
return response;
}
}
var fields = new Dictionary<string, string>
{
{ "entry.11111", "My text" },
{ "entry.22222", "Other text"},
{ "entry.33333", "LINQPad" },
};
var formUrl = "https://docs.google.com/forms/d/e/{YourFormCodeHere}/formResponse";
var submissionService = new GoogleFormsSubmissionService(formUrl);
submissionService.SetFieldValues(fields);
submissionService.SetCheckboxValues("entry.44444", "One fish", "Two fish"); //Multiple checkbox values
submissionService.SetCheckboxValues("entry.55555", "There can be only one"); //Single checkbox value
var response = await submissionService.SubmitAsync();
@ewilkinson-marathon
Copy link

Is there any solution to the post to google forms with the Send Email Receipts FormSetting enabled? It requires a g-recaptcha-response in the data, but I can't find any method to pass one in since they are generated with our own site's recaptcha API keys.

So, any post with that form setting enabled, you have to pass in "emailAddress", "emailReceipt": "true", and "g-recaptcha-response". Ultimately, they fail due to the recaptcha response not being valid (I assume the version and site/secret keys mismatching is the cause of failure).

The second question would be: do you have any thoughts on including the FileUpload field?

@ZodmanPerth
Copy link
Author

It's been a long, long time since I worked on Google Forms. The solution I presented here was for my specific use case, and I have not worked on it since. As such I can't offer any further thoughts (re: FileUpload field).

As for Captcha, as I understand that field is specifically to prevent automated responses. I have no clue how to distinguish between an automated response and the legitimate response of a code handler.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment