Exemple #1
0
        /// <summary>
        /// Returns the users delta in the current domain filtered out with a custom OData filter. If no <paramref name="deltaToken"/> has been provided, all users will be returned with a deltatoken for a next run. If a <paramref name="deltaToken"/> has been provided, all users which were modified after the deltatoken has been generated will be returned.
        /// </summary>
        /// <param name="accessToken">The OAuth 2.0 Access Token to use for invoking the Microsoft Graph</param>
        /// <param name="deltaToken">DeltaToken to indicate requesting changes since this deltatoken has been created. Leave NULL to retrieve all users with a deltatoken to use for subsequent queries.</param>
        /// <param name="filter">OData filter to apply to retrieval of the users from the Microsoft Graph</param>
        /// <param name="orderby">OData orderby instruction</param>
        /// <param name="selectProperties">Allows providing the names of properties to return regarding the users. If not provided, the standard properties will be returned.</param>
        /// <param name="startIndex">First item in the results returned by Microsoft Graph to return</param>
        /// <param name="endIndex">Last item in the results returned by Microsoft Graph to return</param>
        /// <param name="retryCount">Number of times to retry the request in case of throttling</param>
        /// <param name="delay">Milliseconds to wait before retrying the request. The delay will be increased (doubled) every retry.</param>
        /// <returns>List with User objects</returns>
        public static Model.UserDelta ListUserDelta(string accessToken, string deltaToken, string filter, string orderby, string[] selectProperties = null, int startIndex = 0, int endIndex = 999, int retryCount = 10, int delay = 500)
        {
            if (String.IsNullOrEmpty(accessToken))
            {
                throw new ArgumentNullException(nameof(accessToken));
            }

            Model.UserDelta userDelta = new Model.UserDelta
            {
                Users = new List <Model.User>()
            };
            try
            {
                // GET https://graph.microsoft.com/v1.0/users/delta
                string getUserDeltaUrl = $"{GraphHttpClient.MicrosoftGraphV1BaseUri}users/delta?";

                if (selectProperties != null)
                {
                    getUserDeltaUrl += $"$select={string.Join(",", selectProperties)}&";
                }
                if (!string.IsNullOrEmpty(filter))
                {
                    getUserDeltaUrl += $"$filter={filter}&";
                }
                if (!string.IsNullOrEmpty(deltaToken))
                {
                    getUserDeltaUrl += $"$deltatoken={deltaToken}&";
                }
                if (!string.IsNullOrEmpty(orderby))
                {
                    getUserDeltaUrl += $"$orderby={orderby}&";
                }

                getUserDeltaUrl = getUserDeltaUrl.TrimEnd('&').TrimEnd('?');

                int currentIndex = 0;

                while (true)
                {
                    var response = GraphHttpClient.MakeGetRequestForString(
                        requestUrl: getUserDeltaUrl,
                        accessToken: accessToken);

                    var userDeltaResponse = JsonConvert.DeserializeObject <Model.UserDelta>(response);

                    if (!string.IsNullOrEmpty(userDeltaResponse.DeltaToken))
                    {
                        userDelta.DeltaToken = HttpUtility.ParseQueryString(new Uri(userDeltaResponse.DeltaToken).Query).Get("$deltatoken");
                    }

                    foreach (var user in userDeltaResponse.Users)
                    {
                        currentIndex++;

                        if (currentIndex >= startIndex && currentIndex <= endIndex)
                        {
                            userDelta.Users.Add(user);
                        }
                    }

                    if (userDeltaResponse.NextLink != null && currentIndex < endIndex)
                    {
                        getUserDeltaUrl = userDeltaResponse.NextLink;
                    }
                    else
                    {
                        break;
                    }
                }
            }
            catch (ServiceException ex)
            {
                Log.Error(Constants.LOGGING_SOURCE, CoreResources.GraphExtensions_ErrorOccured, ex.Error.Message);
                throw;
            }
            return(userDelta);
        }
        /// <summary>
        /// Returns the users delta in the current domain filtered out with a custom OData filter. If no <paramref name="deltaToken"/> has been provided, all users will be returned with a deltatoken for a next run. If a <paramref name="deltaToken"/> has been provided, all users which were modified after the deltatoken has been generated will be returned.
        /// </summary>
        /// <param name="accessToken">The OAuth 2.0 Access Token to use for invoking the Microsoft Graph</param>
        /// <param name="deltaToken">DeltaToken to indicate requesting changes since this deltatoken has been created. Leave NULL to retrieve all users with a deltatoken to use for subsequent queries.</param>
        /// <param name="filter">OData filter to apply to retrieval of the users from the Microsoft Graph</param>
        /// <param name="orderby">OData orderby instruction</param>
        /// <param name="selectProperties">Allows providing the names of properties to return regarding the users. If not provided, the standard properties will be returned.</param>
        /// <param name="startIndex">First item in the results returned by Microsoft Graph to return</param>
        /// <param name="endIndex">Last item in the results returned by Microsoft Graph to return. Provide NULL to return all results that exist.</param>
        /// <param name="retryCount">Number of times to retry the request in case of throttling</param>
        /// <param name="delay">Milliseconds to wait before retrying the request. The delay will be increased (doubled) every retry.</param>
        /// <param name="useBetaEndPoint">Indicates if the v1.0 (false) or beta (true) endpoint should be used at Microsoft Graph to query for the data</param>
        /// <param name="ignoreDefaultProperties">If set to true, only the properties provided through selectProperties will be loaded. The default properties will not be. Optional. Default is that the default properties will always be retrieved.</param>
        /// <returns>List with User objects</returns>
        public static Model.UserDelta ListUserDelta(string accessToken, string deltaToken, string filter, string orderby, string[] selectProperties = null, int startIndex = 0, int?endIndex = 999, int retryCount = 10, int delay = 500, bool useBetaEndPoint = false, bool ignoreDefaultProperties = false)
        {
            if (String.IsNullOrEmpty(accessToken))
            {
                throw new ArgumentNullException(nameof(accessToken));
            }
            // Rewrite AdditionalProperties to Additional Data
            var propertiesToSelect = ignoreDefaultProperties ? new List <string>() : new List <string> {
                "BusinessPhones", "DisplayName", "GivenName", "JobTitle", "Mail", "MobilePhone", "OfficeLocation", "PreferredLanguage", "Surname", "UserPrincipalName", "Id", "AccountEnabled"
            };

            selectProperties = selectProperties?.Select(p => p == "AdditionalProperties" ? "AdditionalData" : p).ToArray();

            if (selectProperties != null)
            {
                foreach (var property in selectProperties)
                {
                    if (!propertiesToSelect.Contains(property))
                    {
                        propertiesToSelect.Add(property);
                    }
                }
            }

            var queryOptions = new List <QueryOption>();

            if (!string.IsNullOrWhiteSpace(deltaToken))
            {
                queryOptions.Add(new QueryOption("$skiptoken", deltaToken));
            }

            Model.UserDelta result = null;
            try
            {
                // Use a synchronous model to invoke the asynchronous process
                result = Task.Run(async() =>
                {
                    var usersDelta   = new Model.UserDelta();
                    usersDelta.Users = new List <Model.User>();

                    var graphClient = GraphUtility.CreateGraphClient(accessToken, retryCount, delay, useBetaEndPoint: useBetaEndPoint);

                    IUserDeltaCollectionPage pagedUsers;

                    // Retrieve the first batch of users. 999 is the maximum amount of users that Graph allows to be trieved in 1 go. Use maximum size batches to lessen the chance of throttling when retrieving larger amounts of users.
                    pagedUsers = await graphClient.Users.Delta()
                                 .Request(queryOptions)
                                 .Select(string.Join(",", propertiesToSelect))
                                 .Filter(filter)
                                 .OrderBy(orderby)
                                 .Top(!endIndex.HasValue ? 999 : endIndex.Value >= 999 ? 999 : endIndex.Value)
                                 .GetAsync();

                    int pageCount    = 0;
                    int currentIndex = 0;

                    while (true)
                    {
                        pageCount++;

                        foreach (var pagedUser in pagedUsers)
                        {
                            currentIndex++;

                            if (endIndex.HasValue && endIndex.Value < currentIndex)
                            {
                                break;
                            }

                            if (currentIndex >= startIndex)
                            {
                                usersDelta.Users.Add(MapUserEntity(pagedUser, selectProperties));
                            }
                        }

                        if (pagedUsers.NextPageRequest != null && (!endIndex.HasValue || currentIndex < endIndex.Value))
                        {
                            // Retrieve the next batch of users. The possible oData instructions such as select and filter are already incorporated in the nextLink provided by Graph and thus do not need to be specified again.
                            pagedUsers = await pagedUsers.NextPageRequest.GetAsync();
                        }
                        else
                        {
                            // Check if the deltaLink is provided in the response
                            if (pagedUsers.AdditionalData.TryGetValue("@odata.deltaLink", out object deltaLinkObject))
                            {
                                // Use a regular expression to fetch just the deltatoken part from the deltalink. The base of the URL will thereby be cut off. This is the only part we need to use it in a subsequent run.
                                var deltaLinkMatch = System.Text.RegularExpressions.Regex.Match(deltaLinkObject.ToString(), @"(?<=\$deltatoken=)(.*?)(?=$|&)", System.Text.RegularExpressions.RegexOptions.IgnoreCase);

                                if (deltaLinkMatch.Success && !string.IsNullOrWhiteSpace(deltaLinkMatch.Value))
                                {
                                    // Successfully extracted the deltatoken part from the link, assign it to the return variable
                                    usersDelta.DeltaToken = deltaLinkMatch.Value;
                                }
                            }
                            break;
                        }
                    }

                    return(usersDelta);
                }).GetAwaiter().GetResult();
            }
            catch (ServiceException ex)
            {
                Log.Error(Constants.LOGGING_SOURCE, CoreResources.GraphExtensions_ErrorOccured, ex.Error.Message);
                throw;
            }
            return(result);
        }