From 8039386e3cbcf8e537e5077693cab8b60066341f Mon Sep 17 00:00:00 2001 From: dylanbulfinMS <95251881+dylanbulfinMS@users.noreply.github.com> Date: Fri, 10 Dec 2021 11:26:12 -0500 Subject: [PATCH 1/8] Added types for different credentials --- .../src/Auth/ProvisioningSasCredential.cs | 22 ++++++++ .../src/Auth/ProvisioningTokenCredential.cs | 53 +++++++++++++++++++ provisioning/service/src/Auth/TokenHelper.cs | 21 ++++++++ ....Azure.Devices.Provisioning.Service.csproj | 1 + 4 files changed, 97 insertions(+) create mode 100644 provisioning/service/src/Auth/ProvisioningSasCredential.cs create mode 100644 provisioning/service/src/Auth/ProvisioningTokenCredential.cs create mode 100644 provisioning/service/src/Auth/TokenHelper.cs diff --git a/provisioning/service/src/Auth/ProvisioningSasCredential.cs b/provisioning/service/src/Auth/ProvisioningSasCredential.cs new file mode 100644 index 0000000000..85a0148ec5 --- /dev/null +++ b/provisioning/service/src/Auth/ProvisioningSasCredential.cs @@ -0,0 +1,22 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +using Azure; +using Microsoft.Azure.Devices.Common.Service.Auth; + +namespace Microsoft.Azure.Devices.Provisioning.Service.Auth +{ + internal class ProvisioningSasCredential: IAuthorizationHeaderProvider + { + private AzureSasCredential _azureSasCredential; + + public ProvisioningSasCredential(AzureSasCredential azureSasCredential) + { + _azureSasCredential = azureSasCredential; + } + + public string GetAuthorizationHeader() + { + return _azureSasCredential.Signature; + } + } +} diff --git a/provisioning/service/src/Auth/ProvisioningTokenCredential.cs b/provisioning/service/src/Auth/ProvisioningTokenCredential.cs new file mode 100644 index 0000000000..0d444b3281 --- /dev/null +++ b/provisioning/service/src/Auth/ProvisioningTokenCredential.cs @@ -0,0 +1,53 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +using System.Threading; +using Azure.Core; +using Microsoft.Azure.Devices.Common.Service.Auth; + +namespace Microsoft.Azure.Devices.Provisioning.Service.Auth +{ + internal class ProvisioningTokenCredential : IAuthorizationHeaderProvider + { +#if !NET451 + private const string _tokenType = "Bearer"; + private readonly TokenCredential _credential; + private readonly object _tokenLock = new object(); + private AccessToken? _cachedAccessToken; +#endif + +#if NET451 + public ProvisioningTokenCredential() + { + throw new InvalidOperationException("TokenCredential is not supported on NET451"); + } +#else + public ProvisioningTokenCredential(TokenCredential credential) + { + _credential = credential; + } +#endif + + // The HTTP protocol uses this method to get the bearer token for authentication. + public string GetAuthorizationHeader() + { +#if NET451 + throw new InvalidOperationException($"TokenCredential is not supported on NET451"); + +#else + lock (_tokenLock) + { + // A new token is generated if it is the first time or the cached token is close to expiry. + if (!_cachedAccessToken.HasValue + || TokenHelper.IsCloseToExpiry(_cachedAccessToken.Value.ExpiresOn)) + { + _cachedAccessToken = _credential.GetToken( + new TokenRequestContext(new string[] { "https://azure-devices-provisioning.net/.default" }), + new CancellationToken()); + } + } + + return $"{_tokenType} {_cachedAccessToken.Value.Token}"; +#endif + } + } +} diff --git a/provisioning/service/src/Auth/TokenHelper.cs b/provisioning/service/src/Auth/TokenHelper.cs new file mode 100644 index 0000000000..f98c07eac3 --- /dev/null +++ b/provisioning/service/src/Auth/TokenHelper.cs @@ -0,0 +1,21 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +using System; + +namespace Microsoft.Azure.Devices.Provisioning.Service.Auth +{ + internal static class TokenHelper + { + /// + /// Determines if the given token expiry date time is close to expiry. The date and time is + /// considered close to expiry if it has less than 10 minutes relative to the current time. + /// + /// The token expiration date and time. + /// True if the token expiry has less than 10 minutes relative to the current time, otherwise false. + public static bool IsCloseToExpiry(DateTimeOffset expiry) + { + TimeSpan timeToExpiry = expiry - DateTimeOffset.UtcNow; + return timeToExpiry.TotalMinutes < 10; + } + } +} diff --git a/provisioning/service/src/Microsoft.Azure.Devices.Provisioning.Service.csproj b/provisioning/service/src/Microsoft.Azure.Devices.Provisioning.Service.csproj index 9e25d16aba..d1fa2e37d0 100644 --- a/provisioning/service/src/Microsoft.Azure.Devices.Provisioning.Service.csproj +++ b/provisioning/service/src/Microsoft.Azure.Devices.Provisioning.Service.csproj @@ -56,6 +56,7 @@ + all runtime; build; native; contentfiles; analyzers; buildtransitive From dd825565aec98439db4fd9144d94363b2bf242a6 Mon Sep 17 00:00:00 2001 From: dylanbulfinMS <95251881+dylanbulfinMS@users.noreply.github.com> Date: Mon, 13 Dec 2021 12:52:22 -0500 Subject: [PATCH 2/8] Altered code to work with new types --- .../service/src/ProvisioningServiceClient.cs | 73 +++++++++++++++++++ provisioning/service/src/Query.cs | 58 +++++++++++++++ 2 files changed, 131 insertions(+) diff --git a/provisioning/service/src/ProvisioningServiceClient.cs b/provisioning/service/src/ProvisioningServiceClient.cs index df4c53e24e..d68bb0106d 100644 --- a/provisioning/service/src/ProvisioningServiceClient.cs +++ b/provisioning/service/src/ProvisioningServiceClient.cs @@ -6,6 +6,15 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.Azure.Devices.Common.Service.Auth; +using Microsoft.Azure.Devices.Provisioning.Service.Auth; + +#if !NET451 + +using Azure; +using Azure.Core; + +#endif + namespace Microsoft.Azure.Devices.Provisioning.Service { @@ -65,6 +74,8 @@ namespace Microsoft.Azure.Devices.Provisioning.Service public class ProvisioningServiceClient : IDisposable { private readonly ServiceConnectionString _provisioningConnectionString; + private readonly ProvisioningTokenCredential _provisioningTokenCredential; + private readonly ProvisioningSasCredential _provisioningSasCredential; private readonly IContractApiHttp _contractApiHttp; /// @@ -104,6 +115,39 @@ public static ProvisioningServiceClient CreateFromConnectionString(string connec return new ProvisioningServiceClient(connectionString, httpTransportSettings); } +#if !NET451 + public static ProvisioningServiceClient Create(string path, TokenCredential credential) + { + return ProvisioningServiceClient.Create(path, credential, new HttpTransportSettings()); + } + + public static ProvisioningServiceClient Create(string path, TokenCredential credential, HttpTransportSettings httpTransportSettings) + { + if (credential == null) + { + throw new ArgumentNullException($"{nameof(credential)}, Parameter cannot be null"); + } + + return new ProvisioningServiceClient(path, credential, httpTransportSettings); + } + + public static ProvisioningServiceClient Create(string path, AzureSasCredential azureSasCredential) + { + return ProvisioningServiceClient.Create(path, azureSasCredential, new HttpTransportSettings()); + } + + public static ProvisioningServiceClient Create(string path, AzureSasCredential azureSasCredential, HttpTransportSettings httpTransportSettings) + { + if (azureSasCredential == null) + { + throw new ArgumentNullException($"{nameof(azureSasCredential)}, Parameter cannot be null"); + } + + return new ProvisioningServiceClient(path, azureSasCredential, httpTransportSettings); + } + +#endif + /// /// PRIVATE CONSTRUCTOR /// @@ -127,6 +171,35 @@ private ProvisioningServiceClient(string connectionString, HttpTransportSettings httpTransportSettings); } +#if !NET451 + private ProvisioningServiceClient(string path, TokenCredential credential, HttpTransportSettings httpTransportSettings) + { + if (string.IsNullOrWhiteSpace(path ?? throw new ArgumentNullException(nameof(path)))) + { + throw new ArgumentException($"{nameof(path)} cannot be empty string"); + } + + _provisioningTokenCredential = new ProvisioningTokenCredential(credential); + _contractApiHttp = new ContractApiHttp( + new UriBuilder("https", path).Uri, + _provisioningTokenCredential, + httpTransportSettings); + } + + private ProvisioningServiceClient(string path, AzureSasCredential azureSasCredential, HttpTransportSettings httpTransportSettings) + { + if (string.IsNullOrWhiteSpace(path ?? throw new ArgumentNullException(nameof(path)))) + { + throw new ArgumentException($"{nameof(path)} cannot be empty string"); + } + + _provisioningSasCredential = new ProvisioningSasCredential(azureSasCredential); + _contractApiHttp = new ContractApiHttp( + new UriBuilder("https", path).Uri, + _provisioningSasCredential, + httpTransportSettings); + } +#endif /// /// Dispose the Provisioning Service Client and its dependencies. /// diff --git a/provisioning/service/src/Query.cs b/provisioning/service/src/Query.cs index 4b449710ab..a4f766c7dc 100644 --- a/provisioning/service/src/Query.cs +++ b/provisioning/service/src/Query.cs @@ -122,6 +122,64 @@ internal Query( _hasNext = true; } +#if !NET451 + internal Query( + string path, + IAuthorizationHeaderProvider headerProvider, + string serviceName, + QuerySpecification querySpecification, + HttpTransportSettings httpTransportSettings, + int pageSize, + CancellationToken cancellationToken) + { + /* SRS_QUERY_21_001: [The constructor shall throw ArgumentNullException if the provided path is null.] */ + if (path == null) + { + throw new ArgumentNullException(nameof(path)); + } + + /* SRS_QUERY_21_002: [The constructor shall throw ArgumentException if the provided serviceName is null or empty.] */ + if (string.IsNullOrWhiteSpace(serviceName ?? throw new ArgumentNullException(nameof(serviceName)))) + { + throw new ArgumentException($"{nameof(serviceName)} cannot be an empty string"); + } + + /* SRS_QUERY_21_003: [The constructor shall throw ArgumentException if the provided querySpecification is null.] */ + if (querySpecification == null) + { + throw new ArgumentNullException(nameof(querySpecification)); + } + + /* SRS_QUERY_21_004: [The constructor shall throw ArgumentException if the provided pageSize is negative.] */ + if (pageSize < 0) + { + throw new ArgumentException($"{nameof(pageSize)} cannot be negative."); + } + + // TODO: Refactor ContractApiHttp being created again + /* SRS_QUERY_21_005: [The constructor shall create and store a `contractApiHttp` using the provided path and Authorization Header Provider.] */ + _contractApiHttp = new ContractApiHttp( + new UriBuilder("https", path).Uri, + headerProvider, httpTransportSettings); + + /* SRS_QUERY_21_006: [The constructor shall store the provided `pageSize`, and `cancelationToken`.] */ + PageSize = pageSize; + _cancellationToken = cancellationToken; + + /* SRS_QUERY_21_007: [The constructor shall create and store a JSON from the provided querySpecification.] */ + _querySpecificationJson = JsonConvert.SerializeObject(querySpecification); + + /* SRS_QUERY_21_008: [The constructor shall create and store a queryPath adding `/query` to the provided `targetPath`.] */ + _queryPath = GetQueryUri(serviceName); + + /* SRS_QUERY_21_009: [The constructor shall set continuationToken and current as null.] */ + ContinuationToken = null; + + /* SRS_QUERY_21_010: [The constructor shall set hasNext as true.] */ + _hasNext = true; + } +#endif + /// /// Getter for has next /// From 31a0eb2606fad9f6d75245f956ae837db5f60dd0 Mon Sep 17 00:00:00 2001 From: dylanbulfinMS <95251881+dylanbulfinMS@users.noreply.github.com> Date: Mon, 13 Dec 2021 16:44:25 -0500 Subject: [PATCH 3/8] Fixed Managers --- .../src/Manager/EnrollmentGroupManager.cs | 5 +- .../Manager/IndividualEnrollmentManager.cs | 5 +- .../src/Manager/RegistrationStatusManager.cs | 6 +- .../service/src/ProvisioningServiceClient.cs | 133 +++++++++++++----- provisioning/service/src/Query.cs | 8 +- 5 files changed, 110 insertions(+), 47 deletions(-) diff --git a/provisioning/service/src/Manager/EnrollmentGroupManager.cs b/provisioning/service/src/Manager/EnrollmentGroupManager.cs index 9cddfe1fe7..08052420f1 100644 --- a/provisioning/service/src/Manager/EnrollmentGroupManager.cs +++ b/provisioning/service/src/Manager/EnrollmentGroupManager.cs @@ -109,7 +109,8 @@ await contractApiHttp.RequestAsync( } internal static Query CreateQuery( - ServiceConnectionString provisioningConnectionString, + string hostName, + IAuthorizationHeaderProvider headerProvider, QuerySpecification querySpecification, HttpTransportSettings httpTransportSettings, CancellationToken cancellationToken, @@ -128,7 +129,7 @@ internal static Query CreateQuery( /* SRS_ENROLLMENT_GROUP_MANAGER_28_015: [The CreateQuery shall return a new Query for EnrollmentGroup.] */ - return new Query(provisioningConnectionString, ServiceName, querySpecification, httpTransportSettings, pageSize, cancellationToken); + return new Query(hostName, headerProvider, ServiceName, querySpecification, httpTransportSettings, pageSize, cancellationToken); } private static Uri GetEnrollmentUri(string enrollmentGroupId) diff --git a/provisioning/service/src/Manager/IndividualEnrollmentManager.cs b/provisioning/service/src/Manager/IndividualEnrollmentManager.cs index c4c5d40c22..35f9bad5e3 100644 --- a/provisioning/service/src/Manager/IndividualEnrollmentManager.cs +++ b/provisioning/service/src/Manager/IndividualEnrollmentManager.cs @@ -150,7 +150,8 @@ await contractApiHttp.RequestAsync( } internal static Query CreateQuery( - ServiceConnectionString provisioningConnectionString, + string hostName, + IAuthorizationHeaderProvider headerProvider, QuerySpecification querySpecification, HttpTransportSettings httpTransportSettings, CancellationToken cancellationToken, @@ -168,7 +169,7 @@ internal static Query CreateQuery( } /* SRS_INDIVIDUAL_ENROLLMENT_MANAGER_21_015: [The CreateQuery shall return a new Query for IndividualEnrollments.] */ - return new Query(provisioningConnectionString, ServiceName, querySpecification, httpTransportSettings, pageSize, cancellationToken); + return new Query(hostName, headerProvider, ServiceName, querySpecification, httpTransportSettings, pageSize, cancellationToken); } private static Uri GetEnrollmentUri(string registrationId) diff --git a/provisioning/service/src/Manager/RegistrationStatusManager.cs b/provisioning/service/src/Manager/RegistrationStatusManager.cs index cd786744ff..044b7128f2 100644 --- a/provisioning/service/src/Manager/RegistrationStatusManager.cs +++ b/provisioning/service/src/Manager/RegistrationStatusManager.cs @@ -82,7 +82,8 @@ await contractApiHttp.RequestAsync( [SuppressMessage("Microsoft.Design", "CA1068", Justification = "Public API cannot change parameter order.")] internal static Query CreateEnrollmentGroupQuery( - ServiceConnectionString provisioningConnectionString, + string hostName, + IAuthorizationHeaderProvider headerProvider, QuerySpecification querySpecification, HttpTransportSettings httpTransportSettings, CancellationToken cancellationToken, @@ -102,7 +103,8 @@ internal static Query CreateEnrollmentGroupQuery( /* SRS_REGISTRATION_STATUS_MANAGER_28_010: [The CreateQuery shall return a new Query for DeviceRegistrationState.] */ return new Query( - provisioningConnectionString, + hostName, + headerProvider, GetGetDeviceRegistrationStatus(enrollmentGroupId), querySpecification, httpTransportSettings, diff --git a/provisioning/service/src/ProvisioningServiceClient.cs b/provisioning/service/src/ProvisioningServiceClient.cs index d68bb0106d..268809237e 100644 --- a/provisioning/service/src/ProvisioningServiceClient.cs +++ b/provisioning/service/src/ProvisioningServiceClient.cs @@ -78,6 +78,8 @@ public class ProvisioningServiceClient : IDisposable private readonly ProvisioningSasCredential _provisioningSasCredential; private readonly IContractApiHttp _contractApiHttp; + private string _hostName; + /// /// Create a new instance of the ProvisioningServiceClient that exposes /// the API to the Device Provisioning Service. @@ -116,34 +118,57 @@ public static ProvisioningServiceClient CreateFromConnectionString(string connec } #if !NET451 - public static ProvisioningServiceClient Create(string path, TokenCredential credential) + /// + /// + /// + /// + /// + /// + public static ProvisioningServiceClient Create(string hostName, TokenCredential credential) { - return ProvisioningServiceClient.Create(path, credential, new HttpTransportSettings()); + return ProvisioningServiceClient.Create(hostName, credential, new HttpTransportSettings()); } - - public static ProvisioningServiceClient Create(string path, TokenCredential credential, HttpTransportSettings httpTransportSettings) + /// + /// + /// + /// + /// + /// + /// + public static ProvisioningServiceClient Create(string hostName, TokenCredential credential, HttpTransportSettings httpTransportSettings) { if (credential == null) { throw new ArgumentNullException($"{nameof(credential)}, Parameter cannot be null"); } - return new ProvisioningServiceClient(path, credential, httpTransportSettings); + return new ProvisioningServiceClient(hostName, credential, httpTransportSettings); } - - public static ProvisioningServiceClient Create(string path, AzureSasCredential azureSasCredential) + /// + /// + /// + /// + /// + /// + public static ProvisioningServiceClient Create(string hostName, AzureSasCredential azureSasCredential) { - return ProvisioningServiceClient.Create(path, azureSasCredential, new HttpTransportSettings()); + return ProvisioningServiceClient.Create(hostName, azureSasCredential, new HttpTransportSettings()); } - - public static ProvisioningServiceClient Create(string path, AzureSasCredential azureSasCredential, HttpTransportSettings httpTransportSettings) + /// + /// + /// + /// + /// + /// + /// + public static ProvisioningServiceClient Create(string hostName, AzureSasCredential azureSasCredential, HttpTransportSettings httpTransportSettings) { if (azureSasCredential == null) { throw new ArgumentNullException($"{nameof(azureSasCredential)}, Parameter cannot be null"); } - return new ProvisioningServiceClient(path, azureSasCredential, httpTransportSettings); + return new ProvisioningServiceClient(hostName, azureSasCredential, httpTransportSettings); } #endif @@ -165,6 +190,7 @@ private ProvisioningServiceClient(string connectionString, HttpTransportSettings /* SRS_PROVISIONING_SERVICE_CLIENT_21_003: [The constructor shall throw ArgumentException if the ProvisioningConnectionString or one of the inner Managers failed to create a new instance.] */ /* SRS_PROVISIONING_SERVICE_CLIENT_21_004: [The constructor shall create a new instance of the ContractApiHttp class using the provided connectionString.] */ _provisioningConnectionString = ServiceConnectionString.Parse(connectionString); + _hostName = _provisioningConnectionString.HostName; _contractApiHttp = new ContractApiHttp( _provisioningConnectionString.HttpsEndpoint, _provisioningConnectionString, @@ -172,30 +198,32 @@ private ProvisioningServiceClient(string connectionString, HttpTransportSettings } #if !NET451 - private ProvisioningServiceClient(string path, TokenCredential credential, HttpTransportSettings httpTransportSettings) + private ProvisioningServiceClient(string hostName, TokenCredential credential, HttpTransportSettings httpTransportSettings) { - if (string.IsNullOrWhiteSpace(path ?? throw new ArgumentNullException(nameof(path)))) + if (string.IsNullOrWhiteSpace(hostName ?? throw new ArgumentNullException(nameof(hostName)))) { - throw new ArgumentException($"{nameof(path)} cannot be empty string"); + throw new ArgumentException($"{nameof(hostName)} cannot be empty string"); } _provisioningTokenCredential = new ProvisioningTokenCredential(credential); + _hostName = hostName; _contractApiHttp = new ContractApiHttp( - new UriBuilder("https", path).Uri, + new UriBuilder("https", _hostName).Uri, _provisioningTokenCredential, httpTransportSettings); } - private ProvisioningServiceClient(string path, AzureSasCredential azureSasCredential, HttpTransportSettings httpTransportSettings) + private ProvisioningServiceClient(string hostName, AzureSasCredential azureSasCredential, HttpTransportSettings httpTransportSettings) { - if (string.IsNullOrWhiteSpace(path ?? throw new ArgumentNullException(nameof(path)))) + if (string.IsNullOrWhiteSpace(hostName ?? throw new ArgumentNullException(nameof(hostName)))) { - throw new ArgumentException($"{nameof(path)} cannot be empty string"); + throw new ArgumentException($"{nameof(hostName)} cannot be empty string"); } _provisioningSasCredential = new ProvisioningSasCredential(azureSasCredential); + _hostName = hostName; _contractApiHttp = new ContractApiHttp( - new UriBuilder("https", path).Uri, + new UriBuilder("https", _hostName).Uri, _provisioningSasCredential, httpTransportSettings); } @@ -545,7 +573,8 @@ public Query CreateIndividualEnrollmentQuery(QuerySpecification querySpecificati { /* SRS_PROVISIONING_SERVICE_CLIENT_21_014: [The CreateIndividualEnrollmentQuery shall create a new individual enrollment query by calling the CreateQuery in the IndividualEnrollmentManager.] */ return IndividualEnrollmentManager.CreateQuery( - _provisioningConnectionString, + _hostName, + GetHeaderProvider(), querySpecification, new HttpTransportSettings(), CancellationToken.None); @@ -569,7 +598,8 @@ public Query CreateIndividualEnrollmentQuery(QuerySpecification querySpecificati { /* SRS_PROVISIONING_SERVICE_CLIENT_21_014: [The CreateIndividualEnrollmentQuery shall create a new individual enrollment query by calling the CreateQuery in the IndividualEnrollmentManager.] */ return IndividualEnrollmentManager.CreateQuery( - _provisioningConnectionString, + _hostName, + GetHeaderProvider(), querySpecification, httpTransportSettings, CancellationToken.None); @@ -593,7 +623,8 @@ public Query CreateIndividualEnrollmentQuery(QuerySpecification querySpecificati { /* SRS_PROVISIONING_SERVICE_CLIENT_21_014: [The CreateIndividualEnrollmentQuery shall create a new individual enrollment query by calling the CreateQuery in the IndividualEnrollmentManager.] */ return IndividualEnrollmentManager.CreateQuery( - _provisioningConnectionString, + _hostName, + GetHeaderProvider(), querySpecification, new HttpTransportSettings(), cancellationToken); @@ -621,7 +652,8 @@ public Query CreateIndividualEnrollmentQuery(QuerySpecification querySpecificati { /* SRS_PROVISIONING_SERVICE_CLIENT_21_015: [The CreateIndividualEnrollmentQuery shall create a new individual enrollment query by calling the CreateQuery in the IndividualEnrollmentManager.] */ return IndividualEnrollmentManager.CreateQuery( - _provisioningConnectionString, + _hostName, + GetHeaderProvider(), querySpecification, new HttpTransportSettings(), CancellationToken.None, @@ -651,7 +683,8 @@ public Query CreateIndividualEnrollmentQuery(QuerySpecification querySpecificati { /* SRS_PROVISIONING_SERVICE_CLIENT_21_015: [The CreateIndividualEnrollmentQuery shall create a new individual enrollment query by calling the CreateQuery in the IndividualEnrollmentManager.] */ return IndividualEnrollmentManager.CreateQuery( - _provisioningConnectionString, + _hostName, + GetHeaderProvider(), querySpecification, new HttpTransportSettings(), cancellationToken, @@ -681,7 +714,8 @@ public Query CreateIndividualEnrollmentQuery(QuerySpecification querySpecificati { /* SRS_PROVISIONING_SERVICE_CLIENT_21_015: [The CreateIndividualEnrollmentQuery shall create a new individual enrollment query by calling the CreateQuery in the IndividualEnrollmentManager.] */ return IndividualEnrollmentManager.CreateQuery( - _provisioningConnectionString, + _hostName, + GetHeaderProvider(), querySpecification, httpTransportSettings, CancellationToken.None, @@ -928,7 +962,8 @@ public Query CreateEnrollmentGroupQuery(QuerySpecification querySpecification) { /* SRS_PROVISIONING_SERVICE_CLIENT_21_021: [The createEnrollmentGroupQuery shall create a new enrolmentGroup query by calling the createQuery in the EnrollmentGroupManager.] */ return EnrollmentGroupManager.CreateQuery( - _provisioningConnectionString, + _hostName, + GetHeaderProvider(), querySpecification, new HttpTransportSettings(), CancellationToken.None); @@ -952,7 +987,8 @@ public Query CreateEnrollmentGroupQuery(QuerySpecification querySpecification, H { /* SRS_PROVISIONING_SERVICE_CLIENT_21_021: [The createEnrollmentGroupQuery shall create a new enrolmentGroup query by calling the createQuery in the EnrollmentGroupManager.] */ return EnrollmentGroupManager.CreateQuery( - _provisioningConnectionString, + _hostName, + GetHeaderProvider(), querySpecification, httpTransportSettings, CancellationToken.None); @@ -976,7 +1012,8 @@ public Query CreateEnrollmentGroupQuery(QuerySpecification querySpecification, C { /* SRS_PROVISIONING_SERVICE_CLIENT_21_021: [The createEnrollmentGroupQuery shall create a new enrolmentGroup query by calling the createQuery in the EnrollmentGroupManager.] */ return EnrollmentGroupManager.CreateQuery( - _provisioningConnectionString, + _hostName, + GetHeaderProvider(), querySpecification, new HttpTransportSettings(), cancellationToken); @@ -1004,7 +1041,8 @@ public Query CreateEnrollmentGroupQuery(QuerySpecification querySpecification, i { /* SRS_PROVISIONING_SERVICE_CLIENT_21_022: [The createEnrollmentGroupQuery shall create a new enrolmentGroup query by calling the createQuery in the EnrollmentGroupManager.] */ return EnrollmentGroupManager.CreateQuery( - _provisioningConnectionString, + _hostName, + GetHeaderProvider(), querySpecification, new HttpTransportSettings(), CancellationToken.None, @@ -1034,7 +1072,8 @@ public Query CreateEnrollmentGroupQuery(QuerySpecification querySpecification, i { /* SRS_PROVISIONING_SERVICE_CLIENT_21_022: [The createEnrollmentGroupQuery shall create a new enrolmentGroup query by calling the createQuery in the EnrollmentGroupManager.] */ return EnrollmentGroupManager.CreateQuery( - _provisioningConnectionString, + _hostName, + GetHeaderProvider(), querySpecification, new HttpTransportSettings(), cancellationToken, @@ -1064,7 +1103,8 @@ public Query CreateEnrollmentGroupQuery(QuerySpecification querySpecification, i { /* SRS_PROVISIONING_SERVICE_CLIENT_21_022: [The createEnrollmentGroupQuery shall create a new enrolmentGroup query by calling the createQuery in the EnrollmentGroupManager.] */ return EnrollmentGroupManager.CreateQuery( - _provisioningConnectionString, + _hostName, + GetHeaderProvider(), querySpecification, httpTransportSettings, CancellationToken.None, @@ -1251,7 +1291,8 @@ public Query CreateEnrollmentGroupRegistrationStateQuery(QuerySpecification quer { /* SRS_PROVISIONING_SERVICE_CLIENT_21_027: [The createEnrollmentGroupRegistrationStateQuery shall create a new DeviceRegistrationState query by calling the createQuery in the registrationStatusManager.] */ return RegistrationStatusManager.CreateEnrollmentGroupQuery( - _provisioningConnectionString, + _hostName, + GetHeaderProvider(), querySpecification, new HttpTransportSettings(), CancellationToken.None, @@ -1276,7 +1317,8 @@ public Query CreateEnrollmentGroupRegistrationStateQuery(QuerySpecification quer { /* SRS_PROVISIONING_SERVICE_CLIENT_21_027: [The createEnrollmentGroupRegistrationStateQuery shall create a new DeviceRegistrationState query by calling the createQuery in the registrationStatusManager.] */ return RegistrationStatusManager.CreateEnrollmentGroupQuery( - _provisioningConnectionString, + _hostName, + GetHeaderProvider(), querySpecification, httpTransportSettings, CancellationToken.None, @@ -1304,7 +1346,8 @@ public Query CreateEnrollmentGroupRegistrationStateQuery( { /* SRS_PROVISIONING_SERVICE_CLIENT_21_027: [The createEnrollmentGroupRegistrationStateQuery shall create a new DeviceRegistrationState query by calling the createQuery in the registrationStatusManager.] */ return RegistrationStatusManager.CreateEnrollmentGroupQuery( - _provisioningConnectionString, + _hostName, + GetHeaderProvider(), querySpecification, new HttpTransportSettings(), cancellationToken, @@ -1334,7 +1377,8 @@ public Query CreateEnrollmentGroupRegistrationStateQuery(QuerySpecification quer { /* SRS_PROVISIONING_SERVICE_CLIENT_21_028: [The createEnrollmentGroupRegistrationStateQuery shall create a new DeviceRegistrationState query by calling the createQuery in the registrationStatusManager.] */ return RegistrationStatusManager.CreateEnrollmentGroupQuery( - _provisioningConnectionString, + _hostName, + GetHeaderProvider(), querySpecification, new HttpTransportSettings(), CancellationToken.None, @@ -1370,7 +1414,8 @@ public Query CreateEnrollmentGroupRegistrationStateQuery( { /* SRS_PROVISIONING_SERVICE_CLIENT_21_028: [The createEnrollmentGroupRegistrationStateQuery shall create a new DeviceRegistrationState query by calling the createQuery in the registrationStatusManager.] */ return RegistrationStatusManager.CreateEnrollmentGroupQuery( - _provisioningConnectionString, + _hostName, + GetHeaderProvider(), querySpecification, httpTransportSettings, CancellationToken.None, @@ -1406,7 +1451,8 @@ public Query CreateEnrollmentGroupRegistrationStateQuery( { /* SRS_PROVISIONING_SERVICE_CLIENT_21_028: [The createEnrollmentGroupRegistrationStateQuery shall create a new DeviceRegistrationState query by calling the createQuery in the registrationStatusManager.] */ return RegistrationStatusManager.CreateEnrollmentGroupQuery( - _provisioningConnectionString, + _hostName, + GetHeaderProvider(), querySpecification, new HttpTransportSettings(), cancellationToken, @@ -1441,5 +1487,18 @@ public Task GetEnrollmentGroupAttestationAsync(string enro { return EnrollmentGroupManager.GetEnrollmentAttestationAsync(_contractApiHttp, enrollmentGroupId, cancellationToken); } + + internal IAuthorizationHeaderProvider GetHeaderProvider() + { + if (_provisioningConnectionString != null) + { + return _provisioningConnectionString; + } + else if (_provisioningTokenCredential != null) + { + return _provisioningTokenCredential; + } + return _provisioningSasCredential; + } } } diff --git a/provisioning/service/src/Query.cs b/provisioning/service/src/Query.cs index a4f766c7dc..beac287207 100644 --- a/provisioning/service/src/Query.cs +++ b/provisioning/service/src/Query.cs @@ -124,7 +124,7 @@ internal Query( #if !NET451 internal Query( - string path, + string hostName, IAuthorizationHeaderProvider headerProvider, string serviceName, QuerySpecification querySpecification, @@ -133,9 +133,9 @@ internal Query( CancellationToken cancellationToken) { /* SRS_QUERY_21_001: [The constructor shall throw ArgumentNullException if the provided path is null.] */ - if (path == null) + if (hostName == null) { - throw new ArgumentNullException(nameof(path)); + throw new ArgumentNullException(nameof(hostName)); } /* SRS_QUERY_21_002: [The constructor shall throw ArgumentException if the provided serviceName is null or empty.] */ @@ -159,7 +159,7 @@ internal Query( // TODO: Refactor ContractApiHttp being created again /* SRS_QUERY_21_005: [The constructor shall create and store a `contractApiHttp` using the provided path and Authorization Header Provider.] */ _contractApiHttp = new ContractApiHttp( - new UriBuilder("https", path).Uri, + new UriBuilder("https", hostName).Uri, headerProvider, httpTransportSettings); /* SRS_QUERY_21_006: [The constructor shall store the provided `pageSize`, and `cancelationToken`.] */ From a28618ea70846649a80a3a14d76a0724d6bf557d Mon Sep 17 00:00:00 2001 From: dylanbulfinMS <95251881+dylanbulfinMS@users.noreply.github.com> Date: Sun, 9 Jan 2022 15:34:05 -0500 Subject: [PATCH 4/8] removed unneeded #if !NET451 --- provisioning/service/src/ProvisioningServiceClient.cs | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/provisioning/service/src/ProvisioningServiceClient.cs b/provisioning/service/src/ProvisioningServiceClient.cs index 268809237e..599d846063 100644 --- a/provisioning/service/src/ProvisioningServiceClient.cs +++ b/provisioning/service/src/ProvisioningServiceClient.cs @@ -8,14 +8,9 @@ using Microsoft.Azure.Devices.Common.Service.Auth; using Microsoft.Azure.Devices.Provisioning.Service.Auth; -#if !NET451 - using Azure; using Azure.Core; -#endif - - namespace Microsoft.Azure.Devices.Provisioning.Service { /// @@ -117,7 +112,6 @@ public static ProvisioningServiceClient CreateFromConnectionString(string connec return new ProvisioningServiceClient(connectionString, httpTransportSettings); } -#if !NET451 /// /// /// @@ -154,6 +148,7 @@ public static ProvisioningServiceClient Create(string hostName, AzureSasCredenti { return ProvisioningServiceClient.Create(hostName, azureSasCredential, new HttpTransportSettings()); } + /// /// /// @@ -171,7 +166,6 @@ public static ProvisioningServiceClient Create(string hostName, AzureSasCredenti return new ProvisioningServiceClient(hostName, azureSasCredential, httpTransportSettings); } -#endif /// /// PRIVATE CONSTRUCTOR @@ -197,7 +191,6 @@ private ProvisioningServiceClient(string connectionString, HttpTransportSettings httpTransportSettings); } -#if !NET451 private ProvisioningServiceClient(string hostName, TokenCredential credential, HttpTransportSettings httpTransportSettings) { if (string.IsNullOrWhiteSpace(hostName ?? throw new ArgumentNullException(nameof(hostName)))) @@ -227,7 +220,7 @@ private ProvisioningServiceClient(string hostName, AzureSasCredential azureSasCr _provisioningSasCredential, httpTransportSettings); } -#endif + /// /// Dispose the Provisioning Service Client and its dependencies. /// From 862aaea09b27b15de26809e7724567f8746268e2 Mon Sep 17 00:00:00 2001 From: dylanbulfinMS <95251881+dylanbulfinMS@users.noreply.github.com> Date: Sun, 9 Jan 2022 15:48:31 -0500 Subject: [PATCH 5/8] Filled in method summaries --- .../service/src/ProvisioningServiceClient.cs | 50 ++++++++++++------- 1 file changed, 32 insertions(+), 18 deletions(-) diff --git a/provisioning/service/src/ProvisioningServiceClient.cs b/provisioning/service/src/ProvisioningServiceClient.cs index 599d846063..01c336dc68 100644 --- a/provisioning/service/src/ProvisioningServiceClient.cs +++ b/provisioning/service/src/ProvisioningServiceClient.cs @@ -113,22 +113,29 @@ public static ProvisioningServiceClient CreateFromConnectionString(string connec } /// - /// + /// Create a new instance of the ProvisioningServiceClient from the provided hostName and TokenCredential + /// that exposes the API to the Device Provisioning Service. /// - /// - /// - /// + /// + /// The string that carries the hostName that will be used for this object + /// The TokenCredential that provides authentication for this object + /// The ProvisioningServiceClient with the new instance of this object. + /// if the credential is null public static ProvisioningServiceClient Create(string hostName, TokenCredential credential) { return ProvisioningServiceClient.Create(hostName, credential, new HttpTransportSettings()); } + /// - /// + /// Create a new instance of the ProvisioningServiceClient from the provided hostName and TokenCredential + /// that exposes the API to the Device Provisioning Service. /// - /// - /// - /// - /// + /// + /// The string that carries the hostName that will be used for this object + /// The TokenCredential that provides authentication for this object + /// Specifies the HTTP transport settings for the request + /// The ProvisioningServiceClient with the new instance of this object. + /// if the credential is null public static ProvisioningServiceClient Create(string hostName, TokenCredential credential, HttpTransportSettings httpTransportSettings) { if (credential == null) @@ -138,24 +145,31 @@ public static ProvisioningServiceClient Create(string hostName, TokenCredential return new ProvisioningServiceClient(hostName, credential, httpTransportSettings); } + /// - /// + /// Create a new instance of the ProvisioningServiceClient from the provided hostName and TokenCredential + /// that exposes the API to the Device Provisioning Service. /// - /// - /// - /// + /// + /// The string that carries the host name that will be used for this object + /// The AzureSasCredential that provides authentication for this object + /// The ProvisioningServiceClient with the new instance of this object. + /// if the azureSasCredential is null public static ProvisioningServiceClient Create(string hostName, AzureSasCredential azureSasCredential) { return ProvisioningServiceClient.Create(hostName, azureSasCredential, new HttpTransportSettings()); } /// - /// + /// Create a new instance of the ProvisioningServiceClient from the provided hostName and TokenCredential + /// that exposes the API to the Device Provisioning Service. /// - /// - /// - /// - /// + /// + /// The string that carries the host name that will be used for this object + /// The AzureSasCredential that provides authentication for this object + /// Specifies the HTTP transport settings for the request + /// The ProvisioningServiceClient with the new instance of this object. + /// if the azureSasCredential is null public static ProvisioningServiceClient Create(string hostName, AzureSasCredential azureSasCredential, HttpTransportSettings httpTransportSettings) { if (azureSasCredential == null) From 3f22dc038c0d1aaef4276a5b6ea6f7c3fd55147f Mon Sep 17 00:00:00 2001 From: dylanbulfinMS <95251881+dylanbulfinMS@users.noreply.github.com> Date: Sun, 9 Jan 2022 16:12:35 -0500 Subject: [PATCH 6/8] refactored GetHeaderProvider --- .../src/Auth/ProvisioningTokenCredential.cs | 14 -------------- .../service/src/ProvisioningServiceClient.cs | 12 +++--------- 2 files changed, 3 insertions(+), 23 deletions(-) diff --git a/provisioning/service/src/Auth/ProvisioningTokenCredential.cs b/provisioning/service/src/Auth/ProvisioningTokenCredential.cs index 0d444b3281..93de3dd4f2 100644 --- a/provisioning/service/src/Auth/ProvisioningTokenCredential.cs +++ b/provisioning/service/src/Auth/ProvisioningTokenCredential.cs @@ -8,32 +8,19 @@ namespace Microsoft.Azure.Devices.Provisioning.Service.Auth { internal class ProvisioningTokenCredential : IAuthorizationHeaderProvider { -#if !NET451 private const string _tokenType = "Bearer"; private readonly TokenCredential _credential; private readonly object _tokenLock = new object(); private AccessToken? _cachedAccessToken; -#endif -#if NET451 - public ProvisioningTokenCredential() - { - throw new InvalidOperationException("TokenCredential is not supported on NET451"); - } -#else public ProvisioningTokenCredential(TokenCredential credential) { _credential = credential; } -#endif // The HTTP protocol uses this method to get the bearer token for authentication. public string GetAuthorizationHeader() { -#if NET451 - throw new InvalidOperationException($"TokenCredential is not supported on NET451"); - -#else lock (_tokenLock) { // A new token is generated if it is the first time or the cached token is close to expiry. @@ -47,7 +34,6 @@ public string GetAuthorizationHeader() } return $"{_tokenType} {_cachedAccessToken.Value.Token}"; -#endif } } } diff --git a/provisioning/service/src/ProvisioningServiceClient.cs b/provisioning/service/src/ProvisioningServiceClient.cs index 01c336dc68..5b19a45818 100644 --- a/provisioning/service/src/ProvisioningServiceClient.cs +++ b/provisioning/service/src/ProvisioningServiceClient.cs @@ -1497,15 +1497,9 @@ public Task GetEnrollmentGroupAttestationAsync(string enro internal IAuthorizationHeaderProvider GetHeaderProvider() { - if (_provisioningConnectionString != null) - { - return _provisioningConnectionString; - } - else if (_provisioningTokenCredential != null) - { - return _provisioningTokenCredential; - } - return _provisioningSasCredential; + return _provisioningConnectionString + ?? (IAuthorizationHeaderProvider) _provisioningTokenCredential + ?? _provisioningSasCredential; } } } From dc18aab5deb28e528de8bd48d22a58587e7cad98 Mon Sep 17 00:00:00 2001 From: dylanbulfinMS <95251881+dylanbulfinMS@users.noreply.github.com> Date: Mon, 10 Jan 2022 14:13:27 -0500 Subject: [PATCH 7/8] Added documentation --- provisioning/service/src/Auth/ProvisioningSasCredential.cs | 7 ++++++- .../service/src/Auth/ProvisioningTokenCredential.cs | 5 +++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/provisioning/service/src/Auth/ProvisioningSasCredential.cs b/provisioning/service/src/Auth/ProvisioningSasCredential.cs index 85a0148ec5..0c80e999b0 100644 --- a/provisioning/service/src/Auth/ProvisioningSasCredential.cs +++ b/provisioning/service/src/Auth/ProvisioningSasCredential.cs @@ -5,9 +5,14 @@ namespace Microsoft.Azure.Devices.Provisioning.Service.Auth { + /// + /// Allows authentication to the API using a Shared Access Key provided by custom implementation. + /// The PnP client is auto generated from swagger and needs to implement a specific class to pass to the protocol layer + /// unlike the rest of the clients which are hand-written. So, this implementation for authentication is specific to digital twin (Pnp). + /// internal class ProvisioningSasCredential: IAuthorizationHeaderProvider { - private AzureSasCredential _azureSasCredential; + private readonly AzureSasCredential _azureSasCredential; public ProvisioningSasCredential(AzureSasCredential azureSasCredential) { diff --git a/provisioning/service/src/Auth/ProvisioningTokenCredential.cs b/provisioning/service/src/Auth/ProvisioningTokenCredential.cs index 93de3dd4f2..db2aadff0e 100644 --- a/provisioning/service/src/Auth/ProvisioningTokenCredential.cs +++ b/provisioning/service/src/Auth/ProvisioningTokenCredential.cs @@ -6,6 +6,11 @@ namespace Microsoft.Azure.Devices.Provisioning.Service.Auth { + /// + /// Allows authentication to the API using a JWT token generated for Azure active directory. + /// The PnP client is auto generated from swagger and needs to implement a specific class to pass to the protocol layer + /// unlike the rest of the clients which are hand-written. so, this implementation for authentication is specific to digital twin (Pnp). + /// internal class ProvisioningTokenCredential : IAuthorizationHeaderProvider { private const string _tokenType = "Bearer"; From 6b1b9a6cb4b959b57b0055f67dade70dfa18e8c8 Mon Sep 17 00:00:00 2001 From: dylanbulfinMS <95251881+dylanbulfinMS@users.noreply.github.com> Date: Mon, 10 Jan 2022 15:15:17 -0500 Subject: [PATCH 8/8] Formatting fixes to address comments --- .../src/Auth/ProvisioningSasCredential.cs | 2 +- .../src/Auth/ProvisioningTokenCredential.cs | 5 ++- .../service/src/ProvisioningServiceClient.cs | 9 +++--- provisioning/service/src/Query.cs | 31 ------------------- 4 files changed, 7 insertions(+), 40 deletions(-) diff --git a/provisioning/service/src/Auth/ProvisioningSasCredential.cs b/provisioning/service/src/Auth/ProvisioningSasCredential.cs index 0c80e999b0..c003148f6c 100644 --- a/provisioning/service/src/Auth/ProvisioningSasCredential.cs +++ b/provisioning/service/src/Auth/ProvisioningSasCredential.cs @@ -8,7 +8,7 @@ namespace Microsoft.Azure.Devices.Provisioning.Service.Auth /// /// Allows authentication to the API using a Shared Access Key provided by custom implementation. /// The PnP client is auto generated from swagger and needs to implement a specific class to pass to the protocol layer - /// unlike the rest of the clients which are hand-written. So, this implementation for authentication is specific to digital twin (Pnp). + /// unlike the rest of the clients which are hand-written. So, this implementation for authentication is specific to digital twin (PnP). /// internal class ProvisioningSasCredential: IAuthorizationHeaderProvider { diff --git a/provisioning/service/src/Auth/ProvisioningTokenCredential.cs b/provisioning/service/src/Auth/ProvisioningTokenCredential.cs index db2aadff0e..fe05a70ae6 100644 --- a/provisioning/service/src/Auth/ProvisioningTokenCredential.cs +++ b/provisioning/service/src/Auth/ProvisioningTokenCredential.cs @@ -9,11 +9,10 @@ namespace Microsoft.Azure.Devices.Provisioning.Service.Auth /// /// Allows authentication to the API using a JWT token generated for Azure active directory. /// The PnP client is auto generated from swagger and needs to implement a specific class to pass to the protocol layer - /// unlike the rest of the clients which are hand-written. so, this implementation for authentication is specific to digital twin (Pnp). + /// unlike the rest of the clients which are hand-written. so, this implementation for authentication is specific to digital twin (PnP). /// internal class ProvisioningTokenCredential : IAuthorizationHeaderProvider { - private const string _tokenType = "Bearer"; private readonly TokenCredential _credential; private readonly object _tokenLock = new object(); private AccessToken? _cachedAccessToken; @@ -38,7 +37,7 @@ public string GetAuthorizationHeader() } } - return $"{_tokenType} {_cachedAccessToken.Value.Token}"; + return $"Bearer {_cachedAccessToken.Value.Token}"; } } } diff --git a/provisioning/service/src/ProvisioningServiceClient.cs b/provisioning/service/src/ProvisioningServiceClient.cs index 5b19a45818..216627b733 100644 --- a/provisioning/service/src/ProvisioningServiceClient.cs +++ b/provisioning/service/src/ProvisioningServiceClient.cs @@ -5,11 +5,10 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -using Microsoft.Azure.Devices.Common.Service.Auth; -using Microsoft.Azure.Devices.Provisioning.Service.Auth; - using Azure; using Azure.Core; +using Microsoft.Azure.Devices.Common.Service.Auth; +using Microsoft.Azure.Devices.Provisioning.Service.Auth; namespace Microsoft.Azure.Devices.Provisioning.Service { @@ -140,7 +139,7 @@ public static ProvisioningServiceClient Create(string hostName, TokenCredential { if (credential == null) { - throw new ArgumentNullException($"{nameof(credential)}, Parameter cannot be null"); + throw new ArgumentNullException(nameof(credential), "Parameter cannot be null"); } return new ProvisioningServiceClient(hostName, credential, httpTransportSettings); @@ -174,7 +173,7 @@ public static ProvisioningServiceClient Create(string hostName, AzureSasCredenti { if (azureSasCredential == null) { - throw new ArgumentNullException($"{nameof(azureSasCredential)}, Parameter cannot be null"); + throw new ArgumentNullException(nameof(azureSasCredential), "Parameter cannot be null"); } return new ProvisioningServiceClient(hostName, azureSasCredential, httpTransportSettings); diff --git a/provisioning/service/src/Query.cs b/provisioning/service/src/Query.cs index beac287207..183556ec06 100644 --- a/provisioning/service/src/Query.cs +++ b/provisioning/service/src/Query.cs @@ -75,54 +75,43 @@ internal Query( int pageSize, CancellationToken cancellationToken) { - /* SRS_QUERY_21_001: [The constructor shall throw ArgumentNullException if the provided serviceConnectionString is null.] */ if (serviceConnectionString == null) { throw new ArgumentNullException(nameof(serviceConnectionString)); } - /* SRS_QUERY_21_002: [The constructor shall throw ArgumentException if the provided serviceName is null or empty.] */ if (string.IsNullOrWhiteSpace(serviceName ?? throw new ArgumentNullException(nameof(serviceName)))) { throw new ArgumentException($"{nameof(serviceName)} cannot be an empty string"); } - /* SRS_QUERY_21_003: [The constructor shall throw ArgumentException if the provided querySpecification is null.] */ if (querySpecification == null) { throw new ArgumentNullException(nameof(querySpecification)); } - /* SRS_QUERY_21_004: [The constructor shall throw ArgumentException if the provided pageSize is negative.] */ if (pageSize < 0) { throw new ArgumentException($"{nameof(pageSize)} cannot be negative."); } // TODO: Refactor ContractApiHttp being created again - /* SRS_QUERY_21_005: [The constructor shall create and store a `contractApiHttp` using the provided Service Connection String.] */ _contractApiHttp = new ContractApiHttp( serviceConnectionString.HttpsEndpoint, serviceConnectionString, httpTransportSettings); - /* SRS_QUERY_21_006: [The constructor shall store the provided `pageSize`, and `cancelationToken`.] */ PageSize = pageSize; _cancellationToken = cancellationToken; - /* SRS_QUERY_21_007: [The constructor shall create and store a JSON from the provided querySpecification.] */ _querySpecificationJson = JsonConvert.SerializeObject(querySpecification); - /* SRS_QUERY_21_008: [The constructor shall create and store a queryPath adding `/query` to the provided `targetPath`.] */ _queryPath = GetQueryUri(serviceName); - /* SRS_QUERY_21_009: [The constructor shall set continuationToken and current as null.] */ ContinuationToken = null; - /* SRS_QUERY_21_010: [The constructor shall set hasNext as true.] */ _hasNext = true; } -#if !NET451 internal Query( string hostName, IAuthorizationHeaderProvider headerProvider, @@ -132,53 +121,42 @@ internal Query( int pageSize, CancellationToken cancellationToken) { - /* SRS_QUERY_21_001: [The constructor shall throw ArgumentNullException if the provided path is null.] */ if (hostName == null) { throw new ArgumentNullException(nameof(hostName)); } - /* SRS_QUERY_21_002: [The constructor shall throw ArgumentException if the provided serviceName is null or empty.] */ if (string.IsNullOrWhiteSpace(serviceName ?? throw new ArgumentNullException(nameof(serviceName)))) { throw new ArgumentException($"{nameof(serviceName)} cannot be an empty string"); } - /* SRS_QUERY_21_003: [The constructor shall throw ArgumentException if the provided querySpecification is null.] */ if (querySpecification == null) { throw new ArgumentNullException(nameof(querySpecification)); } - /* SRS_QUERY_21_004: [The constructor shall throw ArgumentException if the provided pageSize is negative.] */ if (pageSize < 0) { throw new ArgumentException($"{nameof(pageSize)} cannot be negative."); } // TODO: Refactor ContractApiHttp being created again - /* SRS_QUERY_21_005: [The constructor shall create and store a `contractApiHttp` using the provided path and Authorization Header Provider.] */ _contractApiHttp = new ContractApiHttp( new UriBuilder("https", hostName).Uri, headerProvider, httpTransportSettings); - /* SRS_QUERY_21_006: [The constructor shall store the provided `pageSize`, and `cancelationToken`.] */ PageSize = pageSize; _cancellationToken = cancellationToken; - /* SRS_QUERY_21_007: [The constructor shall create and store a JSON from the provided querySpecification.] */ _querySpecificationJson = JsonConvert.SerializeObject(querySpecification); - /* SRS_QUERY_21_008: [The constructor shall create and store a queryPath adding `/query` to the provided `targetPath`.] */ _queryPath = GetQueryUri(serviceName); - /* SRS_QUERY_21_009: [The constructor shall set continuationToken and current as null.] */ ContinuationToken = null; - /* SRS_QUERY_21_010: [The constructor shall set hasNext as true.] */ _hasNext = true; } -#endif /// /// Getter for has next @@ -213,17 +191,14 @@ public bool HasNext() /// if the query does no have more pages to return. public async Task NextAsync(string continuationToken) { - /* SRS_QUERY_21_011: [The next shall throw IndexOutOfRangeException if the provided continuationToken is null or empty.] */ if (string.IsNullOrWhiteSpace(continuationToken)) { throw new IndexOutOfRangeException($"There is no {nameof(continuationToken)} to get pending elements."); } - /* SRS_QUERY_21_012: [The next shall store the provided continuationToken.] */ ContinuationToken = continuationToken; _hasNext = true; - /* SRS_QUERY_21_013: [The next shall return the next page of results by calling the next().] */ return await NextAsync().ConfigureAwait(false); } @@ -234,25 +209,21 @@ public async Task NextAsync(string continuationToken) /// if the query does no have more pages to return. public async Task NextAsync() { - /* SRS_QUERY_21_014: [The next shall throw IndexOutOfRangeException if the hasNext is false.] */ if (!_hasNext) { throw new IndexOutOfRangeException("There are no more pending elements"); } - /* SRS_QUERY_21_015: [If the pageSize is not 0, the next shall send the HTTP request with `x-ms-max-item-count=[pageSize]` in the header.] */ IDictionary headerParameters = new Dictionary(); if (PageSize != 0) { headerParameters.Add(PageSizeHeaderKey, PageSize.ToString(CultureInfo.InvariantCulture)); } - /* SRS_QUERY_21_016: [If the continuationToken is not null or empty, the next shall send the HTTP request with `x-ms-continuation=[continuationToken]` in the header.] */ if (!string.IsNullOrWhiteSpace(ContinuationToken)) { headerParameters.Add(ContinuationTokenHeaderKey, ContinuationToken); } - /* SRS_QUERY_21_017: [The next shall send a HTTP request with a HTTP verb `POST`.] */ ContractApiResponse httpResponse = await _contractApiHttp.RequestAsync( HttpMethod.Post, _queryPath, @@ -261,12 +232,10 @@ public async Task NextAsync() null, _cancellationToken).ConfigureAwait(false); - /* SRS_QUERY_21_018: [The next shall create and return a new instance of the QueryResult using the `x-ms-item-type` as type, `x-ms-continuation` as the next continuationToken, and the message body.] */ httpResponse.Fields.TryGetValue(ItemTypeHeaderKey, out string type); httpResponse.Fields.TryGetValue(ContinuationTokenHeaderKey, out string continuationToken); ContinuationToken = continuationToken; - /* SRS_QUERY_21_017: [The next shall set hasNext as true if the continuationToken is not null, or false if it is null.] */ _hasNext = (ContinuationToken != null); var result = new QueryResult(type, httpResponse.Body, ContinuationToken);