public async Task <IActionResult> Delete(string id) { if (!string.IsNullOrEmpty(id)) { // Initialize the GraphServiceClient and delete the subscription. var graphClient = await GraphServiceClientFactory.GetAuthenticatedGraphClient(async() => { string result = await tokenAcquisition.GetAccessTokenOnBehalfOfUser( HttpContext, new[] { Infrastructure.Constants.ScopeMailRead }); return(result); }); try { await graphClient.Subscriptions[id].Request().DeleteAsync(); } catch (Exception e) { ViewBag.Message = BuildErrorMessage(e); return(View("Error")); } ViewBag.Message = $"Deleted subscription {id}"; } return(View("Subscription")); }
public async Task <IActionResult> Create() { string userId = User.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier")?.Value; string tenantId = User.FindFirst("http://schemas.microsoft.com/identity/claims/tenantid")?.Value; string clientState = Guid.NewGuid().ToString(); // Initialize the GraphServiceClient var graphClient = await GraphServiceClientFactory.GetAuthenticatedGraphClient(appSettings.Value.GraphApiUrl, async() => { string result = await tokenAcquisition.GetAccessTokenForUserAsync(new[] { subscriptionOptions.Value.Scope }); return(result); }); try { // Create a subscription. var newSubscription = await CreateSubscription(userId, tenantId, clientState, graphClient).ConfigureAwait(false); return(View("Subscription", newSubscription)); } catch (Exception e) { // If a tenant admin hasn't granted consent, this operation returns an Unauthorized error. // This sample caches the initial unauthorized token, so you'll need to start a new browser session. ViewBag.Message = BuildErrorMessage(e); return(View("Error")); } }
public async Task <IActionResult> RenewAppOnly(string id) { if (!string.IsNullOrEmpty(id)) { // Initialize the GraphServiceClient and renew the subscription. var graphClient = await GraphServiceClientFactory.GetAuthenticatedGraphClient(appSettings.Value.BaseUrlWithoutVersion, async() => { return(await tokenAcquisition.GetAccessTokenForAppAsync($"{appSettings.Value.BaseUrlWithoutVersion}/.default")); }); try { var subscription = await graphClient.Subscriptions[id].Request().UpdateAsync(new Subscription { ExpirationDateTime = DateTime.UtcNow + new TimeSpan(0, 0, 15, 0) }); ViewBag.Message = $"Renewed subscription {id}"; return(View("Subscription", subscription)); } catch (Exception e) { ViewBag.Message = BuildErrorMessage(e); return(View("Error")); } } else { return(View("Error", "Subscription id is required")); } }
public async Task <IActionResult> Initialize() { //initialize the MS Graph API client to connect to Graph var graphClient = GraphServiceClientFactory .GetAuthenticatedGraphClient(async() => { return(await _tokenAcquisition .GetAccessTokenForUserAsync(GraphConstants.Scopes)); }); //Get Data - see function below IEnumerable <Patients> sql = await GetDataFromDB(); foreach (Patients patient in sql) { try { //make a new MS Contact Object using the patient data from sql query Contact contact = new PatientContact().NewContact(patient); //send the Contact Object to Microsoft People await graphClient.Me.Contacts .Request() .AddAsync(contact); } catch (ServiceException ex) { return(RedirectToAction("Index") .WithError("Error With the Contact", ex.Error.Message)); } } return(RedirectToAction("Index", "Home")); }
public async Task <IActionResult> CreateAppOnly() { string clientState = Guid.NewGuid().ToString(); // Initialize the GraphServiceClient var graphClient = await GraphServiceClientFactory.GetAuthenticatedGraphClient(appSettings.Value.BaseUrlWithoutVersion, async() => { return(await tokenAcquisition.GetAccessTokenForAppAsync($"{appSettings.Value.BaseUrlWithoutVersion}/.default")); }); try { // Create a subscription. var newSubscription = await CreateSubscription(string.Empty, string.Empty, clientState, graphClient).ConfigureAwait(false); return(View("Subscription", newSubscription)); } catch (Exception e) { // If a tenant admin hasn't granted consent, this operation returns an Unauthorized error. // This sample caches the initial unauthorized token, so you'll need to start a new browser session. ViewBag.Message = BuildErrorMessage(e); return(View("Error")); } }
public async Task <IActionResult> Profile() { // Initialize the GraphServiceClient. var graphClient = await GraphServiceClientFactory.GetAuthenticatedGraphClient(async() => { string result = await tokenAcquisition.GetAccessTokenOnBehalfOfUser( HttpContext, new[] { Constants.ScopeUserRead }); return(result); }, webOptions.GraphApiUrl); // Get user profile info. var me = await graphClient.Me.Request().GetAsync(); ViewData["Me"] = me; try { // Get user photo var photoStream = await graphClient.Me.Photo.Content.Request().GetAsync(); byte[] photoByte = ((MemoryStream)photoStream).ToArray(); ViewData["Photo"] = Convert.ToBase64String(photoByte); } catch (System.Exception) { ViewData["Photo"] = null; } return(View()); }
private async void PostContacts(List <Contact> list) { //initialize the MS Graph API client to connect to Graph var graphClient = GraphServiceClientFactory .GetAuthenticatedGraphClient(async() => { return(await _tokenAcquisition .GetAccessTokenForUserAsync(GraphConstants.Scopes)); }); //TODO: Get all from MS Contacts, compare FileAs to list.Id, keep matches send to a list // with only FileAs and Id = List<> MSContacts var MSContacts = await graphClient.Me.Contacts .Request() //this may not work .Select("fileAs,id") .GetAsync(); var ReadyList = prepareList(list, MSContacts); foreach (Contact c in ReadyList) { //TODO: Delete Contacts {ID} where FileAs = c.Id var id = c.Id; await graphClient.Me.Contacts[id] .Request() .DeleteAsync(); //TODO: Post to Contacts(c) await graphClient.Me.Contacts .Request() .AddAsync(c); } }
private Graph::GraphServiceClient GetGraphServiceClient(string[] scopes) { return(GraphServiceClientFactory.GetAuthenticatedGraphClient(async() => { string result = await tokenAcquisition.GetAccessTokenOnBehalfOfUserAsync(scopes); return result; }, "https://graph.microsoft.com/beta")); }
private Graph::GraphServiceClient GetGraphServiceClient(string[] scopes) { return(GraphServiceClientFactory.GetAuthenticatedGraphClient(async() => { string result = await tokenAcquisition.GetAccessTokenOnBehalfOfUserAsync(scopes); return result; }, webOptions.GraphApiUrl)); }
public async Task <IActionResult> Create() { string userId = User.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier")?.Value; string tenantId = User.FindFirst("http://schemas.microsoft.com/identity/claims/tenantid")?.Value; string clientState = Guid.NewGuid().ToString(); // Initialize the GraphServiceClient. var graphClient = await GraphServiceClientFactory.GetAuthenticatedGraphClient(async() => { string result = await tokenAcquisition.GetAccessTokenOnBehalfOfUser( HttpContext, new[] { Infrastructure.Constants.ScopeMailRead }); return(result); }); Subscription newSubscription = new Subscription(); try { // Create a subscription. // The `Resource` property targets the `users/{user-id}` or `users/{user-principal-name}` path (not `me`) when using application permissions. // The NotificationUrl requires the `https` protocol and supports custom query parameters. newSubscription = await graphClient.Subscriptions.Request().AddAsync(new Subscription { Resource = $"users/{userId}/mailFolders('Inbox')/messages", ChangeType = "created", NotificationUrl = appSettings.NotificationUrl, ClientState = clientState, //ExpirationDateTime = DateTime.UtcNow + new TimeSpan(0, 0, 4230, 0) // current maximum lifespan for messages ExpirationDateTime = DateTime.UtcNow + new TimeSpan(0, 0, 15, 0) // shorter duration useful for testing }); // Verify client state, then store the subscription ID and client state to validate incoming notifications. if (newSubscription.ClientState == clientState) { // This sample temporarily stores the subscription data, but production apps will likely use some method of persistent storage. // This sample stores the client state to validate the subscription, the tenant ID to reuse tokens, and the user ID to filter // messages to display by user. subscriptionStore.SaveSubscriptionInfo(newSubscription.Id, newSubscription.ClientState, userId, tenantId); } else { ViewBag.Message = "Warning! Mismatched client state."; } } catch (Exception e) { // If a tenant admin hasn't granted consent, this operation returns an Unauthorized error. // This sample caches the initial unauthorized token, so you'll need to start a new browser session. ViewBag.Message = BuildErrorMessage(e); return(View("Error")); } return(View("Subscription", newSubscription)); }
public static async Task Run([ActivityTrigger] CreationResult input, ILogger log, ExecutionContext context) { var client = GraphServiceClientFactory.GetInstance(context?.FunctionAppDirectory).Client.Value; if (!await DoesTeamExist(input, client)) { await EnableTeams(input, client); } }
public static async Task <string> Run([ActivityTrigger] string title, ILogger log, ExecutionContext context) { log.LogInformation($"getting group id for {title}"); var client = GraphServiceClientFactory.GetInstance(context?.FunctionAppDirectory).Client.Value; var existingGroups = await client.Groups.Request().Filter($"displayName eq '{title}'").GetAsync(); return(existingGroups.FirstOrDefault()?.Id); }
// Get information about the changed messages and send to browser via SignalR. // A production application would typically queue a background job for reliability. private async Task GetChangedMessagesAsync(IEnumerable <ChangeNotification> notifications) { List <NotificationViewModel> notificationsToDisplay = new List <NotificationViewModel>(); foreach (var notification in notifications) { SubscriptionStore subscription = subscriptionStore.GetSubscriptionInfo(notification.SubscriptionId.Value); // Set the claims for ObjectIdentifier and TenantId, and // use the above claims for the current HttpContext if (!string.IsNullOrEmpty(subscription.UserId)) { HttpContext.User = ClaimsPrincipalFactory.FromTenantIdAndObjectId(subscription.TenantId, subscription.UserId); } if (notification.Resource.Contains("/message", StringComparison.InvariantCultureIgnoreCase)) { // Initialize the GraphServiceClient. var graphClient = await GraphServiceClientFactory.GetAuthenticatedGraphClient(appSettings.Value.BaseUrlWithoutVersion, async() => { return(await tokenAcquisition.GetAccessTokenForAppAsync($"{appSettings.Value.BaseUrlWithoutVersion}/.default")); }); var request = new MessageRequest(graphServiceClient.BaseUrl + "/" + notification.Resource, string.IsNullOrEmpty(subscription.UserId) ? graphClient : graphServiceClient, null); try { var responseValue = await request.GetAsync(); notificationsToDisplay.Add(new NotificationViewModel(new { From = responseValue?.From?.EmailAddress?.Address, responseValue?.Subject, SentDateTime = responseValue?.SentDateTime.HasValue ?? false ? responseValue?.SentDateTime.Value.ToString() : string.Empty, To = responseValue?.ToRecipients?.Select(x => x.EmailAddress.Address)?.ToList(), })); } catch (ServiceException se) { string errorMessage = se.Error.Message; string requestId = se.Error.InnerError?.AdditionalData["request-id"]?.ToString(); string requestDate = se.Error.InnerError?.AdditionalData["date"]?.ToString(); logger.LogError($"RetrievingMessages: { errorMessage } Request ID: { requestId } Date: { requestDate }"); } } else { notificationsToDisplay.Add(new NotificationViewModel(notification.Resource)); } } if (notificationsToDisplay.Count > 0) { await notificationService.SendNotificationToClient(notificationHub, notificationsToDisplay); } }
public static async Task Run([ActivityTrigger] CreationResult input, ILogger log, ExecutionContext context) { log.LogInformation("creating library tabs for client"); var client = GraphServiceClientFactory.GetInstance(context?.FunctionAppDirectory).Client.Value; var tabService = new TeamsTabService(client, AppDefId); await AddConfiguredLibTabsToChannel(input.GroupId, input.ProjectChannelId, input.ProjectSiteUrl, client, tabService, input.ProjectChannelLibTabsLibNames, webExtraction); log.LogInformation("created library tabs for client"); }
public void OnGet() { string[] scopes = new[] { "mail.read" }; GraphServiceClient graphClient = GraphServiceClientFactory.GetAuthenticatedGraphClient(async() => { string result = await tokenAcquisition.GetAccessTokenForUserAsync(scopes); return(result); }, "https://graph.microsoft.com/beta/"); Messages = graphClient.Me.Messages.Request().Top(10).GetAsync().Result; }
public GraphServiceClientFixture() { var azureConfig = Configuration.Instance.GetSection("AzureAd"); var clientId = azureConfig["ClientId"]; var clientSecret = Configuration.Instance["ClientSecret"]; var tenantId = azureConfig["TenantId"]; var authority = azureConfig["Authority"]; var clientApplication = ClientApplicationFactory.CreateConfidentialClient(clientId, clientSecret, tenantId); GraphServiceClient = GraphServiceClientFactory.Create(clientApplication); }
private async Task <IActionResult> ProcessRequestAsync(string method, string all, object content) { var graphClient = GraphServiceClientFactory .GetAuthenticatedGraphClient(async() => { return(await _tokenAcquisition .GetAccessTokenForUserAsync(GraphConstants.Scopes)); } ); var qs = HttpContext.Request.QueryString; var url = $"{GetBaseUrlWithoutVersion(graphClient)}/{all}{qs.ToUriComponent()}"; var request = new BaseRequest(url, graphClient, null) { Method = method, ContentType = HttpContext.Request.ContentType, }; var neededHeaders = Request.Headers.Where(h => h.Key.ToLower() == "if-match").ToList(); if (neededHeaders.Count() > 0) { foreach (var header in neededHeaders) { request.Headers.Add(new HeaderOption(header.Key, string.Join(",", header.Value))); } } var contentType = "application/json"; try { using (var response = await request.SendRequestAsync(content?.ToString(), CancellationToken.None, HttpCompletionOption.ResponseContentRead).ConfigureAwait(false)) { response.Content.Headers.TryGetValues("content-type", out var contentTypes); contentType = contentTypes?.FirstOrDefault() ?? contentType; var byteArrayContent = await response.Content.ReadAsByteArrayAsync().ConfigureAwait(false); return(new HttpResponseMessageResult(ReturnHttpResponseMessage(HttpStatusCode.OK, contentType, new ByteArrayContent(byteArrayContent)))); } } catch (ServiceException ex) { return(new HttpResponseMessageResult(ReturnHttpResponseMessage(ex.StatusCode, contentType, new StringContent(ex.Error.ToString())))); } }
public static async Task <Tuple <string, bool> > Run([ActivityTrigger] CreationResult input, ILogger log, ExecutionContext context) { var client = GraphServiceClientFactory.GetInstance(context?.FunctionAppDirectory).Client.Value; var channels = await client.Teams[input.GroupId].Channels.Request().GetAsync(); var projectChannel = channels.FirstOrDefault(x => x.DisplayName.Equals(input.FullProjectTitle, StringComparison.InvariantCultureIgnoreCase)); if (projectChannel == null) { return(new Tuple <string, bool>(await CreateChannel(input, client), true)); } else { return(new Tuple <string, bool>(projectChannel.Id, false)); } }
public async Task <IActionResult> Groups() { string[] scopes = new[] { GraphScopes.DirectoryReadAll }; GraphServiceClient graphServiceClient = GraphServiceClientFactory.GetAuthenticatedGraphClient(async() => { string result = await tokenAcquisition.GetAccessTokenOnBehalfOfUserAsync(scopes); return(result); }, webOptions.GraphApiUrl); var groups = await graphServiceClient.Me.MemberOf.Request().GetAsync(); ViewData["Groups"] = groups.CurrentPage; return(View()); }
// Gets a Graph client configured with // the specified scopes protected GraphServiceClient GetGraphClientForScopes(string[] scopes) { return(GraphServiceClientFactory .GetAuthenticatedGraphClient(async() => { var token = await _tokenAcquisition .GetAccessTokenForUserAsync(scopes); // Uncomment to print access token to debug console // This will happen for every Graph call, so leave this // out unless you're debugging your token //_logger.LogInformation($"Access token: {token}"); return token; } )); }
// Get information about the changed messages and send to browser via SignalR. // A production application would typically queue a background job for reliability. private async Task GetChangedMessagesAsync(IEnumerable <Notification> notifications) { List <MessageViewModel> messages = new List <MessageViewModel>(); foreach (var notification in notifications) { if (notification.ResourceData.ODataType != "#Microsoft.Graph.Message") { continue; } SubscriptionStore subscription = subscriptionStore.GetSubscriptionInfo(notification.SubscriptionId); // Set the claims for ObjectIdentifier and TenantId, and // use the above claims for the current HttpContext HttpContext.User = ClaimsPrincipalExtension.FromTenantIdAndObjectId(subscription.TenantId, subscription.UserId); // Initialize the GraphServiceClient. var graphClient = await GraphServiceClientFactory.GetAuthenticatedGraphClient(async() => { string result = await tokenAcquisition.GetAccessTokenOnBehalfOfUser( HttpContext, new[] { Infrastructure.Constants.ScopeMailRead }); return(result); }); MessageRequest request = new MessageRequest(graphClient.BaseUrl + "/" + notification.Resource, graphClient, null); try { messages.Add(new MessageViewModel(await request.GetAsync(), subscription.UserId)); } catch (ServiceException se) { string errorMessage = se.Error.Message; string requestId = se.Error.InnerError.AdditionalData["request-id"].ToString(); string requestDate = se.Error.InnerError.AdditionalData["date"].ToString(); logger.LogError($"RetrievingMessages: { errorMessage } Request ID: { requestId } Date: { requestDate }"); } } if (messages.Count > 0) { NotificationService notificationService = new NotificationService(); await notificationService.SendNotificationToClient(this.notificationHub, messages); } }
public async Task <IActionResult> Delete(string id) { if (!string.IsNullOrEmpty(id)) { // Initialize the GraphServiceClient and delete the subscription. var graphClient = await GraphServiceClientFactory.GetAuthenticatedGraphClient(appSettings.Value.GraphApiUrl, async() => { return(await tokenAcquisition.GetAccessTokenForUserAsync(new[] { subscriptionOptions.Value.Scope })); }); try { await graphClient.Subscriptions[id].Request().DeleteAsync(); } catch (Exception e) { ViewBag.Message = BuildErrorMessage(e); return(View("Error")); } ViewBag.Message = $"Deleted subscription {id}"; } return(View("Subscription")); }
public async Task <IActionResult> DeleteAppOnly(string id) { if (!string.IsNullOrEmpty(id)) { // Initialize the GraphServiceClient and delete the subscription. var graphClient = await GraphServiceClientFactory.GetAuthenticatedGraphClient(appSettings.Value.BaseUrlWithoutVersion, async() => { return(await tokenAcquisition.GetAccessTokenForAppAsync($"{appSettings.Value.BaseUrlWithoutVersion}/.default")); }); try { await graphClient.Subscriptions[id].Request().DeleteAsync(); } catch (Exception e) { ViewBag.Message = BuildErrorMessage(e); return(View("Error")); } ViewBag.Message = $"Deleted subscription {id}"; } return(View("Subscription")); }
public GroupsController(GraphServiceClientFactory graphServiceClientFactory) { _graphServiceClientFactory = graphServiceClientFactory; }
// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { // Add Microsoft Identity Platform sign-in services.AddSignIn(options => { Configuration.Bind("AzureAd", options); options.Prompt = "select_account"; var authCodeHandler = options.Events.OnAuthorizationCodeReceived; options.Events.OnAuthorizationCodeReceived = async context => { // Invoke the original handler first // This allows the Microsoft.Identity.Web library to // add the user to its token cache await authCodeHandler(context); var tokenAcquisition = context.HttpContext.RequestServices .GetRequiredService <ITokenAcquisition>() as ITokenAcquisition; var graphClient = GraphServiceClientFactory .GetAuthenticatedGraphClient(async() => { return(await tokenAcquisition .GetAccessTokenForUserAsync(GraphConstants.Scopes)); } ); // Get user information from Graph var user = await graphClient.Me.Request() .Select(u => new { u.DisplayName, u.Mail, u.UserPrincipalName, u.MailboxSettings }) .GetAsync(); context.Principal.AddUserGraphInfo(user); // Get the user's photo // If the user doesn't have a photo, this throws try { var photo = await graphClient.Me .Photos["48x48"] .Content .Request() .GetAsync(); context.Principal.AddUserGraphPhoto(photo); } catch (ServiceException ex) { if (ex.IsMatch("ErrorItemNotFound")) { context.Principal.AddUserGraphPhoto(null); } else { throw ex; } } }; options.Events.OnAuthenticationFailed = context => { var error = WebUtility.UrlEncode(context.Exception.Message); context.Response .Redirect($"/Home/ErrorWithMessage?message=Authentication+error&debug={error}"); context.HandleResponse(); return(Task.FromResult(0)); }; options.Events.OnRemoteFailure = context => { if (context.Failure is OpenIdConnectProtocolException) { var error = WebUtility.UrlEncode(context.Failure.Message); context.Response .Redirect($"/Home/ErrorWithMessage?message=Sign+in+error&debug={error}"); context.HandleResponse(); } return(Task.FromResult(0)); }; }, options => { Configuration.Bind("AzureAd", options); }); // Add ability to call web API (Graph) // and get access tokens services.AddWebAppCallsProtectedWebApi(Configuration, GraphConstants.Scopes) // Use in-memory token cache // See https://github.com/AzureAD/microsoft-identity-web/wiki/token-cache-serialization .AddInMemoryTokenCaches(); // Require authentication services.AddControllersWithViews(options => { var policy = new AuthorizationPolicyBuilder() .RequireAuthenticatedUser() .Build(); options.Filters.Add(new AuthorizeFilter(policy)); }) // Add the Microsoft Identity UI pages for signin/out .AddMicrosoftIdentityUI(); }
public ServiceWrapper(GraphServiceClientFactory graphServiceClientFactory) { _graphServiceClientFactory = graphServiceClientFactory; }
public async Task <IActionResult> New([Bind("Subject,Attendees,Start,End,Body")] NewEvent newEvent) { var timeZone = User.GetUserGraphTimeZone(); // Create a Graph event with the required fields var graphEvent = new Event { Subject = newEvent.Subject, Start = new DateTimeTimeZone { DateTime = newEvent.Start.ToString("o"), // Use the user's time zone TimeZone = timeZone }, End = new DateTimeTimeZone { DateTime = newEvent.End.ToString("o"), // Use the user's time zone TimeZone = timeZone } }; // Add body if present if (!string.IsNullOrEmpty(newEvent.Body)) { graphEvent.Body = new ItemBody { ContentType = BodyType.Text, Content = newEvent.Body }; } // Add attendees if present if (!string.IsNullOrEmpty(newEvent.Attendees)) { var attendees = newEvent.Attendees.Split(';', StringSplitOptions.RemoveEmptyEntries); if (attendees.Length > 0) { var attendeeList = new List <Attendee>(); foreach (var attendee in attendees) { attendeeList.Add(new Attendee { EmailAddress = new EmailAddress { Address = attendee }, Type = AttendeeType.Required }); } } } var graphClient = GraphServiceClientFactory .GetAuthenticatedGraphClient(async() => { return(await _tokenAcquisition .GetAccessTokenForUserAsync(GraphConstants.Scopes)); } ); try { // Add the event await graphClient.Me.Events .Request() .AddAsync(graphEvent); // Redirect to the calendar view with a success message return(RedirectToAction("Index").WithSuccess("Event created")); } catch (ServiceException ex) { // Redirect to the calendar view with an error message return(RedirectToAction("Index") .WithError("Error creating event", ex.Error.Message)); } }
private async Task <IList <Event> > GetUserWeekCalendar(DateTime startOfWeek) { var graphClient = GraphServiceClientFactory .GetAuthenticatedGraphClient(async() => { return(await _tokenAcquisition .GetAccessTokenForUserAsync(_calendarScopes)); } ); // Configure a calendar view for the current week var endOfWeek = startOfWeek.AddDays(7); var viewOptions = new List <QueryOption> { new QueryOption("startDateTime", startOfWeek.ToString("o")), new QueryOption("endDateTime", endOfWeek.ToString("o")) }; var events = await graphClient.Me .CalendarView .Request(viewOptions) // Send user time zone in request so date/time in // response will be in preferred time zone .Header("Prefer", $"outlook.timezone=\"{User.GetUserGraphTimeZone()}\"") // Get max 50 per request .Top(50) // Only return fields app will use .Select(e => new { e.Subject, e.Organizer, e.Start, e.End }) // Order results chronologically .OrderBy("start/dateTime") .GetAsync(); IList <Event> allEvents; // Handle case where there are more than 50 if (events.NextPageRequest != null) { allEvents = new List <Event>(); // Create a page iterator to iterate over subsequent pages // of results. Build a list from the results var pageIterator = PageIterator <Event> .CreatePageIterator( graphClient, events, (e) => { allEvents.Add(e); return(true); } ); await pageIterator.IterateAsync(); } else { // If only one page, just use the result allEvents = events.CurrentPage; } return(allEvents); }