From 6fc4cb7bedabf2ef920072bbeb4c7d886b322f86 Mon Sep 17 00:00:00 2001 From: Buddy Wagner Date: Fri, 30 Jun 2023 14:22:12 -0700 Subject: [PATCH 01/13] Added ColleagueWebApiProxyClient and ColleagueWebApiFilterQueryClient classes that extend their base Ethos verions. Converted EthosIntegrationUrls class from static to normal and created an instance of it at the base EthosClient level for all client objects. Non-static version now swaps out ColleagueApiUrl for base ethos url when using the Colleague versions of the clients. --- .../Client/EthosClientBuilder.cs | 39 +- .../Proxy/ColleagueWebApiFilterQueryClient.cs | 1531 ++++++++++++++++ .../Proxy/ColleagueWebApiProxyClient.cs | 1543 +++++++++++++++++ .../Service/EthosChangeNotificationService.cs | 32 +- .../Service/EthosService.cs | 15 +- 5 files changed, 3154 insertions(+), 6 deletions(-) create mode 100644 Ellucian.Ethos.Integration/Client/Proxy/ColleagueWebApiFilterQueryClient.cs create mode 100644 Ellucian.Ethos.Integration/Client/Proxy/ColleagueWebApiProxyClient.cs diff --git a/Ellucian.Ethos.Integration/Client/EthosClientBuilder.cs b/Ellucian.Ethos.Integration/Client/EthosClientBuilder.cs index 401c493..0b1646d 100644 --- a/Ellucian.Ethos.Integration/Client/EthosClientBuilder.cs +++ b/Ellucian.Ethos.Integration/Client/EthosClientBuilder.cs @@ -28,6 +28,10 @@ public class EthosClientBuilder /// private int? ConnectionTimeout = null; + private readonly string ColleagueApiUrl; + private readonly string ColleagueApiUsername; + private readonly string ColleagueApiPassword; + /// /// Interface used in HttpProtocolClientBuilder. /// @@ -42,6 +46,19 @@ public EthosClientBuilder( string apiKey ) this.apiKey = apiKey; builder ??= new HttpProtocolClientBuilder( null, ConnectionTimeout ); } + /// + /// Constructs this class with the given Colleauge API URL/Credentials. + /// + /// The URL to the Colleague API instance. + /// The username used to connect to the Colleague API. + /// The password used to connect to the Colleague API. + public EthosClientBuilder(string colleagueApiUrl, string colleagueApiUsername, string colleagueApiPassword) + { + builder ??= new HttpProtocolClientBuilder(null, ConnectionTimeout); + ColleagueApiUrl = colleagueApiUrl; + ColleagueApiUsername = colleagueApiUsername; + ColleagueApiPassword = colleagueApiPassword; + } /// /// Give the client factory a connection timeout so that connections will time out after connectionTimeout @@ -97,7 +114,27 @@ public EthosMessagesClient BuildEthosMessagesClient() /// An EthosFilterQueryClient using the given apiKey and timeout values. public EthosFilterQueryClient BuildEthosFilterQueryClient() { - return new EthosFilterQueryClient( apiKey, builder.Client ); + return new EthosFilterQueryClient(apiKey, builder.Client); + } + + /// + /// Gets an that will use the given Colleague credentials to authenticate. + /// + /// An ColleagueWebApiProxyClient using the given Colleague credentials. + public ColleagueWebApiProxyClient BuildColleagueWebApiProxyclient() + { + //TODO + return null; + } + + /// + /// Gets an that will use the Colleague credentials to authenticate. + /// + /// An ColleagueWebApiFilterQueryClient using the given Colleague credentials. + public ColleagueWebApiFilterQueryClient BuildColleagueWebApiFilterQueryClient() + { + // TODO + return null; } } } diff --git a/Ellucian.Ethos.Integration/Client/Proxy/ColleagueWebApiFilterQueryClient.cs b/Ellucian.Ethos.Integration/Client/Proxy/ColleagueWebApiFilterQueryClient.cs new file mode 100644 index 0000000..8a69c8c --- /dev/null +++ b/Ellucian.Ethos.Integration/Client/Proxy/ColleagueWebApiFilterQueryClient.cs @@ -0,0 +1,1531 @@ +/* + * ****************************************************************************** + * Copyright 2022 Ellucian Company L.P. and its affiliates. + * ****************************************************************************** + */ + +using Ellucian.Ethos.Integration.Client.Filter.Extensions; +using Ellucian.Ethos.Integration.Client.Proxy.Filter; + +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +using System; +using System.Collections.Generic; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; + +namespace Ellucian.Ethos.Integration.Client.Proxy +{ + /// + /// An EthosProxyClient that provides the ability to submit GET requests supporting filters and/or named queries with support for paging. + /// + public class ColleagueWebApiFilterQueryClient : EthosProxyClient + { + // Prefix value used when specifying criteria filter syntax. + private const string CRITERIA_FILTER_PREFIX = "?criteria="; + + + /// + /// Instantiates this class using the given API key and HttpClient. + /// + /// A valid API key from Ethos Integration. This is required to be a valid 36 character GUID string. + /// If it is null, empty, or not in a valid GUID format, then an IllegalArgumentException will be thrown. + /// A HttpClient. If it is null/empty, then an will be thrown. + public ColleagueWebApiFilterQueryClient( string apiKey, HttpClient client ) : base( apiKey, client ) + { + + } + + #region Strongly Typed GET + + /// + /// Gets a page of data for the given resource by name and version with the given filter. + /// + /// Type to be included in the returned specified by caller. + /// The name of the resource to get data for. + /// The string resource filter in JSON format contained in the URL, e.g:
?criteria={"names":[{"firstName":"John"}]}
+ /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// An EthosResponse containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + /// Returns exception if the resourceName is null. + /// Returns exception if the criteriaFilterStr is null. + /// Returns exception if the request fails. + public async Task GetWithCriteriaFilterAsync( string resourceName, string criteriaFilterStr, string version = "" ) where T : class + { + var response = await GetWithCriteriaFilterAsync( resourceName, version, criteriaFilterStr ); + return ConvertEthosResponseContentToType( response ); + } + + /// + /// Gets a page of data for the given resource by name and version with the given filter. + /// + /// Type to be included in the returned specified by caller. + /// The name of the resource to get data for. + /// A previously built Criteria containing the filter criteria used in the request URL. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// A simple call to criteriaFilter.BuildCriteria() should output the criteria filter portion of the request URL, + /// e.g: ?criteria={"names":[{"firstName":"John"}]}. + /// An EthosResponse containing an initial page (EthosResponse content) of resource data according to the requested version and filter of the resource. + /// to the requested version and filter of the resource. + /// Throws if the given criteriaFilter is null. + public async Task GetWithCriteriaFilterAsync( string resourceName, CriteriaFilter criteria, string version = "" ) where T : class + { + var response = await GetWithCriteriaFilterAsync( resourceName, version, criteria.BuildCriteria() ); + return ConvertEthosResponseContentToType( response ); + } + + /// + /// Convenience method to submit a GET request with a single set of criteria filter. This is intended only to be used + /// for a single set of criteria filter, e.g: ?criteria={"names":[{"firstName":"John"}]}, where names is the + /// criteriaSetName, firstName is the criteriaKey, and John is the criteriaValue. Requests requiring + /// a more complex criteria filter should first build the Criteria with the necessary criteria, and then call + /// getWithCriteriaFilterAsync(resourceName, version, criteriaFilter). + ///

The parameters criteriaSetName, criteriaKey, and criteriaValue should only specify the values within quotes of the + /// JSON filter syntax. No JSON syntax (square or angeled braces, etc) should be contained within those parameter values.

+ ///
+ /// Type to be included in the returned specified by caller. + /// The name of the resource to get data for. + /// The name of the criteria set that the given criteriaKey and criteriaValue are associated with, + /// e.g: "names":[{"firstName":"John"}]}, where names is the criteriaSetName associated to the + /// criteriaKey (firstName) and criteriaValue (John). + /// The JSON label key for the criteria. + /// The value associated with the criteriaKey. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// An EthosResponse containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + /// Returns exception if the resourceName or criteriaSetName or criteriaKey or criteriaValue is null. + public async Task GetWithSimpleCriteriaValuesAsync( string resourceName, string criteriaSetName, string criteriaKey, string criteriaValue, string version = "" ) where T : class + { + var response = await GetWithSimpleCriteriaValuesAsync( resourceName, version, criteriaSetName, criteriaKey, criteriaValue ); + return ConvertEthosResponseContentToType( response ); + } + + /// + /// Gets a page of data for the given resource by name and version with the given filter. + /// + /// Type to be included in the returned specified by caller. + /// The name of the resource to get data for. + /// The string resource filter in JSON format contained in the URL. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// An EthosResponse containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + /// Returns exception if the resourceName is null. + /// Returns exception if the namedQuery is null. + /// Returns exception if the request fails. + public async Task GetWithNamedQueryFilterAsync( string resourceName, string namedQueryFilterStr, string version = "" ) where T : class + { + var response = await GetWithNamedQueryFilterAsync( resourceName, version, namedQueryFilterStr ); + return ConvertEthosResponseContentToType( response ); + } + + /// + /// Gets a page of data for the given resource by name and version with the given filter. + /// + /// Type to be included in the returned specified by caller. + /// The name of the resource to get data for. + /// A previously built namedQueryFilter containing the filter used in the request URL. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// A simple call to namedQueryFilter.BuildNamedQuery() should output the named query portion of the request URL. + /// An EthosResponse containing an initial page (EthosResponse content) of resource data according to the requested version and filter of the resource. + /// to the requested version and filter of the resource. + /// Throws if the given criteriaFilter is null. + public async Task GetWithNamedQueryFilterAsync( string resourceName, NamedQueryFilter namedQueryFilter, string version = "" ) where T : class + { + var response = await GetWithNamedQueryFilterAsync( resourceName, version, namedQueryFilter.BuildNamedQuery() ); + return ConvertEthosResponseContentToType( response ); + } + + /// + /// Submits a GET request for the given resource and version using the given filterMapStr. The filterMapStr + /// is intended to support the filter syntax for resources versions 7 and older. An example of a filterMapStr is: + /// ?firstName=James. + ///

This is NOT intended to be used for resource versions after version 7 and/or for criteria filters.

+ ///
+ /// Type to be included in the returned specified by caller. + /// The name of the resource to get data for. + /// A string containing the filter syntax used for request URL filters with resource versions 7 or older. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// An EthosResponse containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + /// Returns exception if the resourceName or filterMapStr is null. + public async Task GetWithFilterMapAsync( string resourceName, string filterMapStr, string version = "" ) where T : class + { + var response = await GetWithFilterMapAsync( resourceName, version, filterMapStr ); + return ConvertEthosResponseContentToType( response ); + } + + /// + /// Submits a GET request for the given resource and version using the given filterMap. The filterMap + /// is intended to support the filter syntax for resources versions 7 and older. A FilterMap contains a map of + /// one or many filter parameter pair(s). An example of a filterMap string indicating the contents of the map is: + /// ?firstName=James. + ///

This is NOT intended to be used for resource versions after version 7 and/or for criteria filters.

+ ///
+ /// Type to be included in the returned specified by caller. + /// The name of the resource to get data for. + /// A string containing the filter syntax used for request URL filters with resource versions 7 or older. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// An EthosResponse containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + /// Returns exception if the resourceName or filterMap is null. + public async Task GetWithFilterMapAsync( string resourceName, FilterMap filterMap, string version = "" ) where T : class + { + var response = await GetWithFilterMapAsync( resourceName, version, filterMap.ToString() ); + return ConvertEthosResponseContentToType( response ); + } + + /// + /// Gets all the pages for a given resource using the specified criteria filter and page size for the given version. + /// + /// Type to be included in the returned specified by caller. + /// The name of the resource to get data for. + /// A previously built Criteria containing the filter criteria used in the request URL. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// The size (number of rows) of each page returned in the list. + /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + public async Task> GetPagesWithCriteriaFilterAsync( string resourceName, CriteriaFilter criteria, string version = "", int pageSize = 0 ) where T : class + { + var response = await GetPagesWithCriteriaFilterAsync( resourceName, version, criteria, pageSize ); + return ConvertEthosResponseContentListToType( response ); + } + + /// + /// Gets all the pages for a given resource using the specified namedQueryFilter filter and page size for the given version. + /// + /// Type to be included in the returned specified by caller. + /// The name of the resource to get data for. + /// A previously built namedQueryFilter containing the filter named query used in the request URL. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// The size (number of rows) of each page returned in the list. + /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + public async Task> GetPagesWithNamedQueryFilterAsync( string resourceName, NamedQueryFilter namedQueryFilter, string version = "", int pageSize = 0 ) where T : class + { + var response = await GetPagesWithNamedQueryFilterAsync( resourceName, version, namedQueryFilter, pageSize ); + return ConvertEthosResponseContentListToType( response ); + } + + /// + /// Gets all the pages for a given resource beginning at the given offset index, using the specified criteria filter + /// and page size for the given version. + /// + /// Type to be included in the returned specified by caller. + /// The name of the resource to get data for. + /// A previously built Criteria containing the filter criteria used in the request URL. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// The size (number of rows) of each page returned in the list. + /// The 0 based index from which to begin paging for the given resource. + /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + /// Returns exception if the resourceName or criteriaFilter is null. + public async Task> GetPagesFromOffsetWithCriteriaFilterAsync( string resourceName, CriteriaFilter criteria, string version = "", int pageSize = 0, int offset = 0 ) where T : class + { + var response = await GetPagesFromOffsetWithCriteriaFilterAsync( resourceName, version, criteria, pageSize, offset ); + return ConvertEthosResponseContentListToType( response ); + } + + /// + /// Gets all the pages for a given resource beginning at the given offset index, using the specified namedQueryFilter + /// and page size for the given version. + /// + /// Type to be included in the returned specified by caller. + /// The name of the resource to get data for. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// A previously built namedQueryFilter containing the filter used in the request URL. + /// The size (number of rows) of each page returned in the list. + /// The 0 based index from which to begin paging for the given resource. + /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + /// Returns exception if the resourceName or namedQueryFilter is null. + public async Task> GetPagesFromOffsetWithNamedQueryFilterAsync( string resourceName, NamedQueryFilter namedQueryFilter, string version = "", int pageSize = 0, int offset = 0 ) where T : class + { + var response = await GetPagesFromOffsetWithNamedQueryFilterAsync( resourceName, version, namedQueryFilter, pageSize, offset ); + return ConvertEthosResponseContentListToType( response ); + } + + /// + /// Gets all the pages for a given resource using the specified filter map and page size for the given version. + /// + /// Type to be included in the returned specified by caller. + /// The name of the resource to get data for. + /// A previously built FilterMap containing the filter parameters used in the request URL. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// A simple call to filterMap.tostring() should output the criteria filter portion of the request URL, + /// e.g: ?firstName=John&lastName=Smith. + /// The size (number of rows) of each page returned in the list. + /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + public async Task> GetPagesWithFilterMapAsync( string resourceName, FilterMap filterMap, string version = "", int pageSize = 0 ) where T : class + { + var response = await GetPagesWithFilterMapAsync( resourceName, version, filterMap, pageSize ); + return ConvertEthosResponseContentListToType( response ); + } + + /// + /// Gets all the pages for a given resource beginning at the given offset index, using the specified filter map and + /// page size for the given version. + /// + /// Type to be included in the IEnumerable<> returned specified by caller. + /// The name of the resource to get data for. + /// A previously built FilterMap containing the filter parameters used in the request URL. + /// A simple call to filterMap.tostring() should output the criteria filter portion of the request URL, + /// e.g: ?firstName=John&lastName=Smith. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// The size (number of rows) of each page returned in the list. + /// The 0 based index from which to begin paging for the given resource. + /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + public async Task> GetPagesFromOffsetWithFilterMapAsync( string resourceName, FilterMap filterMap, string version = "", int pageSize = 0, int offset = 0 ) where T : class + { + var response = await GetPagesFromOffsetWithFilterMapAsync( resourceName, version, filterMap, pageSize, offset ); + return ConvertEthosResponseContentListToType( response ); + } + + #endregion Strongly Typed + + /// + /// Gets a page of data for the given resource with the given filter. Uses the default version of the resource. + /// Makes a non-filter API request if the given criteriaFilterStr is null or blank. + /// + /// The name of the resource to get data for. + /// The string resource filter in JSON format contained in the URL, e.g:
?criteria={"names":[{"firstName":"John"}]}
+ /// An EthosResponse containing an initial page (EthosResponse content) of resource data according to the requested version and filter of the resource. + /// to the requested version and filter of the resource. + public async Task GetWithCriteriaFilterAsync( string resourceName, string criteriaFilterStr ) + { + return await GetWithCriteriaFilterAsync( resourceName, DEFAULT_VERSION, criteriaFilterStr ); + } + + /// + /// Gets a page of data for the given resource with the given filter. Uses the default version of the resource. + /// Makes a non-filter API request if the given namedQueryFilterStr is null or blank. + /// + /// The name of the resource to get data for. + /// The string resource filter in JSON format contained in the URL, e.g:
?criteria={"names":[{"firstName":"John"}]}
+ /// An EthosResponse containing an initial page (EthosResponse content) of resource data according to the requested version and filter of the resource. + /// to the requested version and filter of the resource. + public async Task GetWithNamedQueryFilterAsync( string resourceName, string namedQueryFilterStr ) + { + return await GetWithNamedQueryFilterAsync( resourceName, DEFAULT_VERSION, namedQueryFilterStr ); + } + + /// + /// Gets a page of data for the given resource by name and version with the given filter. + /// + /// The name of the resource to get data for. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// The string resource filter in JSON format contained in the URL, e.g:
?criteria={"names":[{"firstName":"John"}]}
+ /// An EthosResponse containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + /// Returns exception if the resourceName is null. + /// Returns exception if the criteriaFilterStr is null. + /// Returns exception if the request fails. + public async Task GetWithCriteriaFilterAsync( string resourceName, string version, string criteriaFilterStr ) + { + if ( string.IsNullOrWhiteSpace( resourceName ) ) + { + throw new ArgumentNullException( "Error: Cannot get resource with criteria filter due to a null or blank resource name." ); + } + if ( string.IsNullOrWhiteSpace( criteriaFilterStr ) ) + { + throw new ArgumentNullException( $"Error: Cannot get resource '{resourceName}' with criteria filter due to a null or blank criteria filter string." ); + } + return await GetEthosResponseAsync( resourceName, version, criteriaFilterStr ); + } + + /// + /// Gets a page of data for the given resource by name and version with the given filter. + /// + /// The name of the resource to get data for. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// The string resource filter in JSON format contained in the URL. + /// An EthosResponse containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + /// Returns exception if the resourceName is null. + /// Returns exception if the namedQuery is null. + /// Returns exception if the request fails. + public async Task GetWithNamedQueryFilterAsync( string resourceName, string version, string namedQueryFilterStr ) + { + if ( string.IsNullOrWhiteSpace( resourceName ) ) + { + throw new ArgumentNullException( "Error: Cannot get resource with criteria filter due to a null or blank resource name." ); + } + if ( string.IsNullOrWhiteSpace( namedQueryFilterStr ) ) + { + throw new ArgumentNullException( $"Error: Cannot get resource '{resourceName}' with named query due to a null or blank named query string." ); + } + return await GetEthosResponseAsync( resourceName, version, namedQueryFilterStr ); + } + + /// + /// Gets Ethos Response. + /// + /// The name of the resource to get data for. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// This can be CriteriaFilter or NamedQuery. + /// An EthosResponse containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + private async Task GetEthosResponseAsync( string resourceName, string version, string criteria ) + { + var filterStr = EncodeString( criteria ); + Dictionary headers = BuildHeadersMap( version ); + EthosResponse response = await GetAsync( headers, EthosIntegrationUrls.ApiFilter( Region, resourceName, filterStr ) ); + return response; + } + + /// + /// Gets a page of data for the given resource by name with the given filter. Uses the default version of the resource. + /// Makes a non-filter API request if the given criteriaFilter is null. + /// A simple call to criteriaFilter.BuildCriteria() should output the criteria filter portion of the request URL, + /// e.g: ?criteria={"names":[{"firstName":"John"}]}. + /// + /// The name of the resource to get data for. + /// A previously built Criteria containing the filter criteria used in the request URL. + /// A simple call to criteriaFilter.BuildCriteria() should output the criteria filter portion of the request URL, + /// e.g: ?criteria={"names":[{"firstName":"John"}]}. + /// An EthosResponse containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + public async Task GetWithCriteriaFilterAsync( string resourceName, CriteriaFilter criteria ) + { + return await GetWithCriteriaFilterAsync( resourceName, DEFAULT_VERSION, criteria.BuildCriteria() ); + } + + /// + /// Gets a page of data for the given resource by name and version with the given filter. + /// + /// The name of the resource to get data for. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// A previously built Criteria containing the filter criteria used in the request URL. + /// A simple call to criteriaFilter.BuildCriteria() should output the criteria filter portion of the request URL, + /// e.g: ?criteria={"names":[{"firstName":"John"}]}. + /// An EthosResponse containing an initial page (EthosResponse content) of resource data according to the requested version and filter of the resource. + /// to the requested version and filter of the resource. + /// Throws if the given criteriaFilter is null. + public async Task GetWithCriteriaFilterAsync( string resourceName, string version, CriteriaFilter criteria ) + { + if ( criteria == null ) + { + throw new ArgumentNullException( $"Error: Cannot get resource '{ resourceName }' with criteria filter due to a null criteria filter reference." ); + } + return await GetWithCriteriaFilterAsync( resourceName, version, criteria.BuildCriteria() ); + } + + /// + /// Gets a page of data for the given resource by name with the given filter. Uses the default version of the resource. + /// Makes a non-filter API request if the given criteriaFilter is null. + /// A simple call to criteriaFilter.BuildCriteria() should output the criteria filter portion of the request URL. + /// + /// The name of the resource to get data for. + /// A previously built namedQueryFilter containing the filter used in the request URL. + /// A simple call to namedQueryFilter.BuildNamedQuery() should output the criteria filter portion of the request URL, + /// e.g: ?criteria={"names":[{"firstName":"John"}]}. + /// An EthosResponse containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + public async Task GetWithNamedQueryFilterAsync( string resourceName, NamedQueryFilter namedQueryFilter ) + { + return await GetWithNamedQueryFilterAsync( resourceName, DEFAULT_VERSION, namedQueryFilter ); + } + + /// + /// Gets a page of data for the given resource by name and version with the given filter. + /// + /// The name of the resource to get data for. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// A previously built namedQueryFilter containing the filter used in the request URL. + /// A simple call to namedQueryFilter.BuildNamedQuery() should output the named query portion of the request URL. + /// An EthosResponse containing an initial page (EthosResponse content) of resource data according to the requested version and filter of the resource. + /// to the requested version and filter of the resource. + /// Throws if the given criteriaFilter is null. + public async Task GetWithNamedQueryFilterAsync( string resourceName, string version, NamedQueryFilter namedQueryFilter ) + { + if ( namedQueryFilter == null ) + { + throw new ArgumentNullException( $"Error: Cannot get resource '{ resourceName }' with named query due to a null named query reference." ); + } + return await GetWithNamedQueryFilterAsync( resourceName, version, namedQueryFilter.BuildNamedQuery() ); + } + + /// + /// Convenience method to submit a GET request with a single set of criteria filter. This is intended only to be used + /// for a single set of criteria filter, e.g: ?criteria={"names":[{"firstName":"John"}]}, where names is the + /// criteriaSetName, firstName is the criteriaKey, and John is the criteriaValue. Requests requiring + /// a more complex criteria filter should first build the Criteria with the necessary criteria, and then call + /// getWithCriteriaFilterAsync(resourceName, criteriaFilter). + ///

The parameters criteriaSetName, criteriaKey, and criteriaValue should only specify the values within quotes of the + /// JSON filter syntax. No JSON syntax (square or angeled braces etc.) should be contained within those parameter values.

+ ///

Uses the default version of the resource.

+ ///
+ /// The name of the resource to get data for. + /// The name of the criteria set that the given criteriaKey and criteriaValue are associated with, + /// e.g: "names":[{"firstName":"John"}]}, where names is the criteriaSetName associated to the + /// criteriaKey (firstName) and criteriaValue (John). + /// The JSON label key for the criteria. + /// The value associated with the criteriaKey. + /// An EthosResponse containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + public async Task GetWithSimpleCriteriaValuesAsync( string resourceName, string criteriaSetName, string criteriaKey, string criteriaValue ) + { + return await GetWithSimpleCriteriaValuesAsync( resourceName, DEFAULT_VERSION, criteriaSetName, criteriaKey, criteriaValue ); + } + + /// + /// Convenience method to submit a GET request with a single set of criteria filter. This is intended only to be used + /// for a single set of criteria filter, e.g: ?criteria={"names":[{"firstName":"John"}]}, where names is the + /// criteriaSetName, firstName is the criteriaKey, and John is the criteriaValue. Requests requiring + /// a more complex criteria filter should first build the Criteria with the necessary criteria, and then call + /// getWithCriteriaFilterAsync(resourceName, version, criteriaFilter). + ///

The parameters criteriaSetName, criteriaKey, and criteriaValue should only specify the values within quotes of the + /// JSON filter syntax. No JSON syntax (square or angeled braces, etc) should be contained within those parameter values.

+ ///
+ /// The name of the resource to get data for. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// The name of the criteria set that the given criteriaKey and criteriaValue are associated with, + /// e.g: "names":[{"firstName":"John"}]}, where names is the criteriaSetName associated to the + /// criteriaKey (firstName) and criteriaValue (John). + /// The JSON label key for the criteria. + /// The value associated with the criteriaKey. + /// An EthosResponse containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + /// Returns exception if the resourceName or criteriaSetName or criteriaKey or criteriaValue is null. + public async Task GetWithSimpleCriteriaValuesAsync( string resourceName, string version, string criteriaSetName, string criteriaKey, string criteriaValue ) + { + if ( string.IsNullOrWhiteSpace( resourceName ) ) + { + throw new ArgumentNullException( "Error: Cannot get resource with filter map due to a null or blank resource name." ); + } + if ( string.IsNullOrWhiteSpace( criteriaSetName ) ) + { + throw new ArgumentNullException( "Error: Cannot get resource due to a null or empty criteria set name parameter." ); + } + if ( string.IsNullOrWhiteSpace( criteriaKey ) ) + { + throw new ArgumentNullException( "Error: Cannot get resource due to a null or empty criteria key parameter." ); + } + if ( string.IsNullOrWhiteSpace( criteriaValue ) ) + { + throw new ArgumentNullException( "Error: Cannot get resource due to a null or empty criteria value parameter." ); + } + var criteriaFilter = new CriteriaFilter().WithSimpleCriteria( criteriaSetName, (criteriaKey, criteriaValue) ) + .BuildCriteria(); + return await GetWithCriteriaFilterAsync( resourceName, version, criteriaFilter ); + } + + /// + /// Submits a GET request for the given resource and version using the given filterMapStr. The filterMapStr + /// is intended to support the filter syntax for resources versions 7 and older. An example of a filterMapStr is: + /// ?firstName=James. + ///

This is NOT intended to be used for resource versions after version 7 and/or for criteria filters.

+ ///
+ /// The name of the resource to get data for. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// A string containing the filter syntax used for request URL filters with resource versions 7 or older. + /// An EthosResponse containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + /// Returns exception if the resourceName or filterMapStr is null. + public async Task GetWithFilterMapAsync( string resourceName, string version, string filterMapStr ) + { + if ( string.IsNullOrWhiteSpace( resourceName ) ) + { + throw new ArgumentNullException( "Error: Cannot get resource with filter map due to a null or blank resource name." ); + } + if ( string.IsNullOrWhiteSpace( filterMapStr ) ) + { + throw new ArgumentNullException( $"Error: Cannot get resource '{ resourceName }' with filter map due to a null or blank filter map string." ); + } + Dictionary headers = BuildHeadersMap( version ); + EthosResponse response = await GetAsync( headers, EthosIntegrationUrls.ApiFilter( Region, resourceName, filterMapStr ) ); + return response; + } + + /// + /// Submits a GET request for the given resource and version using the given filterMap. The filterMap + /// is intended to support the filter syntax for resources versions 7 and older. A FilterMap contains a map of + /// one or many filter parameter pair(s). An example of a filterMap string indicating the contents of the map is: + /// ?firstName=James. + ///

This is NOT intended to be used for resource versions after version 7 and/or for criteria filters.

+ ///
+ /// The name of the resource to get data for. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// A string containing the filter syntax used for request URL filters with resource versions 7 or older. + /// An EthosResponse containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + /// Returns exception if the resourceName or filterMap is null. + public async Task GetWithFilterMapAsync( string resourceName, string version, FilterMap filterMap ) + { + ArgumentNullException.ThrowIfNull( filterMap, $"Error: Cannot get resource '{resourceName}' with filter map due to a null filter map." ); + return await GetWithFilterMapAsync( resourceName, version, filterMap.ToString() ); + } + + /// + /// Gets all the pages for a given resource using the specified criteria filter. Uses the default version of the resource, + /// and the page size is derived from the length of the returned response of the request using the criteria filter. + /// + /// The name of the resource to get data for. + /// A previously built Criteria containing the filter criteria used in the request URL. + /// A simple call to criteriaFilter.BuildCriteria() should output the criteria filter portion of the request URL, + /// e.g: ?criteria={"names":[{"firstName":"John"}]}. + /// An EthosResponse containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + public async Task> GetPagesWithCriteriaFilterAsync( string resourceName, CriteriaFilter criteria ) + { + return await GetPagesWithCriteriaFilterAsync( resourceName, DEFAULT_VERSION, criteria, DEFAULT_PAGE_SIZE ); + } + + /// + /// Gets all the pages for a given resource using the specified criteria filter for the given version. Uses the default + /// page size, which is the length of the returned response of the request using the criteria filter. + /// + /// The name of the resource to get data for. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// A previously built Criteria containing the filter criteria used in the request URL. + /// An EthosResponse containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + public async Task> GetPagesWithCriteriaFilterAsync( string resourceName, string version, CriteriaFilter criteria ) + { + return await GetPagesWithCriteriaFilterAsync( resourceName, version, criteria, DEFAULT_PAGE_SIZE ); + } + + /// + /// Gets all the pages for a given resource using the specified namedQueryFilter filter. Uses the default version of the resource, + /// and the page size is derived from the length of the returned response of the request using the namedQueryFilter filter. + /// + /// The name of the resource to get data for. + /// A previously built namedQueryFilter containing the filter used in the request URL. + /// A simple call to namedQueryFilter.BuildNamedQuery() should output the namedQueryFilter filter portion of the request URL. + /// An EthosResponse containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + public async Task> GetPagesWithNamedQueryFilterAsync( string resourceName, NamedQueryFilter namedQueryFilter ) + { + return await GetPagesWithNamedQueryFilterAsync( resourceName, DEFAULT_VERSION, namedQueryFilter, DEFAULT_PAGE_SIZE ); + } + + /// + /// Gets all the pages for a given resource using the specified namedQueryFilter filter for the given version. Uses the default + /// page size, which is the length of the returned response of the request using the namedQueryFilter filter. + /// + /// The name of the resource to get data for. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// A previously built namedQueryFilter containing the filter used in the request URL. + /// An EthosResponse containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + public async Task> GetPagesWithNamedQueryFilterAsync( string resourceName, string version, NamedQueryFilter namedQueryFilter ) + { + return await GetPagesWithNamedQueryFilterAsync( resourceName, version, namedQueryFilter, DEFAULT_PAGE_SIZE ); + } + + /// + /// Gets all the pages for a given resource using the specified criteria filter and page size. The default version + /// of the resource is used. + /// + /// The name of the resource to get data for. + /// A previously built Criteria containing the filter criteria used in the request URL. + /// The size (number of rows) of each page returned in the list. + /// An EthosResponse containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + public async Task> GetPagesWithCriteriaFilterAsync( string resourceName, CriteriaFilter criteria, int pageSize ) + { + return await GetPagesWithCriteriaFilterAsync( resourceName, DEFAULT_VERSION, criteria, pageSize ); + } + + /// + /// Gets all the pages for a given resource using the specified criteria filter and page size for the given version. + /// + /// The name of the resource to get data for. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// A previously built Criteria containing the filter criteria used in the request URL. + /// The size (number of rows) of each page returned in the list. + /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + public async Task> GetPagesWithCriteriaFilterAsync( string resourceName, string version, CriteriaFilter criteria, int pageSize ) + { + return await GetPagesFromOffsetWithCriteriaFilterAsync( resourceName, version, criteria, pageSize, 0 ); + } + + /// + /// Gets all the pages for a given resource using the specified namedQueryFilter filter and page size. The default version + /// of the resource is used. + /// + /// The name of the resource to get data for. + /// A previously built namedQueryFilter containing the filter used in the request URL. + /// The size (number of rows) of each page returned in the list. + /// An EthosResponse containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + public async Task> GetPagesWithNamedQueryFilterAsync( string resourceName, NamedQueryFilter namedQueryFilter, int pageSize ) + { + return await GetPagesWithNamedQueryFilterAsync( resourceName, DEFAULT_VERSION, namedQueryFilter, pageSize ); + } + + /// + /// Gets all the pages for a given resource using the specified namedQueryFilter filter and page size for the given version. + /// + /// The name of the resource to get data for. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// A previously built namedQueryFilter containing the filter named query used in the request URL. + /// The size (number of rows) of each page returned in the list. + /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + public async Task> GetPagesWithNamedQueryFilterAsync( string resourceName, string version, NamedQueryFilter namedQueryFilter, int pageSize ) + { + return await GetPagesFromOffsetWithNamedQueryFilterAsync( resourceName, version, namedQueryFilter, pageSize, 0 ); + } + + /// + /// Gets all the pages for a given resource beginning at the given offset index, using the specified criteria filter. + /// The page size is determined to be the length of the returned response of the request using the criteria filter. + /// The default version of the resource is used. + /// + /// The name of the resource to get data for. + /// A previously built Criteria containing the filter criteria used in the request URL. + /// The 0 based index from which to begin paging for the given resource. + /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + public async Task> GetPagesFromOffsetWithCriteriaFilterAsync( string resourceName, CriteriaFilter criteria, int offset ) + { + return await GetPagesFromOffsetWithCriteriaFilterAsync( resourceName, DEFAULT_VERSION, criteria, offset ); + } + + /// + /// Gets all the pages for a given resource beginning at the given offset index, using the specified criteria filter + /// for the given version. The page size is determined to be the length of the returned response of the request using + /// the criteria filter. + /// + /// The name of the resource to get data for. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// A previously built Criteria containing the filter criteria used in the request URL. + /// The 0 based index from which to begin paging for the given resource. + /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + public async Task> GetPagesFromOffsetWithCriteriaFilterAsync( string resourceName, string version, CriteriaFilter criteria, int offset ) + { + return await GetPagesFromOffsetWithCriteriaFilterAsync( resourceName, version, criteria, DEFAULT_PAGE_SIZE, offset ); + } + + /// + /// Gets all the pages for a given resource beginning at the given offset index, using the specified namedQueryFilter filter. + /// The page size is determined to be the length of the returned response of the request using the namedQueryFilter filter. + /// The default version of the resource is used. + /// + /// The name of the resource to get data for. + /// + /// The 0 based index from which to begin paging for the given resource. + /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + public async Task> GetPagesFromOffsetWithNamedQueryFilterAsync( string resourceName, NamedQueryFilter namedQueryFilter, int offset ) + { + return await GetPagesFromOffsetWithNamedQueryFilterAsync( resourceName, DEFAULT_VERSION, namedQueryFilter, offset ); + } + + /// + /// Gets all the pages for a given resource beginning at the given offset index, using the specified namedQueryFilter filter + /// for the given version. The page size is determined to be the length of the returned response of the request using + /// the namedQueryFilter filter. + /// + /// The name of the resource to get data for. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// A previously built namedQueryFilter containing the filter used in the request URL. + /// The 0 based index from which to begin paging for the given resource. + /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + public async Task> GetPagesFromOffsetWithNamedQueryFilterAsync( string resourceName, string version, NamedQueryFilter namedQueryFilter, int offset ) + { + return await GetPagesFromOffsetWithNamedQueryFilterAsync( resourceName, version, namedQueryFilter, DEFAULT_PAGE_SIZE, offset ); + } + + /// + /// Gets all the pages for a given resource beginning at the given offset index, using the specified criteria filter + /// and page size for the given version. The default version of the resource is used. + /// + /// The name of the resource to get data for. + /// A previously built Criteria containing the filter criteria used in the request URL. + /// The size (number of rows) of each page returned in the list. + /// The 0 based index from which to begin paging for the given resource. + /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + public async Task> GetPagesFromOffsetWithCriteriaFilterAsync( string resourceName, CriteriaFilter criteria, int pageSize, int offset ) + { + return await GetPagesFromOffsetWithCriteriaFilterAsync( resourceName, DEFAULT_VERSION, criteria, pageSize, offset ); + } + + /// + /// Gets all the pages for a given resource beginning at the given offset index, using the specified criteria filter + /// and page size for the given version. + /// + /// The name of the resource to get data for. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// A previously built Criteria containing the filter criteria used in the request URL. + /// The size (number of rows) of each page returned in the list. + /// The 0 based index from which to begin paging for the given resource. + /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + /// Returns exception if the resourceName or criteriaFilter is null. + public async Task> GetPagesFromOffsetWithCriteriaFilterAsync( string resourceName, string version, CriteriaFilter criteria, int pageSize, int offset ) + { + if ( string.IsNullOrWhiteSpace( resourceName ) ) + { + throw new ArgumentNullException( "Error: Cannot get pages of resource from offset with criteria filter due to a null or blank resource name." ); + } + if ( criteria == null ) + { + throw new ArgumentNullException( $"Error: Cannot get pages of resource '{ resourceName }' from offset with criteria filter due to a null criteria filter reference." ); + } + List ethosResponseList = new List(); + Pager pager = Pager.Build( pg => + { + pg + .ForResource( resourceName ) + .ForVersion( version ) + .WithCriteriaFilter( criteria.BuildCriteria() ) + .WithPageSize( pageSize ) + .FromOffSet( offset ); + } ); + + pager = await PrepareForPagingAsync( pager ); + pager = ShouldDoPaging( pager, false ); + if ( pager.ShouldDoPaging ) + { + ethosResponseList = await DoPagingFromOffsetAsync( pager.ResourceName, pager.Version, pager.CriteriaFilter, pager.TotalCount, pager.PageSize, offset ); + } + else + { + ethosResponseList.Add( await GetWithCriteriaFilterAsync( resourceName, version, criteria ) ); + } + return ethosResponseList; + } + + /// + /// Gets all the pages for a given resource beginning at the given offset index, using the specified namedQueryFilter + /// and page size for the given version. The default version of the resource is used. + /// + /// The name of the resource to get data for. + /// A previously built namedQueryFilter containing the filter used in the request URL. + /// The size (number of rows) of each page returned in the list. + /// The 0 based index from which to begin paging for the given resource. + /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + public async Task> GetPagesFromOffsetWithNamedQueryFilterAsync( string resourceName, NamedQueryFilter namedQueryFilter, int pageSize, int offset ) + { + return await GetPagesFromOffsetWithNamedQueryFilterAsync( resourceName, DEFAULT_VERSION, namedQueryFilter, pageSize, offset ); + } + + /// + /// Gets all the pages for a given resource beginning at the given offset index, using the specified namedQueryFilter + /// and page size for the given version. + /// + /// The name of the resource to get data for. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// A previously built namedQueryFilter containing the filter used in the request URL. + /// The size (number of rows) of each page returned in the list. + /// The 0 based index from which to begin paging for the given resource. + /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + /// Returns exception if the resourceName or namedQueryFilter is null. + public async Task> GetPagesFromOffsetWithNamedQueryFilterAsync( string resourceName, string version, NamedQueryFilter namedQueryFilter, int pageSize, int offset ) + { + if ( string.IsNullOrWhiteSpace( resourceName ) ) + { + throw new ArgumentNullException( "Error: Cannot get pages of resource from offset with named query filter due to a null or blank resource name." ); + } + if ( namedQueryFilter == null ) + { + throw new ArgumentNullException( $"Error: Cannot get pages of resource '{ resourceName }' from offset with named query filter due to a null named query filter reference." ); + } + List ethosResponseList = new List(); + Pager pager = Pager.Build( pg => + { + pg + .ForResource( resourceName ) + .ForVersion( version ) + .WithNamedQuery( namedQueryFilter.BuildNamedQuery() ) + .WithPageSize( pageSize ) + .FromOffSet( offset ); + } ); + + pager = await PrepareForPagingAsync( pager ); + pager = ShouldDoPaging( pager, false ); + if ( pager.ShouldDoPaging ) + { + ethosResponseList = await DoPagingFromOffsetAsync( pager.ResourceName, pager.Version, pager.NamedQueryFilter, pager.TotalCount, pager.PageSize, offset ); + } + else + { + ethosResponseList.Add( await GetWithNamedQueryFilterAsync( resourceName, version, namedQueryFilter ) ); + } + return ethosResponseList; + } + + /// + /// Gets all the pages for a given resource using the specified filter map and page size for the given version. + /// + /// The name of the resource to get data for. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// A previously built FilterMap containing the filter parameters used in the request URL. + /// A simple call to filterMap.tostring() should output the criteria filter portion of the request URL, + /// e.g: ?firstName=John&lastName=Smith. + /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + public async Task> GetPagesWithFilterMapAsync( string resourceName, string version, FilterMap filterMap ) + { + return await GetPagesWithFilterMapAsync( resourceName, version, filterMap, DEFAULT_PAGE_SIZE ); + } + + /// + /// Gets all the pages for a given resource using the specified filter map and page size for the given version. + /// + /// The name of the resource to get data for. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// A previously built FilterMap containing the filter parameters used in the request URL. + /// A simple call to filterMap.tostring() should output the criteria filter portion of the request URL, + /// e.g: ?firstName=John&lastName=Smith. + /// The size (number of rows) of each page returned in the list. + /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + public async Task> GetPagesWithFilterMapAsync( string resourceName, string version, FilterMap filterMap, int pageSize ) + { + return await GetPagesFromOffsetWithFilterMapAsync( resourceName, version, filterMap, pageSize, 0 ); + } + + /// + /// Gets all the pages for a given resource beginning at the given offset index, using the specified filter map and + /// page size for the given version. The page size is determined to be the length of the returned response of the request using + /// the filter map. + /// + /// The name of the resource to get data for. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// A previously built FilterMap containing the filter parameters used in the request URL. + /// A simple call to filterMap.tostring() should output the criteria filter portion of the request URL, + /// e.g: ?firstName=John&lastName=Smith. + /// The 0 based index from which to begin paging for the given resource. + /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + public async Task> GetPagesFromOffsetWithFilterMapAsync( string resourceName, string version, FilterMap filterMap, int offset ) + { + return await GetPagesFromOffsetWithFilterMapAsync( resourceName, version, filterMap, DEFAULT_PAGE_SIZE, offset ); + } + + /// + /// Gets all the pages for a given resource beginning at the given offset index, using the specified filter map and + /// page size for the given version. + /// + /// The name of the resource to get data for. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// A previously built FilterMap containing the filter parameters used in the request URL. + /// A simple call to filterMap.tostring() should output the criteria filter portion of the request URL, + /// e.g: ?firstName=John&lastName=Smith. + /// The size (number of rows) of each page returned in the list. + /// The 0 based index from which to begin paging for the given resource. + /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + public async Task> GetPagesFromOffsetWithFilterMapAsync( string resourceName, string version, FilterMap filterMap, int pageSize, int offset ) + { + if ( string.IsNullOrWhiteSpace( resourceName ) ) + { + throw new ArgumentNullException( "Error: Cannot get pages of resource with filter map due to a null or blank resource name." ); + } + if ( filterMap == null ) + { + throw new ArgumentNullException( $"Error: Cannot get pages of resource '{ resourceName }' with filter map due to a null filter map reference." ); + } + List ethosResponseList = new List(); + Pager pager = Pager.Build( pg => + { + pg + .ForResource( resourceName ) + .ForVersion( version ) + .WithFilterMap( filterMap.ToString() ) + .WithPageSize( pageSize ) + .FromOffSet( offset ); + } ); + + pager = await PrepareForPagingAsync( pager ); + pager = ShouldDoPaging( pager, false ); + if ( pager.ShouldDoPaging ) + { + ethosResponseList = await DoPagingFromOffsetAsync( pager.ResourceName, pager.Version, pager.FilterMap, pager.TotalCount, pager.PageSize, offset ); + } + else + { + ethosResponseList.Add( await GetWithFilterMapAsync( resourceName, version, filterMap ) ); + } + return ethosResponseList; + } + + #region QAPI's + + /// + /// Submits a POST request for the given resourceName with the given qapiRequestBody. The qapiRequestBody should be a string in JSON format. + /// + /// The name of the resource to add an instance of. + /// The full version header value of the resource used for this POST request. + /// The body of the request to POST for the given resource. + /// An EthosResponse containing the instance of the resource that was added by this POST operation. + /// When is passed as null or empty or white space. + /// When is passed as null or empty or white space. + public async Task GetWithQapiAsync( string resourceName, string qapiRequestBody, string version = "" ) + { + if ( string.IsNullOrWhiteSpace( resourceName ) ) + { + throw new ArgumentNullException( $"Error: Cannot submit a POST request due to a null or blank {nameof( resourceName )} parameter." ); + } + + if ( string.IsNullOrWhiteSpace( qapiRequestBody ) ) + { + throw new ArgumentNullException( + $"Error: Cannot submit a POST request for resource {resourceName} due to a null or blank {nameof( qapiRequestBody )} parameter." + ); + } + var headers = BuildHeadersMap( version ); + string url = EthosIntegrationUrls.Qapi( Region, resourceName ); + return await base.PostAsync( headers, url, qapiRequestBody ); + } + + /// + /// Submits a POST request for the given resourceName with the given requestBodyNode. The requestBodyNode should be a JObject. + /// + /// The name of the resource to add an instance of. + /// The full version header value of the resource used for this POST request. + /// The body of the request to POST for the given resource as a JsonNode. + /// An EthosResponse containing the instance of the resource that was added by this POST operation. + /// When is passed as null or empty or white space. + /// When is passed as null. + public async Task GetWithQapiAsync( string resourceName, JObject qapiRequestBodyNode, string version = "" ) + { + ArgumentNullException.ThrowIfNull( qapiRequestBodyNode, $"Error: Cannot submit a POST request for resource {resourceName} due to a null {nameof( qapiRequestBodyNode )} parameter." ); + return await GetWithQapiAsync(resourceName, qapiRequestBodyNode.ToString(), version ); + } + + /// + /// Submits a POST request for the given resourceName with the given qapiRequestBody. The qapiRequestBody should be a T type class. + /// + /// Request type. + /// The name of the resource to add an instance of. + /// The full version header value of the resource used for this POST request. + /// The body of the request to POST for the given resource. + /// An EthosResponse containing the instance of the resource that was added by this POST operation. + /// When is passed as null or empty or white space. + /// When is passed as null. + public async Task GetWithQapiAsync( string resourceName, T qapiRequestBody, string version = "" ) where T : class + { + ArgumentNullException.ThrowIfNull( qapiRequestBody, $"Error: Cannot submit a POST request for resource {resourceName} due to a null {nameof( qapiRequestBody )} parameter." ); + + JsonSerializerSettings jsonSerSettings = GetJsonSerializerSettings(); + var reqBody = JsonConvert.SerializeObject( qapiRequestBody, jsonSerSettings ); + return await GetWithQapiAsync( resourceName, reqBody, version ); + } + + /// + /// Gets the total count of resources available using the given criteriaFilter. Gets the pages for a given resource beginning at the given offset index, + /// using the specified QAPI request body and page size for the given version. + /// + /// The name of the resource to add an instance of. + /// The full version header value of the resource used for this POST request. + /// The body of the request to POST for the given resource. + /// The size (number of rows) of each page returned in the list. + /// The 0 based index from which to begin paging for the given resource. + /// A list of EthosResponses where each EthosResponse contains a page of data. If paging is not required based on the + /// given pageSize and total count( from using the filter), the returned list will only contain one EthosResponse. + /// When is passed as null or empty or white space. + /// When is passed as null. + public async Task> GetPagesFromOffsetWithQAPIAsync( string resourceName, string qapiRequestBody, string version = "", int pageSize = 0, int offset = 0) + { + if ( string.IsNullOrWhiteSpace( resourceName ) ) + { + throw new ArgumentNullException( $"Error: Cannot submit a POST request due to a null or blank {nameof( resourceName )} parameter." ); + } + + if ( string.IsNullOrWhiteSpace( qapiRequestBody ) ) + { + throw new ArgumentNullException( $"Error: Cannot submit a POST request for resource {resourceName} due to a null {nameof( qapiRequestBody )} parameter." ); + } + + List ethosResponseList = new(); + Pager pager = Pager.Build( pg => + { + pg + .ForResource( resourceName ) + .ForVersion( version ) + .FromOffSet( offset ) + .WithPageSize( pageSize ) + .WithQAPIRequestBodyFilter( qapiRequestBody ); + } ); + + pager = await PrepareForPagingAsync( pager ); + pager = ShouldDoPaging( pager, false ); + if ( pager.ShouldDoPaging ) + { + ethosResponseList = await DoPagingFromOffsetForQAPIAsync( pager.ResourceName, pager.Version, qapiRequestBody, pager.TotalCount, pager.PageSize, pager.Offset ); + } + else + { + ethosResponseList.Add( await GetWithQapiAsync( resourceName, qapiRequestBody, version ) ); + } + return ethosResponseList; + } + + /// + /// Gets the total count of resources available using the given criteriaFilter. Gets the pages for a given resource beginning at the given offset index, + /// using the specified QAPI request body and page size for the given version. + /// + /// The name of the resource to add an instance of. + /// The full version header value of the resource used for this POST request. + /// The body of the request to POST for the given resource. + /// The size (number of rows) of each page returned in the list. + /// The 0 based index from which to begin paging for the given resource. + /// A list of EthosResponses where each EthosResponse contains a page of data. If paging is not required based on the + /// given pageSize and total count( from using the filter), the returned list will only contain one EthosResponse. + /// When is passed as null or empty or white space. + /// When is passed as null. + public async Task> GetPagesFromOffsetWithQAPIAsync( string resourceName, JObject qapiRequestBody, string version = "", int pageSize = 0, int offset = 0 ) + { + ArgumentNullException.ThrowIfNull( qapiRequestBody, $"Error: Cannot submit a POST request for resource {resourceName} due to a null {nameof( qapiRequestBody )} parameter." ); + return await GetPagesFromOffsetWithQAPIAsync(resourceName, qapiRequestBody.ToString(), version, pageSize, offset ); + } + + /// + /// Gets the total count of resources available using the given type T. + /// Gets the pages for a given resource beginning at the given offset index, using the specified QAPI request body and page size for the given version. + /// + /// Request type. + /// The name of the resource to add an instance of. + /// The full version header value of the resource used for this POST request. + /// The body of the request to POST for the given resource. + /// The size (number of rows) of each page returned in the list. + /// The 0 based index from which to begin paging for the given resource. + /// A list of EthosResponses where each EthosResponse contains a page of data. If paging is not required based on the + /// given pageSize and total count( from using the filter), the returned list will only contain one EthosResponse. + /// When is passed as null or empty or white space. + /// When is passed as null. + public async Task> GetPagesFromOffsetWithQAPIAsync( string resourceName, T qapiRequestBody, string version = "", int pageSize = 0, int offset = 0 ) where T : class + { + ArgumentNullException.ThrowIfNull( qapiRequestBody, $"Error: Cannot submit a POST request for resource {resourceName} due to a null {nameof( qapiRequestBody )} parameter." ); + + var jsonSerSettings = GetJsonSerializerSettings(); + var reqBody = JsonConvert.SerializeObject( qapiRequestBody, jsonSerSettings ); + return await GetPagesFromOffsetWithQAPIAsync( resourceName, reqBody, version, pageSize, offset ); + } + + /// + /// Gets all the pages for a given resource beginning at offset index 0, using the specified QAPI request body and page size for the given version. + /// + /// The name of the resource to add an instance of. + /// The full version header value of the resource used for this POST request. + /// The body of the request to POST for the given resource. + /// The size (number of rows) of each page returned in the list. + /// A list of EthosResponses where each EthosResponse contains a page of data. If paging is not required based on the + /// given pageSize and total count( from using the filter), the returned list will only contain one EthosResponse. + /// When is passed as null or empty or white space. + /// When is passed as null. + public async Task> GetPagesWithQAPIAsync( string resourceName, string qapiRequestBody, string version = "", int pageSize = 0 ) + { + return await GetPagesFromOffsetWithQAPIAsync(resourceName, qapiRequestBody, version, pageSize, 0 ); + } + + /// + /// Gets all the pages for a given resource beginning at offset index 0, using the specified QAPI request body and page size for the given version. + /// + /// The name of the resource to add an instance of. + /// The full version header value of the resource used for this POST request. + /// The body of the request to POST for the given resource. + /// The size (number of rows) of each page returned in the list. + /// A list of EthosResponses where each EthosResponse contains a page of data. If paging is not required based on the + /// given pageSize and total count( from using the filter), the returned list will only contain one EthosResponse. + /// When is passed as null or empty or white space. + /// When is passed as null. + public async Task> GetPagesWithQAPIAsync( string resourceName, JObject qapiRequestBody, string version = "", int pageSize = 0 ) + { + ArgumentNullException.ThrowIfNull( qapiRequestBody, $"Error: Cannot submit a POST request for resource {resourceName} due to a null {nameof( qapiRequestBody )} parameter." ); + return await GetPagesWithQAPIAsync( resourceName, qapiRequestBody.ToString(), version, pageSize ); + } + + /// + /// Gets all the pages for a given resource beginning at offset index 0, using the specified QAPI request body and page size for the given version. + /// + /// Request type. + /// The name of the resource to add an instance of. + /// The full version header value of the resource used for this POST request. + /// The body of the request to POST for the given resource. + /// The size (number of rows) of each page returned in the list. + /// A list of EthosResponses where each EthosResponse contains a page of data. If paging is not required based on the + /// given pageSize and total count( from using the filter), the returned list will only contain one EthosResponse. + /// When is passed as null or empty or white space. + /// When is passed as null. + public async Task> GetPagesWithQAPIAsync( string resourceName, T qapiRequestBody, string version = "", int pageSize = 0 ) where T : class + { + ArgumentNullException.ThrowIfNull( qapiRequestBody, $"Error: Cannot submit a POST request for resource {resourceName} due to a null {nameof( qapiRequestBody )} parameter." ); + + var jsonSerSettings = GetJsonSerializerSettings(); + var reqBody = JsonConvert.SerializeObject( qapiRequestBody, jsonSerSettings ); + return await GetPagesWithQAPIAsync( resourceName, reqBody, version, pageSize ); + } + + /// + /// Gets the total count of resources available using the given QAPI request body. + /// + /// The name of the resource to get data for. + /// The body of the request to POST for the given resource. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// The number of resource instances available when making a GET request using the given namedQueryFilter, or 0 if the + /// given resourceName or namedQueryFilter is null. + /// Returns exception if the resourceName is null. + /// Returns exception if the qapiRequestBody is null. + public async Task GetTotalCountAsync( string resourceName, string qapiRequestBody, string version = "" ) + { + if ( string.IsNullOrWhiteSpace( resourceName ) || string.IsNullOrWhiteSpace( qapiRequestBody ) ) + { + return default; + } + + EthosResponse ethosResponse = await GetWithQapiAsync( resourceName, qapiRequestBody, version ); + string totalCount = GetHeaderValue( ethosResponse, HDR_X_TOTAL_COUNT ); + if ( int.TryParse( totalCount, out int count ) ) + { + return count; + } + return default; + } + + /// + /// Gets the total count of resources available using the given QAPI request body. + /// + /// The name of the resource to get data for. + /// The body of the request to POST for the given resource. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// The number of resource instances available when making a GET request using the given namedQueryFilter, or 0 if the + /// given resourceName or namedQueryFilter is null. + /// Returns exception if the resourceName is null. + /// Returns exception if the qapiRequestBody is null. + public async Task GetTotalCountAsync( string resourceName, JObject qapiRequestBody, string version = "" ) + { + if( qapiRequestBody is null) return default; + return await GetTotalCountAsync( resourceName, qapiRequestBody.ToString(), version ); + } + + /// + /// Gets the total count of resources available using the given QAPI request body. + /// + /// The name of the resource to get data for. + /// The body of the request to POST for the given resource. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// The number of resource instances available when making a GET request using the given namedQueryFilter, or 0 if the + /// given resourceName or namedQueryFilter is null. + /// Returns exception if the resourceName is null. + /// Returns exception if the qapiRequestBody is null. + public async Task GetTotalCountAsync( string resourceName, T qapiRequestBody, string version = "" ) where T : class + { + if ( string.IsNullOrWhiteSpace( resourceName ) || qapiRequestBody is null ) + { + return default; + } + + EthosResponse ethosResponse = await GetWithQapiAsync( resourceName, qapiRequestBody, version ); + string totalCount = GetHeaderValue( ethosResponse, HDR_X_TOTAL_COUNT ); + if ( int.TryParse( totalCount, out int count ) ) + { + return count; + } + return default; + } + + /// + ///

Intended to be used internally within the SDK.

Performs paging calculations and operations for QAPI requests. + ///
+ /// The name of the resource to add an instance of. + /// The full version header value of the resource used for this POST request. + /// The body of the request to POST for the given resource. + /// The total count of rows for the given resource. + /// The size (number of rows) of each page returned in the list. + /// The 0 based index from which to begin paging for the given resource. + /// Collection of EthosResponse with content. + protected async Task> DoPagingFromOffsetForQAPIAsync( string resourceName, string version, string qapiRequestBody, int totalCount, int pageSize, int offset ) + { + List ethosResponseList = new(); + Dictionary headers = BuildHeadersMap( version ); + decimal numPages = Math.Ceiling( ( Convert.ToDecimal( totalCount ) - Convert.ToDecimal( offset ) ) / Convert.ToDecimal( pageSize ) ); + for ( int i = 0; i < numPages; i++ ) + { + string url = EthosIntegrationUrls.QapiPaging( Region, resourceName, offset, pageSize ); + EthosResponse response = await base.PostAsync( headers, url, qapiRequestBody ); + ethosResponseList.Add( response ); + offset += pageSize; + } + return ethosResponseList; + } + + #endregion QAPI + + /// + /// Gets the total count of resources available using the given criteriaFilter. + /// + /// The name of the resource to get data for. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// A previously built Criteria containing the filter criteria used in the request URL. + /// The number of resource instances available when making a GET request using the given criteriaFilter, or 0 if the + /// given resourceName or criteriaFilter is null. + /// Returns exception if the resourceName is null. + /// Returns exception if the criteriaFilterStr is null. + public async Task GetTotalCountAsync( string resourceName, CriteriaFilter criteria, string version = "" ) + { + if ( string.IsNullOrWhiteSpace( resourceName ) ) + { + return default; + } + if ( criteria == null ) + { + return default; + } + EthosResponse ethosResponse = await GetWithCriteriaFilterAsync( resourceName, version, criteria.BuildCriteria() ); + string totalCount = GetHeaderValue( ethosResponse, HDR_X_TOTAL_COUNT ); + if ( int.TryParse( totalCount, out int count ) ) + { + return count; + } + return default; + } + + /// + /// Gets the total count of resources available using the given namedQueryFilter. + /// + /// The name of the resource to get data for. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// A previously built namedQueryFilter containing the filter used in the request URL. + /// The number of resource instances available when making a GET request using the given namedQueryFilter, or 0 if the + /// given resourceName or namedQueryFilter is null. + /// Returns exception if the resourceName is null. + public async Task GetTotalCountAsync( string resourceName, NamedQueryFilter namedQueryFilter, string version = "" ) + { + if ( string.IsNullOrWhiteSpace( resourceName ) ) + { + return default; + } + if ( namedQueryFilter == null ) + { + return default; + } + EthosResponse ethosResponse = await GetWithNamedQueryFilterAsync( resourceName, version, namedQueryFilter.BuildNamedQuery() ); + string totalCount = GetHeaderValue( ethosResponse, HDR_X_TOTAL_COUNT ); + if ( int.TryParse( totalCount, out int count ) ) + { + return count; + } + return default; + } + + /// + /// Gets the total count of resources available using the given filterMap. + /// + /// The name of the resource to get data for. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// A previously built FilterMap containing the filter parameters used in the request URL. + /// A simple call to filterMap.Tostring() should output the criteria filter portion of the request URL, + /// e.g: ?firstName=John&lastName=Smith. + /// The number of resource instances available when making a GET request using the given criteriaFilter, or 0 if the + /// given resourceName or criteriaFilter is null. + /// Returns exception if the resourceName is null. + public async Task GetTotalCountAsync( string resourceName, FilterMap filterMap, string version = "" ) + { + if ( string.IsNullOrWhiteSpace( resourceName ) ) + { + return default; + } + if ( filterMap == null ) + { + return default; + } + EthosResponse ethosResponse = await GetWithFilterMapAsync( resourceName, version, filterMap.ToString() ); + string totalCount = GetHeaderValue( ethosResponse, HDR_X_TOTAL_COUNT ); + if ( int.TryParse( totalCount, out int count ) ) + { + return count; + } + return default; + } + + /// + ///

Intended to be used internally within the SDK. + ///

+ /// Overrides the prepareForPaging() method in the EthosProxyClient super class. + ///

+ /// Uses the given pager object to prepare for paging operations. The pager object is used to contain various + /// fields required for paging. If the given pager is null, returns the same pager. Sets default values for the + /// version and offset within the pager as needed and makes an initial resource call using the provided pager filter + /// to get metadata about the resource used for paging. Also sets the page size and the total count within the pager, + /// and encodes the filter within the pager.

+ ///
+ /// The Pager object used holding the required fields for paging. + /// The same pager object with the version and offset validated, the page size and total count set, and the filter encoded. + protected new async Task PrepareForPagingAsync( Pager pager ) + { + if ( pager == null ) + { + return pager; + } + if ( string.IsNullOrWhiteSpace( pager.Version ) ) + { + pager.Version = DEFAULT_VERSION; + } + if ( pager.Offset < 1 ) + { + pager.Offset = 0; + } + + pager = await PreparePagerForTotalCountAsync( pager ); + + // Set the pageSize. + pager = PreparePagerForPageSize( pager ); + + // Encode the criteriaFilter if it is not null. + if ( pager.CriteriaFilter != null ) + { + pager.CriteriaFilter = EncodeString( pager.CriteriaFilter ); + } + + // Encode the NamedQueryFilter if it is not null. + if ( pager.NamedQueryFilter != null ) + { + pager.NamedQueryFilter = EncodeString( pager.NamedQueryFilter ); + } + return pager; + } + + /// + /// Intended to be used internally by the SDK. + ///

Prepares the pager object for the total count required for paging calculations. + /// The total count is derived from the response x-total-count header after making an initial request using filters

+ /// (in this case). + ///
+ /// The Pager object used holding the required fields for paging. + /// The pager object containing the total count. If neither a criteria filter, a named query nor a filter map is specified + /// in the pager, then the total count will be 0. + protected async Task PreparePagerForTotalCountAsync( Pager pager ) + { + EthosResponse ethosResponse = null; + if ( pager.CriteriaFilter is not null ) + { + ethosResponse = await GetWithCriteriaFilterAsync( pager.ResourceName, pager.Version, pager.CriteriaFilter ); + pager.EthosResponse = ethosResponse; + } + else if ( pager.NamedQueryFilter is not null ) + { + ethosResponse = await GetWithNamedQueryFilterAsync( pager.ResourceName, pager.Version, pager.NamedQueryFilter ); + pager.EthosResponse = ethosResponse; + } + else if ( pager.FilterMap is not null ) + { + ethosResponse = await GetWithFilterMapAsync( pager.ResourceName, pager.Version, pager.FilterMap ); + pager.EthosResponse = ethosResponse; + } + else if ( pager.QapiRequestBody is not null ) + { + ethosResponse = await GetWithQapiAsync( pager.ResourceName, pager.QapiRequestBody, pager.Version ); + pager.EthosResponse = ethosResponse; + } + else + { + await base.PrepareForPagingAsync( pager ); + } + if ( ethosResponse is not null ) + { + string totalCount = GetHeaderValue( ethosResponse, HDR_X_TOTAL_COUNT ); + if ( int.TryParse( totalCount, out int count ) ) + { + pager.TotalCount = count; + } + } + return pager; + } + + /// + /// Intended to be used internally by the SDK. + ///

+ /// If the page size specified in the pager is <= DEFAULT_PAGE_SIZE, then this method prepares the pager object for the + /// page size required for paging calculations. The page size is derived from the response body length after making an initial request using filters + /// (in this case). If the response is null, the DEFAULT_MAX_PAGE_SIZE is used. If the response body is null, the + /// x-max-page-size header is used.

+ ///

If the page size specified in the pager is > DEFAULT_PAGE_SIZE, this method does nothing and just returns the given pager.

+ ///
+ /// The pager object used to contain the page size for paging operations. + /// The pager object containing the page size. + protected Pager PreparePagerForPageSize( Pager pager ) + { + if ( pager.PageSize <= DEFAULT_PAGE_SIZE ) + { + if ( pager.EthosResponse == null ) + { + pager.PageSize = DEFAULT_MAX_PAGE_SIZE; // Set the page size to the MAX default because there is no ethosResponse. + } + // Set the pageSize from the response body length, if pageSize is <= DEFAULT_PAGE_SIZE. + else if ( !string.IsNullOrWhiteSpace( pager.EthosResponse.Content ) && pager.EthosResponse.GetContentAsJson() != null ) + { + int pageSize = pager.EthosResponse.GetContentCount(); + pager.PageSize = pageSize; + } + else + { + string maxPageSizeStr = GetHeaderValue( pager.EthosResponse, HDR_X_MAX_PAGE_SIZE ); + if ( !string.IsNullOrWhiteSpace( maxPageSizeStr ) ) + { + if ( int.TryParse( maxPageSizeStr, out int pageSize ) ) + { + pager.PageSize = pageSize; + } + } + else + { + pager.PageSize = DEFAULT_MAX_PAGE_SIZE; + } + } + } + return pager; + } + + /// + /// Used internally by the SDK. + ///

+ /// Encodes the given criteriaFilterStr. Supports criteria filter strings that begin with the CRITERIA_FILTER_PREFIX + /// value "?criteria=", and also those that do not. Encodes only the JSON criteria portion of the filter string, removing + /// the CRITERIA_FILTER_PREFIX portion if the filter string starts with it. If the filter string does not start with + /// the CRITERIA_FILTER_PREFIX, the criteriaFilterStr string is simply encoded.

+ ///

Returns a criteria filter string that begins with the CRITERIA_FILTER_PREFIX, with the JSON filter portion of the string + /// encoded. Uses UTF-8 encoding.

+ ///
+ /// The criteria filter string to encode. + /// A criteria filter string beginning with the CRITERIA_FILTER_PREFIX with the JSON filter syntax portion of the + /// string encoded in UTF-8. + private static string EncodeString( string criteriaFilterStr ) + { + StringBuilder sb = new StringBuilder(); + string jsonCriteriaStr; + bool isNamedQuery = false; + if ( criteriaFilterStr.StartsWith( CRITERIA_FILTER_PREFIX ) ) + { + // It starts with "?criteria=", so substring the rest of the filter and encode it. + jsonCriteriaStr = criteriaFilterStr [ ( criteriaFilterStr.IndexOf( "=" ) + 1 ).. ]; + } + else + { + jsonCriteriaStr = criteriaFilterStr; + isNamedQuery = true; + } + jsonCriteriaStr = System.Web.HttpUtility.UrlEncode( jsonCriteriaStr, Encoding.UTF8 ); + if ( !isNamedQuery ) sb.Append( CRITERIA_FILTER_PREFIX ); + sb.Append( jsonCriteriaStr ); + return sb.ToString(); + } + + /// + /// Gets JsonSerializerSettings with date format. + /// + /// Returns JsonSerializerSettings with yyyy'-'MM'-'dd'T'HH':'mm':'ssK date format and ignores null values. + private static JsonSerializerSettings GetJsonSerializerSettings() + { + return new JsonSerializerSettings() + { + DateFormatString = DATE_FORMAT, + NullValueHandling = NullValueHandling.Ignore, + DefaultValueHandling = DefaultValueHandling.Ignore + }; + } + } +} diff --git a/Ellucian.Ethos.Integration/Client/Proxy/ColleagueWebApiProxyClient.cs b/Ellucian.Ethos.Integration/Client/Proxy/ColleagueWebApiProxyClient.cs new file mode 100644 index 0000000..91d00d4 --- /dev/null +++ b/Ellucian.Ethos.Integration/Client/Proxy/ColleagueWebApiProxyClient.cs @@ -0,0 +1,1543 @@ +using Ellucian.Ethos.Integration.Client.Filter.Extensions; +using Ellucian.Ethos.Integration.Client.Proxy.Filter; + +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +using System; +using System.Collections.Generic; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; + +namespace Ellucian.Ethos.Integration.Client.Proxy +{ + /// + /// An EthosProxyClient that provides the ability to submit GET requests supporting filters and/or named queries with support for paging. + /// + public class ColleagueWebApiProxyClient + { + // Prefix value used when specifying criteria filter syntax. + private const string CRITERIA_FILTER_PREFIX = "?criteria="; + private string ColleagueApiUrl; + private string ColleagueApiUsername; + private string ColleagueApiPassword; + private HttpClient Client; + + + /// + /// Instantiates this class using the given Colleague API url and credentials. + /// + /// The URL to the Colleague API instance. If it is null/empty, then an will be thrown. + /// The username used to connect to the Colleague API. If it is null/empty, then an will be thrown. + /// The password used to connect to the Colleague API. If it is null/empty, then an will be thrown. + /// A HttpClient. If it is null/empty, then an will be thrown. + public ColleagueWebApiProxyClient( string colleagueApiUrl, string colleagueApiUsername, string colleagueApiPassword, HttpClient client ) + { + if (colleagueApiUrl == null || colleagueApiUsername == null + || colleagueApiPassword == null || colleagueApiPassword == null) + { + throw new ArgumentNullException($"Colleague API URL and Credentials are required."); + } + if (client == null) + { + throw new ArgumentNullException($"The '{nameof(client)}' parameter is required."); + } + + ColleagueApiUrl = colleagueApiUrl; + ColleagueApiUsername = colleagueApiUsername; + ColleagueApiPassword = colleagueApiPassword; + Client = client; + } + + #region Strongly Typed GET + + /// + /// Gets a page of data for the given resource by name and version with the given filter. + /// + /// Type to be included in the returned specified by caller. + /// The name of the resource to get data for. + /// The string resource filter in JSON format contained in the URL, e.g:
?criteria={"names":[{"firstName":"John"}]}
+ /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// An EthosResponse containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + /// Returns exception if the resourceName is null. + /// Returns exception if the criteriaFilterStr is null. + /// Returns exception if the request fails. + public async Task GetWithCriteriaFilterAsync( string resourceName, string criteriaFilterStr, string version = "" ) where T : class + { + var response = await GetWithCriteriaFilterAsync( resourceName, version, criteriaFilterStr ); + return ConvertEthosResponseContentToType( response ); + } + + /// + /// Gets a page of data for the given resource by name and version with the given filter. + /// + /// Type to be included in the returned specified by caller. + /// The name of the resource to get data for. + /// A previously built Criteria containing the filter criteria used in the request URL. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// A simple call to criteriaFilter.BuildCriteria() should output the criteria filter portion of the request URL, + /// e.g: ?criteria={"names":[{"firstName":"John"}]}. + /// An EthosResponse containing an initial page (EthosResponse content) of resource data according to the requested version and filter of the resource. + /// to the requested version and filter of the resource. + /// Throws if the given criteriaFilter is null. + public async Task GetWithCriteriaFilterAsync( string resourceName, CriteriaFilter criteria, string version = "" ) where T : class + { + var response = await GetWithCriteriaFilterAsync( resourceName, version, criteria.BuildCriteria() ); + return ConvertEthosResponseContentToType( response ); + } + + /// + /// Convenience method to submit a GET request with a single set of criteria filter. This is intended only to be used + /// for a single set of criteria filter, e.g: ?criteria={"names":[{"firstName":"John"}]}, where names is the + /// criteriaSetName, firstName is the criteriaKey, and John is the criteriaValue. Requests requiring + /// a more complex criteria filter should first build the Criteria with the necessary criteria, and then call + /// getWithCriteriaFilterAsync(resourceName, version, criteriaFilter). + ///

The parameters criteriaSetName, criteriaKey, and criteriaValue should only specify the values within quotes of the + /// JSON filter syntax. No JSON syntax (square or angeled braces, etc) should be contained within those parameter values.

+ ///
+ /// Type to be included in the returned specified by caller. + /// The name of the resource to get data for. + /// The name of the criteria set that the given criteriaKey and criteriaValue are associated with, + /// e.g: "names":[{"firstName":"John"}]}, where names is the criteriaSetName associated to the + /// criteriaKey (firstName) and criteriaValue (John). + /// The JSON label key for the criteria. + /// The value associated with the criteriaKey. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// An EthosResponse containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + /// Returns exception if the resourceName or criteriaSetName or criteriaKey or criteriaValue is null. + public async Task GetWithSimpleCriteriaValuesAsync( string resourceName, string criteriaSetName, string criteriaKey, string criteriaValue, string version = "" ) where T : class + { + var response = await GetWithSimpleCriteriaValuesAsync( resourceName, version, criteriaSetName, criteriaKey, criteriaValue ); + return ConvertEthosResponseContentToType( response ); + } + + /// + /// Gets a page of data for the given resource by name and version with the given filter. + /// + /// Type to be included in the returned specified by caller. + /// The name of the resource to get data for. + /// The string resource filter in JSON format contained in the URL. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// An EthosResponse containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + /// Returns exception if the resourceName is null. + /// Returns exception if the namedQuery is null. + /// Returns exception if the request fails. + public async Task GetWithNamedQueryFilterAsync( string resourceName, string namedQueryFilterStr, string version = "" ) where T : class + { + var response = await GetWithNamedQueryFilterAsync( resourceName, version, namedQueryFilterStr ); + return ConvertEthosResponseContentToType( response ); + } + + /// + /// Gets a page of data for the given resource by name and version with the given filter. + /// + /// Type to be included in the returned specified by caller. + /// The name of the resource to get data for. + /// A previously built namedQueryFilter containing the filter used in the request URL. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// A simple call to namedQueryFilter.BuildNamedQuery() should output the named query portion of the request URL. + /// An EthosResponse containing an initial page (EthosResponse content) of resource data according to the requested version and filter of the resource. + /// to the requested version and filter of the resource. + /// Throws if the given criteriaFilter is null. + public async Task GetWithNamedQueryFilterAsync( string resourceName, NamedQueryFilter namedQueryFilter, string version = "" ) where T : class + { + var response = await GetWithNamedQueryFilterAsync( resourceName, version, namedQueryFilter.BuildNamedQuery() ); + return ConvertEthosResponseContentToType( response ); + } + + /// + /// Submits a GET request for the given resource and version using the given filterMapStr. The filterMapStr + /// is intended to support the filter syntax for resources versions 7 and older. An example of a filterMapStr is: + /// ?firstName=James. + ///

This is NOT intended to be used for resource versions after version 7 and/or for criteria filters.

+ ///
+ /// Type to be included in the returned specified by caller. + /// The name of the resource to get data for. + /// A string containing the filter syntax used for request URL filters with resource versions 7 or older. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// An EthosResponse containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + /// Returns exception if the resourceName or filterMapStr is null. + public async Task GetWithFilterMapAsync( string resourceName, string filterMapStr, string version = "" ) where T : class + { + var response = await GetWithFilterMapAsync( resourceName, version, filterMapStr ); + return ConvertEthosResponseContentToType( response ); + } + + /// + /// Submits a GET request for the given resource and version using the given filterMap. The filterMap + /// is intended to support the filter syntax for resources versions 7 and older. A FilterMap contains a map of + /// one or many filter parameter pair(s). An example of a filterMap string indicating the contents of the map is: + /// ?firstName=James. + ///

This is NOT intended to be used for resource versions after version 7 and/or for criteria filters.

+ ///
+ /// Type to be included in the returned specified by caller. + /// The name of the resource to get data for. + /// A string containing the filter syntax used for request URL filters with resource versions 7 or older. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// An EthosResponse containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + /// Returns exception if the resourceName or filterMap is null. + public async Task GetWithFilterMapAsync( string resourceName, FilterMap filterMap, string version = "" ) where T : class + { + var response = await GetWithFilterMapAsync( resourceName, version, filterMap.ToString() ); + return ConvertEthosResponseContentToType( response ); + } + + /// + /// Gets all the pages for a given resource using the specified criteria filter and page size for the given version. + /// + /// Type to be included in the returned specified by caller. + /// The name of the resource to get data for. + /// A previously built Criteria containing the filter criteria used in the request URL. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// The size (number of rows) of each page returned in the list. + /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + public async Task> GetPagesWithCriteriaFilterAsync( string resourceName, CriteriaFilter criteria, string version = "", int pageSize = 0 ) where T : class + { + var response = await GetPagesWithCriteriaFilterAsync( resourceName, version, criteria, pageSize ); + return ConvertEthosResponseContentListToType( response ); + } + + /// + /// Gets all the pages for a given resource using the specified namedQueryFilter filter and page size for the given version. + /// + /// Type to be included in the returned specified by caller. + /// The name of the resource to get data for. + /// A previously built namedQueryFilter containing the filter named query used in the request URL. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// The size (number of rows) of each page returned in the list. + /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + public async Task> GetPagesWithNamedQueryFilterAsync( string resourceName, NamedQueryFilter namedQueryFilter, string version = "", int pageSize = 0 ) where T : class + { + var response = await GetPagesWithNamedQueryFilterAsync( resourceName, version, namedQueryFilter, pageSize ); + return ConvertEthosResponseContentListToType( response ); + } + + /// + /// Gets all the pages for a given resource beginning at the given offset index, using the specified criteria filter + /// and page size for the given version. + /// + /// Type to be included in the returned specified by caller. + /// The name of the resource to get data for. + /// A previously built Criteria containing the filter criteria used in the request URL. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// The size (number of rows) of each page returned in the list. + /// The 0 based index from which to begin paging for the given resource. + /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + /// Returns exception if the resourceName or criteriaFilter is null. + public async Task> GetPagesFromOffsetWithCriteriaFilterAsync( string resourceName, CriteriaFilter criteria, string version = "", int pageSize = 0, int offset = 0 ) where T : class + { + var response = await GetPagesFromOffsetWithCriteriaFilterAsync( resourceName, version, criteria, pageSize, offset ); + return ConvertEthosResponseContentListToType( response ); + } + + /// + /// Gets all the pages for a given resource beginning at the given offset index, using the specified namedQueryFilter + /// and page size for the given version. + /// + /// Type to be included in the returned specified by caller. + /// The name of the resource to get data for. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// A previously built namedQueryFilter containing the filter used in the request URL. + /// The size (number of rows) of each page returned in the list. + /// The 0 based index from which to begin paging for the given resource. + /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + /// Returns exception if the resourceName or namedQueryFilter is null. + public async Task> GetPagesFromOffsetWithNamedQueryFilterAsync( string resourceName, NamedQueryFilter namedQueryFilter, string version = "", int pageSize = 0, int offset = 0 ) where T : class + { + var response = await GetPagesFromOffsetWithNamedQueryFilterAsync( resourceName, version, namedQueryFilter, pageSize, offset ); + return ConvertEthosResponseContentListToType( response ); + } + + /// + /// Gets all the pages for a given resource using the specified filter map and page size for the given version. + /// + /// Type to be included in the returned specified by caller. + /// The name of the resource to get data for. + /// A previously built FilterMap containing the filter parameters used in the request URL. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// A simple call to filterMap.tostring() should output the criteria filter portion of the request URL, + /// e.g: ?firstName=John&lastName=Smith. + /// The size (number of rows) of each page returned in the list. + /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + public async Task> GetPagesWithFilterMapAsync( string resourceName, FilterMap filterMap, string version = "", int pageSize = 0 ) where T : class + { + var response = await GetPagesWithFilterMapAsync( resourceName, version, filterMap, pageSize ); + return ConvertEthosResponseContentListToType( response ); + } + + /// + /// Gets all the pages for a given resource beginning at the given offset index, using the specified filter map and + /// page size for the given version. + /// + /// Type to be included in the IEnumerable<> returned specified by caller. + /// The name of the resource to get data for. + /// A previously built FilterMap containing the filter parameters used in the request URL. + /// A simple call to filterMap.tostring() should output the criteria filter portion of the request URL, + /// e.g: ?firstName=John&lastName=Smith. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// The size (number of rows) of each page returned in the list. + /// The 0 based index from which to begin paging for the given resource. + /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + public async Task> GetPagesFromOffsetWithFilterMapAsync( string resourceName, FilterMap filterMap, string version = "", int pageSize = 0, int offset = 0 ) where T : class + { + var response = await GetPagesFromOffsetWithFilterMapAsync( resourceName, version, filterMap, pageSize, offset ); + return ConvertEthosResponseContentListToType( response ); + } + + #endregion Strongly Typed + + /// + /// Gets a page of data for the given resource with the given filter. Uses the default version of the resource. + /// Makes a non-filter API request if the given criteriaFilterStr is null or blank. + /// + /// The name of the resource to get data for. + /// The string resource filter in JSON format contained in the URL, e.g:
?criteria={"names":[{"firstName":"John"}]}
+ /// An EthosResponse containing an initial page (EthosResponse content) of resource data according to the requested version and filter of the resource. + /// to the requested version and filter of the resource. + public async Task GetWithCriteriaFilterAsync( string resourceName, string criteriaFilterStr ) + { + return await GetWithCriteriaFilterAsync( resourceName, DEFAULT_VERSION, criteriaFilterStr ); + } + + /// + /// Gets a page of data for the given resource with the given filter. Uses the default version of the resource. + /// Makes a non-filter API request if the given namedQueryFilterStr is null or blank. + /// + /// The name of the resource to get data for. + /// The string resource filter in JSON format contained in the URL, e.g:
?criteria={"names":[{"firstName":"John"}]}
+ /// An EthosResponse containing an initial page (EthosResponse content) of resource data according to the requested version and filter of the resource. + /// to the requested version and filter of the resource. + public async Task GetWithNamedQueryFilterAsync( string resourceName, string namedQueryFilterStr ) + { + return await GetWithNamedQueryFilterAsync( resourceName, DEFAULT_VERSION, namedQueryFilterStr ); + } + + /// + /// Gets a page of data for the given resource by name and version with the given filter. + /// + /// The name of the resource to get data for. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// The string resource filter in JSON format contained in the URL, e.g:
?criteria={"names":[{"firstName":"John"}]}
+ /// An EthosResponse containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + /// Returns exception if the resourceName is null. + /// Returns exception if the criteriaFilterStr is null. + /// Returns exception if the request fails. + public async Task GetWithCriteriaFilterAsync( string resourceName, string version, string criteriaFilterStr ) + { + if ( string.IsNullOrWhiteSpace( resourceName ) ) + { + throw new ArgumentNullException( "Error: Cannot get resource with criteria filter due to a null or blank resource name." ); + } + if ( string.IsNullOrWhiteSpace( criteriaFilterStr ) ) + { + throw new ArgumentNullException( $"Error: Cannot get resource '{resourceName}' with criteria filter due to a null or blank criteria filter string." ); + } + return await GetEthosResponseAsync( resourceName, version, criteriaFilterStr ); + } + + /// + /// Gets a page of data for the given resource by name and version with the given filter. + /// + /// The name of the resource to get data for. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// The string resource filter in JSON format contained in the URL. + /// An EthosResponse containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + /// Returns exception if the resourceName is null. + /// Returns exception if the namedQuery is null. + /// Returns exception if the request fails. + public async Task GetWithNamedQueryFilterAsync( string resourceName, string version, string namedQueryFilterStr ) + { + if ( string.IsNullOrWhiteSpace( resourceName ) ) + { + throw new ArgumentNullException( "Error: Cannot get resource with criteria filter due to a null or blank resource name." ); + } + if ( string.IsNullOrWhiteSpace( namedQueryFilterStr ) ) + { + throw new ArgumentNullException( $"Error: Cannot get resource '{resourceName}' with named query due to a null or blank named query string." ); + } + return await GetEthosResponseAsync( resourceName, version, namedQueryFilterStr ); + } + + /// + /// Gets Ethos Response. + /// + /// The name of the resource to get data for. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// This can be CriteriaFilter or NamedQuery. + /// An EthosResponse containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + private async Task GetEthosResponseAsync( string resourceName, string version, string criteria ) + { + var filterStr = EncodeString( criteria ); + Dictionary headers = BuildHeadersMap( version ); + EthosResponse response = await GetAsync( headers, EthosIntegrationUrls.ApiFilter( Region, resourceName, filterStr ) ); + return response; + } + + /// + /// Gets a page of data for the given resource by name with the given filter. Uses the default version of the resource. + /// Makes a non-filter API request if the given criteriaFilter is null. + /// A simple call to criteriaFilter.BuildCriteria() should output the criteria filter portion of the request URL, + /// e.g: ?criteria={"names":[{"firstName":"John"}]}. + /// + /// The name of the resource to get data for. + /// A previously built Criteria containing the filter criteria used in the request URL. + /// A simple call to criteriaFilter.BuildCriteria() should output the criteria filter portion of the request URL, + /// e.g: ?criteria={"names":[{"firstName":"John"}]}. + /// An EthosResponse containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + public async Task GetWithCriteriaFilterAsync( string resourceName, CriteriaFilter criteria ) + { + return await GetWithCriteriaFilterAsync( resourceName, DEFAULT_VERSION, criteria.BuildCriteria() ); + } + + /// + /// Gets a page of data for the given resource by name and version with the given filter. + /// + /// The name of the resource to get data for. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// A previously built Criteria containing the filter criteria used in the request URL. + /// A simple call to criteriaFilter.BuildCriteria() should output the criteria filter portion of the request URL, + /// e.g: ?criteria={"names":[{"firstName":"John"}]}. + /// An EthosResponse containing an initial page (EthosResponse content) of resource data according to the requested version and filter of the resource. + /// to the requested version and filter of the resource. + /// Throws if the given criteriaFilter is null. + public async Task GetWithCriteriaFilterAsync( string resourceName, string version, CriteriaFilter criteria ) + { + if ( criteria == null ) + { + throw new ArgumentNullException( $"Error: Cannot get resource '{ resourceName }' with criteria filter due to a null criteria filter reference." ); + } + return await GetWithCriteriaFilterAsync( resourceName, version, criteria.BuildCriteria() ); + } + + /// + /// Gets a page of data for the given resource by name with the given filter. Uses the default version of the resource. + /// Makes a non-filter API request if the given criteriaFilter is null. + /// A simple call to criteriaFilter.BuildCriteria() should output the criteria filter portion of the request URL. + /// + /// The name of the resource to get data for. + /// A previously built namedQueryFilter containing the filter used in the request URL. + /// A simple call to namedQueryFilter.BuildNamedQuery() should output the criteria filter portion of the request URL, + /// e.g: ?criteria={"names":[{"firstName":"John"}]}. + /// An EthosResponse containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + public async Task GetWithNamedQueryFilterAsync( string resourceName, NamedQueryFilter namedQueryFilter ) + { + return await GetWithNamedQueryFilterAsync( resourceName, DEFAULT_VERSION, namedQueryFilter ); + } + + /// + /// Gets a page of data for the given resource by name and version with the given filter. + /// + /// The name of the resource to get data for. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// A previously built namedQueryFilter containing the filter used in the request URL. + /// A simple call to namedQueryFilter.BuildNamedQuery() should output the named query portion of the request URL. + /// An EthosResponse containing an initial page (EthosResponse content) of resource data according to the requested version and filter of the resource. + /// to the requested version and filter of the resource. + /// Throws if the given criteriaFilter is null. + public async Task GetWithNamedQueryFilterAsync( string resourceName, string version, NamedQueryFilter namedQueryFilter ) + { + if ( namedQueryFilter == null ) + { + throw new ArgumentNullException( $"Error: Cannot get resource '{ resourceName }' with named query due to a null named query reference." ); + } + return await GetWithNamedQueryFilterAsync( resourceName, version, namedQueryFilter.BuildNamedQuery() ); + } + + /// + /// Convenience method to submit a GET request with a single set of criteria filter. This is intended only to be used + /// for a single set of criteria filter, e.g: ?criteria={"names":[{"firstName":"John"}]}, where names is the + /// criteriaSetName, firstName is the criteriaKey, and John is the criteriaValue. Requests requiring + /// a more complex criteria filter should first build the Criteria with the necessary criteria, and then call + /// getWithCriteriaFilterAsync(resourceName, criteriaFilter). + ///

The parameters criteriaSetName, criteriaKey, and criteriaValue should only specify the values within quotes of the + /// JSON filter syntax. No JSON syntax (square or angeled braces etc.) should be contained within those parameter values.

+ ///

Uses the default version of the resource.

+ ///
+ /// The name of the resource to get data for. + /// The name of the criteria set that the given criteriaKey and criteriaValue are associated with, + /// e.g: "names":[{"firstName":"John"}]}, where names is the criteriaSetName associated to the + /// criteriaKey (firstName) and criteriaValue (John). + /// The JSON label key for the criteria. + /// The value associated with the criteriaKey. + /// An EthosResponse containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + public async Task GetWithSimpleCriteriaValuesAsync( string resourceName, string criteriaSetName, string criteriaKey, string criteriaValue ) + { + return await GetWithSimpleCriteriaValuesAsync( resourceName, DEFAULT_VERSION, criteriaSetName, criteriaKey, criteriaValue ); + } + + /// + /// Convenience method to submit a GET request with a single set of criteria filter. This is intended only to be used + /// for a single set of criteria filter, e.g: ?criteria={"names":[{"firstName":"John"}]}, where names is the + /// criteriaSetName, firstName is the criteriaKey, and John is the criteriaValue. Requests requiring + /// a more complex criteria filter should first build the Criteria with the necessary criteria, and then call + /// getWithCriteriaFilterAsync(resourceName, version, criteriaFilter). + ///

The parameters criteriaSetName, criteriaKey, and criteriaValue should only specify the values within quotes of the + /// JSON filter syntax. No JSON syntax (square or angeled braces, etc) should be contained within those parameter values.

+ ///
+ /// The name of the resource to get data for. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// The name of the criteria set that the given criteriaKey and criteriaValue are associated with, + /// e.g: "names":[{"firstName":"John"}]}, where names is the criteriaSetName associated to the + /// criteriaKey (firstName) and criteriaValue (John). + /// The JSON label key for the criteria. + /// The value associated with the criteriaKey. + /// An EthosResponse containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + /// Returns exception if the resourceName or criteriaSetName or criteriaKey or criteriaValue is null. + public async Task GetWithSimpleCriteriaValuesAsync( string resourceName, string version, string criteriaSetName, string criteriaKey, string criteriaValue ) + { + if ( string.IsNullOrWhiteSpace( resourceName ) ) + { + throw new ArgumentNullException( "Error: Cannot get resource with filter map due to a null or blank resource name." ); + } + if ( string.IsNullOrWhiteSpace( criteriaSetName ) ) + { + throw new ArgumentNullException( "Error: Cannot get resource due to a null or empty criteria set name parameter." ); + } + if ( string.IsNullOrWhiteSpace( criteriaKey ) ) + { + throw new ArgumentNullException( "Error: Cannot get resource due to a null or empty criteria key parameter." ); + } + if ( string.IsNullOrWhiteSpace( criteriaValue ) ) + { + throw new ArgumentNullException( "Error: Cannot get resource due to a null or empty criteria value parameter." ); + } + var criteriaFilter = new CriteriaFilter().WithSimpleCriteria( criteriaSetName, (criteriaKey, criteriaValue) ) + .BuildCriteria(); + return await GetWithCriteriaFilterAsync( resourceName, version, criteriaFilter ); + } + + /// + /// Submits a GET request for the given resource and version using the given filterMapStr. The filterMapStr + /// is intended to support the filter syntax for resources versions 7 and older. An example of a filterMapStr is: + /// ?firstName=James. + ///

This is NOT intended to be used for resource versions after version 7 and/or for criteria filters.

+ ///
+ /// The name of the resource to get data for. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// A string containing the filter syntax used for request URL filters with resource versions 7 or older. + /// An EthosResponse containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + /// Returns exception if the resourceName or filterMapStr is null. + public async Task GetWithFilterMapAsync( string resourceName, string version, string filterMapStr ) + { + if ( string.IsNullOrWhiteSpace( resourceName ) ) + { + throw new ArgumentNullException( "Error: Cannot get resource with filter map due to a null or blank resource name." ); + } + if ( string.IsNullOrWhiteSpace( filterMapStr ) ) + { + throw new ArgumentNullException( $"Error: Cannot get resource '{ resourceName }' with filter map due to a null or blank filter map string." ); + } + Dictionary headers = BuildHeadersMap( version ); + EthosResponse response = await GetAsync( headers, EthosIntegrationUrls.ApiFilter( Region, resourceName, filterMapStr ) ); + return response; + } + + /// + /// Submits a GET request for the given resource and version using the given filterMap. The filterMap + /// is intended to support the filter syntax for resources versions 7 and older. A FilterMap contains a map of + /// one or many filter parameter pair(s). An example of a filterMap string indicating the contents of the map is: + /// ?firstName=James. + ///

This is NOT intended to be used for resource versions after version 7 and/or for criteria filters.

+ ///
+ /// The name of the resource to get data for. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// A string containing the filter syntax used for request URL filters with resource versions 7 or older. + /// An EthosResponse containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + /// Returns exception if the resourceName or filterMap is null. + public async Task GetWithFilterMapAsync( string resourceName, string version, FilterMap filterMap ) + { + ArgumentNullException.ThrowIfNull( filterMap, $"Error: Cannot get resource '{resourceName}' with filter map due to a null filter map." ); + return await GetWithFilterMapAsync( resourceName, version, filterMap.ToString() ); + } + + /// + /// Gets all the pages for a given resource using the specified criteria filter. Uses the default version of the resource, + /// and the page size is derived from the length of the returned response of the request using the criteria filter. + /// + /// The name of the resource to get data for. + /// A previously built Criteria containing the filter criteria used in the request URL. + /// A simple call to criteriaFilter.BuildCriteria() should output the criteria filter portion of the request URL, + /// e.g: ?criteria={"names":[{"firstName":"John"}]}. + /// An EthosResponse containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + public async Task> GetPagesWithCriteriaFilterAsync( string resourceName, CriteriaFilter criteria ) + { + return await GetPagesWithCriteriaFilterAsync( resourceName, DEFAULT_VERSION, criteria, DEFAULT_PAGE_SIZE ); + } + + /// + /// Gets all the pages for a given resource using the specified criteria filter for the given version. Uses the default + /// page size, which is the length of the returned response of the request using the criteria filter. + /// + /// The name of the resource to get data for. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// A previously built Criteria containing the filter criteria used in the request URL. + /// An EthosResponse containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + public async Task> GetPagesWithCriteriaFilterAsync( string resourceName, string version, CriteriaFilter criteria ) + { + return await GetPagesWithCriteriaFilterAsync( resourceName, version, criteria, DEFAULT_PAGE_SIZE ); + } + + /// + /// Gets all the pages for a given resource using the specified namedQueryFilter filter. Uses the default version of the resource, + /// and the page size is derived from the length of the returned response of the request using the namedQueryFilter filter. + /// + /// The name of the resource to get data for. + /// A previously built namedQueryFilter containing the filter used in the request URL. + /// A simple call to namedQueryFilter.BuildNamedQuery() should output the namedQueryFilter filter portion of the request URL. + /// An EthosResponse containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + public async Task> GetPagesWithNamedQueryFilterAsync( string resourceName, NamedQueryFilter namedQueryFilter ) + { + return await GetPagesWithNamedQueryFilterAsync( resourceName, DEFAULT_VERSION, namedQueryFilter, DEFAULT_PAGE_SIZE ); + } + + /// + /// Gets all the pages for a given resource using the specified namedQueryFilter filter for the given version. Uses the default + /// page size, which is the length of the returned response of the request using the namedQueryFilter filter. + /// + /// The name of the resource to get data for. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// A previously built namedQueryFilter containing the filter used in the request URL. + /// An EthosResponse containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + public async Task> GetPagesWithNamedQueryFilterAsync( string resourceName, string version, NamedQueryFilter namedQueryFilter ) + { + return await GetPagesWithNamedQueryFilterAsync( resourceName, version, namedQueryFilter, DEFAULT_PAGE_SIZE ); + } + + /// + /// Gets all the pages for a given resource using the specified criteria filter and page size. The default version + /// of the resource is used. + /// + /// The name of the resource to get data for. + /// A previously built Criteria containing the filter criteria used in the request URL. + /// The size (number of rows) of each page returned in the list. + /// An EthosResponse containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + public async Task> GetPagesWithCriteriaFilterAsync( string resourceName, CriteriaFilter criteria, int pageSize ) + { + return await GetPagesWithCriteriaFilterAsync( resourceName, DEFAULT_VERSION, criteria, pageSize ); + } + + /// + /// Gets all the pages for a given resource using the specified criteria filter and page size for the given version. + /// + /// The name of the resource to get data for. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// A previously built Criteria containing the filter criteria used in the request URL. + /// The size (number of rows) of each page returned in the list. + /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + public async Task> GetPagesWithCriteriaFilterAsync( string resourceName, string version, CriteriaFilter criteria, int pageSize ) + { + return await GetPagesFromOffsetWithCriteriaFilterAsync( resourceName, version, criteria, pageSize, 0 ); + } + + /// + /// Gets all the pages for a given resource using the specified namedQueryFilter filter and page size. The default version + /// of the resource is used. + /// + /// The name of the resource to get data for. + /// A previously built namedQueryFilter containing the filter used in the request URL. + /// The size (number of rows) of each page returned in the list. + /// An EthosResponse containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + public async Task> GetPagesWithNamedQueryFilterAsync( string resourceName, NamedQueryFilter namedQueryFilter, int pageSize ) + { + return await GetPagesWithNamedQueryFilterAsync( resourceName, DEFAULT_VERSION, namedQueryFilter, pageSize ); + } + + /// + /// Gets all the pages for a given resource using the specified namedQueryFilter filter and page size for the given version. + /// + /// The name of the resource to get data for. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// A previously built namedQueryFilter containing the filter named query used in the request URL. + /// The size (number of rows) of each page returned in the list. + /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + public async Task> GetPagesWithNamedQueryFilterAsync( string resourceName, string version, NamedQueryFilter namedQueryFilter, int pageSize ) + { + return await GetPagesFromOffsetWithNamedQueryFilterAsync( resourceName, version, namedQueryFilter, pageSize, 0 ); + } + + /// + /// Gets all the pages for a given resource beginning at the given offset index, using the specified criteria filter. + /// The page size is determined to be the length of the returned response of the request using the criteria filter. + /// The default version of the resource is used. + /// + /// The name of the resource to get data for. + /// A previously built Criteria containing the filter criteria used in the request URL. + /// The 0 based index from which to begin paging for the given resource. + /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + public async Task> GetPagesFromOffsetWithCriteriaFilterAsync( string resourceName, CriteriaFilter criteria, int offset ) + { + return await GetPagesFromOffsetWithCriteriaFilterAsync( resourceName, DEFAULT_VERSION, criteria, offset ); + } + + /// + /// Gets all the pages for a given resource beginning at the given offset index, using the specified criteria filter + /// for the given version. The page size is determined to be the length of the returned response of the request using + /// the criteria filter. + /// + /// The name of the resource to get data for. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// A previously built Criteria containing the filter criteria used in the request URL. + /// The 0 based index from which to begin paging for the given resource. + /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + public async Task> GetPagesFromOffsetWithCriteriaFilterAsync( string resourceName, string version, CriteriaFilter criteria, int offset ) + { + return await GetPagesFromOffsetWithCriteriaFilterAsync( resourceName, version, criteria, DEFAULT_PAGE_SIZE, offset ); + } + + /// + /// Gets all the pages for a given resource beginning at the given offset index, using the specified namedQueryFilter filter. + /// The page size is determined to be the length of the returned response of the request using the namedQueryFilter filter. + /// The default version of the resource is used. + /// + /// The name of the resource to get data for. + /// + /// The 0 based index from which to begin paging for the given resource. + /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + public async Task> GetPagesFromOffsetWithNamedQueryFilterAsync( string resourceName, NamedQueryFilter namedQueryFilter, int offset ) + { + return await GetPagesFromOffsetWithNamedQueryFilterAsync( resourceName, DEFAULT_VERSION, namedQueryFilter, offset ); + } + + /// + /// Gets all the pages for a given resource beginning at the given offset index, using the specified namedQueryFilter filter + /// for the given version. The page size is determined to be the length of the returned response of the request using + /// the namedQueryFilter filter. + /// + /// The name of the resource to get data for. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// A previously built namedQueryFilter containing the filter used in the request URL. + /// The 0 based index from which to begin paging for the given resource. + /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + public async Task> GetPagesFromOffsetWithNamedQueryFilterAsync( string resourceName, string version, NamedQueryFilter namedQueryFilter, int offset ) + { + return await GetPagesFromOffsetWithNamedQueryFilterAsync( resourceName, version, namedQueryFilter, DEFAULT_PAGE_SIZE, offset ); + } + + /// + /// Gets all the pages for a given resource beginning at the given offset index, using the specified criteria filter + /// and page size for the given version. The default version of the resource is used. + /// + /// The name of the resource to get data for. + /// A previously built Criteria containing the filter criteria used in the request URL. + /// The size (number of rows) of each page returned in the list. + /// The 0 based index from which to begin paging for the given resource. + /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + public async Task> GetPagesFromOffsetWithCriteriaFilterAsync( string resourceName, CriteriaFilter criteria, int pageSize, int offset ) + { + return await GetPagesFromOffsetWithCriteriaFilterAsync( resourceName, DEFAULT_VERSION, criteria, pageSize, offset ); + } + + /// + /// Gets all the pages for a given resource beginning at the given offset index, using the specified criteria filter + /// and page size for the given version. + /// + /// The name of the resource to get data for. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// A previously built Criteria containing the filter criteria used in the request URL. + /// The size (number of rows) of each page returned in the list. + /// The 0 based index from which to begin paging for the given resource. + /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + /// Returns exception if the resourceName or criteriaFilter is null. + public async Task> GetPagesFromOffsetWithCriteriaFilterAsync( string resourceName, string version, CriteriaFilter criteria, int pageSize, int offset ) + { + if ( string.IsNullOrWhiteSpace( resourceName ) ) + { + throw new ArgumentNullException( "Error: Cannot get pages of resource from offset with criteria filter due to a null or blank resource name." ); + } + if ( criteria == null ) + { + throw new ArgumentNullException( $"Error: Cannot get pages of resource '{ resourceName }' from offset with criteria filter due to a null criteria filter reference." ); + } + List ethosResponseList = new List(); + Pager pager = Pager.Build( pg => + { + pg + .ForResource( resourceName ) + .ForVersion( version ) + .WithCriteriaFilter( criteria.BuildCriteria() ) + .WithPageSize( pageSize ) + .FromOffSet( offset ); + } ); + + pager = await PrepareForPagingAsync( pager ); + pager = ShouldDoPaging( pager, false ); + if ( pager.ShouldDoPaging ) + { + ethosResponseList = await DoPagingFromOffsetAsync( pager.ResourceName, pager.Version, pager.CriteriaFilter, pager.TotalCount, pager.PageSize, offset ); + } + else + { + ethosResponseList.Add( await GetWithCriteriaFilterAsync( resourceName, version, criteria ) ); + } + return ethosResponseList; + } + + /// + /// Gets all the pages for a given resource beginning at the given offset index, using the specified namedQueryFilter + /// and page size for the given version. The default version of the resource is used. + /// + /// The name of the resource to get data for. + /// A previously built namedQueryFilter containing the filter used in the request URL. + /// The size (number of rows) of each page returned in the list. + /// The 0 based index from which to begin paging for the given resource. + /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + public async Task> GetPagesFromOffsetWithNamedQueryFilterAsync( string resourceName, NamedQueryFilter namedQueryFilter, int pageSize, int offset ) + { + return await GetPagesFromOffsetWithNamedQueryFilterAsync( resourceName, DEFAULT_VERSION, namedQueryFilter, pageSize, offset ); + } + + /// + /// Gets all the pages for a given resource beginning at the given offset index, using the specified namedQueryFilter + /// and page size for the given version. + /// + /// The name of the resource to get data for. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// A previously built namedQueryFilter containing the filter used in the request URL. + /// The size (number of rows) of each page returned in the list. + /// The 0 based index from which to begin paging for the given resource. + /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + /// Returns exception if the resourceName or namedQueryFilter is null. + public async Task> GetPagesFromOffsetWithNamedQueryFilterAsync( string resourceName, string version, NamedQueryFilter namedQueryFilter, int pageSize, int offset ) + { + if ( string.IsNullOrWhiteSpace( resourceName ) ) + { + throw new ArgumentNullException( "Error: Cannot get pages of resource from offset with named query filter due to a null or blank resource name." ); + } + if ( namedQueryFilter == null ) + { + throw new ArgumentNullException( $"Error: Cannot get pages of resource '{ resourceName }' from offset with named query filter due to a null named query filter reference." ); + } + List ethosResponseList = new List(); + Pager pager = Pager.Build( pg => + { + pg + .ForResource( resourceName ) + .ForVersion( version ) + .WithNamedQuery( namedQueryFilter.BuildNamedQuery() ) + .WithPageSize( pageSize ) + .FromOffSet( offset ); + } ); + + pager = await PrepareForPagingAsync( pager ); + pager = ShouldDoPaging( pager, false ); + if ( pager.ShouldDoPaging ) + { + ethosResponseList = await DoPagingFromOffsetAsync( pager.ResourceName, pager.Version, pager.NamedQueryFilter, pager.TotalCount, pager.PageSize, offset ); + } + else + { + ethosResponseList.Add( await GetWithNamedQueryFilterAsync( resourceName, version, namedQueryFilter ) ); + } + return ethosResponseList; + } + + /// + /// Gets all the pages for a given resource using the specified filter map and page size for the given version. + /// + /// The name of the resource to get data for. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// A previously built FilterMap containing the filter parameters used in the request URL. + /// A simple call to filterMap.tostring() should output the criteria filter portion of the request URL, + /// e.g: ?firstName=John&lastName=Smith. + /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + public async Task> GetPagesWithFilterMapAsync( string resourceName, string version, FilterMap filterMap ) + { + return await GetPagesWithFilterMapAsync( resourceName, version, filterMap, DEFAULT_PAGE_SIZE ); + } + + /// + /// Gets all the pages for a given resource using the specified filter map and page size for the given version. + /// + /// The name of the resource to get data for. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// A previously built FilterMap containing the filter parameters used in the request URL. + /// A simple call to filterMap.tostring() should output the criteria filter portion of the request URL, + /// e.g: ?firstName=John&lastName=Smith. + /// The size (number of rows) of each page returned in the list. + /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + public async Task> GetPagesWithFilterMapAsync( string resourceName, string version, FilterMap filterMap, int pageSize ) + { + return await GetPagesFromOffsetWithFilterMapAsync( resourceName, version, filterMap, pageSize, 0 ); + } + + /// + /// Gets all the pages for a given resource beginning at the given offset index, using the specified filter map and + /// page size for the given version. The page size is determined to be the length of the returned response of the request using + /// the filter map. + /// + /// The name of the resource to get data for. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// A previously built FilterMap containing the filter parameters used in the request URL. + /// A simple call to filterMap.tostring() should output the criteria filter portion of the request URL, + /// e.g: ?firstName=John&lastName=Smith. + /// The 0 based index from which to begin paging for the given resource. + /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + public async Task> GetPagesFromOffsetWithFilterMapAsync( string resourceName, string version, FilterMap filterMap, int offset ) + { + return await GetPagesFromOffsetWithFilterMapAsync( resourceName, version, filterMap, DEFAULT_PAGE_SIZE, offset ); + } + + /// + /// Gets all the pages for a given resource beginning at the given offset index, using the specified filter map and + /// page size for the given version. + /// + /// The name of the resource to get data for. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// A previously built FilterMap containing the filter parameters used in the request URL. + /// A simple call to filterMap.tostring() should output the criteria filter portion of the request URL, + /// e.g: ?firstName=John&lastName=Smith. + /// The size (number of rows) of each page returned in the list. + /// The 0 based index from which to begin paging for the given resource. + /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according + /// to the requested version and filter of the resource. + public async Task> GetPagesFromOffsetWithFilterMapAsync( string resourceName, string version, FilterMap filterMap, int pageSize, int offset ) + { + if ( string.IsNullOrWhiteSpace( resourceName ) ) + { + throw new ArgumentNullException( "Error: Cannot get pages of resource with filter map due to a null or blank resource name." ); + } + if ( filterMap == null ) + { + throw new ArgumentNullException( $"Error: Cannot get pages of resource '{ resourceName }' with filter map due to a null filter map reference." ); + } + List ethosResponseList = new List(); + Pager pager = Pager.Build( pg => + { + pg + .ForResource( resourceName ) + .ForVersion( version ) + .WithFilterMap( filterMap.ToString() ) + .WithPageSize( pageSize ) + .FromOffSet( offset ); + } ); + + pager = await PrepareForPagingAsync( pager ); + pager = ShouldDoPaging( pager, false ); + if ( pager.ShouldDoPaging ) + { + ethosResponseList = await DoPagingFromOffsetAsync( pager.ResourceName, pager.Version, pager.FilterMap, pager.TotalCount, pager.PageSize, offset ); + } + else + { + ethosResponseList.Add( await GetWithFilterMapAsync( resourceName, version, filterMap ) ); + } + return ethosResponseList; + } + + #region QAPI's + + /// + /// Submits a POST request for the given resourceName with the given qapiRequestBody. The qapiRequestBody should be a string in JSON format. + /// + /// The name of the resource to add an instance of. + /// The full version header value of the resource used for this POST request. + /// The body of the request to POST for the given resource. + /// An EthosResponse containing the instance of the resource that was added by this POST operation. + /// When is passed as null or empty or white space. + /// When is passed as null or empty or white space. + public async Task GetWithQapiAsync( string resourceName, string qapiRequestBody, string version = "" ) + { + if ( string.IsNullOrWhiteSpace( resourceName ) ) + { + throw new ArgumentNullException( $"Error: Cannot submit a POST request due to a null or blank {nameof( resourceName )} parameter." ); + } + + if ( string.IsNullOrWhiteSpace( qapiRequestBody ) ) + { + throw new ArgumentNullException( + $"Error: Cannot submit a POST request for resource {resourceName} due to a null or blank {nameof( qapiRequestBody )} parameter." + ); + } + var headers = BuildHeadersMap( version ); + string url = EthosIntegrationUrls.Qapi( Region, resourceName ); + return await base.PostAsync( headers, url, qapiRequestBody ); + } + + /// + /// Submits a POST request for the given resourceName with the given requestBodyNode. The requestBodyNode should be a JObject. + /// + /// The name of the resource to add an instance of. + /// The full version header value of the resource used for this POST request. + /// The body of the request to POST for the given resource as a JsonNode. + /// An EthosResponse containing the instance of the resource that was added by this POST operation. + /// When is passed as null or empty or white space. + /// When is passed as null. + public async Task GetWithQapiAsync( string resourceName, JObject qapiRequestBodyNode, string version = "" ) + { + ArgumentNullException.ThrowIfNull( qapiRequestBodyNode, $"Error: Cannot submit a POST request for resource {resourceName} due to a null {nameof( qapiRequestBodyNode )} parameter." ); + return await GetWithQapiAsync(resourceName, qapiRequestBodyNode.ToString(), version ); + } + + /// + /// Submits a POST request for the given resourceName with the given qapiRequestBody. The qapiRequestBody should be a T type class. + /// + /// Request type. + /// The name of the resource to add an instance of. + /// The full version header value of the resource used for this POST request. + /// The body of the request to POST for the given resource. + /// An EthosResponse containing the instance of the resource that was added by this POST operation. + /// When is passed as null or empty or white space. + /// When is passed as null. + public async Task GetWithQapiAsync( string resourceName, T qapiRequestBody, string version = "" ) where T : class + { + ArgumentNullException.ThrowIfNull( qapiRequestBody, $"Error: Cannot submit a POST request for resource {resourceName} due to a null {nameof( qapiRequestBody )} parameter." ); + + JsonSerializerSettings jsonSerSettings = GetJsonSerializerSettings(); + var reqBody = JsonConvert.SerializeObject( qapiRequestBody, jsonSerSettings ); + return await GetWithQapiAsync( resourceName, reqBody, version ); + } + + /// + /// Gets the total count of resources available using the given criteriaFilter. Gets the pages for a given resource beginning at the given offset index, + /// using the specified QAPI request body and page size for the given version. + /// + /// The name of the resource to add an instance of. + /// The full version header value of the resource used for this POST request. + /// The body of the request to POST for the given resource. + /// The size (number of rows) of each page returned in the list. + /// The 0 based index from which to begin paging for the given resource. + /// A list of EthosResponses where each EthosResponse contains a page of data. If paging is not required based on the + /// given pageSize and total count( from using the filter), the returned list will only contain one EthosResponse. + /// When is passed as null or empty or white space. + /// When is passed as null. + public async Task> GetPagesFromOffsetWithQAPIAsync( string resourceName, string qapiRequestBody, string version = "", int pageSize = 0, int offset = 0) + { + if ( string.IsNullOrWhiteSpace( resourceName ) ) + { + throw new ArgumentNullException( $"Error: Cannot submit a POST request due to a null or blank {nameof( resourceName )} parameter." ); + } + + if ( string.IsNullOrWhiteSpace( qapiRequestBody ) ) + { + throw new ArgumentNullException( $"Error: Cannot submit a POST request for resource {resourceName} due to a null {nameof( qapiRequestBody )} parameter." ); + } + + List ethosResponseList = new(); + Pager pager = Pager.Build( pg => + { + pg + .ForResource( resourceName ) + .ForVersion( version ) + .FromOffSet( offset ) + .WithPageSize( pageSize ) + .WithQAPIRequestBodyFilter( qapiRequestBody ); + } ); + + pager = await PrepareForPagingAsync( pager ); + pager = ShouldDoPaging( pager, false ); + if ( pager.ShouldDoPaging ) + { + ethosResponseList = await DoPagingFromOffsetForQAPIAsync( pager.ResourceName, pager.Version, qapiRequestBody, pager.TotalCount, pager.PageSize, pager.Offset ); + } + else + { + ethosResponseList.Add( await GetWithQapiAsync( resourceName, qapiRequestBody, version ) ); + } + return ethosResponseList; + } + + /// + /// Gets the total count of resources available using the given criteriaFilter. Gets the pages for a given resource beginning at the given offset index, + /// using the specified QAPI request body and page size for the given version. + /// + /// The name of the resource to add an instance of. + /// The full version header value of the resource used for this POST request. + /// The body of the request to POST for the given resource. + /// The size (number of rows) of each page returned in the list. + /// The 0 based index from which to begin paging for the given resource. + /// A list of EthosResponses where each EthosResponse contains a page of data. If paging is not required based on the + /// given pageSize and total count( from using the filter), the returned list will only contain one EthosResponse. + /// When is passed as null or empty or white space. + /// When is passed as null. + public async Task> GetPagesFromOffsetWithQAPIAsync( string resourceName, JObject qapiRequestBody, string version = "", int pageSize = 0, int offset = 0 ) + { + ArgumentNullException.ThrowIfNull( qapiRequestBody, $"Error: Cannot submit a POST request for resource {resourceName} due to a null {nameof( qapiRequestBody )} parameter." ); + return await GetPagesFromOffsetWithQAPIAsync(resourceName, qapiRequestBody.ToString(), version, pageSize, offset ); + } + + /// + /// Gets the total count of resources available using the given type T. + /// Gets the pages for a given resource beginning at the given offset index, using the specified QAPI request body and page size for the given version. + /// + /// Request type. + /// The name of the resource to add an instance of. + /// The full version header value of the resource used for this POST request. + /// The body of the request to POST for the given resource. + /// The size (number of rows) of each page returned in the list. + /// The 0 based index from which to begin paging for the given resource. + /// A list of EthosResponses where each EthosResponse contains a page of data. If paging is not required based on the + /// given pageSize and total count( from using the filter), the returned list will only contain one EthosResponse. + /// When is passed as null or empty or white space. + /// When is passed as null. + public async Task> GetPagesFromOffsetWithQAPIAsync( string resourceName, T qapiRequestBody, string version = "", int pageSize = 0, int offset = 0 ) where T : class + { + ArgumentNullException.ThrowIfNull( qapiRequestBody, $"Error: Cannot submit a POST request for resource {resourceName} due to a null {nameof( qapiRequestBody )} parameter." ); + + var jsonSerSettings = GetJsonSerializerSettings(); + var reqBody = JsonConvert.SerializeObject( qapiRequestBody, jsonSerSettings ); + return await GetPagesFromOffsetWithQAPIAsync( resourceName, reqBody, version, pageSize, offset ); + } + + /// + /// Gets all the pages for a given resource beginning at offset index 0, using the specified QAPI request body and page size for the given version. + /// + /// The name of the resource to add an instance of. + /// The full version header value of the resource used for this POST request. + /// The body of the request to POST for the given resource. + /// The size (number of rows) of each page returned in the list. + /// A list of EthosResponses where each EthosResponse contains a page of data. If paging is not required based on the + /// given pageSize and total count( from using the filter), the returned list will only contain one EthosResponse. + /// When is passed as null or empty or white space. + /// When is passed as null. + public async Task> GetPagesWithQAPIAsync( string resourceName, string qapiRequestBody, string version = "", int pageSize = 0 ) + { + return await GetPagesFromOffsetWithQAPIAsync(resourceName, qapiRequestBody, version, pageSize, 0 ); + } + + /// + /// Gets all the pages for a given resource beginning at offset index 0, using the specified QAPI request body and page size for the given version. + /// + /// The name of the resource to add an instance of. + /// The full version header value of the resource used for this POST request. + /// The body of the request to POST for the given resource. + /// The size (number of rows) of each page returned in the list. + /// A list of EthosResponses where each EthosResponse contains a page of data. If paging is not required based on the + /// given pageSize and total count( from using the filter), the returned list will only contain one EthosResponse. + /// When is passed as null or empty or white space. + /// When is passed as null. + public async Task> GetPagesWithQAPIAsync( string resourceName, JObject qapiRequestBody, string version = "", int pageSize = 0 ) + { + ArgumentNullException.ThrowIfNull( qapiRequestBody, $"Error: Cannot submit a POST request for resource {resourceName} due to a null {nameof( qapiRequestBody )} parameter." ); + return await GetPagesWithQAPIAsync( resourceName, qapiRequestBody.ToString(), version, pageSize ); + } + + /// + /// Gets all the pages for a given resource beginning at offset index 0, using the specified QAPI request body and page size for the given version. + /// + /// Request type. + /// The name of the resource to add an instance of. + /// The full version header value of the resource used for this POST request. + /// The body of the request to POST for the given resource. + /// The size (number of rows) of each page returned in the list. + /// A list of EthosResponses where each EthosResponse contains a page of data. If paging is not required based on the + /// given pageSize and total count( from using the filter), the returned list will only contain one EthosResponse. + /// When is passed as null or empty or white space. + /// When is passed as null. + public async Task> GetPagesWithQAPIAsync( string resourceName, T qapiRequestBody, string version = "", int pageSize = 0 ) where T : class + { + ArgumentNullException.ThrowIfNull( qapiRequestBody, $"Error: Cannot submit a POST request for resource {resourceName} due to a null {nameof( qapiRequestBody )} parameter." ); + + var jsonSerSettings = GetJsonSerializerSettings(); + var reqBody = JsonConvert.SerializeObject( qapiRequestBody, jsonSerSettings ); + return await GetPagesWithQAPIAsync( resourceName, reqBody, version, pageSize ); + } + + /// + /// Gets the total count of resources available using the given QAPI request body. + /// + /// The name of the resource to get data for. + /// The body of the request to POST for the given resource. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// The number of resource instances available when making a GET request using the given namedQueryFilter, or 0 if the + /// given resourceName or namedQueryFilter is null. + /// Returns exception if the resourceName is null. + /// Returns exception if the qapiRequestBody is null. + public async Task GetTotalCountAsync( string resourceName, string qapiRequestBody, string version = "" ) + { + if ( string.IsNullOrWhiteSpace( resourceName ) || string.IsNullOrWhiteSpace( qapiRequestBody ) ) + { + return default; + } + + EthosResponse ethosResponse = await GetWithQapiAsync( resourceName, qapiRequestBody, version ); + string totalCount = GetHeaderValue( ethosResponse, HDR_X_TOTAL_COUNT ); + if ( int.TryParse( totalCount, out int count ) ) + { + return count; + } + return default; + } + + /// + /// Gets the total count of resources available using the given QAPI request body. + /// + /// The name of the resource to get data for. + /// The body of the request to POST for the given resource. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// The number of resource instances available when making a GET request using the given namedQueryFilter, or 0 if the + /// given resourceName or namedQueryFilter is null. + /// Returns exception if the resourceName is null. + /// Returns exception if the qapiRequestBody is null. + public async Task GetTotalCountAsync( string resourceName, JObject qapiRequestBody, string version = "" ) + { + if( qapiRequestBody is null) return default; + return await GetTotalCountAsync( resourceName, qapiRequestBody.ToString(), version ); + } + + /// + /// Gets the total count of resources available using the given QAPI request body. + /// + /// The name of the resource to get data for. + /// The body of the request to POST for the given resource. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// The number of resource instances available when making a GET request using the given namedQueryFilter, or 0 if the + /// given resourceName or namedQueryFilter is null. + /// Returns exception if the resourceName is null. + /// Returns exception if the qapiRequestBody is null. + public async Task GetTotalCountAsync( string resourceName, T qapiRequestBody, string version = "" ) where T : class + { + if ( string.IsNullOrWhiteSpace( resourceName ) || qapiRequestBody is null ) + { + return default; + } + + EthosResponse ethosResponse = await GetWithQapiAsync( resourceName, qapiRequestBody, version ); + string totalCount = GetHeaderValue( ethosResponse, HDR_X_TOTAL_COUNT ); + if ( int.TryParse( totalCount, out int count ) ) + { + return count; + } + return default; + } + + /// + ///

Intended to be used internally within the SDK.

Performs paging calculations and operations for QAPI requests. + ///
+ /// The name of the resource to add an instance of. + /// The full version header value of the resource used for this POST request. + /// The body of the request to POST for the given resource. + /// The total count of rows for the given resource. + /// The size (number of rows) of each page returned in the list. + /// The 0 based index from which to begin paging for the given resource. + /// Collection of EthosResponse with content. + protected async Task> DoPagingFromOffsetForQAPIAsync( string resourceName, string version, string qapiRequestBody, int totalCount, int pageSize, int offset ) + { + List ethosResponseList = new(); + Dictionary headers = BuildHeadersMap( version ); + decimal numPages = Math.Ceiling( ( Convert.ToDecimal( totalCount ) - Convert.ToDecimal( offset ) ) / Convert.ToDecimal( pageSize ) ); + for ( int i = 0; i < numPages; i++ ) + { + string url = EthosIntegrationUrls.QapiPaging( Region, resourceName, offset, pageSize ); + EthosResponse response = await base.PostAsync( headers, url, qapiRequestBody ); + ethosResponseList.Add( response ); + offset += pageSize; + } + return ethosResponseList; + } + + #endregion QAPI + + /// + /// Gets the total count of resources available using the given criteriaFilter. + /// + /// The name of the resource to get data for. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// A previously built Criteria containing the filter criteria used in the request URL. + /// The number of resource instances available when making a GET request using the given criteriaFilter, or 0 if the + /// given resourceName or criteriaFilter is null. + /// Returns exception if the resourceName is null. + /// Returns exception if the criteriaFilterStr is null. + public async Task GetTotalCountAsync( string resourceName, CriteriaFilter criteria, string version = "" ) + { + if ( string.IsNullOrWhiteSpace( resourceName ) ) + { + return default; + } + if ( criteria == null ) + { + return default; + } + EthosResponse ethosResponse = await GetWithCriteriaFilterAsync( resourceName, version, criteria.BuildCriteria() ); + string totalCount = GetHeaderValue( ethosResponse, HDR_X_TOTAL_COUNT ); + if ( int.TryParse( totalCount, out int count ) ) + { + return count; + } + return default; + } + + /// + /// Gets the total count of resources available using the given namedQueryFilter. + /// + /// The name of the resource to get data for. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// A previously built namedQueryFilter containing the filter used in the request URL. + /// The number of resource instances available when making a GET request using the given namedQueryFilter, or 0 if the + /// given resourceName or namedQueryFilter is null. + /// Returns exception if the resourceName is null. + public async Task GetTotalCountAsync( string resourceName, NamedQueryFilter namedQueryFilter, string version = "" ) + { + if ( string.IsNullOrWhiteSpace( resourceName ) ) + { + return default; + } + if ( namedQueryFilter == null ) + { + return default; + } + EthosResponse ethosResponse = await GetWithNamedQueryFilterAsync( resourceName, version, namedQueryFilter.BuildNamedQuery() ); + string totalCount = GetHeaderValue( ethosResponse, HDR_X_TOTAL_COUNT ); + if ( int.TryParse( totalCount, out int count ) ) + { + return count; + } + return default; + } + + /// + /// Gets the total count of resources available using the given filterMap. + /// + /// The name of the resource to get data for. + /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. + /// A previously built FilterMap containing the filter parameters used in the request URL. + /// A simple call to filterMap.Tostring() should output the criteria filter portion of the request URL, + /// e.g: ?firstName=John&lastName=Smith. + /// The number of resource instances available when making a GET request using the given criteriaFilter, or 0 if the + /// given resourceName or criteriaFilter is null. + /// Returns exception if the resourceName is null. + public async Task GetTotalCountAsync( string resourceName, FilterMap filterMap, string version = "" ) + { + if ( string.IsNullOrWhiteSpace( resourceName ) ) + { + return default; + } + if ( filterMap == null ) + { + return default; + } + EthosResponse ethosResponse = await GetWithFilterMapAsync( resourceName, version, filterMap.ToString() ); + string totalCount = GetHeaderValue( ethosResponse, HDR_X_TOTAL_COUNT ); + if ( int.TryParse( totalCount, out int count ) ) + { + return count; + } + return default; + } + + /// + ///

Intended to be used internally within the SDK. + ///

+ /// Overrides the prepareForPaging() method in the EthosProxyClient super class. + ///

+ /// Uses the given pager object to prepare for paging operations. The pager object is used to contain various + /// fields required for paging. If the given pager is null, returns the same pager. Sets default values for the + /// version and offset within the pager as needed and makes an initial resource call using the provided pager filter + /// to get metadata about the resource used for paging. Also sets the page size and the total count within the pager, + /// and encodes the filter within the pager.

+ ///
+ /// The Pager object used holding the required fields for paging. + /// The same pager object with the version and offset validated, the page size and total count set, and the filter encoded. + protected new async Task PrepareForPagingAsync( Pager pager ) + { + if ( pager == null ) + { + return pager; + } + if ( string.IsNullOrWhiteSpace( pager.Version ) ) + { + pager.Version = DEFAULT_VERSION; + } + if ( pager.Offset < 1 ) + { + pager.Offset = 0; + } + + pager = await PreparePagerForTotalCountAsync( pager ); + + // Set the pageSize. + pager = PreparePagerForPageSize( pager ); + + // Encode the criteriaFilter if it is not null. + if ( pager.CriteriaFilter != null ) + { + pager.CriteriaFilter = EncodeString( pager.CriteriaFilter ); + } + + // Encode the NamedQueryFilter if it is not null. + if ( pager.NamedQueryFilter != null ) + { + pager.NamedQueryFilter = EncodeString( pager.NamedQueryFilter ); + } + return pager; + } + + /// + /// Intended to be used internally by the SDK. + ///

Prepares the pager object for the total count required for paging calculations. + /// The total count is derived from the response x-total-count header after making an initial request using filters

+ /// (in this case). + ///
+ /// The Pager object used holding the required fields for paging. + /// The pager object containing the total count. If neither a criteria filter, a named query nor a filter map is specified + /// in the pager, then the total count will be 0. + protected async Task PreparePagerForTotalCountAsync( Pager pager ) + { + EthosResponse ethosResponse = null; + if ( pager.CriteriaFilter is not null ) + { + ethosResponse = await GetWithCriteriaFilterAsync( pager.ResourceName, pager.Version, pager.CriteriaFilter ); + pager.EthosResponse = ethosResponse; + } + else if ( pager.NamedQueryFilter is not null ) + { + ethosResponse = await GetWithNamedQueryFilterAsync( pager.ResourceName, pager.Version, pager.NamedQueryFilter ); + pager.EthosResponse = ethosResponse; + } + else if ( pager.FilterMap is not null ) + { + ethosResponse = await GetWithFilterMapAsync( pager.ResourceName, pager.Version, pager.FilterMap ); + pager.EthosResponse = ethosResponse; + } + else if ( pager.QapiRequestBody is not null ) + { + ethosResponse = await GetWithQapiAsync( pager.ResourceName, pager.QapiRequestBody, pager.Version ); + pager.EthosResponse = ethosResponse; + } + else + { + await base.PrepareForPagingAsync( pager ); + } + if ( ethosResponse is not null ) + { + string totalCount = GetHeaderValue( ethosResponse, HDR_X_TOTAL_COUNT ); + if ( int.TryParse( totalCount, out int count ) ) + { + pager.TotalCount = count; + } + } + return pager; + } + + /// + /// Intended to be used internally by the SDK. + ///

+ /// If the page size specified in the pager is <= DEFAULT_PAGE_SIZE, then this method prepares the pager object for the + /// page size required for paging calculations. The page size is derived from the response body length after making an initial request using filters + /// (in this case). If the response is null, the DEFAULT_MAX_PAGE_SIZE is used. If the response body is null, the + /// x-max-page-size header is used.

+ ///

If the page size specified in the pager is > DEFAULT_PAGE_SIZE, this method does nothing and just returns the given pager.

+ ///
+ /// The pager object used to contain the page size for paging operations. + /// The pager object containing the page size. + protected Pager PreparePagerForPageSize( Pager pager ) + { + if ( pager.PageSize <= DEFAULT_PAGE_SIZE ) + { + if ( pager.EthosResponse == null ) + { + pager.PageSize = DEFAULT_MAX_PAGE_SIZE; // Set the page size to the MAX default because there is no ethosResponse. + } + // Set the pageSize from the response body length, if pageSize is <= DEFAULT_PAGE_SIZE. + else if ( !string.IsNullOrWhiteSpace( pager.EthosResponse.Content ) && pager.EthosResponse.GetContentAsJson() != null ) + { + int pageSize = pager.EthosResponse.GetContentCount(); + pager.PageSize = pageSize; + } + else + { + string maxPageSizeStr = GetHeaderValue( pager.EthosResponse, HDR_X_MAX_PAGE_SIZE ); + if ( !string.IsNullOrWhiteSpace( maxPageSizeStr ) ) + { + if ( int.TryParse( maxPageSizeStr, out int pageSize ) ) + { + pager.PageSize = pageSize; + } + } + else + { + pager.PageSize = DEFAULT_MAX_PAGE_SIZE; + } + } + } + return pager; + } + + /// + /// Used internally by the SDK. + ///

+ /// Encodes the given criteriaFilterStr. Supports criteria filter strings that begin with the CRITERIA_FILTER_PREFIX + /// value "?criteria=", and also those that do not. Encodes only the JSON criteria portion of the filter string, removing + /// the CRITERIA_FILTER_PREFIX portion if the filter string starts with it. If the filter string does not start with + /// the CRITERIA_FILTER_PREFIX, the criteriaFilterStr string is simply encoded.

+ ///

Returns a criteria filter string that begins with the CRITERIA_FILTER_PREFIX, with the JSON filter portion of the string + /// encoded. Uses UTF-8 encoding.

+ ///
+ /// The criteria filter string to encode. + /// A criteria filter string beginning with the CRITERIA_FILTER_PREFIX with the JSON filter syntax portion of the + /// string encoded in UTF-8. + private static string EncodeString( string criteriaFilterStr ) + { + StringBuilder sb = new StringBuilder(); + string jsonCriteriaStr; + bool isNamedQuery = false; + if ( criteriaFilterStr.StartsWith( CRITERIA_FILTER_PREFIX ) ) + { + // It starts with "?criteria=", so substring the rest of the filter and encode it. + jsonCriteriaStr = criteriaFilterStr [ ( criteriaFilterStr.IndexOf( "=" ) + 1 ).. ]; + } + else + { + jsonCriteriaStr = criteriaFilterStr; + isNamedQuery = true; + } + jsonCriteriaStr = System.Web.HttpUtility.UrlEncode( jsonCriteriaStr, Encoding.UTF8 ); + if ( !isNamedQuery ) sb.Append( CRITERIA_FILTER_PREFIX ); + sb.Append( jsonCriteriaStr ); + return sb.ToString(); + } + + /// + /// Gets JsonSerializerSettings with date format. + /// + /// Returns JsonSerializerSettings with yyyy'-'MM'-'dd'T'HH':'mm':'ssK date format and ignores null values. + private static JsonSerializerSettings GetJsonSerializerSettings() + { + return new JsonSerializerSettings() + { + DateFormatString = DATE_FORMAT, + NullValueHandling = NullValueHandling.Ignore, + DefaultValueHandling = DefaultValueHandling.Ignore + }; + } + } +} diff --git a/Ellucian.Ethos.Integration/Service/EthosChangeNotificationService.cs b/Ellucian.Ethos.Integration/Service/EthosChangeNotificationService.cs index c0187bc..2fb9431 100644 --- a/Ellucian.Ethos.Integration/Service/EthosChangeNotificationService.cs +++ b/Ellucian.Ethos.Integration/Service/EthosChangeNotificationService.cs @@ -35,7 +35,20 @@ public class EthosChangeNotificationService : EthosService /// This constructor is only called from the inner Builder class. ///
/// A api key. - private EthosChangeNotificationService( string apiKey ) : this( new EthosClientBuilder( apiKey ) ) + private EthosChangeNotificationService(string apiKey) + : this( new EthosClientBuilder(apiKey)) + { + + } + + /// + /// Instantiates this service class with Colleague API and credentials. + /// + /// The URL to the Colleague API instance. + /// The username used to connect to the Colleague API. + /// The password used to connect to the Colleague API. + private EthosChangeNotificationService(string colleagueApiUrl, string colleagueApiUsername, string colleagueApiPassword) + : this( new EthosClientBuilder(colleagueApiUrl, colleagueApiUsername, colleagueApiPassword)) { } @@ -333,12 +346,25 @@ private void BuildService( EthosClientBuilder ethosClientBuilder ) /// Actions delegate. /// A api key. /// An instance of the EthosChangeNotificationService. - public static EthosChangeNotificationService Build( Action action, string apiKey ) + public static EthosChangeNotificationService Build( Action action, string apiKey) { - EthosChangeNotificationService ethosChangeNotificationService = new EthosChangeNotificationService( apiKey ); + EthosChangeNotificationService ethosChangeNotificationService = new EthosChangeNotificationService(apiKey); action( ethosChangeNotificationService ); return ethosChangeNotificationService; } + /// + /// Builds an instance of the EthosChangeNotificationService with the given ethosClientBuilder and any resource version overrides. + /// + /// Actions delegate. + /// The URL to the Colleague API instance. + /// The username used to connect to the Colleague API. + /// The password used to connect to the Colleague API. + public static EthosChangeNotificationService Build(Action action, string colleagueApiUrl, string colleagueApiUsername, string colleagueApiPassword) + { + EthosChangeNotificationService ethosChangeNotificationService = new EthosChangeNotificationService(colleagueApiUrl, colleagueApiUsername, colleagueApiPassword); + action(ethosChangeNotificationService); + return ethosChangeNotificationService; + } /// /// Adds resource name and version to a dictionary. If the key (resourceName) already exists with version value, then it replaces same resource with the version provided. diff --git a/Ellucian.Ethos.Integration/Service/EthosService.cs b/Ellucian.Ethos.Integration/Service/EthosService.cs index 414b277..d412fb0 100644 --- a/Ellucian.Ethos.Integration/Service/EthosService.cs +++ b/Ellucian.Ethos.Integration/Service/EthosService.cs @@ -26,9 +26,20 @@ protected EthosService() /// Constructs this service with the given API key. /// /// apiKey The API key used by the EthosClients of this service when obtaining an access token per request. - protected EthosService( string apiKey ) + protected EthosService(string apiKey) { - EthosClientBuilder = new EthosClientBuilder( apiKey ); + EthosClientBuilder = new EthosClientBuilder(apiKey); + } + + /// + /// Constructs this service with the given Colleague API and credentials. + /// + /// The URL to the Colleague API instance. + /// The username used to connect to the Colleague API. + /// The password used to connect to the Colleague API. + protected EthosService(string colleagueApiUrl, string colleagueApiUsername, string colleagueApiPassword) + { + EthosClientBuilder = new EthosClientBuilder(colleagueApiUrl, colleagueApiUsername, colleagueApiPassword); } /// From ccf097b702bbf8df04310ef466eeee3e9c613e28 Mon Sep 17 00:00:00 2001 From: Buddy Wagner Date: Fri, 7 Jul 2023 13:30:08 -0700 Subject: [PATCH 02/13] Added ColleagueWebApiProxyClient and ColleagueWebApiFilterQueryClient classes that extend their base Ethos verions. Converted EthosIntegrationUrls class from static to normal and created an instance of it at the base EthosClient level for all client objects. Non-static version now swaps out ColleagueApiUrl for base ethos url when using the Colleague versions of the clients. --- .../Authentication/SupportedRegions.cs | 8 +- .../Client/Config/EthosConfigurationClient.cs | 4 +- .../Client/Errors/EthosErrorsClient.cs | 10 +- .../Client/EthosClient.cs | 59 +- .../Client/EthosClientBuilder.cs | 3 +- .../Client/Messages/EthosMessagesClient.cs | 4 +- .../Proxy/ColleagueWebApiFilterQueryClient.cs | 1509 +--------------- .../Proxy/ColleagueWebApiProxyClient.cs | 1516 +---------------- .../Client/Proxy/EthosFilterQueryClient.cs | 20 +- .../Client/Proxy/EthosProxyClient.cs | 34 +- .../EthosIntegrationUrls.cs | 52 +- 11 files changed, 149 insertions(+), 3070 deletions(-) diff --git a/Ellucian.Ethos.Integration/Authentication/SupportedRegions.cs b/Ellucian.Ethos.Integration/Authentication/SupportedRegions.cs index 11403ac..047da63 100644 --- a/Ellucian.Ethos.Integration/Authentication/SupportedRegions.cs +++ b/Ellucian.Ethos.Integration/Authentication/SupportedRegions.cs @@ -27,6 +27,10 @@ public enum SupportedRegions /// /// Europe. /// - Europe - } + Europe, + /// + /// Self-Hosted. + /// + SelfHosted + } } \ No newline at end of file diff --git a/Ellucian.Ethos.Integration/Client/Config/EthosConfigurationClient.cs b/Ellucian.Ethos.Integration/Client/Config/EthosConfigurationClient.cs index 2ae8910..487a9c2 100644 --- a/Ellucian.Ethos.Integration/Client/Config/EthosConfigurationClient.cs +++ b/Ellucian.Ethos.Integration/Client/Config/EthosConfigurationClient.cs @@ -151,7 +151,7 @@ public EthosConfigurationClient( string apiKey, HttpClient httpClient ) : base( public async Task GetAppConfigAsync() { Dictionary headers = new Dictionary(); - return await base.GetStringAsync( headers, EthosIntegrationUrls.AppConfig( Region ) ); + return await base.GetStringAsync( headers, IntegrationUrls.AppConfig( Region ) ); } /// @@ -171,7 +171,7 @@ public async Task GetAppConfigJsonAsync() public async Task GetAllAvailableResourcesAsync() { Dictionary headers = new Dictionary(); - return await base.GetStringAsync( headers, EthosIntegrationUrls.AvailableResources( Region ) ); + return await base.GetStringAsync( headers, IntegrationUrls.AvailableResources( Region ) ); } /// diff --git a/Ellucian.Ethos.Integration/Client/Errors/EthosErrorsClient.cs b/Ellucian.Ethos.Integration/Client/Errors/EthosErrorsClient.cs index 24169b5..6bb3615 100644 --- a/Ellucian.Ethos.Integration/Client/Errors/EthosErrorsClient.cs +++ b/Ellucian.Ethos.Integration/Client/Errors/EthosErrorsClient.cs @@ -65,7 +65,7 @@ public EthosErrorsClient( string apiKey, HttpClient client ) : base( apiKey, cli public async Task GetAsync() { Dictionary headers = BuildHeadersMap(); - return await base.GetAsync( headers, EthosIntegrationUrls.Errors( Region ) ); + return await base.GetAsync( headers, IntegrationUrls.Errors( Region ) ); } /// @@ -145,7 +145,7 @@ public async Task GetByIdAsync( string id ) } Dictionary headers = BuildHeadersMap(); - return await base.GetAsync( headers, EthosIntegrationUrls.Errors( Region ) + "/" + id ); + return await base.GetAsync( headers, IntegrationUrls.Errors( Region ) + "/" + id ); } /// @@ -351,7 +351,7 @@ protected async Task> DoPagingAsync( int totalErrorCo int numPages = CalculateNumberOfPages( totalErrorCount, pageSize, offset ); for ( int index = 0; index < numPages; index++ ) { - string url = EthosIntegrationUrls.ErrorsPaging( Region, offset, pageSize ); + string url = IntegrationUrls.ErrorsPaging( Region, offset, pageSize ); EthosResponse response = await GetAsync( headersMap, url ); ethosResponseList.Add( response ); offset += pageSize; @@ -397,7 +397,7 @@ public async Task PostAsync( EthosError newError ) Dictionary headers = new Dictionary(); headers [ "Accept" ] = errorType; string errorRequestBody = JsonConvert.SerializeObject( newError ); - var response = await base.PostAsync( headers, EthosIntegrationUrls.Errors( Region ), errorRequestBody ); + var response = await base.PostAsync( headers, IntegrationUrls.Errors( Region ), errorRequestBody ); return response; } @@ -410,7 +410,7 @@ public async Task PostAsync( EthosError newError ) /// server certificate validation or timeout. public async Task DeleteAsync( string id ) { - await base.DeleteAsync( new Dictionary(), EthosIntegrationUrls.Errors( Region ) + "/" + id ); + await base.DeleteAsync( new Dictionary(), IntegrationUrls.Errors( Region ) + "/" + id ); } /// diff --git a/Ellucian.Ethos.Integration/Client/EthosClient.cs b/Ellucian.Ethos.Integration/Client/EthosClient.cs index f2b0f8d..6dd3340 100644 --- a/Ellucian.Ethos.Integration/Client/EthosClient.cs +++ b/Ellucian.Ethos.Integration/Client/EthosClient.cs @@ -28,6 +28,24 @@ public class EthosClient /// private string ApiKey { get; } + protected EthosIntegrationUrls IntegrationUrls = new EthosIntegrationUrls(); + + // Only used by ColleagueWebAPIProxyClients + /// + /// Api URL to Self-Hosted Colleague API. + /// + protected string ColleagueApiUrl; + /// + /// Self-Hosted Colleague API username. + /// + protected string ColleagueApiUsername; + /// + /// Self-Hosted Colleague API password. + /// + protected string ColleagueApiPassword; + + + /// /// Default token expiration time. /// @@ -102,6 +120,28 @@ public EthosClient( string apiKey, HttpClient client ) this.HttpProtocolClientBuilder ??= new HttpProtocolClientBuilder( client ); EthosResponseBuilder ??= new EthosResponseBuilder(); } + /// + /// Constructor called by subclasses of this class, specifically for ColleagueWebApiProxies. + /// + /// The URL to the Colleague API instance. If it is null/empty, then an will be thrown. + /// The username used to connect to the Colleague API. If it is null/empty, then an will be thrown. + /// The password used to connect to the Colleague API. If it is null/empty, then an will be thrown. + /// A . + public EthosClient(string colleagueApiUrl, string colleagueApiUsername, string colleagueApiPassword, HttpClient client) + { + if (colleagueApiUrl == null || colleagueApiUsername == null + || colleagueApiPassword == null || colleagueApiPassword == null) + { + throw new ArgumentNullException($"Colleague API URL and Credentials are required."); + } + if (client == null) + { + throw new ArgumentNullException($"The '{nameof(client)}' parameter is required."); + } + ApiKey = null; + this.HttpProtocolClientBuilder ??= new HttpProtocolClientBuilder(client); + EthosResponseBuilder ??= new EthosResponseBuilder(); + } #endregion @@ -175,7 +215,7 @@ public async Task GetAccessTokenAsync() /// Returns exception if the request fails. private async Task GetNewTokenAsync() { - string authUrl = $"{ EthosIntegrationUrls.Auth( this.Region )}?expirationMinutes={ ExpirationMinutes }"; + string authUrl = $"{IntegrationUrls.Auth( this.Region )}?expirationMinutes={ ExpirationMinutes }"; HttpProtocolClientBuilder.Client.DefaultRequestHeaders.Add( "Authorization", $"Bearer { ApiKey }" ); //make request HttpResponseMessage response = await HttpProtocolClientBuilder.Client.PostAsync( new Uri( authUrl ), null ); @@ -369,11 +409,20 @@ public async Task DeleteAsync( Dictionary headers, string url ) /// A private async Task AddAccessTokenAuthHeaderAsync( Dictionary headers ) { - AccessToken token = await GetAccessTokenAsync(); - if ( token.GetAuthHeader().TryGetValue( "Authorization", out string authValue ) ) + headers.Remove("Authorization"); + if (Region == SupportedRegions.SelfHosted) + { + byte[] bytes = System.Text.Encoding.UTF8.GetBytes(ColleagueApiUsername + ":" + ColleagueApiPassword); + string token = System.Convert.ToBase64String(bytes); + headers.Add("Authorization", "Basic " + token); + } + else { - headers.Remove( "Authorization" ); - headers.Add( "Authorization", authValue ); + AccessToken token = await GetAccessTokenAsync(); + if (token.GetAuthHeader().TryGetValue("Authorization", out string authValue)) + { + headers.Add("Authorization", authValue); + } } } diff --git a/Ellucian.Ethos.Integration/Client/EthosClientBuilder.cs b/Ellucian.Ethos.Integration/Client/EthosClientBuilder.cs index 0b1646d..e7824b6 100644 --- a/Ellucian.Ethos.Integration/Client/EthosClientBuilder.cs +++ b/Ellucian.Ethos.Integration/Client/EthosClientBuilder.cs @@ -123,8 +123,7 @@ public EthosFilterQueryClient BuildEthosFilterQueryClient() /// An ColleagueWebApiProxyClient using the given Colleague credentials. public ColleagueWebApiProxyClient BuildColleagueWebApiProxyclient() { - //TODO - return null; + return new ColleagueWebApiProxyClient(ColleagueApiUrl, ColleagueApiUsername, ColleagueApiPassword, builder.Client); } /// diff --git a/Ellucian.Ethos.Integration/Client/Messages/EthosMessagesClient.cs b/Ellucian.Ethos.Integration/Client/Messages/EthosMessagesClient.cs index 07b3a34..41c0199 100644 --- a/Ellucian.Ethos.Integration/Client/Messages/EthosMessagesClient.cs +++ b/Ellucian.Ethos.Integration/Client/Messages/EthosMessagesClient.cs @@ -102,7 +102,7 @@ private async Task> GetMessagesAsync( int? limit Dictionary headers = new Dictionary(); headers.Add( "Accept", cnType ); - EthosResponse response = await GetAsync( headers, EthosIntegrationUrls.Consume( Region, lastProcessedID, limit ) ); + EthosResponse response = await GetAsync( headers, IntegrationUrls.Consume( Region, lastProcessedID, limit ) ); return new EthosResponseConverter().ToCNList( response ); } @@ -113,7 +113,7 @@ private async Task> GetMessagesAsync( int? limit /// The number of available messages in the application's queue. public async Task GetNumAvailableMessagesAsync() { - EthosResponse response = await HeadAsync( EthosIntegrationUrls.Consume( Region, -1, -1 ) ); + EthosResponse response = await HeadAsync(IntegrationUrls.Consume( Region, -1, -1 ) ); string remaining = response.GetHeader( "x-remaining" ); if ( int.TryParse( remaining, out int numMessages ) ) { diff --git a/Ellucian.Ethos.Integration/Client/Proxy/ColleagueWebApiFilterQueryClient.cs b/Ellucian.Ethos.Integration/Client/Proxy/ColleagueWebApiFilterQueryClient.cs index 8a69c8c..5263c6a 100644 --- a/Ellucian.Ethos.Integration/Client/Proxy/ColleagueWebApiFilterQueryClient.cs +++ b/Ellucian.Ethos.Integration/Client/Proxy/ColleagueWebApiFilterQueryClient.cs @@ -21,1511 +21,20 @@ namespace Ellucian.Ethos.Integration.Client.Proxy /// /// An EthosProxyClient that provides the ability to submit GET requests supporting filters and/or named queries with support for paging. /// - public class ColleagueWebApiFilterQueryClient : EthosProxyClient + public class ColleagueWebApiFilterQueryClient : EthosFilterQueryClient { - // Prefix value used when specifying criteria filter syntax. - private const string CRITERIA_FILTER_PREFIX = "?criteria="; - - /// - /// Instantiates this class using the given API key and HttpClient. + /// Instantiates this class using the given Colleague API url and credentials. /// - /// A valid API key from Ethos Integration. This is required to be a valid 36 character GUID string. - /// If it is null, empty, or not in a valid GUID format, then an IllegalArgumentException will be thrown. + /// The URL to the Colleague API instance. If it is null/empty, then an will be thrown. + /// The username used to connect to the Colleague API. If it is null/empty, then an will be thrown. + /// The password used to connect to the Colleague API. If it is null/empty, then an will be thrown. /// A HttpClient. If it is null/empty, then an will be thrown. - public ColleagueWebApiFilterQueryClient( string apiKey, HttpClient client ) : base( apiKey, client ) - { - - } - - #region Strongly Typed GET - - /// - /// Gets a page of data for the given resource by name and version with the given filter. - /// - /// Type to be included in the returned specified by caller. - /// The name of the resource to get data for. - /// The string resource filter in JSON format contained in the URL, e.g:
?criteria={"names":[{"firstName":"John"}]}
- /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// An EthosResponse containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - /// Returns exception if the resourceName is null. - /// Returns exception if the criteriaFilterStr is null. - /// Returns exception if the request fails. - public async Task GetWithCriteriaFilterAsync( string resourceName, string criteriaFilterStr, string version = "" ) where T : class - { - var response = await GetWithCriteriaFilterAsync( resourceName, version, criteriaFilterStr ); - return ConvertEthosResponseContentToType( response ); - } - - /// - /// Gets a page of data for the given resource by name and version with the given filter. - /// - /// Type to be included in the returned specified by caller. - /// The name of the resource to get data for. - /// A previously built Criteria containing the filter criteria used in the request URL. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// A simple call to criteriaFilter.BuildCriteria() should output the criteria filter portion of the request URL, - /// e.g: ?criteria={"names":[{"firstName":"John"}]}. - /// An EthosResponse containing an initial page (EthosResponse content) of resource data according to the requested version and filter of the resource. - /// to the requested version and filter of the resource. - /// Throws if the given criteriaFilter is null. - public async Task GetWithCriteriaFilterAsync( string resourceName, CriteriaFilter criteria, string version = "" ) where T : class - { - var response = await GetWithCriteriaFilterAsync( resourceName, version, criteria.BuildCriteria() ); - return ConvertEthosResponseContentToType( response ); - } - - /// - /// Convenience method to submit a GET request with a single set of criteria filter. This is intended only to be used - /// for a single set of criteria filter, e.g: ?criteria={"names":[{"firstName":"John"}]}, where names is the - /// criteriaSetName, firstName is the criteriaKey, and John is the criteriaValue. Requests requiring - /// a more complex criteria filter should first build the Criteria with the necessary criteria, and then call - /// getWithCriteriaFilterAsync(resourceName, version, criteriaFilter). - ///

The parameters criteriaSetName, criteriaKey, and criteriaValue should only specify the values within quotes of the - /// JSON filter syntax. No JSON syntax (square or angeled braces, etc) should be contained within those parameter values.

- ///
- /// Type to be included in the returned specified by caller. - /// The name of the resource to get data for. - /// The name of the criteria set that the given criteriaKey and criteriaValue are associated with, - /// e.g: "names":[{"firstName":"John"}]}, where names is the criteriaSetName associated to the - /// criteriaKey (firstName) and criteriaValue (John). - /// The JSON label key for the criteria. - /// The value associated with the criteriaKey. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// An EthosResponse containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - /// Returns exception if the resourceName or criteriaSetName or criteriaKey or criteriaValue is null. - public async Task GetWithSimpleCriteriaValuesAsync( string resourceName, string criteriaSetName, string criteriaKey, string criteriaValue, string version = "" ) where T : class - { - var response = await GetWithSimpleCriteriaValuesAsync( resourceName, version, criteriaSetName, criteriaKey, criteriaValue ); - return ConvertEthosResponseContentToType( response ); - } - - /// - /// Gets a page of data for the given resource by name and version with the given filter. - /// - /// Type to be included in the returned specified by caller. - /// The name of the resource to get data for. - /// The string resource filter in JSON format contained in the URL. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// An EthosResponse containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - /// Returns exception if the resourceName is null. - /// Returns exception if the namedQuery is null. - /// Returns exception if the request fails. - public async Task GetWithNamedQueryFilterAsync( string resourceName, string namedQueryFilterStr, string version = "" ) where T : class - { - var response = await GetWithNamedQueryFilterAsync( resourceName, version, namedQueryFilterStr ); - return ConvertEthosResponseContentToType( response ); - } - - /// - /// Gets a page of data for the given resource by name and version with the given filter. - /// - /// Type to be included in the returned specified by caller. - /// The name of the resource to get data for. - /// A previously built namedQueryFilter containing the filter used in the request URL. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// A simple call to namedQueryFilter.BuildNamedQuery() should output the named query portion of the request URL. - /// An EthosResponse containing an initial page (EthosResponse content) of resource data according to the requested version and filter of the resource. - /// to the requested version and filter of the resource. - /// Throws if the given criteriaFilter is null. - public async Task GetWithNamedQueryFilterAsync( string resourceName, NamedQueryFilter namedQueryFilter, string version = "" ) where T : class - { - var response = await GetWithNamedQueryFilterAsync( resourceName, version, namedQueryFilter.BuildNamedQuery() ); - return ConvertEthosResponseContentToType( response ); - } - - /// - /// Submits a GET request for the given resource and version using the given filterMapStr. The filterMapStr - /// is intended to support the filter syntax for resources versions 7 and older. An example of a filterMapStr is: - /// ?firstName=James. - ///

This is NOT intended to be used for resource versions after version 7 and/or for criteria filters.

- ///
- /// Type to be included in the returned specified by caller. - /// The name of the resource to get data for. - /// A string containing the filter syntax used for request URL filters with resource versions 7 or older. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// An EthosResponse containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - /// Returns exception if the resourceName or filterMapStr is null. - public async Task GetWithFilterMapAsync( string resourceName, string filterMapStr, string version = "" ) where T : class - { - var response = await GetWithFilterMapAsync( resourceName, version, filterMapStr ); - return ConvertEthosResponseContentToType( response ); - } - - /// - /// Submits a GET request for the given resource and version using the given filterMap. The filterMap - /// is intended to support the filter syntax for resources versions 7 and older. A FilterMap contains a map of - /// one or many filter parameter pair(s). An example of a filterMap string indicating the contents of the map is: - /// ?firstName=James. - ///

This is NOT intended to be used for resource versions after version 7 and/or for criteria filters.

- ///
- /// Type to be included in the returned specified by caller. - /// The name of the resource to get data for. - /// A string containing the filter syntax used for request URL filters with resource versions 7 or older. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// An EthosResponse containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - /// Returns exception if the resourceName or filterMap is null. - public async Task GetWithFilterMapAsync( string resourceName, FilterMap filterMap, string version = "" ) where T : class - { - var response = await GetWithFilterMapAsync( resourceName, version, filterMap.ToString() ); - return ConvertEthosResponseContentToType( response ); - } - - /// - /// Gets all the pages for a given resource using the specified criteria filter and page size for the given version. - /// - /// Type to be included in the returned specified by caller. - /// The name of the resource to get data for. - /// A previously built Criteria containing the filter criteria used in the request URL. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// The size (number of rows) of each page returned in the list. - /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - public async Task> GetPagesWithCriteriaFilterAsync( string resourceName, CriteriaFilter criteria, string version = "", int pageSize = 0 ) where T : class - { - var response = await GetPagesWithCriteriaFilterAsync( resourceName, version, criteria, pageSize ); - return ConvertEthosResponseContentListToType( response ); - } - - /// - /// Gets all the pages for a given resource using the specified namedQueryFilter filter and page size for the given version. - /// - /// Type to be included in the returned specified by caller. - /// The name of the resource to get data for. - /// A previously built namedQueryFilter containing the filter named query used in the request URL. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// The size (number of rows) of each page returned in the list. - /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - public async Task> GetPagesWithNamedQueryFilterAsync( string resourceName, NamedQueryFilter namedQueryFilter, string version = "", int pageSize = 0 ) where T : class - { - var response = await GetPagesWithNamedQueryFilterAsync( resourceName, version, namedQueryFilter, pageSize ); - return ConvertEthosResponseContentListToType( response ); - } - - /// - /// Gets all the pages for a given resource beginning at the given offset index, using the specified criteria filter - /// and page size for the given version. - /// - /// Type to be included in the returned specified by caller. - /// The name of the resource to get data for. - /// A previously built Criteria containing the filter criteria used in the request URL. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// The size (number of rows) of each page returned in the list. - /// The 0 based index from which to begin paging for the given resource. - /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - /// Returns exception if the resourceName or criteriaFilter is null. - public async Task> GetPagesFromOffsetWithCriteriaFilterAsync( string resourceName, CriteriaFilter criteria, string version = "", int pageSize = 0, int offset = 0 ) where T : class - { - var response = await GetPagesFromOffsetWithCriteriaFilterAsync( resourceName, version, criteria, pageSize, offset ); - return ConvertEthosResponseContentListToType( response ); - } - - /// - /// Gets all the pages for a given resource beginning at the given offset index, using the specified namedQueryFilter - /// and page size for the given version. - /// - /// Type to be included in the returned specified by caller. - /// The name of the resource to get data for. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// A previously built namedQueryFilter containing the filter used in the request URL. - /// The size (number of rows) of each page returned in the list. - /// The 0 based index from which to begin paging for the given resource. - /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - /// Returns exception if the resourceName or namedQueryFilter is null. - public async Task> GetPagesFromOffsetWithNamedQueryFilterAsync( string resourceName, NamedQueryFilter namedQueryFilter, string version = "", int pageSize = 0, int offset = 0 ) where T : class - { - var response = await GetPagesFromOffsetWithNamedQueryFilterAsync( resourceName, version, namedQueryFilter, pageSize, offset ); - return ConvertEthosResponseContentListToType( response ); - } - - /// - /// Gets all the pages for a given resource using the specified filter map and page size for the given version. - /// - /// Type to be included in the returned specified by caller. - /// The name of the resource to get data for. - /// A previously built FilterMap containing the filter parameters used in the request URL. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// A simple call to filterMap.tostring() should output the criteria filter portion of the request URL, - /// e.g: ?firstName=John&lastName=Smith. - /// The size (number of rows) of each page returned in the list. - /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - public async Task> GetPagesWithFilterMapAsync( string resourceName, FilterMap filterMap, string version = "", int pageSize = 0 ) where T : class - { - var response = await GetPagesWithFilterMapAsync( resourceName, version, filterMap, pageSize ); - return ConvertEthosResponseContentListToType( response ); - } - - /// - /// Gets all the pages for a given resource beginning at the given offset index, using the specified filter map and - /// page size for the given version. - /// - /// Type to be included in the IEnumerable<> returned specified by caller. - /// The name of the resource to get data for. - /// A previously built FilterMap containing the filter parameters used in the request URL. - /// A simple call to filterMap.tostring() should output the criteria filter portion of the request URL, - /// e.g: ?firstName=John&lastName=Smith. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// The size (number of rows) of each page returned in the list. - /// The 0 based index from which to begin paging for the given resource. - /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - public async Task> GetPagesFromOffsetWithFilterMapAsync( string resourceName, FilterMap filterMap, string version = "", int pageSize = 0, int offset = 0 ) where T : class - { - var response = await GetPagesFromOffsetWithFilterMapAsync( resourceName, version, filterMap, pageSize, offset ); - return ConvertEthosResponseContentListToType( response ); - } - - #endregion Strongly Typed - - /// - /// Gets a page of data for the given resource with the given filter. Uses the default version of the resource. - /// Makes a non-filter API request if the given criteriaFilterStr is null or blank. - /// - /// The name of the resource to get data for. - /// The string resource filter in JSON format contained in the URL, e.g:
?criteria={"names":[{"firstName":"John"}]}
- /// An EthosResponse containing an initial page (EthosResponse content) of resource data according to the requested version and filter of the resource. - /// to the requested version and filter of the resource. - public async Task GetWithCriteriaFilterAsync( string resourceName, string criteriaFilterStr ) - { - return await GetWithCriteriaFilterAsync( resourceName, DEFAULT_VERSION, criteriaFilterStr ); - } - - /// - /// Gets a page of data for the given resource with the given filter. Uses the default version of the resource. - /// Makes a non-filter API request if the given namedQueryFilterStr is null or blank. - /// - /// The name of the resource to get data for. - /// The string resource filter in JSON format contained in the URL, e.g:
?criteria={"names":[{"firstName":"John"}]}
- /// An EthosResponse containing an initial page (EthosResponse content) of resource data according to the requested version and filter of the resource. - /// to the requested version and filter of the resource. - public async Task GetWithNamedQueryFilterAsync( string resourceName, string namedQueryFilterStr ) - { - return await GetWithNamedQueryFilterAsync( resourceName, DEFAULT_VERSION, namedQueryFilterStr ); - } - - /// - /// Gets a page of data for the given resource by name and version with the given filter. - /// - /// The name of the resource to get data for. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// The string resource filter in JSON format contained in the URL, e.g:
?criteria={"names":[{"firstName":"John"}]}
- /// An EthosResponse containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - /// Returns exception if the resourceName is null. - /// Returns exception if the criteriaFilterStr is null. - /// Returns exception if the request fails. - public async Task GetWithCriteriaFilterAsync( string resourceName, string version, string criteriaFilterStr ) - { - if ( string.IsNullOrWhiteSpace( resourceName ) ) - { - throw new ArgumentNullException( "Error: Cannot get resource with criteria filter due to a null or blank resource name." ); - } - if ( string.IsNullOrWhiteSpace( criteriaFilterStr ) ) - { - throw new ArgumentNullException( $"Error: Cannot get resource '{resourceName}' with criteria filter due to a null or blank criteria filter string." ); - } - return await GetEthosResponseAsync( resourceName, version, criteriaFilterStr ); - } - - /// - /// Gets a page of data for the given resource by name and version with the given filter. - /// - /// The name of the resource to get data for. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// The string resource filter in JSON format contained in the URL. - /// An EthosResponse containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - /// Returns exception if the resourceName is null. - /// Returns exception if the namedQuery is null. - /// Returns exception if the request fails. - public async Task GetWithNamedQueryFilterAsync( string resourceName, string version, string namedQueryFilterStr ) - { - if ( string.IsNullOrWhiteSpace( resourceName ) ) - { - throw new ArgumentNullException( "Error: Cannot get resource with criteria filter due to a null or blank resource name." ); - } - if ( string.IsNullOrWhiteSpace( namedQueryFilterStr ) ) - { - throw new ArgumentNullException( $"Error: Cannot get resource '{resourceName}' with named query due to a null or blank named query string." ); - } - return await GetEthosResponseAsync( resourceName, version, namedQueryFilterStr ); - } - - /// - /// Gets Ethos Response. - /// - /// The name of the resource to get data for. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// This can be CriteriaFilter or NamedQuery. - /// An EthosResponse containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - private async Task GetEthosResponseAsync( string resourceName, string version, string criteria ) - { - var filterStr = EncodeString( criteria ); - Dictionary headers = BuildHeadersMap( version ); - EthosResponse response = await GetAsync( headers, EthosIntegrationUrls.ApiFilter( Region, resourceName, filterStr ) ); - return response; - } - - /// - /// Gets a page of data for the given resource by name with the given filter. Uses the default version of the resource. - /// Makes a non-filter API request if the given criteriaFilter is null. - /// A simple call to criteriaFilter.BuildCriteria() should output the criteria filter portion of the request URL, - /// e.g: ?criteria={"names":[{"firstName":"John"}]}. - /// - /// The name of the resource to get data for. - /// A previously built Criteria containing the filter criteria used in the request URL. - /// A simple call to criteriaFilter.BuildCriteria() should output the criteria filter portion of the request URL, - /// e.g: ?criteria={"names":[{"firstName":"John"}]}. - /// An EthosResponse containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - public async Task GetWithCriteriaFilterAsync( string resourceName, CriteriaFilter criteria ) - { - return await GetWithCriteriaFilterAsync( resourceName, DEFAULT_VERSION, criteria.BuildCriteria() ); - } - - /// - /// Gets a page of data for the given resource by name and version with the given filter. - /// - /// The name of the resource to get data for. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// A previously built Criteria containing the filter criteria used in the request URL. - /// A simple call to criteriaFilter.BuildCriteria() should output the criteria filter portion of the request URL, - /// e.g: ?criteria={"names":[{"firstName":"John"}]}. - /// An EthosResponse containing an initial page (EthosResponse content) of resource data according to the requested version and filter of the resource. - /// to the requested version and filter of the resource. - /// Throws if the given criteriaFilter is null. - public async Task GetWithCriteriaFilterAsync( string resourceName, string version, CriteriaFilter criteria ) - { - if ( criteria == null ) - { - throw new ArgumentNullException( $"Error: Cannot get resource '{ resourceName }' with criteria filter due to a null criteria filter reference." ); - } - return await GetWithCriteriaFilterAsync( resourceName, version, criteria.BuildCriteria() ); - } - - /// - /// Gets a page of data for the given resource by name with the given filter. Uses the default version of the resource. - /// Makes a non-filter API request if the given criteriaFilter is null. - /// A simple call to criteriaFilter.BuildCriteria() should output the criteria filter portion of the request URL. - /// - /// The name of the resource to get data for. - /// A previously built namedQueryFilter containing the filter used in the request URL. - /// A simple call to namedQueryFilter.BuildNamedQuery() should output the criteria filter portion of the request URL, - /// e.g: ?criteria={"names":[{"firstName":"John"}]}. - /// An EthosResponse containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - public async Task GetWithNamedQueryFilterAsync( string resourceName, NamedQueryFilter namedQueryFilter ) - { - return await GetWithNamedQueryFilterAsync( resourceName, DEFAULT_VERSION, namedQueryFilter ); - } - - /// - /// Gets a page of data for the given resource by name and version with the given filter. - /// - /// The name of the resource to get data for. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// A previously built namedQueryFilter containing the filter used in the request URL. - /// A simple call to namedQueryFilter.BuildNamedQuery() should output the named query portion of the request URL. - /// An EthosResponse containing an initial page (EthosResponse content) of resource data according to the requested version and filter of the resource. - /// to the requested version and filter of the resource. - /// Throws if the given criteriaFilter is null. - public async Task GetWithNamedQueryFilterAsync( string resourceName, string version, NamedQueryFilter namedQueryFilter ) - { - if ( namedQueryFilter == null ) - { - throw new ArgumentNullException( $"Error: Cannot get resource '{ resourceName }' with named query due to a null named query reference." ); - } - return await GetWithNamedQueryFilterAsync( resourceName, version, namedQueryFilter.BuildNamedQuery() ); - } - - /// - /// Convenience method to submit a GET request with a single set of criteria filter. This is intended only to be used - /// for a single set of criteria filter, e.g: ?criteria={"names":[{"firstName":"John"}]}, where names is the - /// criteriaSetName, firstName is the criteriaKey, and John is the criteriaValue. Requests requiring - /// a more complex criteria filter should first build the Criteria with the necessary criteria, and then call - /// getWithCriteriaFilterAsync(resourceName, criteriaFilter). - ///

The parameters criteriaSetName, criteriaKey, and criteriaValue should only specify the values within quotes of the - /// JSON filter syntax. No JSON syntax (square or angeled braces etc.) should be contained within those parameter values.

- ///

Uses the default version of the resource.

- ///
- /// The name of the resource to get data for. - /// The name of the criteria set that the given criteriaKey and criteriaValue are associated with, - /// e.g: "names":[{"firstName":"John"}]}, where names is the criteriaSetName associated to the - /// criteriaKey (firstName) and criteriaValue (John). - /// The JSON label key for the criteria. - /// The value associated with the criteriaKey. - /// An EthosResponse containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - public async Task GetWithSimpleCriteriaValuesAsync( string resourceName, string criteriaSetName, string criteriaKey, string criteriaValue ) - { - return await GetWithSimpleCriteriaValuesAsync( resourceName, DEFAULT_VERSION, criteriaSetName, criteriaKey, criteriaValue ); - } - - /// - /// Convenience method to submit a GET request with a single set of criteria filter. This is intended only to be used - /// for a single set of criteria filter, e.g: ?criteria={"names":[{"firstName":"John"}]}, where names is the - /// criteriaSetName, firstName is the criteriaKey, and John is the criteriaValue. Requests requiring - /// a more complex criteria filter should first build the Criteria with the necessary criteria, and then call - /// getWithCriteriaFilterAsync(resourceName, version, criteriaFilter). - ///

The parameters criteriaSetName, criteriaKey, and criteriaValue should only specify the values within quotes of the - /// JSON filter syntax. No JSON syntax (square or angeled braces, etc) should be contained within those parameter values.

- ///
- /// The name of the resource to get data for. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// The name of the criteria set that the given criteriaKey and criteriaValue are associated with, - /// e.g: "names":[{"firstName":"John"}]}, where names is the criteriaSetName associated to the - /// criteriaKey (firstName) and criteriaValue (John). - /// The JSON label key for the criteria. - /// The value associated with the criteriaKey. - /// An EthosResponse containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - /// Returns exception if the resourceName or criteriaSetName or criteriaKey or criteriaValue is null. - public async Task GetWithSimpleCriteriaValuesAsync( string resourceName, string version, string criteriaSetName, string criteriaKey, string criteriaValue ) - { - if ( string.IsNullOrWhiteSpace( resourceName ) ) - { - throw new ArgumentNullException( "Error: Cannot get resource with filter map due to a null or blank resource name." ); - } - if ( string.IsNullOrWhiteSpace( criteriaSetName ) ) - { - throw new ArgumentNullException( "Error: Cannot get resource due to a null or empty criteria set name parameter." ); - } - if ( string.IsNullOrWhiteSpace( criteriaKey ) ) - { - throw new ArgumentNullException( "Error: Cannot get resource due to a null or empty criteria key parameter." ); - } - if ( string.IsNullOrWhiteSpace( criteriaValue ) ) - { - throw new ArgumentNullException( "Error: Cannot get resource due to a null or empty criteria value parameter." ); - } - var criteriaFilter = new CriteriaFilter().WithSimpleCriteria( criteriaSetName, (criteriaKey, criteriaValue) ) - .BuildCriteria(); - return await GetWithCriteriaFilterAsync( resourceName, version, criteriaFilter ); - } - - /// - /// Submits a GET request for the given resource and version using the given filterMapStr. The filterMapStr - /// is intended to support the filter syntax for resources versions 7 and older. An example of a filterMapStr is: - /// ?firstName=James. - ///

This is NOT intended to be used for resource versions after version 7 and/or for criteria filters.

- ///
- /// The name of the resource to get data for. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// A string containing the filter syntax used for request URL filters with resource versions 7 or older. - /// An EthosResponse containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - /// Returns exception if the resourceName or filterMapStr is null. - public async Task GetWithFilterMapAsync( string resourceName, string version, string filterMapStr ) - { - if ( string.IsNullOrWhiteSpace( resourceName ) ) - { - throw new ArgumentNullException( "Error: Cannot get resource with filter map due to a null or blank resource name." ); - } - if ( string.IsNullOrWhiteSpace( filterMapStr ) ) - { - throw new ArgumentNullException( $"Error: Cannot get resource '{ resourceName }' with filter map due to a null or blank filter map string." ); - } - Dictionary headers = BuildHeadersMap( version ); - EthosResponse response = await GetAsync( headers, EthosIntegrationUrls.ApiFilter( Region, resourceName, filterMapStr ) ); - return response; - } - - /// - /// Submits a GET request for the given resource and version using the given filterMap. The filterMap - /// is intended to support the filter syntax for resources versions 7 and older. A FilterMap contains a map of - /// one or many filter parameter pair(s). An example of a filterMap string indicating the contents of the map is: - /// ?firstName=James. - ///

This is NOT intended to be used for resource versions after version 7 and/or for criteria filters.

- ///
- /// The name of the resource to get data for. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// A string containing the filter syntax used for request URL filters with resource versions 7 or older. - /// An EthosResponse containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - /// Returns exception if the resourceName or filterMap is null. - public async Task GetWithFilterMapAsync( string resourceName, string version, FilterMap filterMap ) - { - ArgumentNullException.ThrowIfNull( filterMap, $"Error: Cannot get resource '{resourceName}' with filter map due to a null filter map." ); - return await GetWithFilterMapAsync( resourceName, version, filterMap.ToString() ); - } - - /// - /// Gets all the pages for a given resource using the specified criteria filter. Uses the default version of the resource, - /// and the page size is derived from the length of the returned response of the request using the criteria filter. - /// - /// The name of the resource to get data for. - /// A previously built Criteria containing the filter criteria used in the request URL. - /// A simple call to criteriaFilter.BuildCriteria() should output the criteria filter portion of the request URL, - /// e.g: ?criteria={"names":[{"firstName":"John"}]}. - /// An EthosResponse containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - public async Task> GetPagesWithCriteriaFilterAsync( string resourceName, CriteriaFilter criteria ) - { - return await GetPagesWithCriteriaFilterAsync( resourceName, DEFAULT_VERSION, criteria, DEFAULT_PAGE_SIZE ); - } - - /// - /// Gets all the pages for a given resource using the specified criteria filter for the given version. Uses the default - /// page size, which is the length of the returned response of the request using the criteria filter. - /// - /// The name of the resource to get data for. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// A previously built Criteria containing the filter criteria used in the request URL. - /// An EthosResponse containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - public async Task> GetPagesWithCriteriaFilterAsync( string resourceName, string version, CriteriaFilter criteria ) - { - return await GetPagesWithCriteriaFilterAsync( resourceName, version, criteria, DEFAULT_PAGE_SIZE ); - } - - /// - /// Gets all the pages for a given resource using the specified namedQueryFilter filter. Uses the default version of the resource, - /// and the page size is derived from the length of the returned response of the request using the namedQueryFilter filter. - /// - /// The name of the resource to get data for. - /// A previously built namedQueryFilter containing the filter used in the request URL. - /// A simple call to namedQueryFilter.BuildNamedQuery() should output the namedQueryFilter filter portion of the request URL. - /// An EthosResponse containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - public async Task> GetPagesWithNamedQueryFilterAsync( string resourceName, NamedQueryFilter namedQueryFilter ) - { - return await GetPagesWithNamedQueryFilterAsync( resourceName, DEFAULT_VERSION, namedQueryFilter, DEFAULT_PAGE_SIZE ); - } - - /// - /// Gets all the pages for a given resource using the specified namedQueryFilter filter for the given version. Uses the default - /// page size, which is the length of the returned response of the request using the namedQueryFilter filter. - /// - /// The name of the resource to get data for. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// A previously built namedQueryFilter containing the filter used in the request URL. - /// An EthosResponse containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - public async Task> GetPagesWithNamedQueryFilterAsync( string resourceName, string version, NamedQueryFilter namedQueryFilter ) - { - return await GetPagesWithNamedQueryFilterAsync( resourceName, version, namedQueryFilter, DEFAULT_PAGE_SIZE ); - } - - /// - /// Gets all the pages for a given resource using the specified criteria filter and page size. The default version - /// of the resource is used. - /// - /// The name of the resource to get data for. - /// A previously built Criteria containing the filter criteria used in the request URL. - /// The size (number of rows) of each page returned in the list. - /// An EthosResponse containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - public async Task> GetPagesWithCriteriaFilterAsync( string resourceName, CriteriaFilter criteria, int pageSize ) - { - return await GetPagesWithCriteriaFilterAsync( resourceName, DEFAULT_VERSION, criteria, pageSize ); - } - - /// - /// Gets all the pages for a given resource using the specified criteria filter and page size for the given version. - /// - /// The name of the resource to get data for. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// A previously built Criteria containing the filter criteria used in the request URL. - /// The size (number of rows) of each page returned in the list. - /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - public async Task> GetPagesWithCriteriaFilterAsync( string resourceName, string version, CriteriaFilter criteria, int pageSize ) - { - return await GetPagesFromOffsetWithCriteriaFilterAsync( resourceName, version, criteria, pageSize, 0 ); - } - - /// - /// Gets all the pages for a given resource using the specified namedQueryFilter filter and page size. The default version - /// of the resource is used. - /// - /// The name of the resource to get data for. - /// A previously built namedQueryFilter containing the filter used in the request URL. - /// The size (number of rows) of each page returned in the list. - /// An EthosResponse containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - public async Task> GetPagesWithNamedQueryFilterAsync( string resourceName, NamedQueryFilter namedQueryFilter, int pageSize ) - { - return await GetPagesWithNamedQueryFilterAsync( resourceName, DEFAULT_VERSION, namedQueryFilter, pageSize ); - } - - /// - /// Gets all the pages for a given resource using the specified namedQueryFilter filter and page size for the given version. - /// - /// The name of the resource to get data for. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// A previously built namedQueryFilter containing the filter named query used in the request URL. - /// The size (number of rows) of each page returned in the list. - /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - public async Task> GetPagesWithNamedQueryFilterAsync( string resourceName, string version, NamedQueryFilter namedQueryFilter, int pageSize ) - { - return await GetPagesFromOffsetWithNamedQueryFilterAsync( resourceName, version, namedQueryFilter, pageSize, 0 ); - } - - /// - /// Gets all the pages for a given resource beginning at the given offset index, using the specified criteria filter. - /// The page size is determined to be the length of the returned response of the request using the criteria filter. - /// The default version of the resource is used. - /// - /// The name of the resource to get data for. - /// A previously built Criteria containing the filter criteria used in the request URL. - /// The 0 based index from which to begin paging for the given resource. - /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - public async Task> GetPagesFromOffsetWithCriteriaFilterAsync( string resourceName, CriteriaFilter criteria, int offset ) - { - return await GetPagesFromOffsetWithCriteriaFilterAsync( resourceName, DEFAULT_VERSION, criteria, offset ); - } - - /// - /// Gets all the pages for a given resource beginning at the given offset index, using the specified criteria filter - /// for the given version. The page size is determined to be the length of the returned response of the request using - /// the criteria filter. - /// - /// The name of the resource to get data for. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// A previously built Criteria containing the filter criteria used in the request URL. - /// The 0 based index from which to begin paging for the given resource. - /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - public async Task> GetPagesFromOffsetWithCriteriaFilterAsync( string resourceName, string version, CriteriaFilter criteria, int offset ) - { - return await GetPagesFromOffsetWithCriteriaFilterAsync( resourceName, version, criteria, DEFAULT_PAGE_SIZE, offset ); - } - - /// - /// Gets all the pages for a given resource beginning at the given offset index, using the specified namedQueryFilter filter. - /// The page size is determined to be the length of the returned response of the request using the namedQueryFilter filter. - /// The default version of the resource is used. - /// - /// The name of the resource to get data for. - /// - /// The 0 based index from which to begin paging for the given resource. - /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - public async Task> GetPagesFromOffsetWithNamedQueryFilterAsync( string resourceName, NamedQueryFilter namedQueryFilter, int offset ) - { - return await GetPagesFromOffsetWithNamedQueryFilterAsync( resourceName, DEFAULT_VERSION, namedQueryFilter, offset ); - } - - /// - /// Gets all the pages for a given resource beginning at the given offset index, using the specified namedQueryFilter filter - /// for the given version. The page size is determined to be the length of the returned response of the request using - /// the namedQueryFilter filter. - /// - /// The name of the resource to get data for. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// A previously built namedQueryFilter containing the filter used in the request URL. - /// The 0 based index from which to begin paging for the given resource. - /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - public async Task> GetPagesFromOffsetWithNamedQueryFilterAsync( string resourceName, string version, NamedQueryFilter namedQueryFilter, int offset ) - { - return await GetPagesFromOffsetWithNamedQueryFilterAsync( resourceName, version, namedQueryFilter, DEFAULT_PAGE_SIZE, offset ); - } - - /// - /// Gets all the pages for a given resource beginning at the given offset index, using the specified criteria filter - /// and page size for the given version. The default version of the resource is used. - /// - /// The name of the resource to get data for. - /// A previously built Criteria containing the filter criteria used in the request URL. - /// The size (number of rows) of each page returned in the list. - /// The 0 based index from which to begin paging for the given resource. - /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - public async Task> GetPagesFromOffsetWithCriteriaFilterAsync( string resourceName, CriteriaFilter criteria, int pageSize, int offset ) - { - return await GetPagesFromOffsetWithCriteriaFilterAsync( resourceName, DEFAULT_VERSION, criteria, pageSize, offset ); - } - - /// - /// Gets all the pages for a given resource beginning at the given offset index, using the specified criteria filter - /// and page size for the given version. - /// - /// The name of the resource to get data for. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// A previously built Criteria containing the filter criteria used in the request URL. - /// The size (number of rows) of each page returned in the list. - /// The 0 based index from which to begin paging for the given resource. - /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - /// Returns exception if the resourceName or criteriaFilter is null. - public async Task> GetPagesFromOffsetWithCriteriaFilterAsync( string resourceName, string version, CriteriaFilter criteria, int pageSize, int offset ) - { - if ( string.IsNullOrWhiteSpace( resourceName ) ) - { - throw new ArgumentNullException( "Error: Cannot get pages of resource from offset with criteria filter due to a null or blank resource name." ); - } - if ( criteria == null ) - { - throw new ArgumentNullException( $"Error: Cannot get pages of resource '{ resourceName }' from offset with criteria filter due to a null criteria filter reference." ); - } - List ethosResponseList = new List(); - Pager pager = Pager.Build( pg => - { - pg - .ForResource( resourceName ) - .ForVersion( version ) - .WithCriteriaFilter( criteria.BuildCriteria() ) - .WithPageSize( pageSize ) - .FromOffSet( offset ); - } ); - - pager = await PrepareForPagingAsync( pager ); - pager = ShouldDoPaging( pager, false ); - if ( pager.ShouldDoPaging ) - { - ethosResponseList = await DoPagingFromOffsetAsync( pager.ResourceName, pager.Version, pager.CriteriaFilter, pager.TotalCount, pager.PageSize, offset ); - } - else - { - ethosResponseList.Add( await GetWithCriteriaFilterAsync( resourceName, version, criteria ) ); - } - return ethosResponseList; - } - - /// - /// Gets all the pages for a given resource beginning at the given offset index, using the specified namedQueryFilter - /// and page size for the given version. The default version of the resource is used. - /// - /// The name of the resource to get data for. - /// A previously built namedQueryFilter containing the filter used in the request URL. - /// The size (number of rows) of each page returned in the list. - /// The 0 based index from which to begin paging for the given resource. - /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - public async Task> GetPagesFromOffsetWithNamedQueryFilterAsync( string resourceName, NamedQueryFilter namedQueryFilter, int pageSize, int offset ) - { - return await GetPagesFromOffsetWithNamedQueryFilterAsync( resourceName, DEFAULT_VERSION, namedQueryFilter, pageSize, offset ); - } - - /// - /// Gets all the pages for a given resource beginning at the given offset index, using the specified namedQueryFilter - /// and page size for the given version. - /// - /// The name of the resource to get data for. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// A previously built namedQueryFilter containing the filter used in the request URL. - /// The size (number of rows) of each page returned in the list. - /// The 0 based index from which to begin paging for the given resource. - /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - /// Returns exception if the resourceName or namedQueryFilter is null. - public async Task> GetPagesFromOffsetWithNamedQueryFilterAsync( string resourceName, string version, NamedQueryFilter namedQueryFilter, int pageSize, int offset ) - { - if ( string.IsNullOrWhiteSpace( resourceName ) ) - { - throw new ArgumentNullException( "Error: Cannot get pages of resource from offset with named query filter due to a null or blank resource name." ); - } - if ( namedQueryFilter == null ) - { - throw new ArgumentNullException( $"Error: Cannot get pages of resource '{ resourceName }' from offset with named query filter due to a null named query filter reference." ); - } - List ethosResponseList = new List(); - Pager pager = Pager.Build( pg => - { - pg - .ForResource( resourceName ) - .ForVersion( version ) - .WithNamedQuery( namedQueryFilter.BuildNamedQuery() ) - .WithPageSize( pageSize ) - .FromOffSet( offset ); - } ); - - pager = await PrepareForPagingAsync( pager ); - pager = ShouldDoPaging( pager, false ); - if ( pager.ShouldDoPaging ) - { - ethosResponseList = await DoPagingFromOffsetAsync( pager.ResourceName, pager.Version, pager.NamedQueryFilter, pager.TotalCount, pager.PageSize, offset ); - } - else - { - ethosResponseList.Add( await GetWithNamedQueryFilterAsync( resourceName, version, namedQueryFilter ) ); - } - return ethosResponseList; - } - - /// - /// Gets all the pages for a given resource using the specified filter map and page size for the given version. - /// - /// The name of the resource to get data for. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// A previously built FilterMap containing the filter parameters used in the request URL. - /// A simple call to filterMap.tostring() should output the criteria filter portion of the request URL, - /// e.g: ?firstName=John&lastName=Smith. - /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - public async Task> GetPagesWithFilterMapAsync( string resourceName, string version, FilterMap filterMap ) - { - return await GetPagesWithFilterMapAsync( resourceName, version, filterMap, DEFAULT_PAGE_SIZE ); - } - - /// - /// Gets all the pages for a given resource using the specified filter map and page size for the given version. - /// - /// The name of the resource to get data for. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// A previously built FilterMap containing the filter parameters used in the request URL. - /// A simple call to filterMap.tostring() should output the criteria filter portion of the request URL, - /// e.g: ?firstName=John&lastName=Smith. - /// The size (number of rows) of each page returned in the list. - /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - public async Task> GetPagesWithFilterMapAsync( string resourceName, string version, FilterMap filterMap, int pageSize ) - { - return await GetPagesFromOffsetWithFilterMapAsync( resourceName, version, filterMap, pageSize, 0 ); - } - - /// - /// Gets all the pages for a given resource beginning at the given offset index, using the specified filter map and - /// page size for the given version. The page size is determined to be the length of the returned response of the request using - /// the filter map. - /// - /// The name of the resource to get data for. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// A previously built FilterMap containing the filter parameters used in the request URL. - /// A simple call to filterMap.tostring() should output the criteria filter portion of the request URL, - /// e.g: ?firstName=John&lastName=Smith. - /// The 0 based index from which to begin paging for the given resource. - /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - public async Task> GetPagesFromOffsetWithFilterMapAsync( string resourceName, string version, FilterMap filterMap, int offset ) - { - return await GetPagesFromOffsetWithFilterMapAsync( resourceName, version, filterMap, DEFAULT_PAGE_SIZE, offset ); - } - - /// - /// Gets all the pages for a given resource beginning at the given offset index, using the specified filter map and - /// page size for the given version. - /// - /// The name of the resource to get data for. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// A previously built FilterMap containing the filter parameters used in the request URL. - /// A simple call to filterMap.tostring() should output the criteria filter portion of the request URL, - /// e.g: ?firstName=John&lastName=Smith. - /// The size (number of rows) of each page returned in the list. - /// The 0 based index from which to begin paging for the given resource. - /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - public async Task> GetPagesFromOffsetWithFilterMapAsync( string resourceName, string version, FilterMap filterMap, int pageSize, int offset ) - { - if ( string.IsNullOrWhiteSpace( resourceName ) ) - { - throw new ArgumentNullException( "Error: Cannot get pages of resource with filter map due to a null or blank resource name." ); - } - if ( filterMap == null ) - { - throw new ArgumentNullException( $"Error: Cannot get pages of resource '{ resourceName }' with filter map due to a null filter map reference." ); - } - List ethosResponseList = new List(); - Pager pager = Pager.Build( pg => - { - pg - .ForResource( resourceName ) - .ForVersion( version ) - .WithFilterMap( filterMap.ToString() ) - .WithPageSize( pageSize ) - .FromOffSet( offset ); - } ); - - pager = await PrepareForPagingAsync( pager ); - pager = ShouldDoPaging( pager, false ); - if ( pager.ShouldDoPaging ) - { - ethosResponseList = await DoPagingFromOffsetAsync( pager.ResourceName, pager.Version, pager.FilterMap, pager.TotalCount, pager.PageSize, offset ); - } - else - { - ethosResponseList.Add( await GetWithFilterMapAsync( resourceName, version, filterMap ) ); - } - return ethosResponseList; - } - - #region QAPI's - - /// - /// Submits a POST request for the given resourceName with the given qapiRequestBody. The qapiRequestBody should be a string in JSON format. - /// - /// The name of the resource to add an instance of. - /// The full version header value of the resource used for this POST request. - /// The body of the request to POST for the given resource. - /// An EthosResponse containing the instance of the resource that was added by this POST operation. - /// When is passed as null or empty or white space. - /// When is passed as null or empty or white space. - public async Task GetWithQapiAsync( string resourceName, string qapiRequestBody, string version = "" ) - { - if ( string.IsNullOrWhiteSpace( resourceName ) ) - { - throw new ArgumentNullException( $"Error: Cannot submit a POST request due to a null or blank {nameof( resourceName )} parameter." ); - } - - if ( string.IsNullOrWhiteSpace( qapiRequestBody ) ) - { - throw new ArgumentNullException( - $"Error: Cannot submit a POST request for resource {resourceName} due to a null or blank {nameof( qapiRequestBody )} parameter." - ); - } - var headers = BuildHeadersMap( version ); - string url = EthosIntegrationUrls.Qapi( Region, resourceName ); - return await base.PostAsync( headers, url, qapiRequestBody ); - } - - /// - /// Submits a POST request for the given resourceName with the given requestBodyNode. The requestBodyNode should be a JObject. - /// - /// The name of the resource to add an instance of. - /// The full version header value of the resource used for this POST request. - /// The body of the request to POST for the given resource as a JsonNode. - /// An EthosResponse containing the instance of the resource that was added by this POST operation. - /// When is passed as null or empty or white space. - /// When is passed as null. - public async Task GetWithQapiAsync( string resourceName, JObject qapiRequestBodyNode, string version = "" ) - { - ArgumentNullException.ThrowIfNull( qapiRequestBodyNode, $"Error: Cannot submit a POST request for resource {resourceName} due to a null {nameof( qapiRequestBodyNode )} parameter." ); - return await GetWithQapiAsync(resourceName, qapiRequestBodyNode.ToString(), version ); - } - - /// - /// Submits a POST request for the given resourceName with the given qapiRequestBody. The qapiRequestBody should be a T type class. - /// - /// Request type. - /// The name of the resource to add an instance of. - /// The full version header value of the resource used for this POST request. - /// The body of the request to POST for the given resource. - /// An EthosResponse containing the instance of the resource that was added by this POST operation. - /// When is passed as null or empty or white space. - /// When is passed as null. - public async Task GetWithQapiAsync( string resourceName, T qapiRequestBody, string version = "" ) where T : class - { - ArgumentNullException.ThrowIfNull( qapiRequestBody, $"Error: Cannot submit a POST request for resource {resourceName} due to a null {nameof( qapiRequestBody )} parameter." ); - - JsonSerializerSettings jsonSerSettings = GetJsonSerializerSettings(); - var reqBody = JsonConvert.SerializeObject( qapiRequestBody, jsonSerSettings ); - return await GetWithQapiAsync( resourceName, reqBody, version ); - } - - /// - /// Gets the total count of resources available using the given criteriaFilter. Gets the pages for a given resource beginning at the given offset index, - /// using the specified QAPI request body and page size for the given version. - /// - /// The name of the resource to add an instance of. - /// The full version header value of the resource used for this POST request. - /// The body of the request to POST for the given resource. - /// The size (number of rows) of each page returned in the list. - /// The 0 based index from which to begin paging for the given resource. - /// A list of EthosResponses where each EthosResponse contains a page of data. If paging is not required based on the - /// given pageSize and total count( from using the filter), the returned list will only contain one EthosResponse. - /// When is passed as null or empty or white space. - /// When is passed as null. - public async Task> GetPagesFromOffsetWithQAPIAsync( string resourceName, string qapiRequestBody, string version = "", int pageSize = 0, int offset = 0) - { - if ( string.IsNullOrWhiteSpace( resourceName ) ) - { - throw new ArgumentNullException( $"Error: Cannot submit a POST request due to a null or blank {nameof( resourceName )} parameter." ); - } - - if ( string.IsNullOrWhiteSpace( qapiRequestBody ) ) - { - throw new ArgumentNullException( $"Error: Cannot submit a POST request for resource {resourceName} due to a null {nameof( qapiRequestBody )} parameter." ); - } - - List ethosResponseList = new(); - Pager pager = Pager.Build( pg => - { - pg - .ForResource( resourceName ) - .ForVersion( version ) - .FromOffSet( offset ) - .WithPageSize( pageSize ) - .WithQAPIRequestBodyFilter( qapiRequestBody ); - } ); - - pager = await PrepareForPagingAsync( pager ); - pager = ShouldDoPaging( pager, false ); - if ( pager.ShouldDoPaging ) - { - ethosResponseList = await DoPagingFromOffsetForQAPIAsync( pager.ResourceName, pager.Version, qapiRequestBody, pager.TotalCount, pager.PageSize, pager.Offset ); - } - else - { - ethosResponseList.Add( await GetWithQapiAsync( resourceName, qapiRequestBody, version ) ); - } - return ethosResponseList; - } - - /// - /// Gets the total count of resources available using the given criteriaFilter. Gets the pages for a given resource beginning at the given offset index, - /// using the specified QAPI request body and page size for the given version. - /// - /// The name of the resource to add an instance of. - /// The full version header value of the resource used for this POST request. - /// The body of the request to POST for the given resource. - /// The size (number of rows) of each page returned in the list. - /// The 0 based index from which to begin paging for the given resource. - /// A list of EthosResponses where each EthosResponse contains a page of data. If paging is not required based on the - /// given pageSize and total count( from using the filter), the returned list will only contain one EthosResponse. - /// When is passed as null or empty or white space. - /// When is passed as null. - public async Task> GetPagesFromOffsetWithQAPIAsync( string resourceName, JObject qapiRequestBody, string version = "", int pageSize = 0, int offset = 0 ) - { - ArgumentNullException.ThrowIfNull( qapiRequestBody, $"Error: Cannot submit a POST request for resource {resourceName} due to a null {nameof( qapiRequestBody )} parameter." ); - return await GetPagesFromOffsetWithQAPIAsync(resourceName, qapiRequestBody.ToString(), version, pageSize, offset ); - } - - /// - /// Gets the total count of resources available using the given type T. - /// Gets the pages for a given resource beginning at the given offset index, using the specified QAPI request body and page size for the given version. - /// - /// Request type. - /// The name of the resource to add an instance of. - /// The full version header value of the resource used for this POST request. - /// The body of the request to POST for the given resource. - /// The size (number of rows) of each page returned in the list. - /// The 0 based index from which to begin paging for the given resource. - /// A list of EthosResponses where each EthosResponse contains a page of data. If paging is not required based on the - /// given pageSize and total count( from using the filter), the returned list will only contain one EthosResponse. - /// When is passed as null or empty or white space. - /// When is passed as null. - public async Task> GetPagesFromOffsetWithQAPIAsync( string resourceName, T qapiRequestBody, string version = "", int pageSize = 0, int offset = 0 ) where T : class - { - ArgumentNullException.ThrowIfNull( qapiRequestBody, $"Error: Cannot submit a POST request for resource {resourceName} due to a null {nameof( qapiRequestBody )} parameter." ); - - var jsonSerSettings = GetJsonSerializerSettings(); - var reqBody = JsonConvert.SerializeObject( qapiRequestBody, jsonSerSettings ); - return await GetPagesFromOffsetWithQAPIAsync( resourceName, reqBody, version, pageSize, offset ); - } - - /// - /// Gets all the pages for a given resource beginning at offset index 0, using the specified QAPI request body and page size for the given version. - /// - /// The name of the resource to add an instance of. - /// The full version header value of the resource used for this POST request. - /// The body of the request to POST for the given resource. - /// The size (number of rows) of each page returned in the list. - /// A list of EthosResponses where each EthosResponse contains a page of data. If paging is not required based on the - /// given pageSize and total count( from using the filter), the returned list will only contain one EthosResponse. - /// When is passed as null or empty or white space. - /// When is passed as null. - public async Task> GetPagesWithQAPIAsync( string resourceName, string qapiRequestBody, string version = "", int pageSize = 0 ) - { - return await GetPagesFromOffsetWithQAPIAsync(resourceName, qapiRequestBody, version, pageSize, 0 ); - } - - /// - /// Gets all the pages for a given resource beginning at offset index 0, using the specified QAPI request body and page size for the given version. - /// - /// The name of the resource to add an instance of. - /// The full version header value of the resource used for this POST request. - /// The body of the request to POST for the given resource. - /// The size (number of rows) of each page returned in the list. - /// A list of EthosResponses where each EthosResponse contains a page of data. If paging is not required based on the - /// given pageSize and total count( from using the filter), the returned list will only contain one EthosResponse. - /// When is passed as null or empty or white space. - /// When is passed as null. - public async Task> GetPagesWithQAPIAsync( string resourceName, JObject qapiRequestBody, string version = "", int pageSize = 0 ) - { - ArgumentNullException.ThrowIfNull( qapiRequestBody, $"Error: Cannot submit a POST request for resource {resourceName} due to a null {nameof( qapiRequestBody )} parameter." ); - return await GetPagesWithQAPIAsync( resourceName, qapiRequestBody.ToString(), version, pageSize ); - } - - /// - /// Gets all the pages for a given resource beginning at offset index 0, using the specified QAPI request body and page size for the given version. - /// - /// Request type. - /// The name of the resource to add an instance of. - /// The full version header value of the resource used for this POST request. - /// The body of the request to POST for the given resource. - /// The size (number of rows) of each page returned in the list. - /// A list of EthosResponses where each EthosResponse contains a page of data. If paging is not required based on the - /// given pageSize and total count( from using the filter), the returned list will only contain one EthosResponse. - /// When is passed as null or empty or white space. - /// When is passed as null. - public async Task> GetPagesWithQAPIAsync( string resourceName, T qapiRequestBody, string version = "", int pageSize = 0 ) where T : class - { - ArgumentNullException.ThrowIfNull( qapiRequestBody, $"Error: Cannot submit a POST request for resource {resourceName} due to a null {nameof( qapiRequestBody )} parameter." ); - - var jsonSerSettings = GetJsonSerializerSettings(); - var reqBody = JsonConvert.SerializeObject( qapiRequestBody, jsonSerSettings ); - return await GetPagesWithQAPIAsync( resourceName, reqBody, version, pageSize ); - } - - /// - /// Gets the total count of resources available using the given QAPI request body. - /// - /// The name of the resource to get data for. - /// The body of the request to POST for the given resource. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// The number of resource instances available when making a GET request using the given namedQueryFilter, or 0 if the - /// given resourceName or namedQueryFilter is null. - /// Returns exception if the resourceName is null. - /// Returns exception if the qapiRequestBody is null. - public async Task GetTotalCountAsync( string resourceName, string qapiRequestBody, string version = "" ) - { - if ( string.IsNullOrWhiteSpace( resourceName ) || string.IsNullOrWhiteSpace( qapiRequestBody ) ) - { - return default; - } - - EthosResponse ethosResponse = await GetWithQapiAsync( resourceName, qapiRequestBody, version ); - string totalCount = GetHeaderValue( ethosResponse, HDR_X_TOTAL_COUNT ); - if ( int.TryParse( totalCount, out int count ) ) - { - return count; - } - return default; - } - - /// - /// Gets the total count of resources available using the given QAPI request body. - /// - /// The name of the resource to get data for. - /// The body of the request to POST for the given resource. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// The number of resource instances available when making a GET request using the given namedQueryFilter, or 0 if the - /// given resourceName or namedQueryFilter is null. - /// Returns exception if the resourceName is null. - /// Returns exception if the qapiRequestBody is null. - public async Task GetTotalCountAsync( string resourceName, JObject qapiRequestBody, string version = "" ) - { - if( qapiRequestBody is null) return default; - return await GetTotalCountAsync( resourceName, qapiRequestBody.ToString(), version ); - } - - /// - /// Gets the total count of resources available using the given QAPI request body. - /// - /// The name of the resource to get data for. - /// The body of the request to POST for the given resource. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// The number of resource instances available when making a GET request using the given namedQueryFilter, or 0 if the - /// given resourceName or namedQueryFilter is null. - /// Returns exception if the resourceName is null. - /// Returns exception if the qapiRequestBody is null. - public async Task GetTotalCountAsync( string resourceName, T qapiRequestBody, string version = "" ) where T : class - { - if ( string.IsNullOrWhiteSpace( resourceName ) || qapiRequestBody is null ) - { - return default; - } - - EthosResponse ethosResponse = await GetWithQapiAsync( resourceName, qapiRequestBody, version ); - string totalCount = GetHeaderValue( ethosResponse, HDR_X_TOTAL_COUNT ); - if ( int.TryParse( totalCount, out int count ) ) - { - return count; - } - return default; - } - - /// - ///

Intended to be used internally within the SDK.

Performs paging calculations and operations for QAPI requests. - ///
- /// The name of the resource to add an instance of. - /// The full version header value of the resource used for this POST request. - /// The body of the request to POST for the given resource. - /// The total count of rows for the given resource. - /// The size (number of rows) of each page returned in the list. - /// The 0 based index from which to begin paging for the given resource. - /// Collection of EthosResponse with content. - protected async Task> DoPagingFromOffsetForQAPIAsync( string resourceName, string version, string qapiRequestBody, int totalCount, int pageSize, int offset ) - { - List ethosResponseList = new(); - Dictionary headers = BuildHeadersMap( version ); - decimal numPages = Math.Ceiling( ( Convert.ToDecimal( totalCount ) - Convert.ToDecimal( offset ) ) / Convert.ToDecimal( pageSize ) ); - for ( int i = 0; i < numPages; i++ ) - { - string url = EthosIntegrationUrls.QapiPaging( Region, resourceName, offset, pageSize ); - EthosResponse response = await base.PostAsync( headers, url, qapiRequestBody ); - ethosResponseList.Add( response ); - offset += pageSize; - } - return ethosResponseList; - } - - #endregion QAPI - - /// - /// Gets the total count of resources available using the given criteriaFilter. - /// - /// The name of the resource to get data for. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// A previously built Criteria containing the filter criteria used in the request URL. - /// The number of resource instances available when making a GET request using the given criteriaFilter, or 0 if the - /// given resourceName or criteriaFilter is null. - /// Returns exception if the resourceName is null. - /// Returns exception if the criteriaFilterStr is null. - public async Task GetTotalCountAsync( string resourceName, CriteriaFilter criteria, string version = "" ) - { - if ( string.IsNullOrWhiteSpace( resourceName ) ) - { - return default; - } - if ( criteria == null ) - { - return default; - } - EthosResponse ethosResponse = await GetWithCriteriaFilterAsync( resourceName, version, criteria.BuildCriteria() ); - string totalCount = GetHeaderValue( ethosResponse, HDR_X_TOTAL_COUNT ); - if ( int.TryParse( totalCount, out int count ) ) - { - return count; - } - return default; - } - - /// - /// Gets the total count of resources available using the given namedQueryFilter. - /// - /// The name of the resource to get data for. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// A previously built namedQueryFilter containing the filter used in the request URL. - /// The number of resource instances available when making a GET request using the given namedQueryFilter, or 0 if the - /// given resourceName or namedQueryFilter is null. - /// Returns exception if the resourceName is null. - public async Task GetTotalCountAsync( string resourceName, NamedQueryFilter namedQueryFilter, string version = "" ) - { - if ( string.IsNullOrWhiteSpace( resourceName ) ) - { - return default; - } - if ( namedQueryFilter == null ) - { - return default; - } - EthosResponse ethosResponse = await GetWithNamedQueryFilterAsync( resourceName, version, namedQueryFilter.BuildNamedQuery() ); - string totalCount = GetHeaderValue( ethosResponse, HDR_X_TOTAL_COUNT ); - if ( int.TryParse( totalCount, out int count ) ) - { - return count; - } - return default; - } - - /// - /// Gets the total count of resources available using the given filterMap. - /// - /// The name of the resource to get data for. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// A previously built FilterMap containing the filter parameters used in the request URL. - /// A simple call to filterMap.Tostring() should output the criteria filter portion of the request URL, - /// e.g: ?firstName=John&lastName=Smith. - /// The number of resource instances available when making a GET request using the given criteriaFilter, or 0 if the - /// given resourceName or criteriaFilter is null. - /// Returns exception if the resourceName is null. - public async Task GetTotalCountAsync( string resourceName, FilterMap filterMap, string version = "" ) - { - if ( string.IsNullOrWhiteSpace( resourceName ) ) - { - return default; - } - if ( filterMap == null ) - { - return default; - } - EthosResponse ethosResponse = await GetWithFilterMapAsync( resourceName, version, filterMap.ToString() ); - string totalCount = GetHeaderValue( ethosResponse, HDR_X_TOTAL_COUNT ); - if ( int.TryParse( totalCount, out int count ) ) - { - return count; - } - return default; - } - - /// - ///

Intended to be used internally within the SDK. - ///

- /// Overrides the prepareForPaging() method in the EthosProxyClient super class. - ///

- /// Uses the given pager object to prepare for paging operations. The pager object is used to contain various - /// fields required for paging. If the given pager is null, returns the same pager. Sets default values for the - /// version and offset within the pager as needed and makes an initial resource call using the provided pager filter - /// to get metadata about the resource used for paging. Also sets the page size and the total count within the pager, - /// and encodes the filter within the pager.

- ///
- /// The Pager object used holding the required fields for paging. - /// The same pager object with the version and offset validated, the page size and total count set, and the filter encoded. - protected new async Task PrepareForPagingAsync( Pager pager ) - { - if ( pager == null ) - { - return pager; - } - if ( string.IsNullOrWhiteSpace( pager.Version ) ) - { - pager.Version = DEFAULT_VERSION; - } - if ( pager.Offset < 1 ) - { - pager.Offset = 0; - } - - pager = await PreparePagerForTotalCountAsync( pager ); - - // Set the pageSize. - pager = PreparePagerForPageSize( pager ); - - // Encode the criteriaFilter if it is not null. - if ( pager.CriteriaFilter != null ) - { - pager.CriteriaFilter = EncodeString( pager.CriteriaFilter ); - } - - // Encode the NamedQueryFilter if it is not null. - if ( pager.NamedQueryFilter != null ) - { - pager.NamedQueryFilter = EncodeString( pager.NamedQueryFilter ); - } - return pager; - } - - /// - /// Intended to be used internally by the SDK. - ///

Prepares the pager object for the total count required for paging calculations. - /// The total count is derived from the response x-total-count header after making an initial request using filters

- /// (in this case). - ///
- /// The Pager object used holding the required fields for paging. - /// The pager object containing the total count. If neither a criteria filter, a named query nor a filter map is specified - /// in the pager, then the total count will be 0. - protected async Task PreparePagerForTotalCountAsync( Pager pager ) - { - EthosResponse ethosResponse = null; - if ( pager.CriteriaFilter is not null ) - { - ethosResponse = await GetWithCriteriaFilterAsync( pager.ResourceName, pager.Version, pager.CriteriaFilter ); - pager.EthosResponse = ethosResponse; - } - else if ( pager.NamedQueryFilter is not null ) - { - ethosResponse = await GetWithNamedQueryFilterAsync( pager.ResourceName, pager.Version, pager.NamedQueryFilter ); - pager.EthosResponse = ethosResponse; - } - else if ( pager.FilterMap is not null ) - { - ethosResponse = await GetWithFilterMapAsync( pager.ResourceName, pager.Version, pager.FilterMap ); - pager.EthosResponse = ethosResponse; - } - else if ( pager.QapiRequestBody is not null ) - { - ethosResponse = await GetWithQapiAsync( pager.ResourceName, pager.QapiRequestBody, pager.Version ); - pager.EthosResponse = ethosResponse; - } - else - { - await base.PrepareForPagingAsync( pager ); - } - if ( ethosResponse is not null ) - { - string totalCount = GetHeaderValue( ethosResponse, HDR_X_TOTAL_COUNT ); - if ( int.TryParse( totalCount, out int count ) ) - { - pager.TotalCount = count; - } - } - return pager; - } - - /// - /// Intended to be used internally by the SDK. - ///

- /// If the page size specified in the pager is <= DEFAULT_PAGE_SIZE, then this method prepares the pager object for the - /// page size required for paging calculations. The page size is derived from the response body length after making an initial request using filters - /// (in this case). If the response is null, the DEFAULT_MAX_PAGE_SIZE is used. If the response body is null, the - /// x-max-page-size header is used.

- ///

If the page size specified in the pager is > DEFAULT_PAGE_SIZE, this method does nothing and just returns the given pager.

- ///
- /// The pager object used to contain the page size for paging operations. - /// The pager object containing the page size. - protected Pager PreparePagerForPageSize( Pager pager ) - { - if ( pager.PageSize <= DEFAULT_PAGE_SIZE ) - { - if ( pager.EthosResponse == null ) - { - pager.PageSize = DEFAULT_MAX_PAGE_SIZE; // Set the page size to the MAX default because there is no ethosResponse. - } - // Set the pageSize from the response body length, if pageSize is <= DEFAULT_PAGE_SIZE. - else if ( !string.IsNullOrWhiteSpace( pager.EthosResponse.Content ) && pager.EthosResponse.GetContentAsJson() != null ) - { - int pageSize = pager.EthosResponse.GetContentCount(); - pager.PageSize = pageSize; - } - else - { - string maxPageSizeStr = GetHeaderValue( pager.EthosResponse, HDR_X_MAX_PAGE_SIZE ); - if ( !string.IsNullOrWhiteSpace( maxPageSizeStr ) ) - { - if ( int.TryParse( maxPageSizeStr, out int pageSize ) ) - { - pager.PageSize = pageSize; - } - } - else - { - pager.PageSize = DEFAULT_MAX_PAGE_SIZE; - } - } - } - return pager; - } - - /// - /// Used internally by the SDK. - ///

- /// Encodes the given criteriaFilterStr. Supports criteria filter strings that begin with the CRITERIA_FILTER_PREFIX - /// value "?criteria=", and also those that do not. Encodes only the JSON criteria portion of the filter string, removing - /// the CRITERIA_FILTER_PREFIX portion if the filter string starts with it. If the filter string does not start with - /// the CRITERIA_FILTER_PREFIX, the criteriaFilterStr string is simply encoded.

- ///

Returns a criteria filter string that begins with the CRITERIA_FILTER_PREFIX, with the JSON filter portion of the string - /// encoded. Uses UTF-8 encoding.

- ///
- /// The criteria filter string to encode. - /// A criteria filter string beginning with the CRITERIA_FILTER_PREFIX with the JSON filter syntax portion of the - /// string encoded in UTF-8. - private static string EncodeString( string criteriaFilterStr ) - { - StringBuilder sb = new StringBuilder(); - string jsonCriteriaStr; - bool isNamedQuery = false; - if ( criteriaFilterStr.StartsWith( CRITERIA_FILTER_PREFIX ) ) - { - // It starts with "?criteria=", so substring the rest of the filter and encode it. - jsonCriteriaStr = criteriaFilterStr [ ( criteriaFilterStr.IndexOf( "=" ) + 1 ).. ]; - } - else - { - jsonCriteriaStr = criteriaFilterStr; - isNamedQuery = true; - } - jsonCriteriaStr = System.Web.HttpUtility.UrlEncode( jsonCriteriaStr, Encoding.UTF8 ); - if ( !isNamedQuery ) sb.Append( CRITERIA_FILTER_PREFIX ); - sb.Append( jsonCriteriaStr ); - return sb.ToString(); - } - - /// - /// Gets JsonSerializerSettings with date format. - /// - /// Returns JsonSerializerSettings with yyyy'-'MM'-'dd'T'HH':'mm':'ssK date format and ignores null values. - private static JsonSerializerSettings GetJsonSerializerSettings() + public ColleagueWebApiFilterQueryClient(string colleagueApiUrl, string colleagueApiUsername, string colleagueApiPassword, HttpClient client) + : base(colleagueApiUrl, colleagueApiUsername, colleagueApiPassword, client) { - return new JsonSerializerSettings() - { - DateFormatString = DATE_FORMAT, - NullValueHandling = NullValueHandling.Ignore, - DefaultValueHandling = DefaultValueHandling.Ignore - }; + Region = Authentication.SupportedRegions.SelfHosted; + IntegrationUrls.MAIN_BASE_URL = colleagueApiUrl; } } } diff --git a/Ellucian.Ethos.Integration/Client/Proxy/ColleagueWebApiProxyClient.cs b/Ellucian.Ethos.Integration/Client/Proxy/ColleagueWebApiProxyClient.cs index 91d00d4..09f3097 100644 --- a/Ellucian.Ethos.Integration/Client/Proxy/ColleagueWebApiProxyClient.cs +++ b/Ellucian.Ethos.Integration/Client/Proxy/ColleagueWebApiProxyClient.cs @@ -15,16 +15,8 @@ namespace Ellucian.Ethos.Integration.Client.Proxy /// /// An EthosProxyClient that provides the ability to submit GET requests supporting filters and/or named queries with support for paging. /// - public class ColleagueWebApiProxyClient + public class ColleagueWebApiProxyClient : EthosProxyClient { - // Prefix value used when specifying criteria filter syntax. - private const string CRITERIA_FILTER_PREFIX = "?criteria="; - private string ColleagueApiUrl; - private string ColleagueApiUsername; - private string ColleagueApiPassword; - private HttpClient Client; - - /// /// Instantiates this class using the given Colleague API url and credentials. /// @@ -33,1511 +25,11 @@ public class ColleagueWebApiProxyClient /// The password used to connect to the Colleague API. If it is null/empty, then an will be thrown. /// A HttpClient. If it is null/empty, then an will be thrown. public ColleagueWebApiProxyClient( string colleagueApiUrl, string colleagueApiUsername, string colleagueApiPassword, HttpClient client ) + : base(colleagueApiUrl, colleagueApiUsername, colleagueApiPassword, client) { - if (colleagueApiUrl == null || colleagueApiUsername == null - || colleagueApiPassword == null || colleagueApiPassword == null) - { - throw new ArgumentNullException($"Colleague API URL and Credentials are required."); - } - if (client == null) - { - throw new ArgumentNullException($"The '{nameof(client)}' parameter is required."); - } - - ColleagueApiUrl = colleagueApiUrl; - ColleagueApiUsername = colleagueApiUsername; - ColleagueApiPassword = colleagueApiPassword; - Client = client; - } - - #region Strongly Typed GET - - /// - /// Gets a page of data for the given resource by name and version with the given filter. - /// - /// Type to be included in the returned specified by caller. - /// The name of the resource to get data for. - /// The string resource filter in JSON format contained in the URL, e.g:
?criteria={"names":[{"firstName":"John"}]}
- /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// An EthosResponse containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - /// Returns exception if the resourceName is null. - /// Returns exception if the criteriaFilterStr is null. - /// Returns exception if the request fails. - public async Task GetWithCriteriaFilterAsync( string resourceName, string criteriaFilterStr, string version = "" ) where T : class - { - var response = await GetWithCriteriaFilterAsync( resourceName, version, criteriaFilterStr ); - return ConvertEthosResponseContentToType( response ); - } - - /// - /// Gets a page of data for the given resource by name and version with the given filter. - /// - /// Type to be included in the returned specified by caller. - /// The name of the resource to get data for. - /// A previously built Criteria containing the filter criteria used in the request URL. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// A simple call to criteriaFilter.BuildCriteria() should output the criteria filter portion of the request URL, - /// e.g: ?criteria={"names":[{"firstName":"John"}]}. - /// An EthosResponse containing an initial page (EthosResponse content) of resource data according to the requested version and filter of the resource. - /// to the requested version and filter of the resource. - /// Throws if the given criteriaFilter is null. - public async Task GetWithCriteriaFilterAsync( string resourceName, CriteriaFilter criteria, string version = "" ) where T : class - { - var response = await GetWithCriteriaFilterAsync( resourceName, version, criteria.BuildCriteria() ); - return ConvertEthosResponseContentToType( response ); - } - - /// - /// Convenience method to submit a GET request with a single set of criteria filter. This is intended only to be used - /// for a single set of criteria filter, e.g: ?criteria={"names":[{"firstName":"John"}]}, where names is the - /// criteriaSetName, firstName is the criteriaKey, and John is the criteriaValue. Requests requiring - /// a more complex criteria filter should first build the Criteria with the necessary criteria, and then call - /// getWithCriteriaFilterAsync(resourceName, version, criteriaFilter). - ///

The parameters criteriaSetName, criteriaKey, and criteriaValue should only specify the values within quotes of the - /// JSON filter syntax. No JSON syntax (square or angeled braces, etc) should be contained within those parameter values.

- ///
- /// Type to be included in the returned specified by caller. - /// The name of the resource to get data for. - /// The name of the criteria set that the given criteriaKey and criteriaValue are associated with, - /// e.g: "names":[{"firstName":"John"}]}, where names is the criteriaSetName associated to the - /// criteriaKey (firstName) and criteriaValue (John). - /// The JSON label key for the criteria. - /// The value associated with the criteriaKey. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// An EthosResponse containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - /// Returns exception if the resourceName or criteriaSetName or criteriaKey or criteriaValue is null. - public async Task GetWithSimpleCriteriaValuesAsync( string resourceName, string criteriaSetName, string criteriaKey, string criteriaValue, string version = "" ) where T : class - { - var response = await GetWithSimpleCriteriaValuesAsync( resourceName, version, criteriaSetName, criteriaKey, criteriaValue ); - return ConvertEthosResponseContentToType( response ); - } - - /// - /// Gets a page of data for the given resource by name and version with the given filter. - /// - /// Type to be included in the returned specified by caller. - /// The name of the resource to get data for. - /// The string resource filter in JSON format contained in the URL. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// An EthosResponse containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - /// Returns exception if the resourceName is null. - /// Returns exception if the namedQuery is null. - /// Returns exception if the request fails. - public async Task GetWithNamedQueryFilterAsync( string resourceName, string namedQueryFilterStr, string version = "" ) where T : class - { - var response = await GetWithNamedQueryFilterAsync( resourceName, version, namedQueryFilterStr ); - return ConvertEthosResponseContentToType( response ); - } - - /// - /// Gets a page of data for the given resource by name and version with the given filter. - /// - /// Type to be included in the returned specified by caller. - /// The name of the resource to get data for. - /// A previously built namedQueryFilter containing the filter used in the request URL. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// A simple call to namedQueryFilter.BuildNamedQuery() should output the named query portion of the request URL. - /// An EthosResponse containing an initial page (EthosResponse content) of resource data according to the requested version and filter of the resource. - /// to the requested version and filter of the resource. - /// Throws if the given criteriaFilter is null. - public async Task GetWithNamedQueryFilterAsync( string resourceName, NamedQueryFilter namedQueryFilter, string version = "" ) where T : class - { - var response = await GetWithNamedQueryFilterAsync( resourceName, version, namedQueryFilter.BuildNamedQuery() ); - return ConvertEthosResponseContentToType( response ); - } - - /// - /// Submits a GET request for the given resource and version using the given filterMapStr. The filterMapStr - /// is intended to support the filter syntax for resources versions 7 and older. An example of a filterMapStr is: - /// ?firstName=James. - ///

This is NOT intended to be used for resource versions after version 7 and/or for criteria filters.

- ///
- /// Type to be included in the returned specified by caller. - /// The name of the resource to get data for. - /// A string containing the filter syntax used for request URL filters with resource versions 7 or older. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// An EthosResponse containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - /// Returns exception if the resourceName or filterMapStr is null. - public async Task GetWithFilterMapAsync( string resourceName, string filterMapStr, string version = "" ) where T : class - { - var response = await GetWithFilterMapAsync( resourceName, version, filterMapStr ); - return ConvertEthosResponseContentToType( response ); - } - - /// - /// Submits a GET request for the given resource and version using the given filterMap. The filterMap - /// is intended to support the filter syntax for resources versions 7 and older. A FilterMap contains a map of - /// one or many filter parameter pair(s). An example of a filterMap string indicating the contents of the map is: - /// ?firstName=James. - ///

This is NOT intended to be used for resource versions after version 7 and/or for criteria filters.

- ///
- /// Type to be included in the returned specified by caller. - /// The name of the resource to get data for. - /// A string containing the filter syntax used for request URL filters with resource versions 7 or older. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// An EthosResponse containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - /// Returns exception if the resourceName or filterMap is null. - public async Task GetWithFilterMapAsync( string resourceName, FilterMap filterMap, string version = "" ) where T : class - { - var response = await GetWithFilterMapAsync( resourceName, version, filterMap.ToString() ); - return ConvertEthosResponseContentToType( response ); - } - - /// - /// Gets all the pages for a given resource using the specified criteria filter and page size for the given version. - /// - /// Type to be included in the returned specified by caller. - /// The name of the resource to get data for. - /// A previously built Criteria containing the filter criteria used in the request URL. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// The size (number of rows) of each page returned in the list. - /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - public async Task> GetPagesWithCriteriaFilterAsync( string resourceName, CriteriaFilter criteria, string version = "", int pageSize = 0 ) where T : class - { - var response = await GetPagesWithCriteriaFilterAsync( resourceName, version, criteria, pageSize ); - return ConvertEthosResponseContentListToType( response ); - } - - /// - /// Gets all the pages for a given resource using the specified namedQueryFilter filter and page size for the given version. - /// - /// Type to be included in the returned specified by caller. - /// The name of the resource to get data for. - /// A previously built namedQueryFilter containing the filter named query used in the request URL. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// The size (number of rows) of each page returned in the list. - /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - public async Task> GetPagesWithNamedQueryFilterAsync( string resourceName, NamedQueryFilter namedQueryFilter, string version = "", int pageSize = 0 ) where T : class - { - var response = await GetPagesWithNamedQueryFilterAsync( resourceName, version, namedQueryFilter, pageSize ); - return ConvertEthosResponseContentListToType( response ); - } - - /// - /// Gets all the pages for a given resource beginning at the given offset index, using the specified criteria filter - /// and page size for the given version. - /// - /// Type to be included in the returned specified by caller. - /// The name of the resource to get data for. - /// A previously built Criteria containing the filter criteria used in the request URL. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// The size (number of rows) of each page returned in the list. - /// The 0 based index from which to begin paging for the given resource. - /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - /// Returns exception if the resourceName or criteriaFilter is null. - public async Task> GetPagesFromOffsetWithCriteriaFilterAsync( string resourceName, CriteriaFilter criteria, string version = "", int pageSize = 0, int offset = 0 ) where T : class - { - var response = await GetPagesFromOffsetWithCriteriaFilterAsync( resourceName, version, criteria, pageSize, offset ); - return ConvertEthosResponseContentListToType( response ); - } - - /// - /// Gets all the pages for a given resource beginning at the given offset index, using the specified namedQueryFilter - /// and page size for the given version. - /// - /// Type to be included in the returned specified by caller. - /// The name of the resource to get data for. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// A previously built namedQueryFilter containing the filter used in the request URL. - /// The size (number of rows) of each page returned in the list. - /// The 0 based index from which to begin paging for the given resource. - /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - /// Returns exception if the resourceName or namedQueryFilter is null. - public async Task> GetPagesFromOffsetWithNamedQueryFilterAsync( string resourceName, NamedQueryFilter namedQueryFilter, string version = "", int pageSize = 0, int offset = 0 ) where T : class - { - var response = await GetPagesFromOffsetWithNamedQueryFilterAsync( resourceName, version, namedQueryFilter, pageSize, offset ); - return ConvertEthosResponseContentListToType( response ); - } - - /// - /// Gets all the pages for a given resource using the specified filter map and page size for the given version. - /// - /// Type to be included in the returned specified by caller. - /// The name of the resource to get data for. - /// A previously built FilterMap containing the filter parameters used in the request URL. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// A simple call to filterMap.tostring() should output the criteria filter portion of the request URL, - /// e.g: ?firstName=John&lastName=Smith. - /// The size (number of rows) of each page returned in the list. - /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - public async Task> GetPagesWithFilterMapAsync( string resourceName, FilterMap filterMap, string version = "", int pageSize = 0 ) where T : class - { - var response = await GetPagesWithFilterMapAsync( resourceName, version, filterMap, pageSize ); - return ConvertEthosResponseContentListToType( response ); - } - - /// - /// Gets all the pages for a given resource beginning at the given offset index, using the specified filter map and - /// page size for the given version. - /// - /// Type to be included in the IEnumerable<> returned specified by caller. - /// The name of the resource to get data for. - /// A previously built FilterMap containing the filter parameters used in the request URL. - /// A simple call to filterMap.tostring() should output the criteria filter portion of the request URL, - /// e.g: ?firstName=John&lastName=Smith. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// The size (number of rows) of each page returned in the list. - /// The 0 based index from which to begin paging for the given resource. - /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - public async Task> GetPagesFromOffsetWithFilterMapAsync( string resourceName, FilterMap filterMap, string version = "", int pageSize = 0, int offset = 0 ) where T : class - { - var response = await GetPagesFromOffsetWithFilterMapAsync( resourceName, version, filterMap, pageSize, offset ); - return ConvertEthosResponseContentListToType( response ); - } - - #endregion Strongly Typed - - /// - /// Gets a page of data for the given resource with the given filter. Uses the default version of the resource. - /// Makes a non-filter API request if the given criteriaFilterStr is null or blank. - /// - /// The name of the resource to get data for. - /// The string resource filter in JSON format contained in the URL, e.g:
?criteria={"names":[{"firstName":"John"}]}
- /// An EthosResponse containing an initial page (EthosResponse content) of resource data according to the requested version and filter of the resource. - /// to the requested version and filter of the resource. - public async Task GetWithCriteriaFilterAsync( string resourceName, string criteriaFilterStr ) - { - return await GetWithCriteriaFilterAsync( resourceName, DEFAULT_VERSION, criteriaFilterStr ); - } - - /// - /// Gets a page of data for the given resource with the given filter. Uses the default version of the resource. - /// Makes a non-filter API request if the given namedQueryFilterStr is null or blank. - /// - /// The name of the resource to get data for. - /// The string resource filter in JSON format contained in the URL, e.g:
?criteria={"names":[{"firstName":"John"}]}
- /// An EthosResponse containing an initial page (EthosResponse content) of resource data according to the requested version and filter of the resource. - /// to the requested version and filter of the resource. - public async Task GetWithNamedQueryFilterAsync( string resourceName, string namedQueryFilterStr ) - { - return await GetWithNamedQueryFilterAsync( resourceName, DEFAULT_VERSION, namedQueryFilterStr ); - } - - /// - /// Gets a page of data for the given resource by name and version with the given filter. - /// - /// The name of the resource to get data for. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// The string resource filter in JSON format contained in the URL, e.g:
?criteria={"names":[{"firstName":"John"}]}
- /// An EthosResponse containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - /// Returns exception if the resourceName is null. - /// Returns exception if the criteriaFilterStr is null. - /// Returns exception if the request fails. - public async Task GetWithCriteriaFilterAsync( string resourceName, string version, string criteriaFilterStr ) - { - if ( string.IsNullOrWhiteSpace( resourceName ) ) - { - throw new ArgumentNullException( "Error: Cannot get resource with criteria filter due to a null or blank resource name." ); - } - if ( string.IsNullOrWhiteSpace( criteriaFilterStr ) ) - { - throw new ArgumentNullException( $"Error: Cannot get resource '{resourceName}' with criteria filter due to a null or blank criteria filter string." ); - } - return await GetEthosResponseAsync( resourceName, version, criteriaFilterStr ); - } - - /// - /// Gets a page of data for the given resource by name and version with the given filter. - /// - /// The name of the resource to get data for. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// The string resource filter in JSON format contained in the URL. - /// An EthosResponse containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - /// Returns exception if the resourceName is null. - /// Returns exception if the namedQuery is null. - /// Returns exception if the request fails. - public async Task GetWithNamedQueryFilterAsync( string resourceName, string version, string namedQueryFilterStr ) - { - if ( string.IsNullOrWhiteSpace( resourceName ) ) - { - throw new ArgumentNullException( "Error: Cannot get resource with criteria filter due to a null or blank resource name." ); - } - if ( string.IsNullOrWhiteSpace( namedQueryFilterStr ) ) - { - throw new ArgumentNullException( $"Error: Cannot get resource '{resourceName}' with named query due to a null or blank named query string." ); - } - return await GetEthosResponseAsync( resourceName, version, namedQueryFilterStr ); - } - - /// - /// Gets Ethos Response. - /// - /// The name of the resource to get data for. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// This can be CriteriaFilter or NamedQuery. - /// An EthosResponse containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - private async Task GetEthosResponseAsync( string resourceName, string version, string criteria ) - { - var filterStr = EncodeString( criteria ); - Dictionary headers = BuildHeadersMap( version ); - EthosResponse response = await GetAsync( headers, EthosIntegrationUrls.ApiFilter( Region, resourceName, filterStr ) ); - return response; - } - - /// - /// Gets a page of data for the given resource by name with the given filter. Uses the default version of the resource. - /// Makes a non-filter API request if the given criteriaFilter is null. - /// A simple call to criteriaFilter.BuildCriteria() should output the criteria filter portion of the request URL, - /// e.g: ?criteria={"names":[{"firstName":"John"}]}. - /// - /// The name of the resource to get data for. - /// A previously built Criteria containing the filter criteria used in the request URL. - /// A simple call to criteriaFilter.BuildCriteria() should output the criteria filter portion of the request URL, - /// e.g: ?criteria={"names":[{"firstName":"John"}]}. - /// An EthosResponse containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - public async Task GetWithCriteriaFilterAsync( string resourceName, CriteriaFilter criteria ) - { - return await GetWithCriteriaFilterAsync( resourceName, DEFAULT_VERSION, criteria.BuildCriteria() ); - } - - /// - /// Gets a page of data for the given resource by name and version with the given filter. - /// - /// The name of the resource to get data for. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// A previously built Criteria containing the filter criteria used in the request URL. - /// A simple call to criteriaFilter.BuildCriteria() should output the criteria filter portion of the request URL, - /// e.g: ?criteria={"names":[{"firstName":"John"}]}. - /// An EthosResponse containing an initial page (EthosResponse content) of resource data according to the requested version and filter of the resource. - /// to the requested version and filter of the resource. - /// Throws if the given criteriaFilter is null. - public async Task GetWithCriteriaFilterAsync( string resourceName, string version, CriteriaFilter criteria ) - { - if ( criteria == null ) - { - throw new ArgumentNullException( $"Error: Cannot get resource '{ resourceName }' with criteria filter due to a null criteria filter reference." ); - } - return await GetWithCriteriaFilterAsync( resourceName, version, criteria.BuildCriteria() ); - } - - /// - /// Gets a page of data for the given resource by name with the given filter. Uses the default version of the resource. - /// Makes a non-filter API request if the given criteriaFilter is null. - /// A simple call to criteriaFilter.BuildCriteria() should output the criteria filter portion of the request URL. - /// - /// The name of the resource to get data for. - /// A previously built namedQueryFilter containing the filter used in the request URL. - /// A simple call to namedQueryFilter.BuildNamedQuery() should output the criteria filter portion of the request URL, - /// e.g: ?criteria={"names":[{"firstName":"John"}]}. - /// An EthosResponse containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - public async Task GetWithNamedQueryFilterAsync( string resourceName, NamedQueryFilter namedQueryFilter ) - { - return await GetWithNamedQueryFilterAsync( resourceName, DEFAULT_VERSION, namedQueryFilter ); - } - - /// - /// Gets a page of data for the given resource by name and version with the given filter. - /// - /// The name of the resource to get data for. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// A previously built namedQueryFilter containing the filter used in the request URL. - /// A simple call to namedQueryFilter.BuildNamedQuery() should output the named query portion of the request URL. - /// An EthosResponse containing an initial page (EthosResponse content) of resource data according to the requested version and filter of the resource. - /// to the requested version and filter of the resource. - /// Throws if the given criteriaFilter is null. - public async Task GetWithNamedQueryFilterAsync( string resourceName, string version, NamedQueryFilter namedQueryFilter ) - { - if ( namedQueryFilter == null ) - { - throw new ArgumentNullException( $"Error: Cannot get resource '{ resourceName }' with named query due to a null named query reference." ); - } - return await GetWithNamedQueryFilterAsync( resourceName, version, namedQueryFilter.BuildNamedQuery() ); - } - - /// - /// Convenience method to submit a GET request with a single set of criteria filter. This is intended only to be used - /// for a single set of criteria filter, e.g: ?criteria={"names":[{"firstName":"John"}]}, where names is the - /// criteriaSetName, firstName is the criteriaKey, and John is the criteriaValue. Requests requiring - /// a more complex criteria filter should first build the Criteria with the necessary criteria, and then call - /// getWithCriteriaFilterAsync(resourceName, criteriaFilter). - ///

The parameters criteriaSetName, criteriaKey, and criteriaValue should only specify the values within quotes of the - /// JSON filter syntax. No JSON syntax (square or angeled braces etc.) should be contained within those parameter values.

- ///

Uses the default version of the resource.

- ///
- /// The name of the resource to get data for. - /// The name of the criteria set that the given criteriaKey and criteriaValue are associated with, - /// e.g: "names":[{"firstName":"John"}]}, where names is the criteriaSetName associated to the - /// criteriaKey (firstName) and criteriaValue (John). - /// The JSON label key for the criteria. - /// The value associated with the criteriaKey. - /// An EthosResponse containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - public async Task GetWithSimpleCriteriaValuesAsync( string resourceName, string criteriaSetName, string criteriaKey, string criteriaValue ) - { - return await GetWithSimpleCriteriaValuesAsync( resourceName, DEFAULT_VERSION, criteriaSetName, criteriaKey, criteriaValue ); - } - - /// - /// Convenience method to submit a GET request with a single set of criteria filter. This is intended only to be used - /// for a single set of criteria filter, e.g: ?criteria={"names":[{"firstName":"John"}]}, where names is the - /// criteriaSetName, firstName is the criteriaKey, and John is the criteriaValue. Requests requiring - /// a more complex criteria filter should first build the Criteria with the necessary criteria, and then call - /// getWithCriteriaFilterAsync(resourceName, version, criteriaFilter). - ///

The parameters criteriaSetName, criteriaKey, and criteriaValue should only specify the values within quotes of the - /// JSON filter syntax. No JSON syntax (square or angeled braces, etc) should be contained within those parameter values.

- ///
- /// The name of the resource to get data for. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// The name of the criteria set that the given criteriaKey and criteriaValue are associated with, - /// e.g: "names":[{"firstName":"John"}]}, where names is the criteriaSetName associated to the - /// criteriaKey (firstName) and criteriaValue (John). - /// The JSON label key for the criteria. - /// The value associated with the criteriaKey. - /// An EthosResponse containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - /// Returns exception if the resourceName or criteriaSetName or criteriaKey or criteriaValue is null. - public async Task GetWithSimpleCriteriaValuesAsync( string resourceName, string version, string criteriaSetName, string criteriaKey, string criteriaValue ) - { - if ( string.IsNullOrWhiteSpace( resourceName ) ) - { - throw new ArgumentNullException( "Error: Cannot get resource with filter map due to a null or blank resource name." ); - } - if ( string.IsNullOrWhiteSpace( criteriaSetName ) ) - { - throw new ArgumentNullException( "Error: Cannot get resource due to a null or empty criteria set name parameter." ); - } - if ( string.IsNullOrWhiteSpace( criteriaKey ) ) - { - throw new ArgumentNullException( "Error: Cannot get resource due to a null or empty criteria key parameter." ); - } - if ( string.IsNullOrWhiteSpace( criteriaValue ) ) - { - throw new ArgumentNullException( "Error: Cannot get resource due to a null or empty criteria value parameter." ); - } - var criteriaFilter = new CriteriaFilter().WithSimpleCriteria( criteriaSetName, (criteriaKey, criteriaValue) ) - .BuildCriteria(); - return await GetWithCriteriaFilterAsync( resourceName, version, criteriaFilter ); - } - - /// - /// Submits a GET request for the given resource and version using the given filterMapStr. The filterMapStr - /// is intended to support the filter syntax for resources versions 7 and older. An example of a filterMapStr is: - /// ?firstName=James. - ///

This is NOT intended to be used for resource versions after version 7 and/or for criteria filters.

- ///
- /// The name of the resource to get data for. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// A string containing the filter syntax used for request URL filters with resource versions 7 or older. - /// An EthosResponse containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - /// Returns exception if the resourceName or filterMapStr is null. - public async Task GetWithFilterMapAsync( string resourceName, string version, string filterMapStr ) - { - if ( string.IsNullOrWhiteSpace( resourceName ) ) - { - throw new ArgumentNullException( "Error: Cannot get resource with filter map due to a null or blank resource name." ); - } - if ( string.IsNullOrWhiteSpace( filterMapStr ) ) - { - throw new ArgumentNullException( $"Error: Cannot get resource '{ resourceName }' with filter map due to a null or blank filter map string." ); - } - Dictionary headers = BuildHeadersMap( version ); - EthosResponse response = await GetAsync( headers, EthosIntegrationUrls.ApiFilter( Region, resourceName, filterMapStr ) ); - return response; - } - - /// - /// Submits a GET request for the given resource and version using the given filterMap. The filterMap - /// is intended to support the filter syntax for resources versions 7 and older. A FilterMap contains a map of - /// one or many filter parameter pair(s). An example of a filterMap string indicating the contents of the map is: - /// ?firstName=James. - ///

This is NOT intended to be used for resource versions after version 7 and/or for criteria filters.

- ///
- /// The name of the resource to get data for. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// A string containing the filter syntax used for request URL filters with resource versions 7 or older. - /// An EthosResponse containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - /// Returns exception if the resourceName or filterMap is null. - public async Task GetWithFilterMapAsync( string resourceName, string version, FilterMap filterMap ) - { - ArgumentNullException.ThrowIfNull( filterMap, $"Error: Cannot get resource '{resourceName}' with filter map due to a null filter map." ); - return await GetWithFilterMapAsync( resourceName, version, filterMap.ToString() ); - } - - /// - /// Gets all the pages for a given resource using the specified criteria filter. Uses the default version of the resource, - /// and the page size is derived from the length of the returned response of the request using the criteria filter. - /// - /// The name of the resource to get data for. - /// A previously built Criteria containing the filter criteria used in the request URL. - /// A simple call to criteriaFilter.BuildCriteria() should output the criteria filter portion of the request URL, - /// e.g: ?criteria={"names":[{"firstName":"John"}]}. - /// An EthosResponse containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - public async Task> GetPagesWithCriteriaFilterAsync( string resourceName, CriteriaFilter criteria ) - { - return await GetPagesWithCriteriaFilterAsync( resourceName, DEFAULT_VERSION, criteria, DEFAULT_PAGE_SIZE ); - } - - /// - /// Gets all the pages for a given resource using the specified criteria filter for the given version. Uses the default - /// page size, which is the length of the returned response of the request using the criteria filter. - /// - /// The name of the resource to get data for. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// A previously built Criteria containing the filter criteria used in the request URL. - /// An EthosResponse containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - public async Task> GetPagesWithCriteriaFilterAsync( string resourceName, string version, CriteriaFilter criteria ) - { - return await GetPagesWithCriteriaFilterAsync( resourceName, version, criteria, DEFAULT_PAGE_SIZE ); - } - - /// - /// Gets all the pages for a given resource using the specified namedQueryFilter filter. Uses the default version of the resource, - /// and the page size is derived from the length of the returned response of the request using the namedQueryFilter filter. - /// - /// The name of the resource to get data for. - /// A previously built namedQueryFilter containing the filter used in the request URL. - /// A simple call to namedQueryFilter.BuildNamedQuery() should output the namedQueryFilter filter portion of the request URL. - /// An EthosResponse containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - public async Task> GetPagesWithNamedQueryFilterAsync( string resourceName, NamedQueryFilter namedQueryFilter ) - { - return await GetPagesWithNamedQueryFilterAsync( resourceName, DEFAULT_VERSION, namedQueryFilter, DEFAULT_PAGE_SIZE ); - } - - /// - /// Gets all the pages for a given resource using the specified namedQueryFilter filter for the given version. Uses the default - /// page size, which is the length of the returned response of the request using the namedQueryFilter filter. - /// - /// The name of the resource to get data for. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// A previously built namedQueryFilter containing the filter used in the request URL. - /// An EthosResponse containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - public async Task> GetPagesWithNamedQueryFilterAsync( string resourceName, string version, NamedQueryFilter namedQueryFilter ) - { - return await GetPagesWithNamedQueryFilterAsync( resourceName, version, namedQueryFilter, DEFAULT_PAGE_SIZE ); - } - - /// - /// Gets all the pages for a given resource using the specified criteria filter and page size. The default version - /// of the resource is used. - /// - /// The name of the resource to get data for. - /// A previously built Criteria containing the filter criteria used in the request URL. - /// The size (number of rows) of each page returned in the list. - /// An EthosResponse containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - public async Task> GetPagesWithCriteriaFilterAsync( string resourceName, CriteriaFilter criteria, int pageSize ) - { - return await GetPagesWithCriteriaFilterAsync( resourceName, DEFAULT_VERSION, criteria, pageSize ); - } - - /// - /// Gets all the pages for a given resource using the specified criteria filter and page size for the given version. - /// - /// The name of the resource to get data for. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// A previously built Criteria containing the filter criteria used in the request URL. - /// The size (number of rows) of each page returned in the list. - /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - public async Task> GetPagesWithCriteriaFilterAsync( string resourceName, string version, CriteriaFilter criteria, int pageSize ) - { - return await GetPagesFromOffsetWithCriteriaFilterAsync( resourceName, version, criteria, pageSize, 0 ); - } - - /// - /// Gets all the pages for a given resource using the specified namedQueryFilter filter and page size. The default version - /// of the resource is used. - /// - /// The name of the resource to get data for. - /// A previously built namedQueryFilter containing the filter used in the request URL. - /// The size (number of rows) of each page returned in the list. - /// An EthosResponse containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - public async Task> GetPagesWithNamedQueryFilterAsync( string resourceName, NamedQueryFilter namedQueryFilter, int pageSize ) - { - return await GetPagesWithNamedQueryFilterAsync( resourceName, DEFAULT_VERSION, namedQueryFilter, pageSize ); - } - - /// - /// Gets all the pages for a given resource using the specified namedQueryFilter filter and page size for the given version. - /// - /// The name of the resource to get data for. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// A previously built namedQueryFilter containing the filter named query used in the request URL. - /// The size (number of rows) of each page returned in the list. - /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - public async Task> GetPagesWithNamedQueryFilterAsync( string resourceName, string version, NamedQueryFilter namedQueryFilter, int pageSize ) - { - return await GetPagesFromOffsetWithNamedQueryFilterAsync( resourceName, version, namedQueryFilter, pageSize, 0 ); - } - - /// - /// Gets all the pages for a given resource beginning at the given offset index, using the specified criteria filter. - /// The page size is determined to be the length of the returned response of the request using the criteria filter. - /// The default version of the resource is used. - /// - /// The name of the resource to get data for. - /// A previously built Criteria containing the filter criteria used in the request URL. - /// The 0 based index from which to begin paging for the given resource. - /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - public async Task> GetPagesFromOffsetWithCriteriaFilterAsync( string resourceName, CriteriaFilter criteria, int offset ) - { - return await GetPagesFromOffsetWithCriteriaFilterAsync( resourceName, DEFAULT_VERSION, criteria, offset ); - } - - /// - /// Gets all the pages for a given resource beginning at the given offset index, using the specified criteria filter - /// for the given version. The page size is determined to be the length of the returned response of the request using - /// the criteria filter. - /// - /// The name of the resource to get data for. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// A previously built Criteria containing the filter criteria used in the request URL. - /// The 0 based index from which to begin paging for the given resource. - /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - public async Task> GetPagesFromOffsetWithCriteriaFilterAsync( string resourceName, string version, CriteriaFilter criteria, int offset ) - { - return await GetPagesFromOffsetWithCriteriaFilterAsync( resourceName, version, criteria, DEFAULT_PAGE_SIZE, offset ); - } - - /// - /// Gets all the pages for a given resource beginning at the given offset index, using the specified namedQueryFilter filter. - /// The page size is determined to be the length of the returned response of the request using the namedQueryFilter filter. - /// The default version of the resource is used. - /// - /// The name of the resource to get data for. - /// - /// The 0 based index from which to begin paging for the given resource. - /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - public async Task> GetPagesFromOffsetWithNamedQueryFilterAsync( string resourceName, NamedQueryFilter namedQueryFilter, int offset ) - { - return await GetPagesFromOffsetWithNamedQueryFilterAsync( resourceName, DEFAULT_VERSION, namedQueryFilter, offset ); - } - - /// - /// Gets all the pages for a given resource beginning at the given offset index, using the specified namedQueryFilter filter - /// for the given version. The page size is determined to be the length of the returned response of the request using - /// the namedQueryFilter filter. - /// - /// The name of the resource to get data for. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// A previously built namedQueryFilter containing the filter used in the request URL. - /// The 0 based index from which to begin paging for the given resource. - /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - public async Task> GetPagesFromOffsetWithNamedQueryFilterAsync( string resourceName, string version, NamedQueryFilter namedQueryFilter, int offset ) - { - return await GetPagesFromOffsetWithNamedQueryFilterAsync( resourceName, version, namedQueryFilter, DEFAULT_PAGE_SIZE, offset ); - } - - /// - /// Gets all the pages for a given resource beginning at the given offset index, using the specified criteria filter - /// and page size for the given version. The default version of the resource is used. - /// - /// The name of the resource to get data for. - /// A previously built Criteria containing the filter criteria used in the request URL. - /// The size (number of rows) of each page returned in the list. - /// The 0 based index from which to begin paging for the given resource. - /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - public async Task> GetPagesFromOffsetWithCriteriaFilterAsync( string resourceName, CriteriaFilter criteria, int pageSize, int offset ) - { - return await GetPagesFromOffsetWithCriteriaFilterAsync( resourceName, DEFAULT_VERSION, criteria, pageSize, offset ); - } - - /// - /// Gets all the pages for a given resource beginning at the given offset index, using the specified criteria filter - /// and page size for the given version. - /// - /// The name of the resource to get data for. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// A previously built Criteria containing the filter criteria used in the request URL. - /// The size (number of rows) of each page returned in the list. - /// The 0 based index from which to begin paging for the given resource. - /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - /// Returns exception if the resourceName or criteriaFilter is null. - public async Task> GetPagesFromOffsetWithCriteriaFilterAsync( string resourceName, string version, CriteriaFilter criteria, int pageSize, int offset ) - { - if ( string.IsNullOrWhiteSpace( resourceName ) ) - { - throw new ArgumentNullException( "Error: Cannot get pages of resource from offset with criteria filter due to a null or blank resource name." ); - } - if ( criteria == null ) - { - throw new ArgumentNullException( $"Error: Cannot get pages of resource '{ resourceName }' from offset with criteria filter due to a null criteria filter reference." ); - } - List ethosResponseList = new List(); - Pager pager = Pager.Build( pg => - { - pg - .ForResource( resourceName ) - .ForVersion( version ) - .WithCriteriaFilter( criteria.BuildCriteria() ) - .WithPageSize( pageSize ) - .FromOffSet( offset ); - } ); - - pager = await PrepareForPagingAsync( pager ); - pager = ShouldDoPaging( pager, false ); - if ( pager.ShouldDoPaging ) - { - ethosResponseList = await DoPagingFromOffsetAsync( pager.ResourceName, pager.Version, pager.CriteriaFilter, pager.TotalCount, pager.PageSize, offset ); - } - else - { - ethosResponseList.Add( await GetWithCriteriaFilterAsync( resourceName, version, criteria ) ); - } - return ethosResponseList; - } - - /// - /// Gets all the pages for a given resource beginning at the given offset index, using the specified namedQueryFilter - /// and page size for the given version. The default version of the resource is used. - /// - /// The name of the resource to get data for. - /// A previously built namedQueryFilter containing the filter used in the request URL. - /// The size (number of rows) of each page returned in the list. - /// The 0 based index from which to begin paging for the given resource. - /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - public async Task> GetPagesFromOffsetWithNamedQueryFilterAsync( string resourceName, NamedQueryFilter namedQueryFilter, int pageSize, int offset ) - { - return await GetPagesFromOffsetWithNamedQueryFilterAsync( resourceName, DEFAULT_VERSION, namedQueryFilter, pageSize, offset ); - } - - /// - /// Gets all the pages for a given resource beginning at the given offset index, using the specified namedQueryFilter - /// and page size for the given version. - /// - /// The name of the resource to get data for. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// A previously built namedQueryFilter containing the filter used in the request URL. - /// The size (number of rows) of each page returned in the list. - /// The 0 based index from which to begin paging for the given resource. - /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - /// Returns exception if the resourceName or namedQueryFilter is null. - public async Task> GetPagesFromOffsetWithNamedQueryFilterAsync( string resourceName, string version, NamedQueryFilter namedQueryFilter, int pageSize, int offset ) - { - if ( string.IsNullOrWhiteSpace( resourceName ) ) - { - throw new ArgumentNullException( "Error: Cannot get pages of resource from offset with named query filter due to a null or blank resource name." ); - } - if ( namedQueryFilter == null ) - { - throw new ArgumentNullException( $"Error: Cannot get pages of resource '{ resourceName }' from offset with named query filter due to a null named query filter reference." ); - } - List ethosResponseList = new List(); - Pager pager = Pager.Build( pg => - { - pg - .ForResource( resourceName ) - .ForVersion( version ) - .WithNamedQuery( namedQueryFilter.BuildNamedQuery() ) - .WithPageSize( pageSize ) - .FromOffSet( offset ); - } ); - - pager = await PrepareForPagingAsync( pager ); - pager = ShouldDoPaging( pager, false ); - if ( pager.ShouldDoPaging ) - { - ethosResponseList = await DoPagingFromOffsetAsync( pager.ResourceName, pager.Version, pager.NamedQueryFilter, pager.TotalCount, pager.PageSize, offset ); - } - else - { - ethosResponseList.Add( await GetWithNamedQueryFilterAsync( resourceName, version, namedQueryFilter ) ); - } - return ethosResponseList; - } - - /// - /// Gets all the pages for a given resource using the specified filter map and page size for the given version. - /// - /// The name of the resource to get data for. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// A previously built FilterMap containing the filter parameters used in the request URL. - /// A simple call to filterMap.tostring() should output the criteria filter portion of the request URL, - /// e.g: ?firstName=John&lastName=Smith. - /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - public async Task> GetPagesWithFilterMapAsync( string resourceName, string version, FilterMap filterMap ) - { - return await GetPagesWithFilterMapAsync( resourceName, version, filterMap, DEFAULT_PAGE_SIZE ); - } - - /// - /// Gets all the pages for a given resource using the specified filter map and page size for the given version. - /// - /// The name of the resource to get data for. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// A previously built FilterMap containing the filter parameters used in the request URL. - /// A simple call to filterMap.tostring() should output the criteria filter portion of the request URL, - /// e.g: ?firstName=John&lastName=Smith. - /// The size (number of rows) of each page returned in the list. - /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - public async Task> GetPagesWithFilterMapAsync( string resourceName, string version, FilterMap filterMap, int pageSize ) - { - return await GetPagesFromOffsetWithFilterMapAsync( resourceName, version, filterMap, pageSize, 0 ); - } - - /// - /// Gets all the pages for a given resource beginning at the given offset index, using the specified filter map and - /// page size for the given version. The page size is determined to be the length of the returned response of the request using - /// the filter map. - /// - /// The name of the resource to get data for. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// A previously built FilterMap containing the filter parameters used in the request URL. - /// A simple call to filterMap.tostring() should output the criteria filter portion of the request URL, - /// e.g: ?firstName=John&lastName=Smith. - /// The 0 based index from which to begin paging for the given resource. - /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - public async Task> GetPagesFromOffsetWithFilterMapAsync( string resourceName, string version, FilterMap filterMap, int offset ) - { - return await GetPagesFromOffsetWithFilterMapAsync( resourceName, version, filterMap, DEFAULT_PAGE_SIZE, offset ); - } - - /// - /// Gets all the pages for a given resource beginning at the given offset index, using the specified filter map and - /// page size for the given version. - /// - /// The name of the resource to get data for. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// A previously built FilterMap containing the filter parameters used in the request URL. - /// A simple call to filterMap.tostring() should output the criteria filter portion of the request URL, - /// e.g: ?firstName=John&lastName=Smith. - /// The size (number of rows) of each page returned in the list. - /// The 0 based index from which to begin paging for the given resource. - /// An List<EthosResponse> containing an initial page (EthosResponse content) of resource data according - /// to the requested version and filter of the resource. - public async Task> GetPagesFromOffsetWithFilterMapAsync( string resourceName, string version, FilterMap filterMap, int pageSize, int offset ) - { - if ( string.IsNullOrWhiteSpace( resourceName ) ) - { - throw new ArgumentNullException( "Error: Cannot get pages of resource with filter map due to a null or blank resource name." ); - } - if ( filterMap == null ) - { - throw new ArgumentNullException( $"Error: Cannot get pages of resource '{ resourceName }' with filter map due to a null filter map reference." ); - } - List ethosResponseList = new List(); - Pager pager = Pager.Build( pg => - { - pg - .ForResource( resourceName ) - .ForVersion( version ) - .WithFilterMap( filterMap.ToString() ) - .WithPageSize( pageSize ) - .FromOffSet( offset ); - } ); - - pager = await PrepareForPagingAsync( pager ); - pager = ShouldDoPaging( pager, false ); - if ( pager.ShouldDoPaging ) - { - ethosResponseList = await DoPagingFromOffsetAsync( pager.ResourceName, pager.Version, pager.FilterMap, pager.TotalCount, pager.PageSize, offset ); - } - else - { - ethosResponseList.Add( await GetWithFilterMapAsync( resourceName, version, filterMap ) ); - } - return ethosResponseList; - } - - #region QAPI's - - /// - /// Submits a POST request for the given resourceName with the given qapiRequestBody. The qapiRequestBody should be a string in JSON format. - /// - /// The name of the resource to add an instance of. - /// The full version header value of the resource used for this POST request. - /// The body of the request to POST for the given resource. - /// An EthosResponse containing the instance of the resource that was added by this POST operation. - /// When is passed as null or empty or white space. - /// When is passed as null or empty or white space. - public async Task GetWithQapiAsync( string resourceName, string qapiRequestBody, string version = "" ) - { - if ( string.IsNullOrWhiteSpace( resourceName ) ) - { - throw new ArgumentNullException( $"Error: Cannot submit a POST request due to a null or blank {nameof( resourceName )} parameter." ); - } - - if ( string.IsNullOrWhiteSpace( qapiRequestBody ) ) - { - throw new ArgumentNullException( - $"Error: Cannot submit a POST request for resource {resourceName} due to a null or blank {nameof( qapiRequestBody )} parameter." - ); - } - var headers = BuildHeadersMap( version ); - string url = EthosIntegrationUrls.Qapi( Region, resourceName ); - return await base.PostAsync( headers, url, qapiRequestBody ); - } - - /// - /// Submits a POST request for the given resourceName with the given requestBodyNode. The requestBodyNode should be a JObject. - /// - /// The name of the resource to add an instance of. - /// The full version header value of the resource used for this POST request. - /// The body of the request to POST for the given resource as a JsonNode. - /// An EthosResponse containing the instance of the resource that was added by this POST operation. - /// When is passed as null or empty or white space. - /// When is passed as null. - public async Task GetWithQapiAsync( string resourceName, JObject qapiRequestBodyNode, string version = "" ) - { - ArgumentNullException.ThrowIfNull( qapiRequestBodyNode, $"Error: Cannot submit a POST request for resource {resourceName} due to a null {nameof( qapiRequestBodyNode )} parameter." ); - return await GetWithQapiAsync(resourceName, qapiRequestBodyNode.ToString(), version ); - } - - /// - /// Submits a POST request for the given resourceName with the given qapiRequestBody. The qapiRequestBody should be a T type class. - /// - /// Request type. - /// The name of the resource to add an instance of. - /// The full version header value of the resource used for this POST request. - /// The body of the request to POST for the given resource. - /// An EthosResponse containing the instance of the resource that was added by this POST operation. - /// When is passed as null or empty or white space. - /// When is passed as null. - public async Task GetWithQapiAsync( string resourceName, T qapiRequestBody, string version = "" ) where T : class - { - ArgumentNullException.ThrowIfNull( qapiRequestBody, $"Error: Cannot submit a POST request for resource {resourceName} due to a null {nameof( qapiRequestBody )} parameter." ); - - JsonSerializerSettings jsonSerSettings = GetJsonSerializerSettings(); - var reqBody = JsonConvert.SerializeObject( qapiRequestBody, jsonSerSettings ); - return await GetWithQapiAsync( resourceName, reqBody, version ); - } - - /// - /// Gets the total count of resources available using the given criteriaFilter. Gets the pages for a given resource beginning at the given offset index, - /// using the specified QAPI request body and page size for the given version. - /// - /// The name of the resource to add an instance of. - /// The full version header value of the resource used for this POST request. - /// The body of the request to POST for the given resource. - /// The size (number of rows) of each page returned in the list. - /// The 0 based index from which to begin paging for the given resource. - /// A list of EthosResponses where each EthosResponse contains a page of data. If paging is not required based on the - /// given pageSize and total count( from using the filter), the returned list will only contain one EthosResponse. - /// When is passed as null or empty or white space. - /// When is passed as null. - public async Task> GetPagesFromOffsetWithQAPIAsync( string resourceName, string qapiRequestBody, string version = "", int pageSize = 0, int offset = 0) - { - if ( string.IsNullOrWhiteSpace( resourceName ) ) - { - throw new ArgumentNullException( $"Error: Cannot submit a POST request due to a null or blank {nameof( resourceName )} parameter." ); - } - - if ( string.IsNullOrWhiteSpace( qapiRequestBody ) ) - { - throw new ArgumentNullException( $"Error: Cannot submit a POST request for resource {resourceName} due to a null {nameof( qapiRequestBody )} parameter." ); - } - - List ethosResponseList = new(); - Pager pager = Pager.Build( pg => - { - pg - .ForResource( resourceName ) - .ForVersion( version ) - .FromOffSet( offset ) - .WithPageSize( pageSize ) - .WithQAPIRequestBodyFilter( qapiRequestBody ); - } ); - - pager = await PrepareForPagingAsync( pager ); - pager = ShouldDoPaging( pager, false ); - if ( pager.ShouldDoPaging ) - { - ethosResponseList = await DoPagingFromOffsetForQAPIAsync( pager.ResourceName, pager.Version, qapiRequestBody, pager.TotalCount, pager.PageSize, pager.Offset ); - } - else - { - ethosResponseList.Add( await GetWithQapiAsync( resourceName, qapiRequestBody, version ) ); - } - return ethosResponseList; - } - - /// - /// Gets the total count of resources available using the given criteriaFilter. Gets the pages for a given resource beginning at the given offset index, - /// using the specified QAPI request body and page size for the given version. - /// - /// The name of the resource to add an instance of. - /// The full version header value of the resource used for this POST request. - /// The body of the request to POST for the given resource. - /// The size (number of rows) of each page returned in the list. - /// The 0 based index from which to begin paging for the given resource. - /// A list of EthosResponses where each EthosResponse contains a page of data. If paging is not required based on the - /// given pageSize and total count( from using the filter), the returned list will only contain one EthosResponse. - /// When is passed as null or empty or white space. - /// When is passed as null. - public async Task> GetPagesFromOffsetWithQAPIAsync( string resourceName, JObject qapiRequestBody, string version = "", int pageSize = 0, int offset = 0 ) - { - ArgumentNullException.ThrowIfNull( qapiRequestBody, $"Error: Cannot submit a POST request for resource {resourceName} due to a null {nameof( qapiRequestBody )} parameter." ); - return await GetPagesFromOffsetWithQAPIAsync(resourceName, qapiRequestBody.ToString(), version, pageSize, offset ); - } - - /// - /// Gets the total count of resources available using the given type T. - /// Gets the pages for a given resource beginning at the given offset index, using the specified QAPI request body and page size for the given version. - /// - /// Request type. - /// The name of the resource to add an instance of. - /// The full version header value of the resource used for this POST request. - /// The body of the request to POST for the given resource. - /// The size (number of rows) of each page returned in the list. - /// The 0 based index from which to begin paging for the given resource. - /// A list of EthosResponses where each EthosResponse contains a page of data. If paging is not required based on the - /// given pageSize and total count( from using the filter), the returned list will only contain one EthosResponse. - /// When is passed as null or empty or white space. - /// When is passed as null. - public async Task> GetPagesFromOffsetWithQAPIAsync( string resourceName, T qapiRequestBody, string version = "", int pageSize = 0, int offset = 0 ) where T : class - { - ArgumentNullException.ThrowIfNull( qapiRequestBody, $"Error: Cannot submit a POST request for resource {resourceName} due to a null {nameof( qapiRequestBody )} parameter." ); - - var jsonSerSettings = GetJsonSerializerSettings(); - var reqBody = JsonConvert.SerializeObject( qapiRequestBody, jsonSerSettings ); - return await GetPagesFromOffsetWithQAPIAsync( resourceName, reqBody, version, pageSize, offset ); - } - - /// - /// Gets all the pages for a given resource beginning at offset index 0, using the specified QAPI request body and page size for the given version. - /// - /// The name of the resource to add an instance of. - /// The full version header value of the resource used for this POST request. - /// The body of the request to POST for the given resource. - /// The size (number of rows) of each page returned in the list. - /// A list of EthosResponses where each EthosResponse contains a page of data. If paging is not required based on the - /// given pageSize and total count( from using the filter), the returned list will only contain one EthosResponse. - /// When is passed as null or empty or white space. - /// When is passed as null. - public async Task> GetPagesWithQAPIAsync( string resourceName, string qapiRequestBody, string version = "", int pageSize = 0 ) - { - return await GetPagesFromOffsetWithQAPIAsync(resourceName, qapiRequestBody, version, pageSize, 0 ); - } - - /// - /// Gets all the pages for a given resource beginning at offset index 0, using the specified QAPI request body and page size for the given version. - /// - /// The name of the resource to add an instance of. - /// The full version header value of the resource used for this POST request. - /// The body of the request to POST for the given resource. - /// The size (number of rows) of each page returned in the list. - /// A list of EthosResponses where each EthosResponse contains a page of data. If paging is not required based on the - /// given pageSize and total count( from using the filter), the returned list will only contain one EthosResponse. - /// When is passed as null or empty or white space. - /// When is passed as null. - public async Task> GetPagesWithQAPIAsync( string resourceName, JObject qapiRequestBody, string version = "", int pageSize = 0 ) - { - ArgumentNullException.ThrowIfNull( qapiRequestBody, $"Error: Cannot submit a POST request for resource {resourceName} due to a null {nameof( qapiRequestBody )} parameter." ); - return await GetPagesWithQAPIAsync( resourceName, qapiRequestBody.ToString(), version, pageSize ); - } - - /// - /// Gets all the pages for a given resource beginning at offset index 0, using the specified QAPI request body and page size for the given version. - /// - /// Request type. - /// The name of the resource to add an instance of. - /// The full version header value of the resource used for this POST request. - /// The body of the request to POST for the given resource. - /// The size (number of rows) of each page returned in the list. - /// A list of EthosResponses where each EthosResponse contains a page of data. If paging is not required based on the - /// given pageSize and total count( from using the filter), the returned list will only contain one EthosResponse. - /// When is passed as null or empty or white space. - /// When is passed as null. - public async Task> GetPagesWithQAPIAsync( string resourceName, T qapiRequestBody, string version = "", int pageSize = 0 ) where T : class - { - ArgumentNullException.ThrowIfNull( qapiRequestBody, $"Error: Cannot submit a POST request for resource {resourceName} due to a null {nameof( qapiRequestBody )} parameter." ); - - var jsonSerSettings = GetJsonSerializerSettings(); - var reqBody = JsonConvert.SerializeObject( qapiRequestBody, jsonSerSettings ); - return await GetPagesWithQAPIAsync( resourceName, reqBody, version, pageSize ); - } - - /// - /// Gets the total count of resources available using the given QAPI request body. - /// - /// The name of the resource to get data for. - /// The body of the request to POST for the given resource. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// The number of resource instances available when making a GET request using the given namedQueryFilter, or 0 if the - /// given resourceName or namedQueryFilter is null. - /// Returns exception if the resourceName is null. - /// Returns exception if the qapiRequestBody is null. - public async Task GetTotalCountAsync( string resourceName, string qapiRequestBody, string version = "" ) - { - if ( string.IsNullOrWhiteSpace( resourceName ) || string.IsNullOrWhiteSpace( qapiRequestBody ) ) - { - return default; - } - - EthosResponse ethosResponse = await GetWithQapiAsync( resourceName, qapiRequestBody, version ); - string totalCount = GetHeaderValue( ethosResponse, HDR_X_TOTAL_COUNT ); - if ( int.TryParse( totalCount, out int count ) ) - { - return count; - } - return default; - } - - /// - /// Gets the total count of resources available using the given QAPI request body. - /// - /// The name of the resource to get data for. - /// The body of the request to POST for the given resource. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// The number of resource instances available when making a GET request using the given namedQueryFilter, or 0 if the - /// given resourceName or namedQueryFilter is null. - /// Returns exception if the resourceName is null. - /// Returns exception if the qapiRequestBody is null. - public async Task GetTotalCountAsync( string resourceName, JObject qapiRequestBody, string version = "" ) - { - if( qapiRequestBody is null) return default; - return await GetTotalCountAsync( resourceName, qapiRequestBody.ToString(), version ); - } - - /// - /// Gets the total count of resources available using the given QAPI request body. - /// - /// The name of the resource to get data for. - /// The body of the request to POST for the given resource. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// The number of resource instances available when making a GET request using the given namedQueryFilter, or 0 if the - /// given resourceName or namedQueryFilter is null. - /// Returns exception if the resourceName is null. - /// Returns exception if the qapiRequestBody is null. - public async Task GetTotalCountAsync( string resourceName, T qapiRequestBody, string version = "" ) where T : class - { - if ( string.IsNullOrWhiteSpace( resourceName ) || qapiRequestBody is null ) - { - return default; - } - - EthosResponse ethosResponse = await GetWithQapiAsync( resourceName, qapiRequestBody, version ); - string totalCount = GetHeaderValue( ethosResponse, HDR_X_TOTAL_COUNT ); - if ( int.TryParse( totalCount, out int count ) ) - { - return count; - } - return default; - } - - /// - ///

Intended to be used internally within the SDK.

Performs paging calculations and operations for QAPI requests. - ///
- /// The name of the resource to add an instance of. - /// The full version header value of the resource used for this POST request. - /// The body of the request to POST for the given resource. - /// The total count of rows for the given resource. - /// The size (number of rows) of each page returned in the list. - /// The 0 based index from which to begin paging for the given resource. - /// Collection of EthosResponse with content. - protected async Task> DoPagingFromOffsetForQAPIAsync( string resourceName, string version, string qapiRequestBody, int totalCount, int pageSize, int offset ) - { - List ethosResponseList = new(); - Dictionary headers = BuildHeadersMap( version ); - decimal numPages = Math.Ceiling( ( Convert.ToDecimal( totalCount ) - Convert.ToDecimal( offset ) ) / Convert.ToDecimal( pageSize ) ); - for ( int i = 0; i < numPages; i++ ) - { - string url = EthosIntegrationUrls.QapiPaging( Region, resourceName, offset, pageSize ); - EthosResponse response = await base.PostAsync( headers, url, qapiRequestBody ); - ethosResponseList.Add( response ); - offset += pageSize; - } - return ethosResponseList; + Region = Authentication.SupportedRegions.SelfHosted; + IntegrationUrls.MAIN_BASE_URL = colleagueApiUrl; } - #endregion QAPI - - /// - /// Gets the total count of resources available using the given criteriaFilter. - /// - /// The name of the resource to get data for. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// A previously built Criteria containing the filter criteria used in the request URL. - /// The number of resource instances available when making a GET request using the given criteriaFilter, or 0 if the - /// given resourceName or criteriaFilter is null. - /// Returns exception if the resourceName is null. - /// Returns exception if the criteriaFilterStr is null. - public async Task GetTotalCountAsync( string resourceName, CriteriaFilter criteria, string version = "" ) - { - if ( string.IsNullOrWhiteSpace( resourceName ) ) - { - return default; - } - if ( criteria == null ) - { - return default; - } - EthosResponse ethosResponse = await GetWithCriteriaFilterAsync( resourceName, version, criteria.BuildCriteria() ); - string totalCount = GetHeaderValue( ethosResponse, HDR_X_TOTAL_COUNT ); - if ( int.TryParse( totalCount, out int count ) ) - { - return count; - } - return default; - } - - /// - /// Gets the total count of resources available using the given namedQueryFilter. - /// - /// The name of the resource to get data for. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// A previously built namedQueryFilter containing the filter used in the request URL. - /// The number of resource instances available when making a GET request using the given namedQueryFilter, or 0 if the - /// given resourceName or namedQueryFilter is null. - /// Returns exception if the resourceName is null. - public async Task GetTotalCountAsync( string resourceName, NamedQueryFilter namedQueryFilter, string version = "" ) - { - if ( string.IsNullOrWhiteSpace( resourceName ) ) - { - return default; - } - if ( namedQueryFilter == null ) - { - return default; - } - EthosResponse ethosResponse = await GetWithNamedQueryFilterAsync( resourceName, version, namedQueryFilter.BuildNamedQuery() ); - string totalCount = GetHeaderValue( ethosResponse, HDR_X_TOTAL_COUNT ); - if ( int.TryParse( totalCount, out int count ) ) - { - return count; - } - return default; - } - - /// - /// Gets the total count of resources available using the given filterMap. - /// - /// The name of the resource to get data for. - /// The desired resource version header to use, as provided in the HTTP Accept Header of the request. - /// A previously built FilterMap containing the filter parameters used in the request URL. - /// A simple call to filterMap.Tostring() should output the criteria filter portion of the request URL, - /// e.g: ?firstName=John&lastName=Smith. - /// The number of resource instances available when making a GET request using the given criteriaFilter, or 0 if the - /// given resourceName or criteriaFilter is null. - /// Returns exception if the resourceName is null. - public async Task GetTotalCountAsync( string resourceName, FilterMap filterMap, string version = "" ) - { - if ( string.IsNullOrWhiteSpace( resourceName ) ) - { - return default; - } - if ( filterMap == null ) - { - return default; - } - EthosResponse ethosResponse = await GetWithFilterMapAsync( resourceName, version, filterMap.ToString() ); - string totalCount = GetHeaderValue( ethosResponse, HDR_X_TOTAL_COUNT ); - if ( int.TryParse( totalCount, out int count ) ) - { - return count; - } - return default; - } - - /// - ///

Intended to be used internally within the SDK. - ///

- /// Overrides the prepareForPaging() method in the EthosProxyClient super class. - ///

- /// Uses the given pager object to prepare for paging operations. The pager object is used to contain various - /// fields required for paging. If the given pager is null, returns the same pager. Sets default values for the - /// version and offset within the pager as needed and makes an initial resource call using the provided pager filter - /// to get metadata about the resource used for paging. Also sets the page size and the total count within the pager, - /// and encodes the filter within the pager.

- ///
- /// The Pager object used holding the required fields for paging. - /// The same pager object with the version and offset validated, the page size and total count set, and the filter encoded. - protected new async Task PrepareForPagingAsync( Pager pager ) - { - if ( pager == null ) - { - return pager; - } - if ( string.IsNullOrWhiteSpace( pager.Version ) ) - { - pager.Version = DEFAULT_VERSION; - } - if ( pager.Offset < 1 ) - { - pager.Offset = 0; - } - - pager = await PreparePagerForTotalCountAsync( pager ); - - // Set the pageSize. - pager = PreparePagerForPageSize( pager ); - - // Encode the criteriaFilter if it is not null. - if ( pager.CriteriaFilter != null ) - { - pager.CriteriaFilter = EncodeString( pager.CriteriaFilter ); - } - - // Encode the NamedQueryFilter if it is not null. - if ( pager.NamedQueryFilter != null ) - { - pager.NamedQueryFilter = EncodeString( pager.NamedQueryFilter ); - } - return pager; - } - - /// - /// Intended to be used internally by the SDK. - ///

Prepares the pager object for the total count required for paging calculations. - /// The total count is derived from the response x-total-count header after making an initial request using filters

- /// (in this case). - ///
- /// The Pager object used holding the required fields for paging. - /// The pager object containing the total count. If neither a criteria filter, a named query nor a filter map is specified - /// in the pager, then the total count will be 0. - protected async Task PreparePagerForTotalCountAsync( Pager pager ) - { - EthosResponse ethosResponse = null; - if ( pager.CriteriaFilter is not null ) - { - ethosResponse = await GetWithCriteriaFilterAsync( pager.ResourceName, pager.Version, pager.CriteriaFilter ); - pager.EthosResponse = ethosResponse; - } - else if ( pager.NamedQueryFilter is not null ) - { - ethosResponse = await GetWithNamedQueryFilterAsync( pager.ResourceName, pager.Version, pager.NamedQueryFilter ); - pager.EthosResponse = ethosResponse; - } - else if ( pager.FilterMap is not null ) - { - ethosResponse = await GetWithFilterMapAsync( pager.ResourceName, pager.Version, pager.FilterMap ); - pager.EthosResponse = ethosResponse; - } - else if ( pager.QapiRequestBody is not null ) - { - ethosResponse = await GetWithQapiAsync( pager.ResourceName, pager.QapiRequestBody, pager.Version ); - pager.EthosResponse = ethosResponse; - } - else - { - await base.PrepareForPagingAsync( pager ); - } - if ( ethosResponse is not null ) - { - string totalCount = GetHeaderValue( ethosResponse, HDR_X_TOTAL_COUNT ); - if ( int.TryParse( totalCount, out int count ) ) - { - pager.TotalCount = count; - } - } - return pager; - } - - /// - /// Intended to be used internally by the SDK. - ///

- /// If the page size specified in the pager is <= DEFAULT_PAGE_SIZE, then this method prepares the pager object for the - /// page size required for paging calculations. The page size is derived from the response body length after making an initial request using filters - /// (in this case). If the response is null, the DEFAULT_MAX_PAGE_SIZE is used. If the response body is null, the - /// x-max-page-size header is used.

- ///

If the page size specified in the pager is > DEFAULT_PAGE_SIZE, this method does nothing and just returns the given pager.

- ///
- /// The pager object used to contain the page size for paging operations. - /// The pager object containing the page size. - protected Pager PreparePagerForPageSize( Pager pager ) - { - if ( pager.PageSize <= DEFAULT_PAGE_SIZE ) - { - if ( pager.EthosResponse == null ) - { - pager.PageSize = DEFAULT_MAX_PAGE_SIZE; // Set the page size to the MAX default because there is no ethosResponse. - } - // Set the pageSize from the response body length, if pageSize is <= DEFAULT_PAGE_SIZE. - else if ( !string.IsNullOrWhiteSpace( pager.EthosResponse.Content ) && pager.EthosResponse.GetContentAsJson() != null ) - { - int pageSize = pager.EthosResponse.GetContentCount(); - pager.PageSize = pageSize; - } - else - { - string maxPageSizeStr = GetHeaderValue( pager.EthosResponse, HDR_X_MAX_PAGE_SIZE ); - if ( !string.IsNullOrWhiteSpace( maxPageSizeStr ) ) - { - if ( int.TryParse( maxPageSizeStr, out int pageSize ) ) - { - pager.PageSize = pageSize; - } - } - else - { - pager.PageSize = DEFAULT_MAX_PAGE_SIZE; - } - } - } - return pager; - } - - /// - /// Used internally by the SDK. - ///

- /// Encodes the given criteriaFilterStr. Supports criteria filter strings that begin with the CRITERIA_FILTER_PREFIX - /// value "?criteria=", and also those that do not. Encodes only the JSON criteria portion of the filter string, removing - /// the CRITERIA_FILTER_PREFIX portion if the filter string starts with it. If the filter string does not start with - /// the CRITERIA_FILTER_PREFIX, the criteriaFilterStr string is simply encoded.

- ///

Returns a criteria filter string that begins with the CRITERIA_FILTER_PREFIX, with the JSON filter portion of the string - /// encoded. Uses UTF-8 encoding.

- ///
- /// The criteria filter string to encode. - /// A criteria filter string beginning with the CRITERIA_FILTER_PREFIX with the JSON filter syntax portion of the - /// string encoded in UTF-8. - private static string EncodeString( string criteriaFilterStr ) - { - StringBuilder sb = new StringBuilder(); - string jsonCriteriaStr; - bool isNamedQuery = false; - if ( criteriaFilterStr.StartsWith( CRITERIA_FILTER_PREFIX ) ) - { - // It starts with "?criteria=", so substring the rest of the filter and encode it. - jsonCriteriaStr = criteriaFilterStr [ ( criteriaFilterStr.IndexOf( "=" ) + 1 ).. ]; - } - else - { - jsonCriteriaStr = criteriaFilterStr; - isNamedQuery = true; - } - jsonCriteriaStr = System.Web.HttpUtility.UrlEncode( jsonCriteriaStr, Encoding.UTF8 ); - if ( !isNamedQuery ) sb.Append( CRITERIA_FILTER_PREFIX ); - sb.Append( jsonCriteriaStr ); - return sb.ToString(); - } - - /// - /// Gets JsonSerializerSettings with date format. - /// - /// Returns JsonSerializerSettings with yyyy'-'MM'-'dd'T'HH':'mm':'ssK date format and ignores null values. - private static JsonSerializerSettings GetJsonSerializerSettings() - { - return new JsonSerializerSettings() - { - DateFormatString = DATE_FORMAT, - NullValueHandling = NullValueHandling.Ignore, - DefaultValueHandling = DefaultValueHandling.Ignore - }; - } } } diff --git a/Ellucian.Ethos.Integration/Client/Proxy/EthosFilterQueryClient.cs b/Ellucian.Ethos.Integration/Client/Proxy/EthosFilterQueryClient.cs index d28d933..e4c432b 100644 --- a/Ellucian.Ethos.Integration/Client/Proxy/EthosFilterQueryClient.cs +++ b/Ellucian.Ethos.Integration/Client/Proxy/EthosFilterQueryClient.cs @@ -36,6 +36,18 @@ public class EthosFilterQueryClient : EthosProxyClient public EthosFilterQueryClient( string apiKey, HttpClient client ) : base( apiKey, client ) { + } + /// + /// Instantiates this class using the given Colleague URL and credentials and HttpClient. + /// + /// The URL to the Colleague API instance. If it is null/empty, then an will be thrown. + /// The username used to connect to the Colleague API. If it is null/empty, then an will be thrown. + /// The password used to connect to the Colleague API. If it is null/empty, then an will be thrown. + /// A HttpClient. If it is null/empty, then an will be thrown. + public EthosFilterQueryClient(string colleagueApiUrl, string colleagueApiUsername, string colleagueApiPassword, HttpClient client) + : base(colleagueApiUrl, colleagueApiUsername, colleagueApiPassword, client) + { + } #region Strongly Typed GET @@ -372,7 +384,7 @@ private async Task GetEthosResponseAsync( string resourceName, st { var filterStr = EncodeString( criteria ); Dictionary headers = BuildHeadersMap( version ); - EthosResponse response = await GetAsync( headers, EthosIntegrationUrls.ApiFilter( Region, resourceName, filterStr ) ); + EthosResponse response = await GetAsync( headers, IntegrationUrls.ApiFilter( Region, resourceName, filterStr ) ); return response; } @@ -536,7 +548,7 @@ public async Task GetWithFilterMapAsync( string resourceName, str throw new ArgumentNullException( $"Error: Cannot get resource '{ resourceName }' with filter map due to a null or blank filter map string." ); } Dictionary headers = BuildHeadersMap( version ); - EthosResponse response = await GetAsync( headers, EthosIntegrationUrls.ApiFilter( Region, resourceName, filterMapStr ) ); + EthosResponse response = await GetAsync( headers, IntegrationUrls.ApiFilter( Region, resourceName, filterMapStr ) ); return response; } @@ -977,7 +989,7 @@ public async Task GetWithQapiAsync( string resourceName, string q ); } var headers = BuildHeadersMap( version ); - string url = EthosIntegrationUrls.Qapi( Region, resourceName ); + string url = IntegrationUrls.Qapi( Region, resourceName ); return await base.PostAsync( headers, url, qapiRequestBody ); } @@ -1245,7 +1257,7 @@ protected async Task> DoPagingFromOffsetForQAPIAsync( string decimal numPages = Math.Ceiling( ( Convert.ToDecimal( totalCount ) - Convert.ToDecimal( offset ) ) / Convert.ToDecimal( pageSize ) ); for ( int i = 0; i < numPages; i++ ) { - string url = EthosIntegrationUrls.QapiPaging( Region, resourceName, offset, pageSize ); + string url = IntegrationUrls.QapiPaging( Region, resourceName, offset, pageSize ); EthosResponse response = await base.PostAsync( headers, url, qapiRequestBody ); ethosResponseList.Add( response ); offset += pageSize; diff --git a/Ellucian.Ethos.Integration/Client/Proxy/EthosProxyClient.cs b/Ellucian.Ethos.Integration/Client/Proxy/EthosProxyClient.cs index 5025adb..c66a6cc 100644 --- a/Ellucian.Ethos.Integration/Client/Proxy/EthosProxyClient.cs +++ b/Ellucian.Ethos.Integration/Client/Proxy/EthosProxyClient.cs @@ -123,6 +123,18 @@ public class EthosProxyClient : EthosClient public EthosProxyClient( string apiKey, HttpClient client ) : base( apiKey, client ) { + } + /// + /// Constructs an EthosProxyClient using the given Colleague API URL and credentials. + /// + /// The URL to the Colleague API instance. If it is null/empty, then an will be thrown. + /// The username used to connect to the Colleague API. If it is null/empty, then an will be thrown. + /// The password used to connect to the Colleague API. If it is null/empty, then an will be thrown. + /// A . + public EthosProxyClient(string colleagueApiUrl, string colleagueApiUsername, string colleagueApiPassword, HttpClient client) + : base(colleagueApiUrl, colleagueApiUsername, colleagueApiPassword, client) + { + } #region POST @@ -163,7 +175,7 @@ public async Task PostAsync( string resourceName, string version, ); } var headers = BuildHeadersMap( version ); - string url = EthosIntegrationUrls.Api( Region, resourceName, null ); + string url = IntegrationUrls.Api( Region, resourceName, null ); return await base.PostAsync( headers, url, requestBody ); } @@ -245,7 +257,7 @@ public async Task PutAsync( string resourceName, string resourceI } var headers = BuildHeadersMap( version ); - string url = EthosIntegrationUrls.Api( Region, resourceName, resourceId ); + string url = IntegrationUrls.Api( Region, resourceName, resourceId ); return await base.PutAsync( headers, url, requestBody ); } @@ -311,7 +323,7 @@ public async Task DeleteAsync( string resourceName, string id ) ); } var headers = BuildHeadersMap( null ); - string url = EthosIntegrationUrls.Api( Region, resourceName, id ); + string url = IntegrationUrls.Api( Region, resourceName, id ); await base.DeleteAsync( headers, url ); } @@ -553,7 +565,7 @@ internal IEnumerable ConvertEthosResponseContentListToType( IE var version = DEFAULT_VERSION; Dictionary headers = BuildHeadersMap( version ); - string url = $"{ EthosIntegrationUrls.Api( Region, resourceName ) }"; + string url = $"{IntegrationUrls.Api( Region, resourceName ) }"; EthosResponse response = await GetAsync( headers, url ); return response; } @@ -570,7 +582,7 @@ public async Task GetAsync( string resourceName, string version = if ( string.IsNullOrWhiteSpace( resourceName ) ) { throw new ArgumentNullException( nameof( resourceName ) ); } Dictionary headers = BuildHeadersMap( version ); - string url = $"{ EthosIntegrationUrls.Api( Region, resourceName ) }"; + string url = $"{IntegrationUrls.Api( Region, resourceName ) }"; EthosResponse response = await GetAsync( headers, url ); return response; } @@ -618,7 +630,7 @@ public async Task GetAsync( string resourceName, string version = if ( string.IsNullOrWhiteSpace( resourceName ) ) { throw new ArgumentNullException( nameof( resourceName ) ); } Dictionary headers = BuildHeadersMap( version ); - string url = $"{ EthosIntegrationUrls.ApiPaging( Region, resourceName, offset, pageSize ) }"; + string url = $"{IntegrationUrls.ApiPaging( Region, resourceName, offset, pageSize ) }"; EthosResponse response = await GetAsync( headers, url ); return response; } @@ -1341,7 +1353,7 @@ public async Task GetByIdAsync( string resourceName, string id, s } var headersMap = BuildHeadersMap( version ); - string url = EthosIntegrationUrls.Api( Region, resourceName, id ); + string url = IntegrationUrls.Api( Region, resourceName, id ); EthosResponse ethosResponse = await GetAsync( headersMap, url ); return ethosResponse; } @@ -1616,11 +1628,11 @@ protected async Task> DoPagingFromOffsetAsync( string resour string url; if ( string.IsNullOrWhiteSpace( filter ) ) { - url = EthosIntegrationUrls.ApiPaging( Region, resourceName, offset, pageSize ); + url = IntegrationUrls.ApiPaging( Region, resourceName, offset, pageSize ); } else { - url = EthosIntegrationUrls.ApiFilterPaging( Region, resourceName, filter, offset, pageSize ); + url = IntegrationUrls.ApiFilterPaging( Region, resourceName, filter, offset, pageSize ); } EthosResponse response = await GetAsync( headers, url ); ethosResponseList.Add( response ); @@ -1667,7 +1679,7 @@ private async Task> DoPagingFromOffsetForNumPagesAsync( stri { break; } - string url = EthosIntegrationUrls.ApiPaging( Region, resourceName, offset, pageSize ); + string url = IntegrationUrls.ApiPaging( Region, resourceName, offset, pageSize ); EthosResponse response = await GetAsync( headers, url ); ethosResponseList.Add( response ); offset += pageSize; @@ -1721,7 +1733,7 @@ private async Task> DoPagingFromOffsetForNumRowsAsync( strin { pageSize = rowsRemaining; } - string url = EthosIntegrationUrls.ApiPaging( Region, resourceName, offset, pageSize ); + string url = IntegrationUrls.ApiPaging( Region, resourceName, offset, pageSize ); EthosResponse response = await GetAsync( headers, url ); ethosResponseList.Add( response ); offset += pageSize; diff --git a/Ellucian.Ethos.Integration/EthosIntegrationUrls.cs b/Ellucian.Ethos.Integration/EthosIntegrationUrls.cs index a1206a8..3e2ec2a 100644 --- a/Ellucian.Ethos.Integration/EthosIntegrationUrls.cs +++ b/Ellucian.Ethos.Integration/EthosIntegrationUrls.cs @@ -14,7 +14,7 @@ namespace Ellucian.Ethos.Integration /// /// Utility class used for building Ethos Integration URLs with various criteria. /// - public static class EthosIntegrationUrls + public class EthosIntegrationUrls { /// /// A Dictionary<SupportedRegions,string> of supported regions where each region is assigned the @@ -35,16 +35,17 @@ public static class EthosIntegrationUrls /// /// /// - private static readonly Dictionary RegionUrlPostFix = new Dictionary + private readonly Dictionary RegionUrlPostFix = new Dictionary { [ SupportedRegions.US ] = ".com", [ SupportedRegions.Canada ] = ".ca", [ SupportedRegions.Europe ] = ".ie", - [ SupportedRegions.Australia ] = ".com.au" + [ SupportedRegions.Australia ] = ".com.au", + [ SupportedRegions.SelfHosted ] = "" }; ///The main domain for Ethos Integration. - private const string MAIN_BASE_URL = "https://integrate.elluciancloud"; + public string MAIN_BASE_URL = "https://integrate.elluciancloud"; /// /// The base URL for getting Api result(s) in Ethos Integration. @@ -53,15 +54,15 @@ public static class EthosIntegrationUrls /// The Ethos resource the URL should contain. /// The (optional) ID for the given resource to build URLs for "get by ID" requests. /// A string value containing the URL to use for interacting with Ethos Integration Proxy APIs. - public static string Api( SupportedRegions region, string resource, string id = "" ) + public string Api( SupportedRegions region, string resource, string id = "" ) { - string url = BuildUrl( region, "/api" ); - if ( !string.IsNullOrWhiteSpace( resource ) ) + string url = BuildUrl(region, "/api"); + if (!string.IsNullOrWhiteSpace(resource)) { - url += ( "/" + resource ); - if ( !string.IsNullOrWhiteSpace( id ) ) + url += ("/" + resource); + if (!string.IsNullOrWhiteSpace(id)) { - url += ( "/" + id ); + url += ("/" + id); } } return url; @@ -74,7 +75,7 @@ public static string Api( SupportedRegions region, string resource, string id = /// The Ethos resource the URL should contain. /// The resource filter the URL should contain. /// A string value containing the URL to use for interacting with Ethos Integration Proxy APIs, supporting filters. - public static string ApiFilter( SupportedRegions region, string resource, string filter ) + public string ApiFilter( SupportedRegions region, string resource, string filter ) { string url = Api( region, resource, null ); StringBuilder sb = new StringBuilder(); @@ -92,7 +93,7 @@ public static string ApiFilter( SupportedRegions region, string resource, string /// A supported region. /// The Ethos resource the URL should contain. /// A string value containing the URL to use for interacting with Ethos Integration Proxy APIs. - public static string Qapi( SupportedRegions region, string resource ) + public string Qapi( SupportedRegions region, string resource ) { string url = BuildUrl( region, "/qapi" ); if ( !string.IsNullOrWhiteSpace( resource ) ) @@ -110,7 +111,7 @@ public static string Qapi( SupportedRegions region, string resource ) /// The row index from which to begin paging for data for the given resource. /// The number of rows each response can contain. /// A string value containing the URL to use for interacting with Ethos Integration Proxy APIs. - public static string QapiPaging( SupportedRegions region, string resource, int offset, int pageSize ) + public string QapiPaging( SupportedRegions region, string resource, int offset, int pageSize ) { string url = Qapi( region, resource ); return AddPaging( url, offset, pageSize ); @@ -126,7 +127,7 @@ public static string QapiPaging( SupportedRegions region, string resource, int o /// The row index from which to begin paging for data for the given resource. /// The number of rows each response can contain. /// A string value containing the URL to use for interacting with Ethos Integration Proxy APIs, supporting filters. - public static string ApiFilterPaging( SupportedRegions region, string resource, string filter, int offset, int pageSize ) + public string ApiFilterPaging( SupportedRegions region, string resource, string filter, int offset, int pageSize ) { string url = ApiFilter( region, resource, filter ); return AddPaging( url, offset, pageSize ); @@ -140,7 +141,7 @@ public static string ApiFilterPaging( SupportedRegions region, string resource, /// The row index from which to begin paging for data for the given resource. /// The number of rows each response can contain. /// A string value containing the URL to use for interacting with Ethos Integration Proxy APIs, in support of paging. - public static string ApiPaging( SupportedRegions region, string resource, int offset, int pageSize ) + public string ApiPaging( SupportedRegions region, string resource, int offset, int pageSize ) { string urlStr = Api( region, resource, null ); return AddPaging( urlStr, offset, pageSize ); @@ -151,7 +152,7 @@ public static string ApiPaging( SupportedRegions region, string resource, int of /// /// The appropriate supported region to build the URL with. /// A string value containing the URL to use for interacting with Ethos Integration Errors APIs. - public static string Errors( SupportedRegions region ) + public string Errors( SupportedRegions region ) { return BuildUrl( region, "/errors" ); } @@ -163,7 +164,7 @@ public static string Errors( SupportedRegions region ) /// The row index from which to begin paging for errors. /// The number of errors (limit) each response can contain. /// A string value containing the URL to use for interacting with EthosIntegration Errors API, in support of paging. - public static string ErrorsPaging( SupportedRegions region, int offset, int pageSize ) + public string ErrorsPaging( SupportedRegions region, int offset, int pageSize ) { string url = Errors( region ); return AddPaging( url, offset, pageSize ); @@ -174,7 +175,7 @@ public static string ErrorsPaging( SupportedRegions region, int offset, int page ///
/// The appropriate supported region to build the URL with. /// A string value containing the URL to use for interacting with Ethos Integration Token API. - public static string Auth( SupportedRegions region ) + public string Auth( SupportedRegions region ) { return BuildUrl( region, "/auth" ); } @@ -184,7 +185,7 @@ public static string Auth( SupportedRegions region ) ///
/// A supported region. /// The region specific /appconfig URL - public static string AppConfig( SupportedRegions region ) + public string AppConfig( SupportedRegions region ) { return BuildUrl( region, "/appconfig" ); } @@ -194,7 +195,7 @@ public static string AppConfig( SupportedRegions region ) ///
/// A supported region. /// The region specific /available-resources URL - public static string AvailableResources( SupportedRegions region ) + public string AvailableResources( SupportedRegions region ) { return BuildUrl( region, "/admin/available-resources" ); } @@ -209,7 +210,7 @@ public static string AvailableResources( SupportedRegions region ) /// A value to use for the 'limit' query parameter. Any value greater than zero will be added to the URL as /// a query parameter. If the value is zero or less, it will not be added to the URL. /// The URL to use for calling the Ethos Integration consume endpoint. - public static string Consume( SupportedRegions region, long? lastProcessedID, int? limit ) + public string Consume( SupportedRegions region, long? lastProcessedID, int? limit ) { StringBuilder builder = new StringBuilder(); @@ -236,7 +237,7 @@ public static string Consume( SupportedRegions region, long? lastProcessedID, in ///
/// A supported region. /// - public static string BaseUrl( SupportedRegions region ) + public string BaseUrl( SupportedRegions region ) { return $"{MAIN_BASE_URL}{RegionUrlPostFix [ region ]}"; } @@ -245,10 +246,11 @@ public static string BaseUrl( SupportedRegions region ) /// Builds the URL with the mainBaseUrl, the supported region, and the correct path. ///
/// The appropriate supported region to build the URL with. - /// The correct path for the type of API the URL will be used with (/api for Proxy API URL, + /// The correct path for the type of API the URL will be used with (/api for Proxy API URL, + /// If provided, swaps out the MAIN_BASE_URL for the ColleagueApiUrl, /// for Token API URL, etc.). /// - private static string BuildUrl( SupportedRegions region, string urlEnd ) + private string BuildUrl( SupportedRegions region, string urlEnd) { return $"{MAIN_BASE_URL}{RegionUrlPostFix [ region ]}{urlEnd}"; } @@ -260,7 +262,7 @@ private static string BuildUrl( SupportedRegions region, string urlEnd ) /// The offset param to page from. /// The limit param to page with. /// A URL string containing the offset and limit params for paging. - private static string AddPaging( string urlStr, int offset, int pageSize ) + private string AddPaging( string urlStr, int offset, int pageSize ) { StringBuilder sb = new StringBuilder( urlStr ); if ( offset >= 0 && pageSize > 0 ) From ead042c415582c30e9ec8b4da1264bdd27e530ad Mon Sep 17 00:00:00 2001 From: Neal Webb Date: Fri, 7 Jul 2023 19:20:53 -0400 Subject: [PATCH 03/13] Complete implementation for Colleague API support --- Ellucian.Ethos.Integration/Client/EthosClient.cs | 3 +++ Ellucian.Ethos.Integration/Client/EthosClientBuilder.cs | 3 +-- Ellucian.Ethos.Integration/EthosIntegrationUrls.cs | 9 ++++++--- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/Ellucian.Ethos.Integration/Client/EthosClient.cs b/Ellucian.Ethos.Integration/Client/EthosClient.cs index 6dd3340..94ccec3 100644 --- a/Ellucian.Ethos.Integration/Client/EthosClient.cs +++ b/Ellucian.Ethos.Integration/Client/EthosClient.cs @@ -139,6 +139,9 @@ public EthosClient(string colleagueApiUrl, string colleagueApiUsername, string c throw new ArgumentNullException($"The '{nameof(client)}' parameter is required."); } ApiKey = null; + this.ColleagueApiUrl = colleagueApiUrl; + this.ColleagueApiUsername = colleagueApiUsername; + this.ColleagueApiPassword = colleagueApiPassword; this.HttpProtocolClientBuilder ??= new HttpProtocolClientBuilder(client); EthosResponseBuilder ??= new EthosResponseBuilder(); } diff --git a/Ellucian.Ethos.Integration/Client/EthosClientBuilder.cs b/Ellucian.Ethos.Integration/Client/EthosClientBuilder.cs index e7824b6..587abc2 100644 --- a/Ellucian.Ethos.Integration/Client/EthosClientBuilder.cs +++ b/Ellucian.Ethos.Integration/Client/EthosClientBuilder.cs @@ -132,8 +132,7 @@ public ColleagueWebApiProxyClient BuildColleagueWebApiProxyclient() /// An ColleagueWebApiFilterQueryClient using the given Colleague credentials. public ColleagueWebApiFilterQueryClient BuildColleagueWebApiFilterQueryClient() { - // TODO - return null; + return new ColleagueWebApiFilterQueryClient(ColleagueApiUrl, ColleagueApiUsername, ColleagueApiPassword, builder.Client); } } } diff --git a/Ellucian.Ethos.Integration/EthosIntegrationUrls.cs b/Ellucian.Ethos.Integration/EthosIntegrationUrls.cs index 3e2ec2a..c5d21c1 100644 --- a/Ellucian.Ethos.Integration/EthosIntegrationUrls.cs +++ b/Ellucian.Ethos.Integration/EthosIntegrationUrls.cs @@ -247,12 +247,15 @@ public string BaseUrl( SupportedRegions region ) ///
/// The appropriate supported region to build the URL with. /// The correct path for the type of API the URL will be used with (/api for Proxy API URL, - /// If provided, swaps out the MAIN_BASE_URL for the ColleagueApiUrl, - /// for Token API URL, etc.). + /// for Token API URL, etc.). /// private string BuildUrl( SupportedRegions region, string urlEnd) { - return $"{MAIN_BASE_URL}{RegionUrlPostFix [ region ]}{urlEnd}"; + return region == SupportedRegions.SelfHosted + ? $"{MAIN_BASE_URL}" + : $"{MAIN_BASE_URL}{RegionUrlPostFix[region]}{urlEnd}"; + + // return $"{MAIN_BASE_URL}{RegionUrlPostFix [ region ]}{urlEnd}"; } /// From 0aa0df8e346f429622271b867d4fbfa6f792e680 Mon Sep 17 00:00:00 2001 From: Neal Webb Date: Fri, 7 Jul 2023 19:21:15 -0400 Subject: [PATCH 04/13] Add sample project using the client to access the Colleague API --- .../ColleagueApiExample.csproj | 14 +++++++ ColleagueApiExample/Program.cs | 37 +++++++++++++++++++ Ellucian.Ethos.Integration.sln | 17 +++++++++ 3 files changed, 68 insertions(+) create mode 100644 ColleagueApiExample/ColleagueApiExample.csproj create mode 100644 ColleagueApiExample/Program.cs diff --git a/ColleagueApiExample/ColleagueApiExample.csproj b/ColleagueApiExample/ColleagueApiExample.csproj new file mode 100644 index 0000000..05f53cb --- /dev/null +++ b/ColleagueApiExample/ColleagueApiExample.csproj @@ -0,0 +1,14 @@ + + + + Exe + net6.0 + enable + enable + + + + + + + diff --git a/ColleagueApiExample/Program.cs b/ColleagueApiExample/Program.cs new file mode 100644 index 0000000..717c212 --- /dev/null +++ b/ColleagueApiExample/Program.cs @@ -0,0 +1,37 @@ +using Ellucian.Ethos.Integration.Client; +using Ellucian.Ethos.Integration.Client.Filter.Extensions; +using Ellucian.Ethos.Integration.Client.Proxy.Filter; +using Newtonsoft.Json.Linq; + +var proxyClient = + new EthosClientBuilder( + colleagueApiUrl: "", + colleagueApiUsername: "", + colleagueApiPassword: "") + .BuildColleagueWebApiProxyclient(); + +var academicPeriod = + await proxyClient.GetAsJObjectByIdAsync("academic-periods", "a4b5fddc-fa2f-4e94-82e9-cbe219a5029b"); + +Console.WriteLine(academicPeriod.ToString()); + +var queryClient = + new EthosClientBuilder( + colleagueApiUrl: "", + colleagueApiUsername: "", + colleagueApiPassword: "") + .BuildColleagueWebApiFilterQueryClient(); + +var filter = + new CriteriaFilter() + .WithSimpleCriteria("startOn", ("$gte", "2020-01-01")); + +var responses = + await queryClient.GetPagesWithCriteriaFilterAsync("academic-periods", filter); + +foreach (var response in responses) +{ + var acadPeriods = JArray.Parse(response.Content); + + Console.WriteLine(acadPeriods.ToString()); +} \ No newline at end of file diff --git a/Ellucian.Ethos.Integration.sln b/Ellucian.Ethos.Integration.sln index 3c713e7..e93ce60 100644 --- a/Ellucian.Ethos.Integration.sln +++ b/Ellucian.Ethos.Integration.sln @@ -17,6 +17,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{80815184 EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Src", "Src", "{1402F60B-E306-4A41-B41E-2EF9136DFB36}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{B29BB850-080B-4A04-AF80-BB1B3FD91BC9}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ColleagueApiExample", "ColleagueApiExample\ColleagueApiExample.csproj", "{41EC6B03-53B4-43FC-AA8B-0E74C143F2FD}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -51,6 +55,18 @@ Global {DC26CC20-E923-4AA4-93C2-BCBEFC10EF26}.Release|x64.Build.0 = Release|Any CPU {DC26CC20-E923-4AA4-93C2-BCBEFC10EF26}.Release|x86.ActiveCfg = Release|Any CPU {DC26CC20-E923-4AA4-93C2-BCBEFC10EF26}.Release|x86.Build.0 = Release|Any CPU + {41EC6B03-53B4-43FC-AA8B-0E74C143F2FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {41EC6B03-53B4-43FC-AA8B-0E74C143F2FD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {41EC6B03-53B4-43FC-AA8B-0E74C143F2FD}.Debug|x64.ActiveCfg = Debug|Any CPU + {41EC6B03-53B4-43FC-AA8B-0E74C143F2FD}.Debug|x64.Build.0 = Debug|Any CPU + {41EC6B03-53B4-43FC-AA8B-0E74C143F2FD}.Debug|x86.ActiveCfg = Debug|Any CPU + {41EC6B03-53B4-43FC-AA8B-0E74C143F2FD}.Debug|x86.Build.0 = Debug|Any CPU + {41EC6B03-53B4-43FC-AA8B-0E74C143F2FD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {41EC6B03-53B4-43FC-AA8B-0E74C143F2FD}.Release|Any CPU.Build.0 = Release|Any CPU + {41EC6B03-53B4-43FC-AA8B-0E74C143F2FD}.Release|x64.ActiveCfg = Release|Any CPU + {41EC6B03-53B4-43FC-AA8B-0E74C143F2FD}.Release|x64.Build.0 = Release|Any CPU + {41EC6B03-53B4-43FC-AA8B-0E74C143F2FD}.Release|x86.ActiveCfg = Release|Any CPU + {41EC6B03-53B4-43FC-AA8B-0E74C143F2FD}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -58,6 +74,7 @@ Global GlobalSection(NestedProjects) = preSolution {34B4B30E-C0E0-43E9-88D0-27B31BA01574} = {1402F60B-E306-4A41-B41E-2EF9136DFB36} {DC26CC20-E923-4AA4-93C2-BCBEFC10EF26} = {80815184-6446-4B0F-B7A4-B190E5E53F70} + {41EC6B03-53B4-43FC-AA8B-0E74C143F2FD} = {B29BB850-080B-4A04-AF80-BB1B3FD91BC9} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {BB6A0A9A-4183-491A-97B0-86939AB919E1} From 9bfbf80a83f59e626e8e140373b132f3fb24ad99 Mon Sep 17 00:00:00 2001 From: John Stauffer Date: Thu, 13 Jul 2023 13:16:35 -0400 Subject: [PATCH 05/13] Create azure-artifacts-publish.yml --- .github/workflows/azure-artifacts-publish.yml | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 .github/workflows/azure-artifacts-publish.yml diff --git a/.github/workflows/azure-artifacts-publish.yml b/.github/workflows/azure-artifacts-publish.yml new file mode 100644 index 0000000..71e32b5 --- /dev/null +++ b/.github/workflows/azure-artifacts-publish.yml @@ -0,0 +1,65 @@ +name: Build and Publish to Azure Artifacts + +on: + release: + types: [published] + +env: + AZURE_ARTIFACTS_FEED_URL: https://pkgs.dev.azure.com/intuitionps/01c84548-9607-4655-80e7-6ad95390a38c/_packaging/private/nuget/v3/index.json + BUILD_CONFIGURATION: 'Release' # set this to the appropriate build configuration + DOTNET_VERSION: '6.x' + +jobs: + build: + runs-on: ubuntu-latest + steps: + # Checkout the repo + - uses: actions/checkout@v2 + + # Setup .NET Core SDK + - name: Setup .NET Core + uses: actions/setup-dotnet@v1 + with: + dotnet-version: ${{ env.DOTNET_VERSION }} + + # Run dotnet build and test + - name: dotnet build and test + run: | + dotnet restore + dotnet build --configuration '${{ env.BUILD_CONFIGURATION }}' + dotnet test --configuration '${{ env.BUILD_CONFIGURATION }}' + + az-artifacts-build-and-deploy: + needs: build + runs-on: ubuntu-latest + steps: + # Checkout the repo + - uses: actions/checkout@v2 + + # Extract git version + - name: Extract git tag + run: echo "VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV + + # Setup .NET Core SDK + - name: Setup .NET Core + uses: actions/setup-dotnet@v1 + with: + dotnet-version: ${{ env.DOTNET_VERSION }} + source-url: ${{ env.AZURE_ARTIFACTS_FEED_URL }} + env: + NUGET_AUTH_TOKEN: ${{ secrets.AZURE_ARTIFACTS_PAT }} + + # Run dotnet build and package + - name: dotnet build and publish + run: | + dotnet restore + dotnet build --configuration '${{ env.BUILD_CONFIGURATION }}' /p:Version=${{ github.event.release.tag_name }} + dotnet pack -c '${{ env.BUILD_CONFIGURATION }}' + + # Publish the package to Azure Artifacts + - name: 'dotnet publish to Azure Artifacts' + run: dotnet nuget push --api-key AzureArtifacts Ellucian.Ethos.Integration/bin/Release/*.nupkg + + # Publish the package to GitHub Packages + - name: 'dotnet publish to GitHub Packages' + run: dotnet nuget push --api-key ${{ secrets.GH_PACKAGES_PAT }} --source https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json Ellucian.Ethos.Integration/bin/Release/*.nupkg From aebe4d37c0cb30e3e080b294b37b9c9e7b51cf5f Mon Sep 17 00:00:00 2001 From: John Stauffer Date: Thu, 13 Jul 2023 13:19:24 -0400 Subject: [PATCH 06/13] Create _azure-pipelines-CI.yml --- _azure-pipelines-CI.yml | 76 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 _azure-pipelines-CI.yml diff --git a/_azure-pipelines-CI.yml b/_azure-pipelines-CI.yml new file mode 100644 index 0000000..61bf2a2 --- /dev/null +++ b/_azure-pipelines-CI.yml @@ -0,0 +1,76 @@ +# Build Pipeline - Continuous Integration +# if trigger is not merge commit from pull request, then pipeline will abort + +trigger: +- main + +pr: none + +pool: + vmImage: 'windows-latest' + +variables: + solution: '**/*.sln' + buildPlatform: 'Any CPU' + buildConfiguration: 'Release' + +steps: +- task: PowerShell@2 + displayName: Get Pull Request + inputs: + targetType: 'inline' + script: | + try { + $headers = @{ "Authorization" = "Bearer $(GitHubToken)"} + $uri = 'https://api.github.com/repos/$(Build.Repository.Name)/commits/$(Build.SourceVersion)/pulls' + $response = Invoke-WebRequest -Uri $uri -Headers $headers -Method Get + $content = $response.content | ConvertFrom-Json + if (-not($content -and $content[0] -and $content[0].id)) { + throw "** abort non-PR commit" + } + } catch { + Write-Host "Error getting pull request | $_" + exit 1 + } + +- task: NuGetToolInstaller@1 + displayName: Install NuGet Tool + +- task: NuGetCommand@2 + displayName: Restore Solution + inputs: + restoreSolution: '$(solution)' + +- task: SonarQubePrepare@5 + displayName: SonarQube - Prepare Analysis Configuration + inputs: + SonarQube: 'SonarQube' + scannerMode: 'MSBuild' + projectKey: 'Ethos-Integration-SDK' + +- task: VSBuild@1 + displayName: Build Solution + inputs: + solution: '$(solution)' + msbuildArgs: '/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:DesktopBuildPackageLocation="$(build.artifactStagingDirectory)\WebApp.zip"' + platform: '$(buildPlatform)' + configuration: '$(buildConfiguration)' + +- task: SonarQubeAnalyze@5 + displayName: SonarQube - Run Code Analysis + +- task: SonarQubePublish@5 + displayName: SonarQube - Publish Quality Gate Result + inputs: + pollingTimeoutSec: '300' + +- task: sonar-buildbreaker@8 + inputs: + SonarQube: 'SonarQube' + +- task: PublishBuildArtifacts@1 + displayName: Publish Pipeline Artifacts + inputs: + PathtoPublish: '$(Build.ArtifactStagingDirectory)' + ArtifactName: 'drop' + publishLocation: 'Container' From 0a21b8b9b44b466044cb9def047de3e4bba8a79f Mon Sep 17 00:00:00 2001 From: John Stauffer Date: Thu, 13 Jul 2023 13:22:38 -0400 Subject: [PATCH 07/13] Create _azure-pipelines-PR.yml --- _azure-pipelines-PR.yml | 51 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 _azure-pipelines-PR.yml diff --git a/_azure-pipelines-PR.yml b/_azure-pipelines-PR.yml new file mode 100644 index 0000000..24dc86a --- /dev/null +++ b/_azure-pipelines-PR.yml @@ -0,0 +1,51 @@ +# Build Pipeline - Pull Request + +trigger: none + +pr: +- main +- development + +pool: + vmImage: 'windows-latest' + +variables: + solution: '**/*.sln' + buildPlatform: 'Any CPU' + buildConfiguration: 'Debug' + +steps: +- task: NuGetToolInstaller@1 + displayName: Install NuGet Tool + +- task: NuGetCommand@2 + displayName: Restore Solution + inputs: + restoreSolution: '$(solution)' + +- task: SonarQubePrepare@5 + displayName: Prepare Analysis Configuration + inputs: + SonarQube: 'SonarQube' + scannerMode: 'MSBuild' + projectKey: 'Ethos-Integration-SDK' + +- task: VSBuild@1 + displayName: Build Solution + inputs: + solution: '$(solution)' + msbuildArgs: '/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:DesktopBuildPackageLocation="$(build.artifactStagingDirectory)\WebApp.zip"' + platform: '$(buildPlatform)' + configuration: '$(buildConfiguration)' + +- task: SonarQubeAnalyze@5 + displayName: SonarQube - Run Code Analysis + +- task: SonarQubePublish@5 + displayName: SonarQube - Publish Quality Gate Result + inputs: + pollingTimeoutSec: '300' + +- task: sonar-buildbreaker@8 + inputs: + SonarQube: 'SonarQube' From 111947cccbbef66efaf14fd5c8c19fb9647840fb Mon Sep 17 00:00:00 2001 From: Neal Webb Date: Wed, 19 Jul 2023 10:20:31 -0400 Subject: [PATCH 08/13] Revert EthosIntegrationUrls to a static class Fixes the Ellucian delivered unit tests --- .../Client/Config/EthosConfigurationClient.cs | 4 +- .../Client/Errors/EthosErrorsClient.cs | 10 ++-- .../Client/EthosClient.cs | 4 +- .../Client/Messages/EthosMessagesClient.cs | 4 +- .../Proxy/ColleagueWebApiFilterQueryClient.cs | 2 +- .../Proxy/ColleagueWebApiProxyClient.cs | 2 +- .../Client/Proxy/EthosFilterQueryClient.cs | 8 +-- .../Client/Proxy/EthosProxyClient.cs | 22 +++---- .../EthosIntegrationUrls.cs | 58 ++++++++++++------- 9 files changed, 66 insertions(+), 48 deletions(-) diff --git a/Ellucian.Ethos.Integration/Client/Config/EthosConfigurationClient.cs b/Ellucian.Ethos.Integration/Client/Config/EthosConfigurationClient.cs index 487a9c2..2ae8910 100644 --- a/Ellucian.Ethos.Integration/Client/Config/EthosConfigurationClient.cs +++ b/Ellucian.Ethos.Integration/Client/Config/EthosConfigurationClient.cs @@ -151,7 +151,7 @@ public EthosConfigurationClient( string apiKey, HttpClient httpClient ) : base( public async Task GetAppConfigAsync() { Dictionary headers = new Dictionary(); - return await base.GetStringAsync( headers, IntegrationUrls.AppConfig( Region ) ); + return await base.GetStringAsync( headers, EthosIntegrationUrls.AppConfig( Region ) ); } /// @@ -171,7 +171,7 @@ public async Task GetAppConfigJsonAsync() public async Task GetAllAvailableResourcesAsync() { Dictionary headers = new Dictionary(); - return await base.GetStringAsync( headers, IntegrationUrls.AvailableResources( Region ) ); + return await base.GetStringAsync( headers, EthosIntegrationUrls.AvailableResources( Region ) ); } /// diff --git a/Ellucian.Ethos.Integration/Client/Errors/EthosErrorsClient.cs b/Ellucian.Ethos.Integration/Client/Errors/EthosErrorsClient.cs index 6bb3615..24169b5 100644 --- a/Ellucian.Ethos.Integration/Client/Errors/EthosErrorsClient.cs +++ b/Ellucian.Ethos.Integration/Client/Errors/EthosErrorsClient.cs @@ -65,7 +65,7 @@ public EthosErrorsClient( string apiKey, HttpClient client ) : base( apiKey, cli public async Task GetAsync() { Dictionary headers = BuildHeadersMap(); - return await base.GetAsync( headers, IntegrationUrls.Errors( Region ) ); + return await base.GetAsync( headers, EthosIntegrationUrls.Errors( Region ) ); } /// @@ -145,7 +145,7 @@ public async Task GetByIdAsync( string id ) } Dictionary headers = BuildHeadersMap(); - return await base.GetAsync( headers, IntegrationUrls.Errors( Region ) + "/" + id ); + return await base.GetAsync( headers, EthosIntegrationUrls.Errors( Region ) + "/" + id ); } /// @@ -351,7 +351,7 @@ protected async Task> DoPagingAsync( int totalErrorCo int numPages = CalculateNumberOfPages( totalErrorCount, pageSize, offset ); for ( int index = 0; index < numPages; index++ ) { - string url = IntegrationUrls.ErrorsPaging( Region, offset, pageSize ); + string url = EthosIntegrationUrls.ErrorsPaging( Region, offset, pageSize ); EthosResponse response = await GetAsync( headersMap, url ); ethosResponseList.Add( response ); offset += pageSize; @@ -397,7 +397,7 @@ public async Task PostAsync( EthosError newError ) Dictionary headers = new Dictionary(); headers [ "Accept" ] = errorType; string errorRequestBody = JsonConvert.SerializeObject( newError ); - var response = await base.PostAsync( headers, IntegrationUrls.Errors( Region ), errorRequestBody ); + var response = await base.PostAsync( headers, EthosIntegrationUrls.Errors( Region ), errorRequestBody ); return response; } @@ -410,7 +410,7 @@ public async Task PostAsync( EthosError newError ) /// server certificate validation or timeout. public async Task DeleteAsync( string id ) { - await base.DeleteAsync( new Dictionary(), IntegrationUrls.Errors( Region ) + "/" + id ); + await base.DeleteAsync( new Dictionary(), EthosIntegrationUrls.Errors( Region ) + "/" + id ); } /// diff --git a/Ellucian.Ethos.Integration/Client/EthosClient.cs b/Ellucian.Ethos.Integration/Client/EthosClient.cs index 94ccec3..8b49901 100644 --- a/Ellucian.Ethos.Integration/Client/EthosClient.cs +++ b/Ellucian.Ethos.Integration/Client/EthosClient.cs @@ -28,7 +28,7 @@ public class EthosClient /// private string ApiKey { get; } - protected EthosIntegrationUrls IntegrationUrls = new EthosIntegrationUrls(); + // protected EthosEthosIntegrationUrls EthosIntegrationUrls = new EthosEthosIntegrationUrls(); // Only used by ColleagueWebAPIProxyClients /// @@ -218,7 +218,7 @@ public async Task GetAccessTokenAsync() /// Returns exception if the request fails. private async Task GetNewTokenAsync() { - string authUrl = $"{IntegrationUrls.Auth( this.Region )}?expirationMinutes={ ExpirationMinutes }"; + string authUrl = $"{EthosIntegrationUrls.Auth( this.Region )}?expirationMinutes={ ExpirationMinutes }"; HttpProtocolClientBuilder.Client.DefaultRequestHeaders.Add( "Authorization", $"Bearer { ApiKey }" ); //make request HttpResponseMessage response = await HttpProtocolClientBuilder.Client.PostAsync( new Uri( authUrl ), null ); diff --git a/Ellucian.Ethos.Integration/Client/Messages/EthosMessagesClient.cs b/Ellucian.Ethos.Integration/Client/Messages/EthosMessagesClient.cs index 41c0199..08458bd 100644 --- a/Ellucian.Ethos.Integration/Client/Messages/EthosMessagesClient.cs +++ b/Ellucian.Ethos.Integration/Client/Messages/EthosMessagesClient.cs @@ -102,7 +102,7 @@ private async Task> GetMessagesAsync( int? limit Dictionary headers = new Dictionary(); headers.Add( "Accept", cnType ); - EthosResponse response = await GetAsync( headers, IntegrationUrls.Consume( Region, lastProcessedID, limit ) ); + EthosResponse response = await GetAsync( headers, EthosIntegrationUrls.Consume( Region, lastProcessedID, limit ) ); return new EthosResponseConverter().ToCNList( response ); } @@ -113,7 +113,7 @@ private async Task> GetMessagesAsync( int? limit /// The number of available messages in the application's queue. public async Task GetNumAvailableMessagesAsync() { - EthosResponse response = await HeadAsync(IntegrationUrls.Consume( Region, -1, -1 ) ); + EthosResponse response = await HeadAsync(EthosIntegrationUrls.Consume( Region, -1, -1 ) ); string remaining = response.GetHeader( "x-remaining" ); if ( int.TryParse( remaining, out int numMessages ) ) { diff --git a/Ellucian.Ethos.Integration/Client/Proxy/ColleagueWebApiFilterQueryClient.cs b/Ellucian.Ethos.Integration/Client/Proxy/ColleagueWebApiFilterQueryClient.cs index 5263c6a..23dff29 100644 --- a/Ellucian.Ethos.Integration/Client/Proxy/ColleagueWebApiFilterQueryClient.cs +++ b/Ellucian.Ethos.Integration/Client/Proxy/ColleagueWebApiFilterQueryClient.cs @@ -34,7 +34,7 @@ public ColleagueWebApiFilterQueryClient(string colleagueApiUrl, string colleague : base(colleagueApiUrl, colleagueApiUsername, colleagueApiPassword, client) { Region = Authentication.SupportedRegions.SelfHosted; - IntegrationUrls.MAIN_BASE_URL = colleagueApiUrl; + EthosIntegrationUrls.SelfHostBaseUrl = colleagueApiUrl; } } } diff --git a/Ellucian.Ethos.Integration/Client/Proxy/ColleagueWebApiProxyClient.cs b/Ellucian.Ethos.Integration/Client/Proxy/ColleagueWebApiProxyClient.cs index 09f3097..00f4557 100644 --- a/Ellucian.Ethos.Integration/Client/Proxy/ColleagueWebApiProxyClient.cs +++ b/Ellucian.Ethos.Integration/Client/Proxy/ColleagueWebApiProxyClient.cs @@ -28,7 +28,7 @@ public ColleagueWebApiProxyClient( string colleagueApiUrl, string colleagueApiUs : base(colleagueApiUrl, colleagueApiUsername, colleagueApiPassword, client) { Region = Authentication.SupportedRegions.SelfHosted; - IntegrationUrls.MAIN_BASE_URL = colleagueApiUrl; + EthosIntegrationUrls.SelfHostBaseUrl = colleagueApiUrl; } } diff --git a/Ellucian.Ethos.Integration/Client/Proxy/EthosFilterQueryClient.cs b/Ellucian.Ethos.Integration/Client/Proxy/EthosFilterQueryClient.cs index e4c432b..91b2180 100644 --- a/Ellucian.Ethos.Integration/Client/Proxy/EthosFilterQueryClient.cs +++ b/Ellucian.Ethos.Integration/Client/Proxy/EthosFilterQueryClient.cs @@ -384,7 +384,7 @@ private async Task GetEthosResponseAsync( string resourceName, st { var filterStr = EncodeString( criteria ); Dictionary headers = BuildHeadersMap( version ); - EthosResponse response = await GetAsync( headers, IntegrationUrls.ApiFilter( Region, resourceName, filterStr ) ); + EthosResponse response = await GetAsync( headers, EthosIntegrationUrls.ApiFilter( Region, resourceName, filterStr ) ); return response; } @@ -548,7 +548,7 @@ public async Task GetWithFilterMapAsync( string resourceName, str throw new ArgumentNullException( $"Error: Cannot get resource '{ resourceName }' with filter map due to a null or blank filter map string." ); } Dictionary headers = BuildHeadersMap( version ); - EthosResponse response = await GetAsync( headers, IntegrationUrls.ApiFilter( Region, resourceName, filterMapStr ) ); + EthosResponse response = await GetAsync( headers, EthosIntegrationUrls.ApiFilter( Region, resourceName, filterMapStr ) ); return response; } @@ -989,7 +989,7 @@ public async Task GetWithQapiAsync( string resourceName, string q ); } var headers = BuildHeadersMap( version ); - string url = IntegrationUrls.Qapi( Region, resourceName ); + string url = EthosIntegrationUrls.Qapi( Region, resourceName ); return await base.PostAsync( headers, url, qapiRequestBody ); } @@ -1257,7 +1257,7 @@ protected async Task> DoPagingFromOffsetForQAPIAsync( string decimal numPages = Math.Ceiling( ( Convert.ToDecimal( totalCount ) - Convert.ToDecimal( offset ) ) / Convert.ToDecimal( pageSize ) ); for ( int i = 0; i < numPages; i++ ) { - string url = IntegrationUrls.QapiPaging( Region, resourceName, offset, pageSize ); + string url = EthosIntegrationUrls.QapiPaging( Region, resourceName, offset, pageSize ); EthosResponse response = await base.PostAsync( headers, url, qapiRequestBody ); ethosResponseList.Add( response ); offset += pageSize; diff --git a/Ellucian.Ethos.Integration/Client/Proxy/EthosProxyClient.cs b/Ellucian.Ethos.Integration/Client/Proxy/EthosProxyClient.cs index c66a6cc..53dbbb3 100644 --- a/Ellucian.Ethos.Integration/Client/Proxy/EthosProxyClient.cs +++ b/Ellucian.Ethos.Integration/Client/Proxy/EthosProxyClient.cs @@ -175,7 +175,7 @@ public async Task PostAsync( string resourceName, string version, ); } var headers = BuildHeadersMap( version ); - string url = IntegrationUrls.Api( Region, resourceName, null ); + string url = EthosIntegrationUrls.Api( Region, resourceName, null ); return await base.PostAsync( headers, url, requestBody ); } @@ -257,7 +257,7 @@ public async Task PutAsync( string resourceName, string resourceI } var headers = BuildHeadersMap( version ); - string url = IntegrationUrls.Api( Region, resourceName, resourceId ); + string url = EthosIntegrationUrls.Api( Region, resourceName, resourceId ); return await base.PutAsync( headers, url, requestBody ); } @@ -323,7 +323,7 @@ public async Task DeleteAsync( string resourceName, string id ) ); } var headers = BuildHeadersMap( null ); - string url = IntegrationUrls.Api( Region, resourceName, id ); + string url = EthosIntegrationUrls.Api( Region, resourceName, id ); await base.DeleteAsync( headers, url ); } @@ -565,7 +565,7 @@ internal IEnumerable ConvertEthosResponseContentListToType( IE var version = DEFAULT_VERSION; Dictionary headers = BuildHeadersMap( version ); - string url = $"{IntegrationUrls.Api( Region, resourceName ) }"; + string url = $"{EthosIntegrationUrls.Api( Region, resourceName ) }"; EthosResponse response = await GetAsync( headers, url ); return response; } @@ -582,7 +582,7 @@ public async Task GetAsync( string resourceName, string version = if ( string.IsNullOrWhiteSpace( resourceName ) ) { throw new ArgumentNullException( nameof( resourceName ) ); } Dictionary headers = BuildHeadersMap( version ); - string url = $"{IntegrationUrls.Api( Region, resourceName ) }"; + string url = $"{EthosIntegrationUrls.Api( Region, resourceName ) }"; EthosResponse response = await GetAsync( headers, url ); return response; } @@ -630,7 +630,7 @@ public async Task GetAsync( string resourceName, string version = if ( string.IsNullOrWhiteSpace( resourceName ) ) { throw new ArgumentNullException( nameof( resourceName ) ); } Dictionary headers = BuildHeadersMap( version ); - string url = $"{IntegrationUrls.ApiPaging( Region, resourceName, offset, pageSize ) }"; + string url = $"{EthosIntegrationUrls.ApiPaging( Region, resourceName, offset, pageSize ) }"; EthosResponse response = await GetAsync( headers, url ); return response; } @@ -1353,7 +1353,7 @@ public async Task GetByIdAsync( string resourceName, string id, s } var headersMap = BuildHeadersMap( version ); - string url = IntegrationUrls.Api( Region, resourceName, id ); + string url = EthosIntegrationUrls.Api( Region, resourceName, id ); EthosResponse ethosResponse = await GetAsync( headersMap, url ); return ethosResponse; } @@ -1628,11 +1628,11 @@ protected async Task> DoPagingFromOffsetAsync( string resour string url; if ( string.IsNullOrWhiteSpace( filter ) ) { - url = IntegrationUrls.ApiPaging( Region, resourceName, offset, pageSize ); + url = EthosIntegrationUrls.ApiPaging( Region, resourceName, offset, pageSize ); } else { - url = IntegrationUrls.ApiFilterPaging( Region, resourceName, filter, offset, pageSize ); + url = EthosIntegrationUrls.ApiFilterPaging( Region, resourceName, filter, offset, pageSize ); } EthosResponse response = await GetAsync( headers, url ); ethosResponseList.Add( response ); @@ -1679,7 +1679,7 @@ private async Task> DoPagingFromOffsetForNumPagesAsync( stri { break; } - string url = IntegrationUrls.ApiPaging( Region, resourceName, offset, pageSize ); + string url = EthosIntegrationUrls.ApiPaging( Region, resourceName, offset, pageSize ); EthosResponse response = await GetAsync( headers, url ); ethosResponseList.Add( response ); offset += pageSize; @@ -1733,7 +1733,7 @@ private async Task> DoPagingFromOffsetForNumRowsAsync( strin { pageSize = rowsRemaining; } - string url = IntegrationUrls.ApiPaging( Region, resourceName, offset, pageSize ); + string url = EthosIntegrationUrls.ApiPaging( Region, resourceName, offset, pageSize ); EthosResponse response = await GetAsync( headers, url ); ethosResponseList.Add( response ); offset += pageSize; diff --git a/Ellucian.Ethos.Integration/EthosIntegrationUrls.cs b/Ellucian.Ethos.Integration/EthosIntegrationUrls.cs index c5d21c1..78bf4f2 100644 --- a/Ellucian.Ethos.Integration/EthosIntegrationUrls.cs +++ b/Ellucian.Ethos.Integration/EthosIntegrationUrls.cs @@ -14,7 +14,7 @@ namespace Ellucian.Ethos.Integration /// /// Utility class used for building Ethos Integration URLs with various criteria. /// - public class EthosIntegrationUrls + public static class EthosIntegrationUrls { /// /// A Dictionary<SupportedRegions,string> of supported regions where each region is assigned the @@ -33,9 +33,12 @@ public class EthosIntegrationUrls /// /// AUSTRALIA: .com.au /// + /// + /// SELF-HOSTED + /// /// /// - private readonly Dictionary RegionUrlPostFix = new Dictionary + private static readonly Dictionary RegionUrlPostFix = new Dictionary { [ SupportedRegions.US ] = ".com", [ SupportedRegions.Canada ] = ".ca", @@ -44,8 +47,25 @@ public class EthosIntegrationUrls [ SupportedRegions.SelfHosted ] = "" }; + +#pragma warning disable S1075 + const string MAIN_ETHOS_BASE_URL = "https://integrate.elluciancloud"; +#pragma warning restore S1075 + + /// The override for self-hosted ERP clients. + public static string SelfHostBaseUrl { get; set; } = ""; + ///The main domain for Ethos Integration. - public string MAIN_BASE_URL = "https://integrate.elluciancloud"; + public static string MAIN_BASE_URL + { + get + { + if (string.IsNullOrWhiteSpace(SelfHostBaseUrl)) + return MAIN_ETHOS_BASE_URL; + + return SelfHostBaseUrl; + } + } /// /// The base URL for getting Api result(s) in Ethos Integration. @@ -54,7 +74,7 @@ public class EthosIntegrationUrls /// The Ethos resource the URL should contain. /// The (optional) ID for the given resource to build URLs for "get by ID" requests. /// A string value containing the URL to use for interacting with Ethos Integration Proxy APIs. - public string Api( SupportedRegions region, string resource, string id = "" ) + public static string Api( SupportedRegions region, string resource, string id = "" ) { string url = BuildUrl(region, "/api"); if (!string.IsNullOrWhiteSpace(resource)) @@ -75,7 +95,7 @@ public string Api( SupportedRegions region, string resource, string id = "" ) /// The Ethos resource the URL should contain. /// The resource filter the URL should contain. /// A string value containing the URL to use for interacting with Ethos Integration Proxy APIs, supporting filters. - public string ApiFilter( SupportedRegions region, string resource, string filter ) + public static string ApiFilter( SupportedRegions region, string resource, string filter ) { string url = Api( region, resource, null ); StringBuilder sb = new StringBuilder(); @@ -93,7 +113,7 @@ public string ApiFilter( SupportedRegions region, string resource, string filter /// A supported region. /// The Ethos resource the URL should contain. /// A string value containing the URL to use for interacting with Ethos Integration Proxy APIs. - public string Qapi( SupportedRegions region, string resource ) + public static string Qapi( SupportedRegions region, string resource ) { string url = BuildUrl( region, "/qapi" ); if ( !string.IsNullOrWhiteSpace( resource ) ) @@ -111,7 +131,7 @@ public string Qapi( SupportedRegions region, string resource ) /// The row index from which to begin paging for data for the given resource. /// The number of rows each response can contain. /// A string value containing the URL to use for interacting with Ethos Integration Proxy APIs. - public string QapiPaging( SupportedRegions region, string resource, int offset, int pageSize ) + public static string QapiPaging( SupportedRegions region, string resource, int offset, int pageSize ) { string url = Qapi( region, resource ); return AddPaging( url, offset, pageSize ); @@ -127,7 +147,7 @@ public string QapiPaging( SupportedRegions region, string resource, int offset, /// The row index from which to begin paging for data for the given resource. /// The number of rows each response can contain. /// A string value containing the URL to use for interacting with Ethos Integration Proxy APIs, supporting filters. - public string ApiFilterPaging( SupportedRegions region, string resource, string filter, int offset, int pageSize ) + public static string ApiFilterPaging( SupportedRegions region, string resource, string filter, int offset, int pageSize ) { string url = ApiFilter( region, resource, filter ); return AddPaging( url, offset, pageSize ); @@ -141,7 +161,7 @@ public string ApiFilterPaging( SupportedRegions region, string resource, string /// The row index from which to begin paging for data for the given resource. /// The number of rows each response can contain. /// A string value containing the URL to use for interacting with Ethos Integration Proxy APIs, in support of paging. - public string ApiPaging( SupportedRegions region, string resource, int offset, int pageSize ) + public static string ApiPaging( SupportedRegions region, string resource, int offset, int pageSize ) { string urlStr = Api( region, resource, null ); return AddPaging( urlStr, offset, pageSize ); @@ -152,7 +172,7 @@ public string ApiPaging( SupportedRegions region, string resource, int offset, i /// /// The appropriate supported region to build the URL with. /// A string value containing the URL to use for interacting with Ethos Integration Errors APIs. - public string Errors( SupportedRegions region ) + public static string Errors( SupportedRegions region ) { return BuildUrl( region, "/errors" ); } @@ -164,7 +184,7 @@ public string Errors( SupportedRegions region ) /// The row index from which to begin paging for errors. /// The number of errors (limit) each response can contain. /// A string value containing the URL to use for interacting with EthosIntegration Errors API, in support of paging. - public string ErrorsPaging( SupportedRegions region, int offset, int pageSize ) + public static string ErrorsPaging( SupportedRegions region, int offset, int pageSize ) { string url = Errors( region ); return AddPaging( url, offset, pageSize ); @@ -175,7 +195,7 @@ public string ErrorsPaging( SupportedRegions region, int offset, int pageSize ) /// /// The appropriate supported region to build the URL with. /// A string value containing the URL to use for interacting with Ethos Integration Token API. - public string Auth( SupportedRegions region ) + public static string Auth( SupportedRegions region ) { return BuildUrl( region, "/auth" ); } @@ -185,7 +205,7 @@ public string Auth( SupportedRegions region ) /// /// A supported region. /// The region specific /appconfig URL - public string AppConfig( SupportedRegions region ) + public static string AppConfig( SupportedRegions region ) { return BuildUrl( region, "/appconfig" ); } @@ -195,7 +215,7 @@ public string AppConfig( SupportedRegions region ) /// /// A supported region. /// The region specific /available-resources URL - public string AvailableResources( SupportedRegions region ) + public static string AvailableResources( SupportedRegions region ) { return BuildUrl( region, "/admin/available-resources" ); } @@ -210,7 +230,7 @@ public string AvailableResources( SupportedRegions region ) /// A value to use for the 'limit' query parameter. Any value greater than zero will be added to the URL as /// a query parameter. If the value is zero or less, it will not be added to the URL. /// The URL to use for calling the Ethos Integration consume endpoint. - public string Consume( SupportedRegions region, long? lastProcessedID, int? limit ) + public static string Consume( SupportedRegions region, long? lastProcessedID, int? limit ) { StringBuilder builder = new StringBuilder(); @@ -237,7 +257,7 @@ public string Consume( SupportedRegions region, long? lastProcessedID, int? limi /// /// A supported region. /// - public string BaseUrl( SupportedRegions region ) + public static string BaseUrl( SupportedRegions region ) { return $"{MAIN_BASE_URL}{RegionUrlPostFix [ region ]}"; } @@ -249,13 +269,11 @@ public string BaseUrl( SupportedRegions region ) /// The correct path for the type of API the URL will be used with (/api for Proxy API URL, /// for Token API URL, etc.). /// - private string BuildUrl( SupportedRegions region, string urlEnd) + private static string BuildUrl( SupportedRegions region, string urlEnd) { return region == SupportedRegions.SelfHosted ? $"{MAIN_BASE_URL}" : $"{MAIN_BASE_URL}{RegionUrlPostFix[region]}{urlEnd}"; - - // return $"{MAIN_BASE_URL}{RegionUrlPostFix [ region ]}{urlEnd}"; } /// @@ -265,7 +283,7 @@ private string BuildUrl( SupportedRegions region, string urlEnd) /// The offset param to page from. /// The limit param to page with. /// A URL string containing the offset and limit params for paging. - private string AddPaging( string urlStr, int offset, int pageSize ) + private static string AddPaging( string urlStr, int offset, int pageSize ) { StringBuilder sb = new StringBuilder( urlStr ); if ( offset >= 0 && pageSize > 0 ) From 6e9cb1cbb00c2f47d1c4171bab830a94b8008354 Mon Sep 17 00:00:00 2001 From: John Stauffer Date: Wed, 19 Jul 2023 16:29:42 -0400 Subject: [PATCH 09/13] Update README.md Arbitrary change to push a release through Azure DevOps since the publish to Azure Artifacts failed and when attempting to re-run the GitHub Action we get an error that the feed already contains 'Ellucian.Ethos.Integration 1.0.0-1'. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index e0ddd36..7b4aae6 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ # Ellucian Ethos Integration SDK +> Modifications by Intuition Payment Solutions Ethos Integration SDK provides utilities and libraries that make it easier for developers to quickly start building Ethos-based integrations. From 30c4e0ebe4654ac8fbceeee442a1e83f319ca4d1 Mon Sep 17 00:00:00 2001 From: John Stauffer Date: Wed, 19 Jul 2023 16:51:36 -0400 Subject: [PATCH 10/13] Update azure-artifacts-publish.yml Modified azure-artifacts-publish.yml to only publish Ellucian.Ethos.Integration.${{ github.event.release.tag_name }}.nupkg since building creates packages for our fork as well as the source. --- .github/workflows/azure-artifacts-publish.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/azure-artifacts-publish.yml b/.github/workflows/azure-artifacts-publish.yml index 71e32b5..589de24 100644 --- a/.github/workflows/azure-artifacts-publish.yml +++ b/.github/workflows/azure-artifacts-publish.yml @@ -58,8 +58,8 @@ jobs: # Publish the package to Azure Artifacts - name: 'dotnet publish to Azure Artifacts' - run: dotnet nuget push --api-key AzureArtifacts Ellucian.Ethos.Integration/bin/Release/*.nupkg + run: dotnet nuget push --api-key AzureArtifacts Ellucian.Ethos.Integration/bin/Release/Ellucian.Ethos.Integration.${{ github.event.release.tag_name }}.nupkg # Publish the package to GitHub Packages - name: 'dotnet publish to GitHub Packages' - run: dotnet nuget push --api-key ${{ secrets.GH_PACKAGES_PAT }} --source https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json Ellucian.Ethos.Integration/bin/Release/*.nupkg + run: dotnet nuget push --api-key ${{ secrets.GH_PACKAGES_PAT }} --source https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json Ellucian.Ethos.Integration/bin/Release/Ellucian.Ethos.Integration.${{ github.event.release.tag_name }}.nupkg From 02bb1e09332c16d3df9d25d90e22fa29b86c9ccc Mon Sep 17 00:00:00 2001 From: John Stauffer Date: Thu, 3 Aug 2023 08:17:49 -0400 Subject: [PATCH 11/13] Azure DevOps Updates --- ...rtifacts-publish.yml => publish-nupkg.yml} | 26 ++-- .../Ellucian.Ethos.Integration.csproj | 1 + Ellucian.Ethos.Integration/packages.lock.json | 87 +++++++++++++ README.md | 11 ++ _azure-pipelines-CI.yml | 120 ++++++++++++++++-- _azure-pipelines-PR.yml | 51 +++++++- 6 files changed, 274 insertions(+), 22 deletions(-) rename .github/workflows/{azure-artifacts-publish.yml => publish-nupkg.yml} (56%) create mode 100644 Ellucian.Ethos.Integration/packages.lock.json diff --git a/.github/workflows/azure-artifacts-publish.yml b/.github/workflows/publish-nupkg.yml similarity index 56% rename from .github/workflows/azure-artifacts-publish.yml rename to .github/workflows/publish-nupkg.yml index 589de24..ee97495 100644 --- a/.github/workflows/azure-artifacts-publish.yml +++ b/.github/workflows/publish-nupkg.yml @@ -1,17 +1,19 @@ -name: Build and Publish to Azure Artifacts +name: Build and Publish to Azure Artifacts / GitHub Packages on: release: types: [published] env: - AZURE_ARTIFACTS_FEED_URL: https://pkgs.dev.azure.com/intuitionps/01c84548-9607-4655-80e7-6ad95390a38c/_packaging/private/nuget/v3/index.json + AZURE_ARTIFACTS_FEED_URL: https://pkgs.dev.azure.com/intuitionps/01c84548-9607-4655-80e7-6ad95390a38c/_packaging/private/nuget/v3/index.json + GITHUB_PACKAGES_URL: https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json + PROJECT_NAME: Ellucian.Ethos.Integration BUILD_CONFIGURATION: 'Release' # set this to the appropriate build configuration - DOTNET_VERSION: '6.x' - + DOTNET_VERSION: '6.x' + jobs: build: - runs-on: ubuntu-latest + runs-on: windows-latest steps: # Checkout the repo - uses: actions/checkout@v2 @@ -25,13 +27,15 @@ jobs: # Run dotnet build and test - name: dotnet build and test run: | + dotnet nuget add source ${{ env.GITHUB_PACKAGES_URL }} --name intuitionps --username ${{ github.actor }} --password ${{ secrets.GH_PACKAGES_PAT }} + dotnet nuget add source https://api.nuget.org/v3/index.json -name nugetorg dotnet restore dotnet build --configuration '${{ env.BUILD_CONFIGURATION }}' dotnet test --configuration '${{ env.BUILD_CONFIGURATION }}' az-artifacts-build-and-deploy: needs: build - runs-on: ubuntu-latest + runs-on: windows-latest steps: # Checkout the repo - uses: actions/checkout@v2 @@ -52,14 +56,16 @@ jobs: # Run dotnet build and package - name: dotnet build and publish run: | + dotnet nuget add source ${{ env.GITHUB_PACKAGES_URL }} --name intuitionps --username ${{ github.actor }} --password ${{ secrets.GH_PACKAGES_PAT }} + dotnet nuget add source https://api.nuget.org/v3/index.json -name nugetorg dotnet restore dotnet build --configuration '${{ env.BUILD_CONFIGURATION }}' /p:Version=${{ github.event.release.tag_name }} dotnet pack -c '${{ env.BUILD_CONFIGURATION }}' - # Publish the package to Azure Artifacts + # Publish the package to Azure Artifacts | must specify our version since the ellucian-developer/integration-sdk-csharp gets packaged as well - name: 'dotnet publish to Azure Artifacts' - run: dotnet nuget push --api-key AzureArtifacts Ellucian.Ethos.Integration/bin/Release/Ellucian.Ethos.Integration.${{ github.event.release.tag_name }}.nupkg + run: dotnet nuget push --api-key AzureArtifacts ${{ env.PROJECT_NAME }}.${{ github.event.release.tag_name }}\bin\Release\*.nupkg - # Publish the package to GitHub Packages + # Publish the package to GitHub Packages | must specify our version since the ellucian-developer/integration-sdk-csharp gets packaged as well - name: 'dotnet publish to GitHub Packages' - run: dotnet nuget push --api-key ${{ secrets.GH_PACKAGES_PAT }} --source https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json Ellucian.Ethos.Integration/bin/Release/Ellucian.Ethos.Integration.${{ github.event.release.tag_name }}.nupkg + run: dotnet nuget push --api-key ${{ secrets.GH_PACKAGES_PAT }} --source ${{ env.GITHUB_PACKAGES_URL }} ${{ env.PROJECT_NAME }}.${{ github.event.release.tag_name }}\bin\Release\*.nupkg \ No newline at end of file diff --git a/Ellucian.Ethos.Integration/Ellucian.Ethos.Integration.csproj b/Ellucian.Ethos.Integration/Ellucian.Ethos.Integration.csproj index 59d7ef3..da1da9a 100644 --- a/Ellucian.Ethos.Integration/Ellucian.Ethos.Integration.csproj +++ b/Ellucian.Ethos.Integration/Ellucian.Ethos.Integration.csproj @@ -31,6 +31,7 @@ The Ethos Integration SDK makes the application development process less expensi README.md True https://github.com/ellucian-developer/integration-sdk-csharp + true diff --git a/Ellucian.Ethos.Integration/packages.lock.json b/Ellucian.Ethos.Integration/packages.lock.json new file mode 100644 index 0000000..7ea511f --- /dev/null +++ b/Ellucian.Ethos.Integration/packages.lock.json @@ -0,0 +1,87 @@ +{ + "version": 1, + "dependencies": { + "net6.0": { + "Microsoft.Extensions.DependencyInjection": { + "type": "Direct", + "requested": "[6.0.0, )", + "resolved": "6.0.0", + "contentHash": "k6PWQMuoBDGGHOQTtyois2u4AwyVcIwL2LaSLlTZQm2CYcJ1pxbt6jfAnpWmzENA/wfrYRI/X9DTLoUkE4AsLw==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0", + "System.Runtime.CompilerServices.Unsafe": "6.0.0" + } + }, + "Microsoft.Extensions.Http": { + "type": "Direct", + "requested": "[6.0.0, )", + "resolved": "6.0.0", + "contentHash": "15+pa2G0bAMHbHewaQIdr/y6ag2H3yh4rd9hTXavtWDzQBkvpe2RMqFg8BxDpcQWssmjmBApGPcw93QRz6YcMg==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0", + "Microsoft.Extensions.Logging": "6.0.0", + "Microsoft.Extensions.Logging.Abstractions": "6.0.0", + "Microsoft.Extensions.Options": "6.0.0" + } + }, + "Newtonsoft.Json": { + "type": "Direct", + "requested": "[13.0.1, )", + "resolved": "13.0.1", + "contentHash": "ppPFpBcvxdsfUonNcvITKqLl3bqxWbDCZIzDWHzjpdAHRFfZe0Dw9HmA0+za13IdyrgJwpkDTDA9fHaxOrt20A==" + }, + "Microsoft.Extensions.DependencyInjection.Abstractions": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "xlzi2IYREJH3/m6+lUrQlujzX8wDitm4QGnUu6kUXTQAWPuZY8i+ticFJbzfqaetLA6KR/rO6Ew/HuYD+bxifg==" + }, + "Microsoft.Extensions.Logging": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "eIbyj40QDg1NDz0HBW0S5f3wrLVnKWnDJ/JtZ+yJDFnDj90VoPuoPmFkeaXrtu+0cKm5GRAwoDf+dBWXK0TUdg==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection": "6.0.0", + "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0", + "Microsoft.Extensions.Logging.Abstractions": "6.0.0", + "Microsoft.Extensions.Options": "6.0.0", + "System.Diagnostics.DiagnosticSource": "6.0.0" + } + }, + "Microsoft.Extensions.Logging.Abstractions": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "/HggWBbTwy8TgebGSX5DBZ24ndhzi93sHUBDvP1IxbZD7FDokYzdAr6+vbWGjw2XAfR2EJ1sfKUotpjHnFWPxA==" + }, + "Microsoft.Extensions.Options": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "dzXN0+V1AyjOe2xcJ86Qbo233KHuLEY0njf/P2Kw8SfJU+d45HNS2ctJdnEnrWbM9Ye2eFgaC5Mj9otRMU6IsQ==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0", + "Microsoft.Extensions.Primitives": "6.0.0" + } + }, + "Microsoft.Extensions.Primitives": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "9+PnzmQFfEFNR9J2aDTfJGGupShHjOuGw4VUv+JB044biSHrnmCIMD+mJHmb2H7YryrfBEXDurxQ47gJZdCKNQ==", + "dependencies": { + "System.Runtime.CompilerServices.Unsafe": "6.0.0" + } + }, + "System.Diagnostics.DiagnosticSource": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "frQDfv0rl209cKm1lnwTgFPzNigy2EKk1BS3uAvHvlBVKe5cymGyHO+Sj+NLv5VF/AhHsqPIUUwya5oV4CHMUw==", + "dependencies": { + "System.Runtime.CompilerServices.Unsafe": "6.0.0" + } + }, + "System.Runtime.CompilerServices.Unsafe": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg==" + } + } + } +} \ No newline at end of file diff --git a/README.md b/README.md index 7b4aae6..33243f0 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,17 @@ # Ellucian Ethos Integration SDK > Modifications by Intuition Payment Solutions +![Azure DevOps Release Pipeline Status](https://vsrm.dev.azure.com/intuitionps/_apis/public/Release/badge/01c84548-9607-4655-80e7-6ad95390a38c/18/46) + +[![Build and Publish to Azure Artifacts / GitHub Packages](https://github.com/iNtuitionPS/ethos-integration-sdk-fork/actions/workflows/publish-nupkg.yml/badge.svg)](https://github.com/iNtuitionPS/ethos-integration-sdk-fork/actions/workflows/publish-nupkg.yml) + +| Branch | Build Pipeline Status | +|:---|:---| +| `main` | | +| `developmment` | N/A | + +# + Ethos Integration SDK provides utilities and libraries that make it easier for developers to quickly start building Ethos-based integrations. The Ethos Integration SDK for .NET allows you to easily develop applications in C# that integrate with Ellucian Ethos Integration. The SDK diff --git a/_azure-pipelines-CI.yml b/_azure-pipelines-CI.yml index 61bf2a2..2d1efdd 100644 --- a/_azure-pipelines-CI.yml +++ b/_azure-pipelines-CI.yml @@ -1,5 +1,5 @@ # Build Pipeline - Continuous Integration -# if trigger is not merge commit from pull request, then pipeline will abort +# if commit is not from a pull request, then the pipeline will abort - bypass this check by setting the SkipPullRequestCheck variable at queue time trigger: - main @@ -12,41 +12,124 @@ pool: variables: solution: '**/*.sln' buildPlatform: 'Any CPU' - buildConfiguration: 'Release' + NUGET_PACKAGES: $(Pipeline.Workspace)/.nuget/packages steps: +- checkout: self + persistCredentials: true + - task: PowerShell@2 displayName: Get Pull Request + condition: and(succeeded(), eq(variables['SkipPullRequestCheck'], '')) inputs: targetType: 'inline' script: | try { $headers = @{ "Authorization" = "Bearer $(GitHubToken)"} $uri = 'https://api.github.com/repos/$(Build.Repository.Name)/commits/$(Build.SourceVersion)/pulls' + Write-Output "uri = $uri" $response = Invoke-WebRequest -Uri $uri -Headers $headers -Method Get $content = $response.content | ConvertFrom-Json - if (-not($content -and $content[0] -and $content[0].id)) { - throw "** abort non-PR commit" + # Check if the $content is not empty and iterate through each pull request + if (-not ($content -and $content.Count -gt 0)) { + Write-Host "##vso[task.logissue type=error;]Failed: Commit is not from a pull request." + exit 1 + } + $matchedPullRequest = $null + foreach ($pullRequest in $content) { + if ($pullRequest.merge_commit_sha -eq "$(Build.SourceVersion)") { + $matchedPullRequest = $pullRequest + break + } + } + # Check if a matching pull request was found + if (-not $matchedPullRequest) { + Write-Host "##vso[task.logissue type=error;]Failed: No pull request found with merge commit SHA = '$(Build.SourceVersion)'." + exit 1 } + # If a matching pull request is found, set the variables and continue + Write-Host "##vso[task.setvariable variable=pullRequestHeadRef;]$($matchedPullRequest.head.ref)" + Write-Host "##vso[task.setvariable variable=pullRequestBaseRef;]$($matchedPullRequest.base.ref)" } catch { - Write-Host "Error getting pull request | $_" + Write-Host "##vso[task.logissue type=error;]Error getting pull request - | $_" exit 1 } + +- task: PowerShell@2 + displayName: Reset Development Branch + condition: and(succeeded(), eq(variables['SkipPullRequestCheck'], '')) + inputs: + targetType: 'inline' + script: | + if ("$(pullRequestHeadRef)" -eq "development" -and "$(pullRequestBaseRef)" -eq "main") { + # Define required headers for Azure DevOps | url is pulled from 'common' variable group in library + $azureDevOpsAuthenicationHeader = @{Authorization = 'Basic ' + [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(":$(AzureDevOpsToken)")); "Content-Type" = "application/json"} + # Define the base URL for Azure DevOps API + $azureDevOpsRequestUri = "$(AzureDevOpsBuildApiUrl)/_apis/build/definitions/$(System.DefinitionId)?api-version=7.0" + try { + $base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f "", "$(GitHubToken)"))) + # Get the current pipeline definition + $current_definition = Invoke-RestMethod -Method Get -Uri $azureDevOpsRequestUri -Headers $azureDevOpsAuthenicationHeader + # Disable build pipeline + $current_definition.queueStatus = "disabled" + $disabled_definition = $current_definition | ConvertTo-Json -Depth 100 + Invoke-RestMethod -Method Put -Uri $azureDevOpsRequestUri -Headers $azureDevOpsAuthenicationHeader -Body $disabled_definition + # Perform the reset + git config user.email "no-reply@intuitionps.com" + git config user.name "intuitionps Azure DevOps" + git checkout development + if ($LASTEXITCODE -ne 0) { throw "git checkout development" } + git fetch origin + if ($LASTEXITCODE -ne 0) { throw "git fetch origin" } + git reset --hard origin/main + if ($LASTEXITCODE -ne 0) { throw "git reset --hard origin/main" } + git push --force origin development + if ($LASTEXITCODE -ne 0) { throw "git push --force origin development" } + Write-Host "Successfully reset development branch from main branch." + } catch { + Write-Host "##vso[task.logissue type=error;]Error resetting development branch with main branch - | $_" + } finally { + try { + # Get the current pipeline definition + $current_definition = Invoke-RestMethod -Method Get -Uri $azureDevOpsRequestUri -Headers $azureDevOpsAuthenicationHeader + # Enable build pipeline + $current_definition.queueStatus = "enabled" + $enabled_definition = $current_definition | ConvertTo-Json -Depth 100 + Invoke-RestMethod -Method Put -Uri $azureDevOpsRequestUri -Headers $azureDevOpsAuthenicationHeader -Body $enabled_definition + } catch { + Write-Host "##vso[task.logissue type=error;]Error re-enabling build pipeline - | $_" + } + } + } else { + Write-Host "##vso[task.logissue type=warning;]Aborted: Only reset if base branch is 'main' and head branch is 'development'." + } + ignoreLASTEXITCODE: true - task: NuGetToolInstaller@1 displayName: Install NuGet Tool +- task: Cache@2 + displayName: Cache NuGet packages + inputs: + key: 'nuget | "$(Agent.OS)" | **/packages.lock.json,!**/bin/**,!**/obj/**' + restoreKeys: | + nuget | "$(Agent.OS)" + nuget + path: '$(NUGET_PACKAGES)' + - task: NuGetCommand@2 displayName: Restore Solution inputs: restoreSolution: '$(solution)' + feedsToUse: 'select' + vstsFeed: '01c84548-9607-4655-80e7-6ad95390a38c/3823d26d-e8ca-40c4-a6f3-c3bd13f9658b' - task: SonarQubePrepare@5 displayName: SonarQube - Prepare Analysis Configuration inputs: SonarQube: 'SonarQube' scannerMode: 'MSBuild' - projectKey: 'Ethos-Integration-SDK' + projectKey: '$(SonarQubeProjectKey)' - task: VSBuild@1 displayName: Build Solution @@ -64,9 +147,30 @@ steps: inputs: pollingTimeoutSec: '300' -- task: sonar-buildbreaker@8 +- task: PowerShell@2 + displayName: SonarQube - Get Project Status inputs: - SonarQube: 'SonarQube' + targetType: 'inline' + script: | + try { + $headers = @{ + "Content-Type" = "application/json" + "Authorization" = "Basic " + [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes("$(SonarQubeToken):")) + } + $uri = 'https://ca-intuition-devops-sonarqube.azurewebsites.net/api/qualitygates/project_status?projectKey=$(SonarQubeProjectKey)&branch=$(Build.SourceBranchName)' + Write-Output "uri = $uri" + $response = Invoke-WebRequest -Uri $uri -Headers $headers -Method Get + $content = $response.Content | ConvertFrom-Json + $status = $content.projectStatus.status + Write-Output "SonarQube Project Status = $status" + if ($content.projectStatus.status -eq "ERROR") { + Write-Host "##vso[task.logissue type=error;]Failed: Code analysis did not pass SonarQube quality gate." + exit 1 + } + } catch { + Write-Host "##vso[task.logissue type=error;]Error getting project status - | $_" + exit 1 + } - task: PublishBuildArtifacts@1 displayName: Publish Pipeline Artifacts diff --git a/_azure-pipelines-PR.yml b/_azure-pipelines-PR.yml index 24dc86a..d3d6698 100644 --- a/_azure-pipelines-PR.yml +++ b/_azure-pipelines-PR.yml @@ -1,4 +1,5 @@ # Build Pipeline - Pull Request +# if target branch is 'main' and source branch is not 'development', then the pipeline will abort trigger: none @@ -12,23 +13,44 @@ pool: variables: solution: '**/*.sln' buildPlatform: 'Any CPU' - buildConfiguration: 'Debug' + NUGET_PACKAGES: $(Pipeline.Workspace)/.nuget/packages steps: +- task: PowerShell@2 + displayName: Check Target Branch + inputs: + targetType: 'inline' + script: | + if ("$(system.pullRequest.targetBranch)" -eq "main" -and "$(system.pullRequest.sourceBranch)" -ne "development") { + Write-Host "##vso[task.logissue type=error;]Failed: Target branch is 'main' and source branch is not 'development'." + exit 1 + } + - task: NuGetToolInstaller@1 displayName: Install NuGet Tool +- task: Cache@2 + displayName: Cache NuGet packages + inputs: + key: 'nuget | "$(Agent.OS)" | **/packages.lock.json,!**/bin/**,!**/obj/**' + restoreKeys: | + nuget | "$(Agent.OS)" + nuget + path: '$(NUGET_PACKAGES)' + - task: NuGetCommand@2 displayName: Restore Solution inputs: restoreSolution: '$(solution)' + feedsToUse: 'select' + vstsFeed: '01c84548-9607-4655-80e7-6ad95390a38c/3823d26d-e8ca-40c4-a6f3-c3bd13f9658b' - task: SonarQubePrepare@5 displayName: Prepare Analysis Configuration inputs: SonarQube: 'SonarQube' scannerMode: 'MSBuild' - projectKey: 'Ethos-Integration-SDK' + projectKey: '$(SonarQubeProjectKey)' - task: VSBuild@1 displayName: Build Solution @@ -46,6 +68,27 @@ steps: inputs: pollingTimeoutSec: '300' -- task: sonar-buildbreaker@8 +- task: PowerShell@2 + displayName: SonarQube - Get Project Status inputs: - SonarQube: 'SonarQube' + targetType: 'inline' + script: | + try { + $headers = @{ + "Content-Type" = "application/json" + "Authorization" = "Basic " + [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes("$(SonarQubeToken):")) + } + $uri = 'https://ca-intuition-devops-sonarqube.azurewebsites.net/api/qualitygates/project_status?projectKey=$(SonarQubeProjectKey)&pullRequest=$(system.pullRequest.pullRequestNumber)' + Write-Output "uri = $uri" + $response = Invoke-WebRequest -Uri $uri -Headers $headers -Method Get + $content = $response.Content | ConvertFrom-Json + $status = $content.projectStatus.status + Write-Output "SonarQube Project Status = $status" + if ($content.projectStatus.status -eq "ERROR") { + Write-Host "##vso[task.logissue type=error;]Failed: Code analysis did not pass SonarQube quality gate." + exit 1 + } + } catch { + Write-Host "##vso[task.logissue type=error;]Error getting project status - | $_" + exit 1 + } \ No newline at end of file From bb2ef469dbd3f224ebc62901b6bc6da22ba62b11 Mon Sep 17 00:00:00 2001 From: John Stauffer Date: Thu, 3 Aug 2023 10:08:44 -0400 Subject: [PATCH 12/13] Update publish-nupkg.yml --- .github/workflows/publish-nupkg.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish-nupkg.yml b/.github/workflows/publish-nupkg.yml index ee97495..dca1323 100644 --- a/.github/workflows/publish-nupkg.yml +++ b/.github/workflows/publish-nupkg.yml @@ -64,8 +64,8 @@ jobs: # Publish the package to Azure Artifacts | must specify our version since the ellucian-developer/integration-sdk-csharp gets packaged as well - name: 'dotnet publish to Azure Artifacts' - run: dotnet nuget push --api-key AzureArtifacts ${{ env.PROJECT_NAME }}.${{ github.event.release.tag_name }}\bin\Release\*.nupkg + run: dotnet nuget push --api-key AzureArtifacts ${{ env.PROJECT_NAME }}\bin\Release\${{ env.PROJECT_NAME }}.${{ github.event.release.tag_name }}.nupkg # Publish the package to GitHub Packages | must specify our version since the ellucian-developer/integration-sdk-csharp gets packaged as well - name: 'dotnet publish to GitHub Packages' - run: dotnet nuget push --api-key ${{ secrets.GH_PACKAGES_PAT }} --source ${{ env.GITHUB_PACKAGES_URL }} ${{ env.PROJECT_NAME }}.${{ github.event.release.tag_name }}\bin\Release\*.nupkg \ No newline at end of file + run: dotnet nuget push --api-key ${{ secrets.GH_PACKAGES_PAT }} --source ${{ env.GITHUB_PACKAGES_URL }} ${{ env.PROJECT_NAME }}\bin\Release\${{ env.PROJECT_NAME }}.${{ github.event.release.tag_name }}.nupkg From 29010d46a45ca04227c99cf151c9a7348283da09 Mon Sep 17 00:00:00 2001 From: John Stauffer Date: Mon, 30 Sep 2024 08:26:47 -0400 Subject: [PATCH 13/13] Updated ColleagueApiExample and Ellucian.Ethos.Integration to .NET 8.0 and unloaded Ellucian.Ethos.Integration.Test project. --- .../ColleagueApiExample.csproj | 2 +- .../Client/HttpProtocolClientBuilder.cs | 11 +- .../Ellucian.Ethos.Integration.csproj | 8 +- Ellucian.Ethos.Integration/packages.lock.json | 136 ++++++++++++------ 4 files changed, 101 insertions(+), 56 deletions(-) diff --git a/ColleagueApiExample/ColleagueApiExample.csproj b/ColleagueApiExample/ColleagueApiExample.csproj index 05f53cb..8100c8c 100644 --- a/ColleagueApiExample/ColleagueApiExample.csproj +++ b/ColleagueApiExample/ColleagueApiExample.csproj @@ -2,7 +2,7 @@ Exe - net6.0 + net8.0 enable enable diff --git a/Ellucian.Ethos.Integration/Client/HttpProtocolClientBuilder.cs b/Ellucian.Ethos.Integration/Client/HttpProtocolClientBuilder.cs index 1c138a8..01634df 100644 --- a/Ellucian.Ethos.Integration/Client/HttpProtocolClientBuilder.cs +++ b/Ellucian.Ethos.Integration/Client/HttpProtocolClientBuilder.cs @@ -24,9 +24,9 @@ public class HttpProtocolClientBuilder : IHttpProtocolClientBuilder /// Time in seconds to allow an http connection to time out. Default is /// 300 seconds (5 minutes). /// - private static int CONNECTION_TIMEOUT = 300; + private static readonly int CONNECTION_TIMEOUT = 300; - private const SslProtocols PROTOCOL = SslProtocols.Tls13 | SslProtocols.Tls12 | SslProtocols.Tls11; + private const SslProtocols PROTOCOL = SslProtocols.Tls13 | SslProtocols.Tls12; private const string CLIENT_NAME = "EllucianEthosIntegrationSdk-dotnet"; @@ -44,10 +44,7 @@ public class HttpProtocolClientBuilder : IHttpProtocolClientBuilder /// 300 seconds (5 minutes). public HttpProtocolClientBuilder( HttpClient client, int? connectionTimeOut = null ) { - if ( client == null ) - { - client = BuildHttpClient( connectionTimeOut.HasValue ? connectionTimeOut : CONNECTION_TIMEOUT ); - } + client ??= BuildHttpClient( connectionTimeOut.HasValue ? connectionTimeOut : CONNECTION_TIMEOUT ); Client = client; } @@ -66,7 +63,7 @@ public HttpClient BuildHttpClient( int? connectionTimeout ) client.DefaultRequestHeaders.Clear(); client.DefaultRequestHeaders.Add( "pragma", "no-cache" ); client.DefaultRequestHeaders.Add( "cache-control", "no-cache" ); - ProductInfoHeaderValue prodHeaderVal = new ProductInfoHeaderValue( CLIENT_NAME, Assembly.GetExecutingAssembly().GetName()?.Version?.ToString() ); + ProductInfoHeaderValue prodHeaderVal = new( CLIENT_NAME, Assembly.GetExecutingAssembly().GetName()?.Version?.ToString() ); client.DefaultRequestHeaders.UserAgent.Add( prodHeaderVal ); client.Timeout = TimeSpan.FromMinutes( ( double ) connectionTimeout ); } ) diff --git a/Ellucian.Ethos.Integration/Ellucian.Ethos.Integration.csproj b/Ellucian.Ethos.Integration/Ellucian.Ethos.Integration.csproj index da1da9a..0d21884 100644 --- a/Ellucian.Ethos.Integration/Ellucian.Ethos.Integration.csproj +++ b/Ellucian.Ethos.Integration/Ellucian.Ethos.Integration.csproj @@ -1,7 +1,7 @@ - net6.0 + net8.0 Ellucian.Ethos.Integration 1.0.0 Ellucian Ethos Integration Team @@ -59,9 +59,9 @@ The Ethos Integration SDK makes the application development process less expensi - - - + + + diff --git a/Ellucian.Ethos.Integration/packages.lock.json b/Ellucian.Ethos.Integration/packages.lock.json index 7ea511f..e772b8d 100644 --- a/Ellucian.Ethos.Integration/packages.lock.json +++ b/Ellucian.Ethos.Integration/packages.lock.json @@ -1,86 +1,134 @@ { "version": 1, "dependencies": { - "net6.0": { + "net8.0": { "Microsoft.Extensions.DependencyInjection": { "type": "Direct", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "k6PWQMuoBDGGHOQTtyois2u4AwyVcIwL2LaSLlTZQm2CYcJ1pxbt6jfAnpWmzENA/wfrYRI/X9DTLoUkE4AsLw==", + "requested": "[8.0.0, )", + "resolved": "8.0.0", + "contentHash": "V8S3bsm50ig6JSyrbcJJ8bW2b9QLGouz+G1miK3UTaOWmMtFwNNNzUf4AleyDWUmTrWMLNnFSLEQtxmxgNQnNQ==", "dependencies": { - "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0", - "System.Runtime.CompilerServices.Unsafe": "6.0.0" + "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0" } }, "Microsoft.Extensions.Http": { "type": "Direct", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "15+pa2G0bAMHbHewaQIdr/y6ag2H3yh4rd9hTXavtWDzQBkvpe2RMqFg8BxDpcQWssmjmBApGPcw93QRz6YcMg==", + "requested": "[8.0.0, )", + "resolved": "8.0.0", + "contentHash": "cWz4caHwvx0emoYe7NkHPxII/KkTI8R/LC9qdqJqnKv2poTJ4e2qqPGQqvRoQ5kaSA4FU5IV3qFAuLuOhoqULQ==", "dependencies": { - "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0", - "Microsoft.Extensions.Logging": "6.0.0", - "Microsoft.Extensions.Logging.Abstractions": "6.0.0", - "Microsoft.Extensions.Options": "6.0.0" + "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", + "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0", + "Microsoft.Extensions.Diagnostics": "8.0.0", + "Microsoft.Extensions.Logging": "8.0.0", + "Microsoft.Extensions.Logging.Abstractions": "8.0.0", + "Microsoft.Extensions.Options": "8.0.0" } }, "Newtonsoft.Json": { "type": "Direct", - "requested": "[13.0.1, )", - "resolved": "13.0.1", - "contentHash": "ppPFpBcvxdsfUonNcvITKqLl3bqxWbDCZIzDWHzjpdAHRFfZe0Dw9HmA0+za13IdyrgJwpkDTDA9fHaxOrt20A==" + "requested": "[13.0.3, )", + "resolved": "13.0.3", + "contentHash": "HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ==" + }, + "Microsoft.Extensions.Configuration": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "0J/9YNXTMWSZP2p2+nvl8p71zpSwokZXZuJW+VjdErkegAnFdO1XlqtA62SJtgVYHdKu3uPxJHcMR/r35HwFBA==", + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", + "Microsoft.Extensions.Primitives": "8.0.0" + } + }, + "Microsoft.Extensions.Configuration.Abstractions": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "3lE/iLSutpgX1CC0NOW70FJoGARRHbyKmG7dc0klnUZ9Dd9hS6N/POPWhKhMLCEuNN5nXEY5agmlFtH562vqhQ==", + "dependencies": { + "Microsoft.Extensions.Primitives": "8.0.0" + } + }, + "Microsoft.Extensions.Configuration.Binder": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "mBMoXLsr5s1y2zOHWmKsE9veDcx8h1x/c3rz4baEdQKTeDcmQAPNbB54Pi/lhFO3K431eEq6PFbMgLaa6PHFfA==", + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "8.0.0" + } }, "Microsoft.Extensions.DependencyInjection.Abstractions": { "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "xlzi2IYREJH3/m6+lUrQlujzX8wDitm4QGnUu6kUXTQAWPuZY8i+ticFJbzfqaetLA6KR/rO6Ew/HuYD+bxifg==" + "resolved": "8.0.0", + "contentHash": "cjWrLkJXK0rs4zofsK4bSdg+jhDLTaxrkXu4gS6Y7MAlCvRyNNgwY/lJi5RDlQOnSZweHqoyvgvbdvQsRIW+hg==" + }, + "Microsoft.Extensions.Diagnostics": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "3PZp/YSkIXrF7QK7PfC1bkyRYwqOHpWFad8Qx+4wkuumAeXo1NHaxpS9LboNA9OvNSAu+QOVlXbMyoY+pHSqcw==", + "dependencies": { + "Microsoft.Extensions.Configuration": "8.0.0", + "Microsoft.Extensions.Diagnostics.Abstractions": "8.0.0", + "Microsoft.Extensions.Options.ConfigurationExtensions": "8.0.0" + } + }, + "Microsoft.Extensions.Diagnostics.Abstractions": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "JHYCQG7HmugNYUhOl368g+NMxYE/N/AiclCYRNlgCY9eVyiBkOHMwK4x60RYMxv9EL3+rmj1mqHvdCiPpC+D4Q==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0", + "Microsoft.Extensions.Options": "8.0.0", + "System.Diagnostics.DiagnosticSource": "8.0.0" + } }, "Microsoft.Extensions.Logging": { "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "eIbyj40QDg1NDz0HBW0S5f3wrLVnKWnDJ/JtZ+yJDFnDj90VoPuoPmFkeaXrtu+0cKm5GRAwoDf+dBWXK0TUdg==", + "resolved": "8.0.0", + "contentHash": "tvRkov9tAJ3xP51LCv3FJ2zINmv1P8Hi8lhhtcKGqM+ImiTCC84uOPEI4z8Cdq2C3o9e+Aa0Gw0rmrsJD77W+w==", "dependencies": { - "Microsoft.Extensions.DependencyInjection": "6.0.0", - "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0", - "Microsoft.Extensions.Logging.Abstractions": "6.0.0", - "Microsoft.Extensions.Options": "6.0.0", - "System.Diagnostics.DiagnosticSource": "6.0.0" + "Microsoft.Extensions.DependencyInjection": "8.0.0", + "Microsoft.Extensions.Logging.Abstractions": "8.0.0", + "Microsoft.Extensions.Options": "8.0.0" } }, "Microsoft.Extensions.Logging.Abstractions": { "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "/HggWBbTwy8TgebGSX5DBZ24ndhzi93sHUBDvP1IxbZD7FDokYzdAr6+vbWGjw2XAfR2EJ1sfKUotpjHnFWPxA==" + "resolved": "8.0.0", + "contentHash": "arDBqTgFCyS0EvRV7O3MZturChstm50OJ0y9bDJvAcmEPJm0FFpFyjU/JLYyStNGGey081DvnQYlncNX5SJJGA==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0" + } }, "Microsoft.Extensions.Options": { "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "dzXN0+V1AyjOe2xcJ86Qbo233KHuLEY0njf/P2Kw8SfJU+d45HNS2ctJdnEnrWbM9Ye2eFgaC5Mj9otRMU6IsQ==", + "resolved": "8.0.0", + "contentHash": "JOVOfqpnqlVLUzINQ2fox8evY2SKLYJ3BV8QDe/Jyp21u1T7r45x/R/5QdteURMR5r01GxeJSBBUOCOyaNXA3g==", "dependencies": { - "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0", - "Microsoft.Extensions.Primitives": "6.0.0" + "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0", + "Microsoft.Extensions.Primitives": "8.0.0" } }, - "Microsoft.Extensions.Primitives": { + "Microsoft.Extensions.Options.ConfigurationExtensions": { "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "9+PnzmQFfEFNR9J2aDTfJGGupShHjOuGw4VUv+JB044biSHrnmCIMD+mJHmb2H7YryrfBEXDurxQ47gJZdCKNQ==", + "resolved": "8.0.0", + "contentHash": "0f4DMRqEd50zQh+UyJc+/HiBsZ3vhAQALgdkcQEalSH1L2isdC7Yj54M3cyo5e+BeO5fcBQ7Dxly8XiBBcvRgw==", "dependencies": { - "System.Runtime.CompilerServices.Unsafe": "6.0.0" + "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", + "Microsoft.Extensions.Configuration.Binder": "8.0.0", + "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0", + "Microsoft.Extensions.Options": "8.0.0", + "Microsoft.Extensions.Primitives": "8.0.0" } }, - "System.Diagnostics.DiagnosticSource": { + "Microsoft.Extensions.Primitives": { "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "frQDfv0rl209cKm1lnwTgFPzNigy2EKk1BS3uAvHvlBVKe5cymGyHO+Sj+NLv5VF/AhHsqPIUUwya5oV4CHMUw==", - "dependencies": { - "System.Runtime.CompilerServices.Unsafe": "6.0.0" - } + "resolved": "8.0.0", + "contentHash": "bXJEZrW9ny8vjMF1JV253WeLhpEVzFo1lyaZu1vQ4ZxWUlVvknZ/+ftFgVheLubb4eZPSwwxBeqS1JkCOjxd8g==" }, - "System.Runtime.CompilerServices.Unsafe": { + "System.Diagnostics.DiagnosticSource": { "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg==" + "resolved": "8.0.0", + "contentHash": "c9xLpVz6PL9lp/djOWtk5KPDZq3cSYpmXoJQY524EOtuFl5z9ZtsotpsyrDW40U1DRnQSYvcPKEUV0X//u6gkQ==" } } }