internal static async Task <ApiCallRequest> BuildGetAPICallAsync <TModel>(BaseDataModel <TModel> model, EntityInfo entity, ODataQuery <TModel> oDataQuery, ApiCall apiOverride, bool forceSPORest = false, bool useLinqGet = false, bool loadPages = false) { // Can we use Microsoft Graph for this GET request? bool useGraph = model.PnPContext.GraphFirst && // See if Graph First is enabled/configured !forceSPORest && // and if we are not forced to use SPO REST entity.CanUseGraphGet; // and if the entity supports GET via Graph // If entity cannot be surfaced with SharePoint Rest then force graph if (string.IsNullOrEmpty(entity.SharePointType)) { useGraph = true; } // Else if we've overriden the query then simply take what was set in the query override else if (!apiOverride.Equals(default(ApiCall))) { useGraph = apiOverride.Type == ApiType.Graph; } if (useGraph) { return(await BuildGetAPICallGraphAsync(model, entity, oDataQuery, apiOverride, useLinqGet, loadPages).ConfigureAwait(false)); } else { return(await BuildGetAPICallRestAsync(model, entity, oDataQuery, apiOverride, useLinqGet, loadPages).ConfigureAwait(false)); } }
internal static async Task <ApiCallRequest> BuildGetAPICallAsync <TModel>(BaseDataModel <TModel> model, EntityInfo entity, ODataQuery <TModel> oDataQuery, ApiCall apiOverride, bool forceSPORest = false, bool useLinqGet = false, bool loadPages = false) { // Can we use Microsoft Graph for this GET request? bool useGraph = model.PnPContext.GraphFirst && // See if Graph First is enabled/configured !forceSPORest && // and if we are not forced to use SPO REST entity.CanUseGraphGet; // and if the entity supports GET via Graph // If entity cannot be surfaced with SharePoint Rest then force graph if (string.IsNullOrEmpty(entity.SharePointType)) { useGraph = true; } // Else if we've overriden the query then simply take what was set in the query override else if (!apiOverride.Equals(default(ApiCall))) { useGraph = apiOverride.Type == ApiType.Graph; } else if (useGraph && useLinqGet) { // LINQ Get will based upon the defined LinqGet query + query arguments determined via entity and oDataQuery. // e.g. _api/web/lists or _api/web/webs // When there are no query arguments and when the model supports Graph (e.g. Web) then useGraph = true while // the queried collections (e.g. webs, lists) might not be decorated with a GraphType attribute if (string.IsNullOrEmpty(entity.GraphLinqGet) && !string.IsNullOrEmpty(entity.SharePointLinqGet)) { useGraph = false; } } if (useGraph) { return(await BuildGetAPICallGraphAsync(model, entity, oDataQuery, apiOverride, useLinqGet, loadPages).ConfigureAwait(false)); } else { return(await BuildGetAPICallRestAsync(model, entity, oDataQuery, apiOverride, useLinqGet, loadPages).ConfigureAwait(false)); } }
private static async Task <ApiCallRequest> BuildGetAPICallRestAsync <TModel>(BaseDataModel <TModel> model, EntityInfo entity, ODataQuery <TModel> oDataQuery, ApiCall apiOverride, bool useLinqGet, bool loadPages) { string getApi = useLinqGet ? entity.SharePointLinqGet : entity.SharePointGet; IEnumerable <EntityFieldInfo> fields = entity.Fields.Where(p => p.Load); Dictionary <string, string> urlParameters = new Dictionary <string, string>(); StringBuilder sb = new StringBuilder(); // Only add select statement whenever there was a filter specified if (entity.SharePointFieldsLoadedViaExpression) { // $select foreach (var field in fields) { // If there was a selection on which fields to include in an expand (via the QueryProperties() option) then add those fields if (field.SharePointExpandable && field.ExpandFieldInfo != null) { AddExpandableSelectRest(sb, field, null, ""); } else { sb.Append($"{JsonMappingHelper.GetRestField(field)},"); } } urlParameters.Add("$select", sb.ToString().TrimEnd(new char[] { ',' })); sb.Clear(); } // $expand foreach (var field in fields.Where(p => p.SharePointExpandable)) { if (entity.SharePointFieldsLoadedViaExpression) { sb.Append($"{JsonMappingHelper.GetRestField(field)},"); // If there was a selection on which fields to include in an expand (via the Include() option) and the included field was expandable itself then add it if (field.ExpandFieldInfo != null) { string path = ""; AddExpandableExpandRest(sb, field, null, path); } } else { if (field.ExpandableByDefault) { sb.Append($"{JsonMappingHelper.GetRestField(field)},"); } } } urlParameters.Add("$expand", sb.ToString().TrimEnd(new char[] { ',' })); oDataQuery.AddODataToUrlParameters(urlParameters, ODataTargetPlatform.SPORest); // REST apis do not apply a default top // In order to not receive all items in one request, we apply a default top // We don't change the original ODataQuery to avoid side effects if (useLinqGet && !urlParameters.ContainsKey(ODataQuery <TModel> .TopKey)) { urlParameters.Add(ODataQuery <TModel> .TopKey, model.PnPContext.GlobalOptions.HttpSharePointRestDefaultPageSize.ToString()); } sb.Clear(); // Build the API call string baseApiCall = ""; if (apiOverride.Equals(default(ApiCall))) { baseApiCall = $"{model.PnPContext.Uri.AbsoluteUri.TrimEnd(new char[] { '/' })}/{getApi}"; } else { baseApiCall = $"{model.PnPContext.Uri.AbsoluteUri.TrimEnd(new char[] { '/' })}/{apiOverride.Request}"; } // Parse tokens in the base api call baseApiCall = await ApiHelper.ParseApiCallAsync(model, baseApiCall).ConfigureAwait(false); sb.Append(baseApiCall); // Build the querystring parameters NameValueCollection queryString = HttpUtility.ParseQueryString(string.Empty); foreach (var urlParameter in urlParameters.Where(i => !string.IsNullOrEmpty(i.Value))) { // Add key and value, which will be automatically URL-encoded, if needed queryString.Add(urlParameter.Key, urlParameter.Value); } // Build the whole URL if (queryString.AllKeys.Length > 0) { // In .NET Framework to ToString() of a NameValueCollection will use HttpUtility.UrlEncodeUnicode under // the covers resulting in issues. So we decode and encode again as a workaround. This code produces the // same result when used under .NET5/Core versus .NET Framework sb.Append($"?{queryString.ToEncodedString()}"); } // Create ApiCall instance and call the override option if needed var call = new ApiCallRequest(new ApiCall(sb.ToString(), ApiType.SPORest, loadPages: loadPages)); if (model.GetApiCallOverrideHandler != null) { call = await model.GetApiCallOverrideHandler.Invoke(call).ConfigureAwait(false); } return(call); }