Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge previews/mockclients to master #2117

Merged
merged 7 commits into from
Jul 21, 2021
419 changes: 0 additions & 419 deletions iothub/service/src/AmqpServiceClient.cs

This file was deleted.

122 changes: 65 additions & 57 deletions iothub/service/src/DigitalTwin/DigitalTwinClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,60 +27,12 @@ public class DigitalTwinClient : IDisposable
private readonly IotHubGatewayServiceAPIs _client;
private readonly PnpDigitalTwin _protocolLayer;

private DigitalTwinClient(string hostName, DigitalTwinServiceClientCredentials credentials, params DelegatingHandler[] handlers)
{
var httpsEndpoint = new UriBuilder(HttpsEndpointPrefix, hostName).Uri;
var httpMessageHandler = HttpClientHelper.CreateDefaultHttpMessageHandler(null, httpsEndpoint, ServicePointHelpers.DefaultConnectionLeaseTimeout);
#pragma warning disable CA2000 // Dispose objects before losing scope (httpMessageHandlerWithDelegatingHandlers is disposed when the http client owning it is disposed)
HttpMessageHandler httpMessageHandlerWithDelegatingHandlers = CreateHttpHandlerPipeline(httpMessageHandler, handlers);
#pragma warning restore CA2000 // Dispose objects before losing scope

#pragma warning disable CA2000 // Dispose objects before losing scope (httpClient is disposed when the protocol layer client owning it is disposed)
var httpClient = new HttpClient(httpMessageHandlerWithDelegatingHandlers, true)
{
BaseAddress = httpsEndpoint
};
#pragma warning restore CA2000 // Dispose objects before losing scope

#pragma warning restore CA2000 // Dispose objects before losing scope

// When this client is disposed, all the http message handlers and delegating handlers will be disposed automatically
_client = new IotHubGatewayServiceAPIs(credentials, httpClient, true);
_client.BaseUri = httpsEndpoint;
_protocolLayer = new PnpDigitalTwin(_client);
}

// Creates a single HttpMessageHandler to construct a HttpClient with from a base httpMessageHandler and some number of custom delegating handlers
// This is almost a copy of the Microsoft.Rest.ClientRuntime library's implementation, but with the return and parameter type HttpClientHandler replaced
// with the more abstract HttpMessageHandler in order for us to set the base handler as either a SocketsHttpHandler for .net core or an HttpClientHandler otherwise
// https://github.com/Azure/azure-sdk-for-net/blob/99f4da88ab0aa01c79aa291c6c101ab94c4ac940/sdk/mgmtcommon/ClientRuntime/ClientRuntime/ServiceClient.cs#L376
private static HttpMessageHandler CreateHttpHandlerPipeline(HttpMessageHandler httpMessageHandler, params DelegatingHandler[] handlers)
/// <summary>
/// Creates an instance of <see cref="DigitalTwinClient"/>, provided for unit testing purposes only.
/// Use the CreateFromConnectionString or Create method to create an instance to use the client.
/// </summary>
public DigitalTwinClient()
{
// The RetryAfterDelegatingHandler should be the absolute outermost handler
// because it's extremely lightweight and non-interfering
HttpMessageHandler currentHandler =
#pragma warning disable CA2000 // Dispose objects before losing scope (delegating handler is disposed when the http client that uses it is disposed)
new RetryDelegatingHandler(new RetryAfterDelegatingHandler { InnerHandler = httpMessageHandler });
#pragma warning restore CA2000 // Dispose objects before losing scope

if (handlers != null)
{
for (int i = handlers.Length - 1; i >= 0; --i)
{
DelegatingHandler handler = handlers[i];
// Non-delegating handlers are ignored since we always
// have RetryDelegatingHandler as the outer-most handler
while (handler.InnerHandler is DelegatingHandler)
{
handler = handler.InnerHandler as DelegatingHandler;
}

handler.InnerHandler = currentHandler;
currentHandler = handlers[i];
}
}

return currentHandler;
}

/// <summary>
Expand Down Expand Up @@ -157,7 +109,7 @@ public static DigitalTwinClient CreateFromConnectionString(string connectionStri
/// <param name="digitalTwinId">The Id of the digital twin.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>The application/json digital twin and the http response.</returns>
public async Task<HttpOperationResponse<T, DigitalTwinGetHeaders>> GetDigitalTwinAsync<T>(string digitalTwinId, CancellationToken cancellationToken = default)
public virtual async Task<HttpOperationResponse<T, DigitalTwinGetHeaders>> GetDigitalTwinAsync<T>(string digitalTwinId, CancellationToken cancellationToken = default)
{
using HttpOperationResponse<string, DigitalTwinGetHeaders> response = await _protocolLayer.GetDigitalTwinWithHttpMessagesAsync(digitalTwinId, null, cancellationToken)
.ConfigureAwait(false);
Expand All @@ -179,7 +131,7 @@ public static DigitalTwinClient CreateFromConnectionString(string connectionStri
/// <param name="requestOptions">The optional settings for this request.</param>
/// <param name="cancellationToken">The cancellationToken.</param>
/// <returns>The http response.</returns>
public Task<HttpOperationHeaderResponse<DigitalTwinUpdateHeaders>> UpdateDigitalTwinAsync(
public virtual Task<HttpOperationHeaderResponse<DigitalTwinUpdateHeaders>> UpdateDigitalTwinAsync(
string digitalTwinId,
string digitalTwinUpdateOperations,
DigitalTwinUpdateRequestOptions requestOptions = default,
Expand All @@ -197,7 +149,7 @@ public static DigitalTwinClient CreateFromConnectionString(string connectionStri
/// <param name="requestOptions">The optional settings for this request.</param>
/// <param name="cancellationToken">The cancellationToken.</param>
/// <returns>The application/json command invocation response and the http response. </returns>
public async Task<HttpOperationResponse<DigitalTwinCommandResponse, DigitalTwinInvokeCommandHeaders>> InvokeCommandAsync(
public virtual async Task<HttpOperationResponse<DigitalTwinCommandResponse, DigitalTwinInvokeCommandHeaders>> InvokeCommandAsync(
string digitalTwinId,
string commandName,
string payload = default,
Expand Down Expand Up @@ -232,7 +184,7 @@ public static DigitalTwinClient CreateFromConnectionString(string connectionStri
/// <param name="requestOptions">The optional settings for this request.</param>
/// <param name="cancellationToken">The cancellationToken.</param>
/// <returns>The application/json command invocation response and the http response. </returns>
public async Task<HttpOperationResponse<DigitalTwinCommandResponse, DigitalTwinInvokeCommandHeaders>> InvokeComponentCommandAsync(
public virtual async Task<HttpOperationResponse<DigitalTwinCommandResponse, DigitalTwinInvokeCommandHeaders>> InvokeComponentCommandAsync(
string digitalTwinId,
string componentName,
string commandName,
Expand Down Expand Up @@ -274,5 +226,61 @@ protected virtual void Dispose(bool disposing)
{
_client?.Dispose();
}

private DigitalTwinClient(string hostName, DigitalTwinServiceClientCredentials credentials, params DelegatingHandler[] handlers)
{
var httpsEndpoint = new UriBuilder(HttpsEndpointPrefix, hostName).Uri;
var httpMessageHandler = HttpClientHelper.CreateDefaultHttpMessageHandler(null, httpsEndpoint, ServicePointHelpers.DefaultConnectionLeaseTimeout);
#pragma warning disable CA2000 // Dispose objects before losing scope (httpMessageHandlerWithDelegatingHandlers is disposed when the http client owning it is disposed)
HttpMessageHandler httpMessageHandlerWithDelegatingHandlers = CreateHttpHandlerPipeline(httpMessageHandler, handlers);
#pragma warning restore CA2000 // Dispose objects before losing scope

#pragma warning disable CA2000 // Dispose objects before losing scope (httpClient is disposed when the protocol layer client owning it is disposed)
var httpClient = new HttpClient(httpMessageHandlerWithDelegatingHandlers, true)
{
BaseAddress = httpsEndpoint
};
#pragma warning restore CA2000 // Dispose objects before losing scope

#pragma warning restore CA2000 // Dispose objects before losing scope

// When this client is disposed, all the http message handlers and delegating handlers will be disposed automatically
_client = new IotHubGatewayServiceAPIs(credentials, httpClient, true);
_client.BaseUri = httpsEndpoint;
_protocolLayer = new PnpDigitalTwin(_client);
}

// Creates a single HttpMessageHandler to construct a HttpClient with from a base httpMessageHandler and some number of custom delegating handlers
// This is almost a copy of the Microsoft.Rest.ClientRuntime library's implementation, but with the return and parameter type HttpClientHandler replaced
// with the more abstract HttpMessageHandler in order for us to set the base handler as either a SocketsHttpHandler for .net core or an HttpClientHandler otherwise
// https://github.com/Azure/azure-sdk-for-net/blob/99f4da88ab0aa01c79aa291c6c101ab94c4ac940/sdk/mgmtcommon/ClientRuntime/ClientRuntime/ServiceClient.cs#L376
private static HttpMessageHandler CreateHttpHandlerPipeline(HttpMessageHandler httpMessageHandler, params DelegatingHandler[] handlers)
{
// The RetryAfterDelegatingHandler should be the absolute outermost handler
// because it's extremely lightweight and non-interfering
HttpMessageHandler currentHandler =
#pragma warning disable CA2000 // Dispose objects before losing scope (delegating handler is disposed when the http client that uses it is disposed)
new RetryDelegatingHandler(new RetryAfterDelegatingHandler { InnerHandler = httpMessageHandler });
#pragma warning restore CA2000 // Dispose objects before losing scope

if (handlers != null)
{
for (int i = handlers.Length - 1; i >= 0; --i)
{
DelegatingHandler handler = handlers[i];
// Non-delegating handlers are ignored since we always
// have RetryDelegatingHandler as the outer-most handler
while (handler.InnerHandler is DelegatingHandler)
{
handler = handler.InnerHandler as DelegatingHandler;
}

handler.InnerHandler = currentHandler;
currentHandler = handlers[i];
}
}

return currentHandler;
}
}
}