Search code examples
c#.netforms.net-6.0microsoft-forms

How do I authenticate and read responses from Microsoft Forms?


I'm using .net 6 to do the authentication and read the responses but nothing seems to work, I do not know if I am authenticated correctly, much less if my code is correct

All configurations in azure have been done according to the documentation I tried in several ways but I can not succeed, this was my last code to try to make it work

using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text.Json;
using System.Threading.Tasks;

namespace MicrosoftFormsExample
{
    class Program
    {
        static async Task Main(string[] args)
        {
            var responses = await GetFormResponses();
            PrintResponses(responses);
        }

        private static async Task<IList<FormResponse>> GetFormResponses()
        {
            var clientId = "<your-client-id>";
            var tenantId = "<your-tenant-id>";
            var clientSecret = "<your-client-secret>";
            var formId = "<form-id>";

            var token = await GetToken(clientId, tenantId, clientSecret);

            using var httpClient = new HttpClient();
            httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);

            var response = await httpClient.GetAsync($"https://graph.microsoft.com/v1.0/forms/{formId}/responses");
            response.EnsureSuccessStatusCode();

            var content = await response.Content.ReadAsStringAsync();
            var options = new JsonSerializerOptions
            {
                PropertyNamingPolicy = JsonNamingPolicy.CamelCase
            };

            var formResponses = JsonSerializer.Deserialize<FormResponseCollection>(content, options).Value;
            return formResponses;
        }

        private static async Task<string> GetToken(string clientId, string tenantId, string clientSecret)
        {
            using var httpClient = new HttpClient();

            var content = new FormUrlEncodedContent(new Dictionary<string, string>
            {
                {"client_id", clientId},
                {"scope", "https://graph.microsoft.com/.default"},
                {"client_secret", clientSecret},
                {"grant_type", "client_credentials"}
            });

            var response = await httpClient.PostAsync($"https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/token", content);
            response.EnsureSuccessStatusCode();

            var tokenResponse = await response.Content.ReadAsStringAsync();
            var token = JsonSerializer.Deserialize<TokenResponse>(tokenResponse).AccessToken;
            return token;
        }

        private static void PrintResponses(IList<FormResponse> responses)
        {
            foreach (var response in responses)
            {
                Console.WriteLine($"Response ID: {response.Id}");
                Console.WriteLine($"Submitted Date and Time: {response.SubmittedDateTime}");
                Console.WriteLine("Answers:");

                foreach (var question in response.Questions)
                {
                    Console.WriteLine($"  {question.QuestionText}: {question.ResponseText}");
                }

                Console.WriteLine();
            }
        }
    }

    class FormResponseCollection
    {
        public IList<FormResponse> Value { get; set; }
    }

    class FormResponse
    {
        public string Id { get; set; }
        public DateTimeOffset SubmittedDateTime { get; set; }
        public IList<QuestionResponse> Questions { get; set; }
    }

    class QuestionResponse
    {
        public string QuestionText { get; set; }
        public string ResponseText { get; set; }
    }

    class TokenResponse
    {
        public string AccessToken { get; set; }
    }
}

Can you help me?


Solution

  • This integration does not work, i ended up having to integrate using Power Automate, in it I convert the answers to list and through this code I can read the answers and delete them

    using Azure.Core;
    using Azure.Identity;
    using Microsoft.Extensions.Configuration;
    using RestSharp;
    using RestSharp.Authenticators.OAuth2;
    using System.Collections.Generic;
    using System.Text.Json;
    using System.Text.RegularExpressions;
    using System.Threading.Tasks;
    using System;
    using System.Text.RegularExpressions;
    using System.Linq.Expressions;
    using Microsoft.Extensions.Logging;
    
    public async Task<Root> GetFormsResponse()
    {
        string listId = _listId;
        string siteId = _siteId;
        string siteUrl = _siteUrl;
        string tenantId = _tenantId;
        string clientId = _clientId;
        string clientSecret = _clientSecret;
        string apiEndpoint = $"{siteUrl}/{siteId}/lists/{listId}/items/?expand=fields";
    
        var accessToken = await GetAccessToken(clientId, clientSecret, tenantId);
        var authenticator = new OAuth2AuthorizationRequestHeaderAuthenticator(accessToken, "Bearer");
        var options = new RestClientOptions(apiEndpoint)
        {
            Authenticator = authenticator
        };
        var client = new RestClient(options);
        var request = new RestRequest(apiEndpoint);
        var response = await client.GetAsync(request);
    
        string responseString = response.Content.ToString();
    
        var responseDeserialize = JsonSerializer.Deserialize<Root>(responseString);
    
        return responseDeserialize;
    }
    public async void DeleteItemList(int id)
    {
        string listId = _listId;
        string siteId = _siteId;
        string siteUrl = _siteUrl;
        string tenantId = _tenantId;
        string clientId = _clientId;
        string clientSecret = _clientSecret;
        string apiEndpoint = $"{siteUrl}/{siteId}/lists/{listId}/items/{id}?expand=fields";
    
        var accessToken = await GetAccessToken(clientId, clientSecret, tenantId);
        var authenticator = new OAuth2AuthorizationRequestHeaderAuthenticator(accessToken, "Bearer");
        var options = new RestClientOptions(apiEndpoint)
        {
            Authenticator = authenticator
        };
        var client = new RestClient(options);
        var request = new RestRequest(apiEndpoint);
        await client.DeleteAsync(request);
    }
    public async Task<string> GetAccessToken(string clientId, string clientSecret, string tenantId)
    {
        var clientSecretCredential = new ClientSecretCredential(tenantId, clientId, clientSecret);
        var tokenRequestContext = new TokenRequestContext(new[] { "https://graph.microsoft.com/.default" });
        var accessToken = await clientSecretCredential.GetTokenAsync(tokenRequestContext);
    
        return accessToken.Token;
    }