Skip to content

Commit

Permalink
Merge pull request #2195 from Azure/abmisr/mergeFromMaster
Browse files Browse the repository at this point in the history
Bring updates from main to preview feature branch
  • Loading branch information
abhipsaMisra authored Oct 7, 2021
2 parents 900717a + 90622b6 commit 469ba65
Show file tree
Hide file tree
Showing 122 changed files with 1,381 additions and 886 deletions.
2 changes: 1 addition & 1 deletion .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# Track1 .NET Azure IoT Hub and DPS SDKs

* @drwill-ms @timtay-microsoft @abhipsaMisra @vinagesh @azabbasi @jamdavi
* @drwill-ms @timtay-microsoft @abhipsaMisra @azabbasi @jamdavi @andykwong-ms
18 changes: 9 additions & 9 deletions .github/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,13 @@ That is definitely something we want to hear about. Please open an issue on gith

## Contribute documentation

For simple markdown files, we accept documentation pull requests submitted against the `master` branch, if it's about existing SDK features.
For simple markdown files, we accept documentation pull requests submitted against the `main` branch, if it's about existing SDK features.
If your PR is about future changes or has changes to the comments in the code itself, we'll treat is as a code change (see the next section).

## Contribute code
Our SDKs are open-source and we do accept pull-requests if you feel like taking a stab at fixing the bug and maybe adding your name to our commit history :) Please mention any relevant issue number in the pull request description, and follow the contributing guidelines [below](#contributing-guidelines).

Pull-requests for code are to be submitted against the `master` branch. We will review the request and once approved we will be running it in our gated build system. We try to maintain a high bar for code quality and maintainability, we insist on having tests associated with the code, and if necessary, additions/modifications to the requirement documents.
Pull-requests for code are to be submitted against the `main` branch. We will review the request and once approved we will be running it in our gated build system. We try to maintain a high bar for code quality and maintainability, we insist on having tests associated with the code, and if necessary, additions/modifications to the requirement documents.

Also, have you signed the [Contribution License Agreement](https://cla.microsoft.com/) ([CLA](https://cla.microsoft.com/))? A friendly bot will remind you about it when you submit your pull-request.

Expand All @@ -44,9 +44,9 @@ sure your plans and ours are in sync :) Just open an issue on github and tag it
1. If the change affects the public API, extract the updated public API surface and submit a PR for review. Make sure you get a signoff before you move to Step 2.
2. Post API surface approval, follow the below guidelines for contributing code:

a) Follow the steps [here](https://github.com/Azure/azure-iot-sdk-csharp/blob/master/doc/devbox_setup.md) for setting up your development environment.
a) Follow the steps [here](https://github.com/Azure/azure-iot-sdk-csharp/blob/main/doc/devbox_setup.md) for setting up your development environment.

b) Follow the [C# Coding Style](https://github.com/Azure/azure-iot-sdk-csharp/blob/master/doc/coding-style.md).
b) Follow the [C# Coding Style](https://github.com/Azure/azure-iot-sdk-csharp/blob/main/doc/coding-style.md).

c) Unit Tests:
We write unit tests for any new function or block of application code that impacts the existing behavior of the code.
Expand All @@ -73,9 +73,9 @@ sure your plans and ours are in sync :) Just open an issue on github and tag it
```
d) E2E Tests:
Any new feature or functionality added must have associated end-to-end tests.
1. Update/ Add the E2E tests [here](https://github.com/Azure/azure-iot-sdk-csharp/tree/master/e2e/test).
2. In case environmental setup required for the application is changed, update the pre-requisites [here](https://github.com/Azure/azure-iot-sdk-csharp/tree/master/e2e/test/prerequisites).
3. Run the E2E test suite and ensure that all the tests pass successfully. You can also test against the [CI script](https://github.com/Azure/azure-iot-sdk-csharp/blob/master/jenkins/windows_csharp.cmd) that is used in our gated build system.
1. Update/ Add the E2E tests [here](https://github.com/Azure/azure-iot-sdk-csharp/tree/main/e2e/test).
2. In case environmental setup required for the application is changed, update the pre-requisites [here](https://github.com/Azure/azure-iot-sdk-csharp/tree/main/e2e/test/prerequisites).
3. Run the E2E test suite and ensure that all the tests pass successfully. You can also test against the [CI script](https://github.com/Azure/azure-iot-sdk-csharp/blob/main/jenkins/windows_csharp.cmd) that is used in our gated build system.
e) Samples:
Add relevant samples to the [Azure IoT Samples for C# Repo](https://github.com/Azure-Samples/azure-iot-samples-csharp). Make sure to add a supporting readme file demonstrating the steps to run the sample.
Expand All @@ -100,7 +100,7 @@ sure your plans and ours are in sync :) Just open an issue on github and tag it
}
}
```
3. Post completion of all of the above steps, create a PR against `master`.
3. Post completion of all of the above steps, create a PR against `main`.
#### Commit Guidelines
We have very precise rules over how our git commit messages can be formatted. This leads to more readable messages that are easy to follow when looking through the project history.
Expand Down Expand Up @@ -130,7 +130,7 @@ If the commit reverts a previous commit, it should begin with `revert:`, followe

**Rebase and Squash**

* Its manadatory to squash all your commits per scope (i.e package). It is also important to rebase your commits on master.
* Its manadatory to squash all your commits per scope (i.e package). It is also important to rebase your commits on `main`.
* Optionally you can split your commits on the basis of the package you are providing code to.

**Type**
Expand Down
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,5 @@ Please use your Azure subscription if you need to share any information from you

## Console log of the issue:
<!-- Please share logs as possible, that will help debugging. -->
<!-- See https://github.com/Azure/azure-iot-sdk-csharp/tree/master/tools/CaptureLogs and
<!-- See https://github.com/Azure/azure-iot-sdk-csharp/tree/main/tools/CaptureLogs and
https://github.com/dotnet/corefx/blob/master/Documentation/debugging/windows-instructions.md#traces -->
4 changes: 2 additions & 2 deletions .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ Please follow the instructions and template below to save us time requesting add
4. Include enough information for us to address the bug:
- A detailed description.
- A [Minimal Complete Reproducible Example](https://stackoverflow.com/help/mcve). This is code we can cut and paste into a readily available sample and run, or a link to a project you've written that we can compile to reproduce the bug.
- Console logs (https://github.com/Azure/azure-iot-sdk-csharp/tree/master/tools/CaptureLogs).
- Console logs (https://github.com/Azure/azure-iot-sdk-csharp/tree/main/tools/CaptureLogs).

5. Delete these instructions before submitting the bug.

Expand All @@ -51,5 +51,5 @@ Please be as detailed as possible: which feature has a problem, how often does i
Please remove any connection string information!

## Console log of the issue
Consider setting the DEBUG environment variable to '*'. This will produce a much more verbose output that will help debugging
Follow the instructions [here](https://github.com/Azure/azure-iot-sdk-csharp/tree/main/tools/CaptureLogs) to capture SDK logs.
Don't forget to remove any connection string information!
6 changes: 3 additions & 3 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ Need support?
-->

## Checklist
- [ ] I have read the [contribution guidelines](https://github.com/Azure/azure-iot-sdk-csharp/blob/master/.github/CONTRIBUTING.md).
- [ ] I have read the [contribution guidelines](https://github.com/Azure/azure-iot-sdk-csharp/blob/main/.github/CONTRIBUTING.md).
- [ ] I added or modified the existing tests to cover the change (we do not allow our test coverage to go down).
- [ ] This pull-request is submitted against the `master` branch.
<!-- If not against master, please add the reason. -->
- [ ] This pull-request is submitted against the `main` branch.
<!-- If not against main, please add the reason. -->

## Description of the changes
<!-- Itemized list of changes. -->
Expand Down
65 changes: 65 additions & 0 deletions common/src/HttpContentExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System.IO;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;

namespace Microsoft.Azure.Devices.Shared
{
/// <summary>
/// Extensions added to simplify the usage of <see cref="HttpContent"/> APIs based on the .NET implementation used.
/// </summary>
internal static class HttpContentExtensions
{
internal static async Task CopyToStreamAsync(this HttpContent content, Stream stream, CancellationToken cancellationToken)
{
#if NET5_0
await content.CopyToAsync(stream, cancellationToken).ConfigureAwait(false);
#else
// .NET implementations < .NET 5.0 do not support CancellationTokens for HttpContent APIs, so we will discard it.
_ = cancellationToken;

await content.CopyToAsync(stream).ConfigureAwait(false);
#endif
}

internal static Task<Stream> ReadHttpContentAsStream(this HttpContent httpContent, CancellationToken cancellationToken)
{
#if NET5_0
return httpContent.ReadAsStreamAsync(cancellationToken);
#else
// .NET implementations < .NET 5.0 do not support CancellationTokens for HttpContent APIs, so we will discard it.
_ = cancellationToken;

return httpContent.ReadAsStreamAsync();
#endif
}

internal static Task<byte[]> ReadHttpContentAsByteArrayAsync(this HttpContent content, CancellationToken cancellationToken)
{
#if NET5_0
return content.ReadAsByteArrayAsync(cancellationToken);
#else
// .NET implementations < .NET 5.0 do not support CancellationTokens for HttpContent APIs, so we will discard it.
_ = cancellationToken;

return content.ReadAsByteArrayAsync();
#endif
}

internal static Task<string> ReadHttpContentAsStringAsync(this HttpContent content, CancellationToken cancellationToken)
{
#if NET5_0
return content.ReadAsStringAsync(cancellationToken);
#else
// .NET implementations < .NET 5.0 do not support CancellationTokens for HttpContent APIs, so we will discard it.
_ = cancellationToken;

return content.ReadAsStringAsync();
#endif
}

}
}
35 changes: 35 additions & 0 deletions common/src/HttpMessageHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System.Net.Http;
using System.Text;
using Newtonsoft.Json;

#if NET451
using System.Net.Http.Formatting;
#endif

namespace Microsoft.Azure.Devices.Shared
{
/// <summary>
/// A helper class to simplify operations with Http messages based on the .NET implementation used.
/// </summary>
internal static class HttpMessageHelper
{
#if NET451
private static readonly JsonMediaTypeFormatter s_jsonFormatter = new JsonMediaTypeFormatter();
#else
private const string ApplicationJson = "application/json";
#endif

internal static void SetHttpRequestMessageContent<T>(HttpRequestMessage requestMessage, T entity)
{
#if NET451
requestMessage.Content = new ObjectContent<T>(entity, s_jsonFormatter);
#else
string str = JsonConvert.SerializeObject(entity);
requestMessage.Content = new StringContent(str, Encoding.UTF8, ApplicationJson);
#endif
}
}
}
24 changes: 24 additions & 0 deletions common/src/StreamExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System.IO;
using System.Threading;
using System.Threading.Tasks;

namespace Microsoft.Azure.Devices.Shared
{
/// <summary>
/// Extensions added to simplify the usage of <see cref="Stream"/> APIs based on the .NET implementation used.
/// </summary>
internal static class StreamExtensions
{
internal static async Task WriteToStreamAsync(this Stream stream, byte[] requestBytes, CancellationToken cancellationToken)
{
#if NET451 || NET472 || NETSTANDARD2_0
await stream.WriteAsync(requestBytes, 0, requestBytes.Length, cancellationToken).ConfigureAwait(false);
#else
await stream.WriteAsync(requestBytes, cancellationToken).ConfigureAwait(false);
#endif
}
}
}
27 changes: 27 additions & 0 deletions common/src/TaskCompletionSource.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// 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.Tasks;

namespace Microsoft.Azure.Devices.Shared
{
/// <summary>
/// A <see cref="TaskCompletionSource{boolean}"/> implementation that returns a <see cref="Task"/> when completed.
/// </summary>
/// <remarks>
/// Represents the producer side of a <see cref="Task"/> unbound to a delegate, providing access to the consumer side through the <see cref="Task"/> property.
/// This is used for .NET implementations lower than .NET 5.0, which lack a native implementation of the non-generic TaskCompletionSource.
/// </remarks>
internal sealed class TaskCompletionSource : TaskCompletionSource<bool>
{
public TaskCompletionSource()
{
}

public bool TrySetResult() => TrySetResult(true);

public void SetResult() => SetResult(true);

public override string ToString() => $"TaskCompletionSource[status: {Task.Status}]";
}
}
59 changes: 14 additions & 45 deletions common/src/service/HttpClientHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Azure.Devices.Common;
Expand All @@ -19,19 +18,13 @@
using Microsoft.Azure.Devices.Shared;
using Newtonsoft.Json;

#if NET451
using System.Net.Http.Formatting;
#endif
using static Microsoft.Azure.Devices.Shared.HttpMessageHelper;

namespace Microsoft.Azure.Devices
{
internal sealed class HttpClientHelper : IHttpClientHelper
{
private const string ApplicationJson = "application/json";

#if NET451
static readonly JsonMediaTypeFormatter JsonFormatter = new JsonMediaTypeFormatter();
#endif
private readonly Uri _baseAddress;
private readonly IAuthorizationHeaderProvider _authenticationHeaderProvider;
private readonly IReadOnlyDictionary<HttpStatusCode, Func<HttpResponseMessage, Task<Exception>>> _defaultErrorMapping;
Expand Down Expand Up @@ -179,12 +172,8 @@ await ExecuteAsync(
(requestMsg, token) =>
{
InsertEtag(requestMsg, entity, operationType);
#if NET451
requestMsg.Content = new ObjectContent<T>(entity, JsonFormatter);
#else
string str = JsonConvert.SerializeObject(entity);
requestMsg.Content = new StringContent(str, Encoding.UTF8, ApplicationJson);
#endif
SetHttpRequestMessageContent(requestMsg, entity);

return Task.FromResult(0);
},
async (httpClient, token) => result = await ReadResponseMessageAsync<T>(httpClient, token).ConfigureAwait(false),
Expand All @@ -208,12 +197,7 @@ await ExecuteAsync(
new Uri(_baseAddress, requestUri),
(requestMsg, token) =>
{
#if NET451
requestMsg.Content = new ObjectContent<T>(entity, JsonFormatter);
#else
string str = JsonConvert.SerializeObject(entity);
requestMsg.Content = new StringContent(str, System.Text.Encoding.UTF8, ApplicationJson);
#endif
SetHttpRequestMessageContent<T>(requestMsg, entity);
return Task.FromResult(0);
},
async (httpClient, token) => result = await ReadResponseMessageAsync<T2>(httpClient, token).ConfigureAwait(false),
Expand All @@ -237,12 +221,8 @@ await ExecuteAsync(
(requestMsg, token) =>
{
InsertEtag(requestMsg, etag, operationType);
#if NET451
requestMsg.Content = new ObjectContent<T>(entity, JsonFormatter);
#else
string str = Newtonsoft.Json.JsonConvert.SerializeObject(entity);
requestMsg.Content = new StringContent(str, System.Text.Encoding.UTF8, ApplicationJson);
#endif
SetHttpRequestMessageContent<T>(requestMsg, entity);

return Task.FromResult(0);
},
null,
Expand All @@ -267,12 +247,8 @@ await ExecuteAsync(
{
// TODO: skintali: Use string etag when service side changes are ready
InsertEtag(requestMsg, etag, operationType);
#if NET451
requestMsg.Content = new ObjectContent<T>(entity, JsonFormatter);
#else
string str = JsonConvert.SerializeObject(entity);
requestMsg.Content = new StringContent(str, Encoding.UTF8, ApplicationJson);
#endif
SetHttpRequestMessageContent<T>(requestMsg, entity);

return Task.FromResult(0);
},
async (httpClient, token) => result = await ReadResponseMessageAsync<T2>(httpClient, token).ConfigureAwait(false),
Expand All @@ -291,12 +267,8 @@ await ExecuteAsync(
(requestMsg, token) =>
{
InsertEtag(requestMsg, etag, PutOperationType.UpdateEntity);
#if NET451
requestMsg.Content = new ObjectContent<T>(entity, JsonFormatter);
#else
string str = JsonConvert.SerializeObject(entity);
requestMsg.Content = new StringContent(str, Encoding.UTF8, ApplicationJson);
#endif
SetHttpRequestMessageContent<T>(requestMsg, entity);

return Task.FromResult(0);
},
null,
Expand All @@ -317,12 +289,8 @@ await ExecuteAsync(
(requestMsg, token) =>
{
InsertEtag(requestMsg, etag, putOperationType);
#if NET451
requestMsg.Content = new ObjectContent<T>(entity, JsonFormatter);
#else
string str = JsonConvert.SerializeObject(entity);
requestMsg.Content = new StringContent(str, System.Text.Encoding.UTF8, ApplicationJson);
#endif
SetHttpRequestMessageContent<T>(requestMsg, entity);

return Task.FromResult(0);
},
async (httpClient, token) => result = await ReadResponseMessageAsync<T2>(httpClient, token).ConfigureAwait(false),
Expand All @@ -342,9 +310,10 @@ private static async Task<T> ReadResponseMessageAsync<T>(HttpResponseMessage mes
#if NET451
T entity = await message.Content.ReadAsAsync<T>(token).ConfigureAwait(false);
#else
string str = await message.Content.ReadAsStringAsync().ConfigureAwait(false);
string str = await message.Content.ReadHttpContentAsStringAsync(token).ConfigureAwait(false);
T entity = JsonConvert.DeserializeObject<T>(str);
#endif

// Etag in the header is considered authoritative
var eTagHolder = entity as IETagHolder;
if (eTagHolder != null)
Expand Down
Loading

0 comments on commit 469ba65

Please sign in to comment.