From 8796c0e8c375857cf2768cad03b488e159f03164 Mon Sep 17 00:00:00 2001 From: JoshLove-msft <54595583+JoshLove-msft@users.noreply.github.com> Date: Mon, 30 Nov 2020 11:23:52 -0800 Subject: [PATCH 1/4] CloudNative.CloudEvents bridge library --- eng/Packages.Data.props | 1 + ...zure.Messaging.EventGrid.netstandard2.0.cs | 4 + .../Customization/EventGridPublisherClient.cs | 142 +++++++++++++----- .../CHANGELOG.md | 7 + .../Directory.Build.props | 7 + .../README.md | 49 ++++++ ...ve.CloudEvents.EventGrid.netstandard2.0.cs | 8 + .../src/EventGridPublisherClientExtensions.cs | 101 +++++++++++++ ...e.CloudNative.CloudEvents.EventGrid.csproj | 21 +++ .../tests/CloudEventTests.cs | 137 +++++++++++++++++ .../tests/CloudNativeLiveTests.cs | 64 ++++++++ ...dNative.CloudEvents.EventGrid.Tests.csproj | 23 +++ .../CanPublishCloudEvent.json | 37 +++++ .../CanPublishCloudEventAsync.json | 37 +++++ 14 files changed, 597 insertions(+), 41 deletions(-) create mode 100644 sdk/eventgrid/Microsoft.Azure.CloudNative.CloudEvents.EventGrid/CHANGELOG.md create mode 100644 sdk/eventgrid/Microsoft.Azure.CloudNative.CloudEvents.EventGrid/Directory.Build.props create mode 100644 sdk/eventgrid/Microsoft.Azure.CloudNative.CloudEvents.EventGrid/README.md create mode 100644 sdk/eventgrid/Microsoft.Azure.CloudNative.CloudEvents.EventGrid/api/Microsoft.Azure.CloudNative.CloudEvents.EventGrid.netstandard2.0.cs create mode 100644 sdk/eventgrid/Microsoft.Azure.CloudNative.CloudEvents.EventGrid/src/EventGridPublisherClientExtensions.cs create mode 100644 sdk/eventgrid/Microsoft.Azure.CloudNative.CloudEvents.EventGrid/src/Microsoft.Azure.CloudNative.CloudEvents.EventGrid.csproj create mode 100644 sdk/eventgrid/Microsoft.Azure.CloudNative.CloudEvents.EventGrid/tests/CloudEventTests.cs create mode 100644 sdk/eventgrid/Microsoft.Azure.CloudNative.CloudEvents.EventGrid/tests/CloudNativeLiveTests.cs create mode 100644 sdk/eventgrid/Microsoft.Azure.CloudNative.CloudEvents.EventGrid/tests/Microsoft.Azure.CloudNative.CloudEvents.EventGrid.Tests.csproj create mode 100644 sdk/eventgrid/Microsoft.Azure.CloudNative.CloudEvents.EventGrid/tests/SessionRecords/CloudNativeLiveTests/CanPublishCloudEvent.json create mode 100644 sdk/eventgrid/Microsoft.Azure.CloudNative.CloudEvents.EventGrid/tests/SessionRecords/CloudNativeLiveTests/CanPublishCloudEventAsync.json diff --git a/eng/Packages.Data.props b/eng/Packages.Data.props index 7cef773fe2789..39cb864836ae5 100644 --- a/eng/Packages.Data.props +++ b/eng/Packages.Data.props @@ -32,6 +32,7 @@ + diff --git a/sdk/eventgrid/Azure.Messaging.EventGrid/api/Azure.Messaging.EventGrid.netstandard2.0.cs b/sdk/eventgrid/Azure.Messaging.EventGrid/api/Azure.Messaging.EventGrid.netstandard2.0.cs index 52dba42fda0a7..33bf6722ffe1a 100644 --- a/sdk/eventgrid/Azure.Messaging.EventGrid/api/Azure.Messaging.EventGrid.netstandard2.0.cs +++ b/sdk/eventgrid/Azure.Messaging.EventGrid/api/Azure.Messaging.EventGrid.netstandard2.0.cs @@ -49,6 +49,10 @@ public EventGridPublisherClient(System.Uri endpoint, Azure.AzureKeyCredential cr public EventGridPublisherClient(System.Uri endpoint, Azure.Messaging.EventGrid.EventGridSharedAccessSignatureCredential credential) { } public EventGridPublisherClient(System.Uri endpoint, Azure.Messaging.EventGrid.EventGridSharedAccessSignatureCredential credential, Azure.Messaging.EventGrid.EventGridPublisherClientOptions options) { } public static string BuildSharedAccessSignature(System.Uri endpoint, System.DateTimeOffset expirationUtc, Azure.AzureKeyCredential key, Azure.Messaging.EventGrid.EventGridPublisherClientOptions.ServiceVersion apiVersion = Azure.Messaging.EventGrid.EventGridPublisherClientOptions.ServiceVersion.V2018_01_01) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public virtual Azure.Response SendEncodedCloudEvents(System.ReadOnlyMemory cloudEvents, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public virtual System.Threading.Tasks.Task SendEncodedCloudEventsAsync(System.ReadOnlyMemory cloudEvents, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public virtual Azure.Response SendEvents(System.Collections.Generic.IEnumerable events, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public virtual Azure.Response SendEvents(System.Collections.Generic.IEnumerable events, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public virtual Azure.Response SendEvents(System.Collections.Generic.IEnumerable events, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } diff --git a/sdk/eventgrid/Azure.Messaging.EventGrid/src/Customization/EventGridPublisherClient.cs b/sdk/eventgrid/Azure.Messaging.EventGrid/src/Customization/EventGridPublisherClient.cs index c49c5de25f342..6cf44215f122e 100644 --- a/sdk/eventgrid/Azure.Messaging.EventGrid/src/Customization/EventGridPublisherClient.cs +++ b/sdk/eventgrid/Azure.Messaging.EventGrid/src/Customization/EventGridPublisherClient.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.ComponentModel; using System.Diagnostics; using System.Globalization; using System.IO; @@ -20,7 +21,7 @@ namespace Azure.Messaging.EventGrid { /// - /// Client used to interact with the Event Grid service. + /// The is used to publish events to Event Grid topics. /// public class EventGridPublisherClient { @@ -29,37 +30,39 @@ public class EventGridPublisherClient private string _hostName => _endpoint.Host; private readonly Uri _endpoint; private readonly AzureKeyCredential _key; + private readonly HttpPipeline _pipeline; private readonly string _apiVersion; private readonly ObjectSerializer _dataSerializer; private const string TraceParentHeaderName = "traceparent"; private const string TraceStateHeaderName = "tracestate"; - /// Initalizes an instance of EventGridClient. + /// Initalizes a new instance of the class for mocking. protected EventGridPublisherClient() { } - /// Initalizes an instance of EventGridClient. - /// Topic endpoint. For example, "https://TOPIC-NAME.REGION-NAME-1.eventgrid.azure.net/api/events". - /// Credential used to connect to Azure. + /// Initalizes a new instance of the class. + /// The topic endpoint. For example, "https://TOPIC-NAME.REGION-NAME-1.eventgrid.azure.net/api/events". + /// The key credential used to authenticate with the service. public EventGridPublisherClient(Uri endpoint, AzureKeyCredential credential) : this(endpoint, credential, new EventGridPublisherClientOptions()) { } - /// Initalizes an instance of EventGridClient. - /// Topic endpoint. For example, "https://TOPIC-NAME.REGION-NAME-1.eventgrid.azure.net/api/events". - /// Credential used to connect to Azure. + /// Initalizes a new instance of the class. + /// The topic endpoint. For example, "https://TOPIC-NAME.REGION-NAME-1.eventgrid.azure.net/api/events". + /// The Shared Access Signature credential used to authenticate with the service.This signature + /// can be constructed using . public EventGridPublisherClient(Uri endpoint, EventGridSharedAccessSignatureCredential credential) : this(endpoint, credential, new EventGridPublisherClientOptions()) { } - /// Initalizes an instance of the class. - /// Topic endpoint. For example, "https://TOPIC-NAME.REGION-NAME-1.eventgrid.azure.net/api/events". - /// Credential used to connect to Azure. - /// Configuring options. + /// Initalizes a new instance of the class. + /// The topic endpoint. For example, "https://TOPIC-NAME.REGION-NAME-1.eventgrid.azure.net/api/events". + /// The key credential used to authenticate with the service. + /// The set of options to use for configuring the client. public EventGridPublisherClient(Uri endpoint, AzureKeyCredential credential, EventGridPublisherClientOptions options) { Argument.AssertNotNull(credential, nameof(credential)); @@ -68,17 +71,74 @@ public EventGridPublisherClient(Uri endpoint, AzureKeyCredential credential, Eve _dataSerializer = options.Serializer ?? new JsonObjectSerializer(); _endpoint = endpoint; _key = credential; - HttpPipeline pipeline = HttpPipelineBuilder.Build(options, new AzureKeyCredentialPolicy(credential, Constants.SasKeyName)); - _serviceRestClient = new EventGridRestClient(new ClientDiagnostics(options), pipeline, options.Version.GetVersionString()); + _pipeline = HttpPipelineBuilder.Build(options, new AzureKeyCredentialPolicy(credential, Constants.SasKeyName)); + _serviceRestClient = new EventGridRestClient(new ClientDiagnostics(options), _pipeline, options.Version.GetVersionString()); _clientDiagnostics = new ClientDiagnostics(options); } + /// Publishes a set of encoded cloud events to an Event Grid topic. + /// The set of encoded cloud events to be published to Event Grid. + /// An optional cancellation token instance to signal the request to cancel the operation. + [EditorBrowsable(EditorBrowsableState.Never)] + public virtual async Task SendEncodedCloudEventsAsync(ReadOnlyMemory cloudEvents, CancellationToken cancellationToken = default) + => await SendCloudNativeCloudEventsInternalAsync(cloudEvents, true, cancellationToken).ConfigureAwait(false); + + /// Publishes a set of encoded cloud events to an Event Grid topic. + /// The set of encoded cloud events to be published to Event Grid. + /// An optional cancellation token instance to signal the request to cancel the operation. + [EditorBrowsable(EditorBrowsableState.Never)] + public virtual Response SendEncodedCloudEvents(ReadOnlyMemory cloudEvents, CancellationToken cancellationToken = default) + => SendCloudNativeCloudEventsInternalAsync(cloudEvents, false, cancellationToken).EnsureCompleted(); + + private async Task SendCloudNativeCloudEventsInternalAsync(ReadOnlyMemory cloudEvents, bool async, CancellationToken cancellationToken = default) + { + using DiagnosticScope scope = _clientDiagnostics.CreateScope($"{nameof(EventGridPublisherClient)}.{nameof(SendEncodedCloudEvents)}"); + scope.Start(); + + try + { + using HttpMessage message = _pipeline.CreateMessage(); + Request request = message.Request; + request.Method = RequestMethod.Post; + var uri = new RawRequestUriBuilder(); + uri.AppendRaw("https://", false); + uri.AppendRaw(_hostName, false); + uri.AppendPath("/api/events", false); + uri.AppendQuery("api-version", _apiVersion, true); + request.Uri = uri; + request.Headers.Add("Content-Type", "application/cloudevents-batch+json; charset=utf-8"); + RequestContent content = RequestContent.Create(cloudEvents); + request.Content = content; + if (async) + { + await _pipeline.SendAsync(message, cancellationToken).ConfigureAwait(false); + } + else + { + _pipeline.Send(message, cancellationToken); + } + return message.Response.Status switch + { + 200 => message.Response, + _ => async ? + throw await _clientDiagnostics.CreateRequestFailedExceptionAsync(message.Response).ConfigureAwait(false) : + throw _clientDiagnostics.CreateRequestFailedException(message.Response) + }; + } + catch (Exception e) + { + scope.Failed(e); + throw; + } + } + /// /// Initializes a new instance of the class. /// - /// Topic endpoint. For example, "https://TOPIC-NAME.REGION-NAME-1.eventgrid.azure.net/api/events". - /// Credential used to connect to Azure. - /// Configuring options. + /// The topic endpoint. For example, "https://TOPIC-NAME.REGION-NAME-1.eventgrid.azure.net/api/events". + /// The Shared Access Signature credential used to connect to Azure. This signature + /// can be constructed using . + /// The set of options to use for configuring the client. public EventGridPublisherClient(Uri endpoint, EventGridSharedAccessSignatureCredential credential, EventGridPublisherClientOptions options) { Argument.AssertNotNull(credential, nameof(credential)); @@ -90,22 +150,22 @@ public EventGridPublisherClient(Uri endpoint, EventGridSharedAccessSignatureCred _clientDiagnostics = new ClientDiagnostics(options); } - /// Publishes a batch of EventGridEvents to an Azure Event Grid topic. - /// An array of events to be published to Event Grid. - /// The cancellation token to use. + /// Publishes a set of EventGridEvents to an Event Grid topic. + /// The set of events to be published to Event Grid. + /// An optional cancellation token instance to signal the request to cancel the operation. public virtual async Task SendEventsAsync(IEnumerable events, CancellationToken cancellationToken = default) => await SendEventsInternal(events, true /*async*/, cancellationToken).ConfigureAwait(false); - /// Publishes a batch of EventGridEvents to an Azure Event Grid topic. - /// An array of events to be published to Event Grid. - /// The cancellation token to use. + /// Publishes a set of EventGridEvents to an Event Grid topic. + /// The set of events to be published to Event Grid. + /// An optional cancellation token instance to signal the request to cancel the operation. public virtual Response SendEvents(IEnumerable events, CancellationToken cancellationToken = default) => SendEventsInternal(events, false /*async*/, cancellationToken).EnsureCompleted(); - /// Publishes a batch of EventGridEvents to an Azure Event Grid topic. - /// An array of events to be published to Event Grid. + /// Publishes a set of EventGridEvents to an Event Grid topic. + /// The set of events to be published to Event Grid. /// Whether to invoke the operation asynchronously. - /// The cancellation token to use. + /// An optional cancellation token instance to signal the request to cancel the operation. private async Task SendEventsInternal(IEnumerable events, bool async, CancellationToken cancellationToken = default) { using DiagnosticScope scope = _clientDiagnostics.CreateScope($"{nameof(EventGridPublisherClient)}.{nameof(SendEvents)}"); @@ -175,20 +235,20 @@ private async Task SendEventsInternal(IEnumerable even } } - /// Publishes a batch of CloudEvents to an Azure Event Grid topic. - /// An array of events to be published to Event Grid. - /// The cancellation token to use. + /// Publishes a set of CloudEvents to an Event Grid topic. + /// The set of events to be published to Event Grid. + /// An optional cancellation token instance to signal the request to cancel the operation. public virtual async Task SendEventsAsync(IEnumerable events, CancellationToken cancellationToken = default) => await SendCloudEventsInternal(events, true /*async*/, cancellationToken).ConfigureAwait(false); - /// Publishes a batch of CloudEvents to an Azure Event Grid topic. - /// An array of events to be published to Event Grid. - /// The cancellation token to use. + /// Publishes a set of CloudEvents to an Event Grid topic. + /// The set of events to be published to Event Grid. + /// An optional cancellation token instance to signal the request to cancel the operation. public virtual Response SendEvents(IEnumerable events, CancellationToken cancellationToken = default) => SendCloudEventsInternal(events, false /*async*/, cancellationToken).EnsureCompleted(); - /// Publishes a batch of CloudEvents to an Azure Event Grid topic. - /// An array of events to be published to Event Grid. + /// Publishes a set of CloudEvents to an Event Grid topic. + /// The set of events to be published to Event Grid. /// Whether to invoke the operation asynchronously. /// The cancellation token to use. private async Task SendCloudEventsInternal(IEnumerable events, bool async, CancellationToken cancellationToken = default) @@ -277,15 +337,15 @@ private async Task SendCloudEventsInternal(IEnumerable eve } } - /// Publishes a batch of custom events to an Azure Event Grid topic. + /// Publishes a set of custom events to an Event Grid topic. /// An array of events to be published to Event Grid. - /// The cancellation token to use. + /// An optional cancellation token instance to signal the request to cancel the operation. public virtual async Task SendEventsAsync(IEnumerable events, CancellationToken cancellationToken = default) => await PublishCustomEventsInternal(events, true /*async*/, cancellationToken).ConfigureAwait(false); - /// Publishes a batch of custom events to an Azure Event Grid topic. + /// Publishes a set of custom events to an Event Grid topic. /// An array of events to be published to Event Grid. - /// The cancellation token to use. + /// An optional cancellation token instance to signal the request to cancel the operation. public virtual Response SendEvents(IEnumerable events, CancellationToken cancellationToken = default) => PublishCustomEventsInternal(events, false /*async*/, cancellationToken).EnsureCompleted(); @@ -328,12 +388,12 @@ private async Task PublishCustomEventsInternal(IEnumerable eve } /// - /// Creates a SAS token for use with Event Grid service. + /// Creates a SAS token for use with the Event Grid service. /// /// The path for the event grid topic to which you're sending events. For example, "https://TOPIC-NAME.REGION-NAME.eventgrid.azure.net/eventGrid/api/events". /// Time at which the SAS token becomes invalid for authentication. - /// Key credential used to generate the token. - /// Service version to use when handling requests made with the SAS token. + /// The key credential used to generate the token. + /// The service version to use when handling requests made with the SAS token. /// The generated SAS token string. public static string BuildSharedAccessSignature(Uri endpoint, DateTimeOffset expirationUtc, AzureKeyCredential key, EventGridPublisherClientOptions.ServiceVersion apiVersion = EventGridPublisherClientOptions.LatestVersion) { diff --git a/sdk/eventgrid/Microsoft.Azure.CloudNative.CloudEvents.EventGrid/CHANGELOG.md b/sdk/eventgrid/Microsoft.Azure.CloudNative.CloudEvents.EventGrid/CHANGELOG.md new file mode 100644 index 0000000000000..eeb2fd72d6362 --- /dev/null +++ b/sdk/eventgrid/Microsoft.Azure.CloudNative.CloudEvents.EventGrid/CHANGELOG.md @@ -0,0 +1,7 @@ +# Release History + +## 1.0.0-preview.1 (Unreleased) + +### Added + +- Bridge library to allow sending CloudNative CloudEvents using Azure Event Grid. diff --git a/sdk/eventgrid/Microsoft.Azure.CloudNative.CloudEvents.EventGrid/Directory.Build.props b/sdk/eventgrid/Microsoft.Azure.CloudNative.CloudEvents.EventGrid/Directory.Build.props new file mode 100644 index 0000000000000..ecd524f8c15f5 --- /dev/null +++ b/sdk/eventgrid/Microsoft.Azure.CloudNative.CloudEvents.EventGrid/Directory.Build.props @@ -0,0 +1,7 @@ + + + true + + + + diff --git a/sdk/eventgrid/Microsoft.Azure.CloudNative.CloudEvents.EventGrid/README.md b/sdk/eventgrid/Microsoft.Azure.CloudNative.CloudEvents.EventGrid/README.md new file mode 100644 index 0000000000000..b75b0733adb3c --- /dev/null +++ b/sdk/eventgrid/Microsoft.Azure.CloudNative.CloudEvents.EventGrid/README.md @@ -0,0 +1,49 @@ +# CloudNative CloudEvent support for Azure.Messaging.EventGrid library for .NET + +TODO + +## Getting started + +TODO + +### Install the package + +TODO + +### Prerequisites + +TODO + +### Authenticate the client + +TODO + +## Key concepts + +TODO + +## Examples + +TODO + +## Troubleshooting + +TODO + +## Next steps + +TODO + +## Contributing + +This project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, visit . + +When you submit a pull request, a CLA-bot will automatically determine whether you need to provide a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions provided by the bot. You will only need to do this once across all repos using our CLA. + +This project has adopted the [Microsoft Open Source Code of Conduct][code_of_conduct]. For more information see the [Code of Conduct FAQ][code_of_conduct_faq] or contact opencode@microsoft.com with any additional questions or comments. + +![Impressions](https://azure-sdk-impressions.azurewebsites.net/api/impressions/azure-sdk-for-net%2Fsdk%2Fcore%2FMicrosoft.Azure.Core.NewtonsoftJson%2FREADME.png) + +[code_of_conduct]: https://opensource.microsoft.com/codeofconduct +[code_of_conduct_faq]: https://opensource.microsoft.com/codeofconduct/faq/ +[microsoft_spatial_package]: https://www.nuget.org/packages/Microsoft.Spatial/ diff --git a/sdk/eventgrid/Microsoft.Azure.CloudNative.CloudEvents.EventGrid/api/Microsoft.Azure.CloudNative.CloudEvents.EventGrid.netstandard2.0.cs b/sdk/eventgrid/Microsoft.Azure.CloudNative.CloudEvents.EventGrid/api/Microsoft.Azure.CloudNative.CloudEvents.EventGrid.netstandard2.0.cs new file mode 100644 index 0000000000000..d503fa50e4b62 --- /dev/null +++ b/sdk/eventgrid/Microsoft.Azure.CloudNative.CloudEvents.EventGrid/api/Microsoft.Azure.CloudNative.CloudEvents.EventGrid.netstandard2.0.cs @@ -0,0 +1,8 @@ +namespace Microsoft.Azure.CloudNative.CloudEvents.EventGrid +{ + public static partial class EventGridPublisherClientExtensions + { + public static Azure.Response SendCloudEvents(this Azure.Messaging.EventGrid.EventGridPublisherClient client, System.Collections.Generic.IEnumerable cloudEvents, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public static System.Threading.Tasks.Task SendCloudEventsAsync(this Azure.Messaging.EventGrid.EventGridPublisherClient client, System.Collections.Generic.IEnumerable cloudEvents, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + } +} diff --git a/sdk/eventgrid/Microsoft.Azure.CloudNative.CloudEvents.EventGrid/src/EventGridPublisherClientExtensions.cs b/sdk/eventgrid/Microsoft.Azure.CloudNative.CloudEvents.EventGrid/src/EventGridPublisherClientExtensions.cs new file mode 100644 index 0000000000000..8e1443346cc4b --- /dev/null +++ b/sdk/eventgrid/Microsoft.Azure.CloudNative.CloudEvents.EventGrid/src/EventGridPublisherClientExtensions.cs @@ -0,0 +1,101 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Azure; +using Azure.Core; +using Azure.Core.Pipeline; +using Azure.Messaging.EventGrid; +using CloudNative.CloudEvents; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Text.Json; +using System.Threading; +using System.Threading.Tasks; +using CloudEvent = CloudNative.CloudEvents.CloudEvent; + +#pragma warning disable AZC0001 // Use one of the following pre-approved namespace groups (https://azure.github.io/azure-sdk/registered_namespaces.html): Azure.AI, Azure.Analytics, Azure.Communication, Azure.Data, Azure.DigitalTwins, Azure.Iot, Azure.Learn, Azure.Media, Azure.Management, Azure.Messaging, Azure.Search, Azure.Security, Azure.Storage, Azure.Template, Azure.Identity, Microsoft.Extensions.Azure +namespace Microsoft.Azure.CloudNative.CloudEvents.EventGrid +#pragma warning restore AZC0001 // Use one of the following pre-approved namespace groups (https://azure.github.io/azure-sdk/registered_namespaces.html): Azure.AI, Azure.Analytics, Azure.Communication, Azure.Data, Azure.DigitalTwins, Azure.Iot, Azure.Learn, Azure.Media, Azure.Management, Azure.Messaging, Azure.Search, Azure.Security, Azure.Storage, Azure.Template, Azure.Identity, Microsoft.Extensions.Azure +{ + /// + /// This class contains extension methods to enable usage of the CloudNative.CloudEvent + /// library with the Azure Event Grid library. + /// + public static class EventGridPublisherClientExtensions + { + private static readonly JsonEventFormatter s_eventFormatter = new JsonEventFormatter(); + private const string TraceParentHeaderName = "traceparent"; + private const string TraceStateHeaderName = "tracestate"; + + /// Publishes a set of CloudEvents to an Event Grid topic. + /// The instance to extend. + /// The set of events to be published to Event Grid. + /// An optional cancellation token instance to signal the request to cancel the operation. + public static Response SendCloudEvents( + this EventGridPublisherClient client, + IEnumerable cloudEvents, + CancellationToken cancellationToken = default) => + SendCloudEventsInternalAsync(client, cloudEvents, false, cancellationToken).EnsureCompleted(); + + /// Publishes a set of CloudEvents to an Event Grid topic. + /// The instance to extend. + /// The set of events to be published to Event Grid. + /// An optional cancellation token instance to signal the request to cancel the operation. + public static async Task SendCloudEventsAsync( + this EventGridPublisherClient client, + IEnumerable cloudEvents, + CancellationToken cancellationToken = default) => + await SendCloudEventsInternalAsync(client, cloudEvents, true, cancellationToken).ConfigureAwait(false); + + private static async Task SendCloudEventsInternalAsync( + EventGridPublisherClient client, + IEnumerable cloudEvents, + bool async, + CancellationToken cancellationToken = default) + { + Argument.AssertNotNull(client, nameof(client)); + string activityId = null; + string traceState = null; + Activity currentActivity = Activity.Current; + if (currentActivity != null && currentActivity.IsW3CFormat()) + { + activityId = currentActivity.Id; + currentActivity.TryGetTraceState(out traceState); + } + + using var stream = new MemoryStream(); + var writer = new Utf8JsonWriter(stream); + writer.WriteStartArray(); + foreach (var cloudEvent in cloudEvents) + { + var attributes = cloudEvent.GetAttributes(); + if (activityId != null && + !attributes.ContainsKey(TraceParentHeaderName) && + !attributes.ContainsKey(TraceStateHeaderName)) + { + attributes.Add(TraceParentHeaderName, activityId); + if (traceState != null) + { + attributes.Add(TraceStateHeaderName, traceState); + } + } + + byte[] bytes = s_eventFormatter.EncodeStructuredEvent(cloudEvent, out var _); + using JsonDocument document = JsonDocument.Parse(bytes); + document.RootElement.WriteTo(writer); + } + writer.WriteEndArray(); + writer.Flush(); + if (async) + { + return await client.SendEncodedCloudEventsAsync(stream.GetBuffer().AsMemory(0, (int)stream.Position), cancellationToken).ConfigureAwait(false); + } + else + { + return client.SendEncodedCloudEvents(stream.GetBuffer().AsMemory(0, (int)stream.Position), cancellationToken); + } + } + } +} diff --git a/sdk/eventgrid/Microsoft.Azure.CloudNative.CloudEvents.EventGrid/src/Microsoft.Azure.CloudNative.CloudEvents.EventGrid.csproj b/sdk/eventgrid/Microsoft.Azure.CloudNative.CloudEvents.EventGrid/src/Microsoft.Azure.CloudNative.CloudEvents.EventGrid.csproj new file mode 100644 index 0000000000000..f3ff45edef939 --- /dev/null +++ b/sdk/eventgrid/Microsoft.Azure.CloudNative.CloudEvents.EventGrid/src/Microsoft.Azure.CloudNative.CloudEvents.EventGrid.csproj @@ -0,0 +1,21 @@ + + + CloudNative CloudEvents support for Azure.Messaging.EventGrid library + This library allows the CloudEvent model from CloudNative.CloudEvents to be published using the Azure Event Grid client library. + 1.0.0-preview.1 + Microsoft Azure SDK CloudNative CloudEvents + $(RequiredTargetFrameworks) + + + + + + + + + + + + + + diff --git a/sdk/eventgrid/Microsoft.Azure.CloudNative.CloudEvents.EventGrid/tests/CloudEventTests.cs b/sdk/eventgrid/Microsoft.Azure.CloudNative.CloudEvents.EventGrid/tests/CloudEventTests.cs new file mode 100644 index 0000000000000..487b38001a503 --- /dev/null +++ b/sdk/eventgrid/Microsoft.Azure.CloudNative.CloudEvents.EventGrid/tests/CloudEventTests.cs @@ -0,0 +1,137 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Text.Json; +using System.Threading; +using System.Threading.Tasks; +using Azure; +using Azure.Core; +using Azure.Core.Pipeline; +using Azure.Core.TestFramework; +using Azure.Messaging.EventGrid; +using CloudNative.CloudEvents; +using NUnit.Framework; +using CloudEvent = CloudNative.CloudEvents.CloudEvent; + +namespace Microsoft.Azure.CloudNative.CloudEvents.EventGrid.Tests +{ + public class CloudEventTests + { + + private const string TraceParentHeaderName = "traceparent"; + private const string TraceStateHeaderName = "tracestate"; + + private static readonly JsonEventFormatter s_eventFormatter = new JsonEventFormatter(); + + + [Test] + [TestCase(false, false)] + [TestCase(true, true)] + [TestCase(true, false)] + [TestCase(false, true)] + public async Task SetsTraceParentExtension(bool inclTraceparent, bool inclTracestate) + { + var mockTransport = new MockTransport(new MockResponse(200)); + var options = new EventGridPublisherClientOptions + { + Transport = mockTransport + }; + EventGridPublisherClient client = + new EventGridPublisherClient( + new Uri("http://localHost"), + new AzureKeyCredential("fakeKey"), + options); + var activity = new Activity($"{nameof(EventGridPublisherClient)}.{nameof(EventGridPublisherClient.SendEvents)}"); + activity.SetW3CFormat(); + activity.Start(); + List eventsList = new List(); + for (int i = 0; i < 10; i++) + { + var cloudEvent = + new CloudEvent( + "record", + new Uri("http://localHost"), + Guid.NewGuid().ToString(), + DateTime.Now); + + if (inclTraceparent && inclTracestate && i % 2 == 0) + { + cloudEvent.GetAttributes().Add("traceparent", "traceparentValue"); + } + if (inclTracestate && i % 2 == 0) + { + cloudEvent.GetAttributes().Add("tracestate", "param:value"); + } + eventsList.Add(cloudEvent); + } + await client.SendCloudEventsAsync(eventsList); + + activity.Stop(); + List cloudEvents = DeserializeRequest(mockTransport.SingleRequest); + IEnumerator cloudEnum = eventsList.GetEnumerator(); + foreach (CloudEvent cloudEvent in cloudEvents) + { + cloudEnum.MoveNext(); + IDictionary cloudEventAttr = cloudEnum.Current.GetAttributes(); + if (cloudEventAttr.ContainsKey(TraceParentHeaderName) && + cloudEventAttr.ContainsKey(TraceStateHeaderName)) + { + Assert.AreEqual( + cloudEventAttr[TraceParentHeaderName], + cloudEvent.GetAttributes()[TraceParentHeaderName]); + + Assert.AreEqual( + cloudEventAttr[TraceStateHeaderName], + cloudEvent.GetAttributes()[TraceStateHeaderName]); + } + else if (cloudEventAttr.ContainsKey(TraceParentHeaderName)) + { + Assert.AreEqual( + cloudEventAttr[TraceParentHeaderName], + cloudEvent.GetAttributes()[TraceParentHeaderName]); + } + else if (cloudEventAttr.ContainsKey(TraceStateHeaderName)) + { + Assert.AreEqual( + cloudEventAttr[TraceStateHeaderName], + cloudEvent.GetAttributes()[TraceStateHeaderName]); + } + else + { + Assert.AreEqual( + activity.Id, + cloudEvent.GetAttributes()[TraceParentHeaderName]); + } + } + } + + private static List DeserializeRequest(Request request) + { + var content = request.Content; + var stream = new MemoryStream(); + content.WriteTo(stream, CancellationToken.None); + stream.Position = 0; + JsonDocument requestDocument = JsonDocument.Parse(stream); + var cloudEvents = new List(); + // Parse JsonElement into separate events, deserialize event envelope properties + if (requestDocument.RootElement.ValueKind == JsonValueKind.Object) + { + var bytes = JsonSerializer.SerializeToUtf8Bytes(requestDocument.RootElement, typeof(JsonElement)); + cloudEvents.Add(s_eventFormatter.DecodeStructuredEvent(bytes)); + } + else if (requestDocument.RootElement.ValueKind == JsonValueKind.Array) + { + foreach (JsonElement property in requestDocument.RootElement.EnumerateArray()) + { + var bytes = JsonSerializer.SerializeToUtf8Bytes(property, typeof(JsonElement)); + cloudEvents.Add(s_eventFormatter.DecodeStructuredEvent(bytes)); + } + } + return cloudEvents; + } + } +} diff --git a/sdk/eventgrid/Microsoft.Azure.CloudNative.CloudEvents.EventGrid/tests/CloudNativeLiveTests.cs b/sdk/eventgrid/Microsoft.Azure.CloudNative.CloudEvents.EventGrid/tests/CloudNativeLiveTests.cs new file mode 100644 index 0000000000000..5905a4e4f415c --- /dev/null +++ b/sdk/eventgrid/Microsoft.Azure.CloudNative.CloudEvents.EventGrid/tests/CloudNativeLiveTests.cs @@ -0,0 +1,64 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Azure; +using Azure.Messaging.EventGrid; +using Azure.Messaging.EventGrid.Tests; +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using CloudEvent = CloudNative.CloudEvents.CloudEvent; + +namespace Microsoft.Azure.CloudNative.CloudEvents.EventGrid.Tests +{ + public class CloudNativeLiveTests : EventGridLiveTestBase + { + public CloudNativeLiveTests(bool async) : base(async) + { + } + + [Test] + public async Task CanPublishCloudEvent() + { + EventGridPublisherClientOptions options = InstrumentClientOptions(new EventGridPublisherClientOptions()); + EventGridPublisherClient client = InstrumentClient( + new EventGridPublisherClient( + new Uri(TestEnvironment.CloudEventTopicHost), + new AzureKeyCredential(TestEnvironment.CloudEventTopicKey), + options)); + + List eventsList = new List(); + + for (int i = 0; i < 10; i++) + { + eventsList.Add( + new CloudEvent( + "record", + new Uri("http://localHost"), + Recording.Random.NewGuid().ToString(), + Recording.Now.DateTime) + { + Data = new TestPayload("name", i) + } + ); + } + + await client.SendCloudEventsAsync(eventsList); + } + + private class TestPayload + { + public TestPayload(string name, int age) + { + Name = name; + Age = age; + } + + public TestPayload() { } + + public string Name { get; set; } + public int Age { get; set; } + } + } +} diff --git a/sdk/eventgrid/Microsoft.Azure.CloudNative.CloudEvents.EventGrid/tests/Microsoft.Azure.CloudNative.CloudEvents.EventGrid.Tests.csproj b/sdk/eventgrid/Microsoft.Azure.CloudNative.CloudEvents.EventGrid/tests/Microsoft.Azure.CloudNative.CloudEvents.EventGrid.Tests.csproj new file mode 100644 index 0000000000000..6673007f01b71 --- /dev/null +++ b/sdk/eventgrid/Microsoft.Azure.CloudNative.CloudEvents.EventGrid/tests/Microsoft.Azure.CloudNative.CloudEvents.EventGrid.Tests.csproj @@ -0,0 +1,23 @@ + + + $(RequiredTargetFrameworks) + + + $(NoWarn);CS1591 + + + + + + + + + + + + + + + + + diff --git a/sdk/eventgrid/Microsoft.Azure.CloudNative.CloudEvents.EventGrid/tests/SessionRecords/CloudNativeLiveTests/CanPublishCloudEvent.json b/sdk/eventgrid/Microsoft.Azure.CloudNative.CloudEvents.EventGrid/tests/SessionRecords/CloudNativeLiveTests/CanPublishCloudEvent.json new file mode 100644 index 0000000000000..27303f6137a81 --- /dev/null +++ b/sdk/eventgrid/Microsoft.Azure.CloudNative.CloudEvents.EventGrid/tests/SessionRecords/CloudNativeLiveTests/CanPublishCloudEvent.json @@ -0,0 +1,37 @@ +{ + "Entries": [ + { + "RequestUri": "https://jolov-cloud.centralus-1.eventgrid.azure.net/api/events?api-version=2018-01-01", + "RequestMethod": "POST", + "RequestHeaders": { + "aeg-sas-key": "Sanitized", + "Content-Length": "1781", + "Content-Type": "application/cloudevents-batch\u002Bjson; charset=utf-8", + "traceparent": "00-c33cd77a9b0cf64db9a343c819425b8f-e480df32f8f3144b-00", + "User-Agent": [ + "azsdk-net-Messaging.EventGrid/4.0.0-alpha.20201129.1", + "(.NET Core 4.6.29321.03; Microsoft Windows 10.0.19042 )" + ], + "x-ms-client-request-id": "0321e9b9eacbad983f9e70f28ef5998b", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": "[{\u0022specversion\u0022:\u00221.0\u0022,\u0022type\u0022:\u0022record\u0022,\u0022source\u0022:\u0022http://localHost\u0022,\u0022id\u0022:\u0022299650a5-2d8c-307e-1137-a085391db9b1\u0022,\u0022time\u0022:\u00222020-11-29T21:55:11.1606909\u0022,\u0022data\u0022:{\u0022Name\u0022:\u0022name\u0022,\u0022Age\u0022:0}},{\u0022specversion\u0022:\u00221.0\u0022,\u0022type\u0022:\u0022record\u0022,\u0022source\u0022:\u0022http://localHost\u0022,\u0022id\u0022:\u00221d75081d-5719-7a05-2fe6-631351199925\u0022,\u0022time\u0022:\u00222020-11-29T21:55:11.1606909\u0022,\u0022data\u0022:{\u0022Name\u0022:\u0022name\u0022,\u0022Age\u0022:1}},{\u0022specversion\u0022:\u00221.0\u0022,\u0022type\u0022:\u0022record\u0022,\u0022source\u0022:\u0022http://localHost\u0022,\u0022id\u0022:\u0022c146fcd0-efdf-5614-509a-c0a80073016c\u0022,\u0022time\u0022:\u00222020-11-29T21:55:11.1606909\u0022,\u0022data\u0022:{\u0022Name\u0022:\u0022name\u0022,\u0022Age\u0022:2}},{\u0022specversion\u0022:\u00221.0\u0022,\u0022type\u0022:\u0022record\u0022,\u0022source\u0022:\u0022http://localHost\u0022,\u0022id\u0022:\u0022601f0be2-b8d2-4e0f-4a1c-f9a5c96adff8\u0022,\u0022time\u0022:\u00222020-11-29T21:55:11.1606909\u0022,\u0022data\u0022:{\u0022Name\u0022:\u0022name\u0022,\u0022Age\u0022:3}},{\u0022specversion\u0022:\u00221.0\u0022,\u0022type\u0022:\u0022record\u0022,\u0022source\u0022:\u0022http://localHost\u0022,\u0022id\u0022:\u00223db47b9e-f7d6-2dd1-f31f-cd7f965d79bc\u0022,\u0022time\u0022:\u00222020-11-29T21:55:11.1606909\u0022,\u0022data\u0022:{\u0022Name\u0022:\u0022name\u0022,\u0022Age\u0022:4}},{\u0022specversion\u0022:\u00221.0\u0022,\u0022type\u0022:\u0022record\u0022,\u0022source\u0022:\u0022http://localHost\u0022,\u0022id\u0022:\u00224531f7e5-38fa-1852-edf8-77c2f56f8de5\u0022,\u0022time\u0022:\u00222020-11-29T21:55:11.1606909\u0022,\u0022data\u0022:{\u0022Name\u0022:\u0022name\u0022,\u0022Age\u0022:5}},{\u0022specversion\u0022:\u00221.0\u0022,\u0022type\u0022:\u0022record\u0022,\u0022source\u0022:\u0022http://localHost\u0022,\u0022id\u0022:\u00228409c8ba-c4be-ea95-3af1-6db3ea8fb8ec\u0022,\u0022time\u0022:\u00222020-11-29T21:55:11.1606909\u0022,\u0022data\u0022:{\u0022Name\u0022:\u0022name\u0022,\u0022Age\u0022:6}},{\u0022specversion\u0022:\u00221.0\u0022,\u0022type\u0022:\u0022record\u0022,\u0022source\u0022:\u0022http://localHost\u0022,\u0022id\u0022:\u0022d1bf3da2-9a39-65fe-299b-50de800f3884\u0022,\u0022time\u0022:\u00222020-11-29T21:55:11.1606909\u0022,\u0022data\u0022:{\u0022Name\u0022:\u0022name\u0022,\u0022Age\u0022:7}},{\u0022specversion\u0022:\u00221.0\u0022,\u0022type\u0022:\u0022record\u0022,\u0022source\u0022:\u0022http://localHost\u0022,\u0022id\u0022:\u0022cdc4e792-f454-21fd-6146-0b08cb9e2d5d\u0022,\u0022time\u0022:\u00222020-11-29T21:55:11.1606909\u0022,\u0022data\u0022:{\u0022Name\u0022:\u0022name\u0022,\u0022Age\u0022:8}},{\u0022specversion\u0022:\u00221.0\u0022,\u0022type\u0022:\u0022record\u0022,\u0022source\u0022:\u0022http://localHost\u0022,\u0022id\u0022:\u0022b8208a3f-bbaf-20ac-caa4-5b2274b7692a\u0022,\u0022time\u0022:\u00222020-11-29T21:55:11.1606909\u0022,\u0022data\u0022:{\u0022Name\u0022:\u0022name\u0022,\u0022Age\u0022:9}}]", + "StatusCode": 200, + "ResponseHeaders": { + "api-supported-versions": "2018-01-01", + "Content-Length": "0", + "Date": "Mon, 30 Nov 2020 05:55:12 GMT", + "Server": "Microsoft-HTTPAPI/2.0", + "Strict-Transport-Security": "max-age=31536000; includeSubDomains", + "x-ms-request-id": "ac5e3e7a-e884-4db6-a912-0ad7ceea41d0" + }, + "ResponseBody": [] + } + ], + "Variables": { + "DateTimeOffsetNow": "2020-11-29T21:55:11.1606909-08:00", + "EVENT_GRID_CLOUD_EVENT_TOPIC_ENDPOINT": "https://jolov-cloud.centralus-1.eventgrid.azure.net/api/events", + "EVENT_GRID_CLOUD_EVENT_TOPIC_KEY": "Kg==", + "RandomSeed": "1844326433" + } +} \ No newline at end of file diff --git a/sdk/eventgrid/Microsoft.Azure.CloudNative.CloudEvents.EventGrid/tests/SessionRecords/CloudNativeLiveTests/CanPublishCloudEventAsync.json b/sdk/eventgrid/Microsoft.Azure.CloudNative.CloudEvents.EventGrid/tests/SessionRecords/CloudNativeLiveTests/CanPublishCloudEventAsync.json new file mode 100644 index 0000000000000..2569ef1cdec7e --- /dev/null +++ b/sdk/eventgrid/Microsoft.Azure.CloudNative.CloudEvents.EventGrid/tests/SessionRecords/CloudNativeLiveTests/CanPublishCloudEventAsync.json @@ -0,0 +1,37 @@ +{ + "Entries": [ + { + "RequestUri": "https://jolov-cloud.centralus-1.eventgrid.azure.net/api/events?api-version=2018-01-01", + "RequestMethod": "POST", + "RequestHeaders": { + "aeg-sas-key": "Sanitized", + "Content-Length": "1781", + "Content-Type": "application/cloudevents-batch\u002Bjson; charset=utf-8", + "traceparent": "00-311a021742be0342af86b57696c8cc82-e5fe93188753ee4d-00", + "User-Agent": [ + "azsdk-net-Messaging.EventGrid/4.0.0-alpha.20201129.1", + "(.NET Core 4.6.29321.03; Microsoft Windows 10.0.19042 )" + ], + "x-ms-client-request-id": "d477ae309ee47ce40be0b26663c0e67b", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": "[{\u0022specversion\u0022:\u00221.0\u0022,\u0022type\u0022:\u0022record\u0022,\u0022source\u0022:\u0022http://localHost\u0022,\u0022id\u0022:\u0022145e6f54-aa2d-c053-a4c3-301770ec52ee\u0022,\u0022time\u0022:\u00222020-11-29T21:55:12.3886877\u0022,\u0022data\u0022:{\u0022Name\u0022:\u0022name\u0022,\u0022Age\u0022:0}},{\u0022specversion\u0022:\u00221.0\u0022,\u0022type\u0022:\u0022record\u0022,\u0022source\u0022:\u0022http://localHost\u0022,\u0022id\u0022:\u0022284b2e88-19d2-a979-86eb-0df80b801106\u0022,\u0022time\u0022:\u00222020-11-29T21:55:12.3886877\u0022,\u0022data\u0022:{\u0022Name\u0022:\u0022name\u0022,\u0022Age\u0022:1}},{\u0022specversion\u0022:\u00221.0\u0022,\u0022type\u0022:\u0022record\u0022,\u0022source\u0022:\u0022http://localHost\u0022,\u0022id\u0022:\u00229c124e18-a907-8a2c-4107-3e866b82dd59\u0022,\u0022time\u0022:\u00222020-11-29T21:55:12.3886877\u0022,\u0022data\u0022:{\u0022Name\u0022:\u0022name\u0022,\u0022Age\u0022:2}},{\u0022specversion\u0022:\u00221.0\u0022,\u0022type\u0022:\u0022record\u0022,\u0022source\u0022:\u0022http://localHost\u0022,\u0022id\u0022:\u0022c8d3e3e5-bb0a-3b27-f5b5-8e419c5bb524\u0022,\u0022time\u0022:\u00222020-11-29T21:55:12.3886877\u0022,\u0022data\u0022:{\u0022Name\u0022:\u0022name\u0022,\u0022Age\u0022:3}},{\u0022specversion\u0022:\u00221.0\u0022,\u0022type\u0022:\u0022record\u0022,\u0022source\u0022:\u0022http://localHost\u0022,\u0022id\u0022:\u002221fe29b1-b5da-dfe6-02c0-e6cbdbf23d03\u0022,\u0022time\u0022:\u00222020-11-29T21:55:12.3886877\u0022,\u0022data\u0022:{\u0022Name\u0022:\u0022name\u0022,\u0022Age\u0022:4}},{\u0022specversion\u0022:\u00221.0\u0022,\u0022type\u0022:\u0022record\u0022,\u0022source\u0022:\u0022http://localHost\u0022,\u0022id\u0022:\u00222712b40e-48ac-5dfc-26d7-a7521aeaeee6\u0022,\u0022time\u0022:\u00222020-11-29T21:55:12.3886877\u0022,\u0022data\u0022:{\u0022Name\u0022:\u0022name\u0022,\u0022Age\u0022:5}},{\u0022specversion\u0022:\u00221.0\u0022,\u0022type\u0022:\u0022record\u0022,\u0022source\u0022:\u0022http://localHost\u0022,\u0022id\u0022:\u002242d51a52-bb84-307e-fdf4-c64ad55c5f02\u0022,\u0022time\u0022:\u00222020-11-29T21:55:12.3886877\u0022,\u0022data\u0022:{\u0022Name\u0022:\u0022name\u0022,\u0022Age\u0022:6}},{\u0022specversion\u0022:\u00221.0\u0022,\u0022type\u0022:\u0022record\u0022,\u0022source\u0022:\u0022http://localHost\u0022,\u0022id\u0022:\u0022e8338a77-8d49-6877-2da0-fb020d93c417\u0022,\u0022time\u0022:\u00222020-11-29T21:55:12.3886877\u0022,\u0022data\u0022:{\u0022Name\u0022:\u0022name\u0022,\u0022Age\u0022:7}},{\u0022specversion\u0022:\u00221.0\u0022,\u0022type\u0022:\u0022record\u0022,\u0022source\u0022:\u0022http://localHost\u0022,\u0022id\u0022:\u0022c17800d2-fb1d-527f-35e2-2ab782b187c9\u0022,\u0022time\u0022:\u00222020-11-29T21:55:12.3886877\u0022,\u0022data\u0022:{\u0022Name\u0022:\u0022name\u0022,\u0022Age\u0022:8}},{\u0022specversion\u0022:\u00221.0\u0022,\u0022type\u0022:\u0022record\u0022,\u0022source\u0022:\u0022http://localHost\u0022,\u0022id\u0022:\u00228fdba577-05b7-c49c-a26c-15e3c07b2269\u0022,\u0022time\u0022:\u00222020-11-29T21:55:12.3886877\u0022,\u0022data\u0022:{\u0022Name\u0022:\u0022name\u0022,\u0022Age\u0022:9}}]", + "StatusCode": 200, + "ResponseHeaders": { + "api-supported-versions": "2018-01-01", + "Content-Length": "0", + "Date": "Mon, 30 Nov 2020 05:55:12 GMT", + "Server": "Microsoft-HTTPAPI/2.0", + "Strict-Transport-Security": "max-age=31536000; includeSubDomains", + "x-ms-request-id": "e395be7e-1331-4473-a709-82aa8e9cb6db" + }, + "ResponseBody": [] + } + ], + "Variables": { + "DateTimeOffsetNow": "2020-11-29T21:55:12.3886877-08:00", + "EVENT_GRID_CLOUD_EVENT_TOPIC_ENDPOINT": "https://jolov-cloud.centralus-1.eventgrid.azure.net/api/events", + "EVENT_GRID_CLOUD_EVENT_TOPIC_KEY": "Kg==", + "RandomSeed": "966298239" + } +} \ No newline at end of file From 25867224af7efa466f6a2ad0a71e61c0a69284b0 Mon Sep 17 00:00:00 2001 From: JoshLove-msft <54595583+JoshLove-msft@users.noreply.github.com> Date: Tue, 1 Dec 2020 12:34:25 -0800 Subject: [PATCH 2/4] PR fb --- eng/.docsettings.yml | 1 + .../Azure.Messaging.EventGrid.sln | 12 ++++++++++++ .../CHANGELOG.md | 0 .../Directory.Build.props | 0 .../README.md | 5 ++--- ...ive.CloudEvents.EventGrid.netstandard2.0.cs | 0 .../src/EventGridPublisherClientExtensions.cs | 4 ++-- ...ng.EventGrid.CloudNativeCloudEvents.csproj} | 0 .../tests/CloudEventTests.cs | 18 +++++------------- .../tests/CloudNativeLiveTests.cs | 2 +- ...ntGrid.CloudNativeCloudEvents.Tests.csproj} | 10 ++++++---- .../CanPublishCloudEvent.json | 0 .../CanPublishCloudEventAsync.json | 0 13 files changed, 29 insertions(+), 23 deletions(-) rename sdk/eventgrid/{Microsoft.Azure.CloudNative.CloudEvents.EventGrid => Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents}/CHANGELOG.md (100%) rename sdk/eventgrid/{Microsoft.Azure.CloudNative.CloudEvents.EventGrid => Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents}/Directory.Build.props (100%) rename sdk/eventgrid/{Microsoft.Azure.CloudNative.CloudEvents.EventGrid => Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents}/README.md (87%) rename sdk/eventgrid/{Microsoft.Azure.CloudNative.CloudEvents.EventGrid => Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents}/api/Microsoft.Azure.CloudNative.CloudEvents.EventGrid.netstandard2.0.cs (100%) rename sdk/eventgrid/{Microsoft.Azure.CloudNative.CloudEvents.EventGrid => Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents}/src/EventGridPublisherClientExtensions.cs (97%) rename sdk/eventgrid/{Microsoft.Azure.CloudNative.CloudEvents.EventGrid/src/Microsoft.Azure.CloudNative.CloudEvents.EventGrid.csproj => Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents/src/Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents.csproj} (100%) rename sdk/eventgrid/{Microsoft.Azure.CloudNative.CloudEvents.EventGrid => Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents}/tests/CloudEventTests.cs (87%) rename sdk/eventgrid/{Microsoft.Azure.CloudNative.CloudEvents.EventGrid => Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents}/tests/CloudNativeLiveTests.cs (96%) rename sdk/eventgrid/{Microsoft.Azure.CloudNative.CloudEvents.EventGrid/tests/Microsoft.Azure.CloudNative.CloudEvents.EventGrid.Tests.csproj => Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents/tests/Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents.Tests.csproj} (79%) rename sdk/eventgrid/{Microsoft.Azure.CloudNative.CloudEvents.EventGrid => Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents}/tests/SessionRecords/CloudNativeLiveTests/CanPublishCloudEvent.json (100%) rename sdk/eventgrid/{Microsoft.Azure.CloudNative.CloudEvents.EventGrid => Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents}/tests/SessionRecords/CloudNativeLiveTests/CanPublishCloudEventAsync.json (100%) diff --git a/eng/.docsettings.yml b/eng/.docsettings.yml index 9048aab2e49d2..49ec02099f58d 100644 --- a/eng/.docsettings.yml +++ b/eng/.docsettings.yml @@ -148,6 +148,7 @@ known_content_issues: - ['sdk/extensions/Azure.Extensions.AspNetCore.Configuration.Secrets/README.md', 'azure-sdk-tools/issues/404'] - ['sdk/extensions/Microsoft.Azure.WebJobs.Extensions.Clients/README.md','azure-sdk-tools/issues/404'] - ['sdk/extensions/Microsoft.Extensions.Azure/README.md','#5499'] + - ['sdk/eventgrid/Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents/README.md', '#15423'] - ['sdk/eventhub/README.md','azure-sdk-tools/issues/42'] - ['sdk/search/README.md','azure-sdk-tools/issues/42'] - ['sdk/formrecognizer/Azure.AI.FormRecognizer/README.md','#5499'] diff --git a/sdk/eventgrid/Azure.Messaging.EventGrid/Azure.Messaging.EventGrid.sln b/sdk/eventgrid/Azure.Messaging.EventGrid/Azure.Messaging.EventGrid.sln index 2474f9baa6cad..f7da22ebd0d86 100644 --- a/sdk/eventgrid/Azure.Messaging.EventGrid/Azure.Messaging.EventGrid.sln +++ b/sdk/eventgrid/Azure.Messaging.EventGrid/Azure.Messaging.EventGrid.sln @@ -13,6 +13,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Azure.Core.Experimental", " EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Azure.Core", "..\..\core\Azure.Core\src\Azure.Core.csproj", "{21CF4B4A-5027-46D0-B50A-976BF8483095}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents", "..\Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents\src\Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents.csproj", "{A24C8A1C-B6A0-4F50-A690-9B1D3DF9228C}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents.Tests", "..\Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents\tests\Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents.Tests.csproj", "{28B77D76-084F-4C7E-8A1B-631444EED6A2}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -39,6 +43,14 @@ Global {21CF4B4A-5027-46D0-B50A-976BF8483095}.Debug|Any CPU.Build.0 = Debug|Any CPU {21CF4B4A-5027-46D0-B50A-976BF8483095}.Release|Any CPU.ActiveCfg = Release|Any CPU {21CF4B4A-5027-46D0-B50A-976BF8483095}.Release|Any CPU.Build.0 = Release|Any CPU + {A24C8A1C-B6A0-4F50-A690-9B1D3DF9228C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A24C8A1C-B6A0-4F50-A690-9B1D3DF9228C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A24C8A1C-B6A0-4F50-A690-9B1D3DF9228C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A24C8A1C-B6A0-4F50-A690-9B1D3DF9228C}.Release|Any CPU.Build.0 = Release|Any CPU + {28B77D76-084F-4C7E-8A1B-631444EED6A2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {28B77D76-084F-4C7E-8A1B-631444EED6A2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {28B77D76-084F-4C7E-8A1B-631444EED6A2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {28B77D76-084F-4C7E-8A1B-631444EED6A2}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/sdk/eventgrid/Microsoft.Azure.CloudNative.CloudEvents.EventGrid/CHANGELOG.md b/sdk/eventgrid/Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents/CHANGELOG.md similarity index 100% rename from sdk/eventgrid/Microsoft.Azure.CloudNative.CloudEvents.EventGrid/CHANGELOG.md rename to sdk/eventgrid/Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents/CHANGELOG.md diff --git a/sdk/eventgrid/Microsoft.Azure.CloudNative.CloudEvents.EventGrid/Directory.Build.props b/sdk/eventgrid/Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents/Directory.Build.props similarity index 100% rename from sdk/eventgrid/Microsoft.Azure.CloudNative.CloudEvents.EventGrid/Directory.Build.props rename to sdk/eventgrid/Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents/Directory.Build.props diff --git a/sdk/eventgrid/Microsoft.Azure.CloudNative.CloudEvents.EventGrid/README.md b/sdk/eventgrid/Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents/README.md similarity index 87% rename from sdk/eventgrid/Microsoft.Azure.CloudNative.CloudEvents.EventGrid/README.md rename to sdk/eventgrid/Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents/README.md index b75b0733adb3c..595712464b08f 100644 --- a/sdk/eventgrid/Microsoft.Azure.CloudNative.CloudEvents.EventGrid/README.md +++ b/sdk/eventgrid/Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents/README.md @@ -42,8 +42,7 @@ When you submit a pull request, a CLA-bot will automatically determine whether y This project has adopted the [Microsoft Open Source Code of Conduct][code_of_conduct]. For more information see the [Code of Conduct FAQ][code_of_conduct_faq] or contact opencode@microsoft.com with any additional questions or comments. -![Impressions](https://azure-sdk-impressions.azurewebsites.net/api/impressions/azure-sdk-for-net%2Fsdk%2Fcore%2FMicrosoft.Azure.Core.NewtonsoftJson%2FREADME.png) +![Impressions](https://azure-sdk-impressions.azurewebsites.net/api/impressions/azure-sdk-for-net%2Fsdk%2Feventgrid%2FMicrosoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents%2FREADME.png) [code_of_conduct]: https://opensource.microsoft.com/codeofconduct -[code_of_conduct_faq]: https://opensource.microsoft.com/codeofconduct/faq/ -[microsoft_spatial_package]: https://www.nuget.org/packages/Microsoft.Spatial/ +[code_of_conduct_faq]: https://opensource.microsoft.com/codeofconduct/faq/ \ No newline at end of file diff --git a/sdk/eventgrid/Microsoft.Azure.CloudNative.CloudEvents.EventGrid/api/Microsoft.Azure.CloudNative.CloudEvents.EventGrid.netstandard2.0.cs b/sdk/eventgrid/Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents/api/Microsoft.Azure.CloudNative.CloudEvents.EventGrid.netstandard2.0.cs similarity index 100% rename from sdk/eventgrid/Microsoft.Azure.CloudNative.CloudEvents.EventGrid/api/Microsoft.Azure.CloudNative.CloudEvents.EventGrid.netstandard2.0.cs rename to sdk/eventgrid/Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents/api/Microsoft.Azure.CloudNative.CloudEvents.EventGrid.netstandard2.0.cs diff --git a/sdk/eventgrid/Microsoft.Azure.CloudNative.CloudEvents.EventGrid/src/EventGridPublisherClientExtensions.cs b/sdk/eventgrid/Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents/src/EventGridPublisherClientExtensions.cs similarity index 97% rename from sdk/eventgrid/Microsoft.Azure.CloudNative.CloudEvents.EventGrid/src/EventGridPublisherClientExtensions.cs rename to sdk/eventgrid/Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents/src/EventGridPublisherClientExtensions.cs index 8e1443346cc4b..6123fd0eae19f 100644 --- a/sdk/eventgrid/Microsoft.Azure.CloudNative.CloudEvents.EventGrid/src/EventGridPublisherClientExtensions.cs +++ b/sdk/eventgrid/Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents/src/EventGridPublisherClientExtensions.cs @@ -16,7 +16,7 @@ using CloudEvent = CloudNative.CloudEvents.CloudEvent; #pragma warning disable AZC0001 // Use one of the following pre-approved namespace groups (https://azure.github.io/azure-sdk/registered_namespaces.html): Azure.AI, Azure.Analytics, Azure.Communication, Azure.Data, Azure.DigitalTwins, Azure.Iot, Azure.Learn, Azure.Media, Azure.Management, Azure.Messaging, Azure.Search, Azure.Security, Azure.Storage, Azure.Template, Azure.Identity, Microsoft.Extensions.Azure -namespace Microsoft.Azure.CloudNative.CloudEvents.EventGrid +namespace Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents #pragma warning restore AZC0001 // Use one of the following pre-approved namespace groups (https://azure.github.io/azure-sdk/registered_namespaces.html): Azure.AI, Azure.Analytics, Azure.Communication, Azure.Data, Azure.DigitalTwins, Azure.Iot, Azure.Learn, Azure.Media, Azure.Management, Azure.Messaging, Azure.Search, Azure.Security, Azure.Storage, Azure.Template, Azure.Identity, Microsoft.Extensions.Azure { /// @@ -66,7 +66,7 @@ private static async Task SendCloudEventsInternalAsync( } using var stream = new MemoryStream(); - var writer = new Utf8JsonWriter(stream); + using var writer = new Utf8JsonWriter(stream); writer.WriteStartArray(); foreach (var cloudEvent in cloudEvents) { diff --git a/sdk/eventgrid/Microsoft.Azure.CloudNative.CloudEvents.EventGrid/src/Microsoft.Azure.CloudNative.CloudEvents.EventGrid.csproj b/sdk/eventgrid/Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents/src/Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents.csproj similarity index 100% rename from sdk/eventgrid/Microsoft.Azure.CloudNative.CloudEvents.EventGrid/src/Microsoft.Azure.CloudNative.CloudEvents.EventGrid.csproj rename to sdk/eventgrid/Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents/src/Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents.csproj diff --git a/sdk/eventgrid/Microsoft.Azure.CloudNative.CloudEvents.EventGrid/tests/CloudEventTests.cs b/sdk/eventgrid/Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents/tests/CloudEventTests.cs similarity index 87% rename from sdk/eventgrid/Microsoft.Azure.CloudNative.CloudEvents.EventGrid/tests/CloudEventTests.cs rename to sdk/eventgrid/Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents/tests/CloudEventTests.cs index 487b38001a503..5b0f8c74ea7ec 100644 --- a/sdk/eventgrid/Microsoft.Azure.CloudNative.CloudEvents.EventGrid/tests/CloudEventTests.cs +++ b/sdk/eventgrid/Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents/tests/CloudEventTests.cs @@ -17,7 +17,7 @@ using NUnit.Framework; using CloudEvent = CloudNative.CloudEvents.CloudEvent; -namespace Microsoft.Azure.CloudNative.CloudEvents.EventGrid.Tests +namespace Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents.Tests { public class CloudEventTests { @@ -27,7 +27,6 @@ public class CloudEventTests private static readonly JsonEventFormatter s_eventFormatter = new JsonEventFormatter(); - [Test] [TestCase(false, false)] [TestCase(true, true)] @@ -117,20 +116,13 @@ private static List DeserializeRequest(Request request) stream.Position = 0; JsonDocument requestDocument = JsonDocument.Parse(stream); var cloudEvents = new List(); - // Parse JsonElement into separate events, deserialize event envelope properties - if (requestDocument.RootElement.ValueKind == JsonValueKind.Object) + + foreach (JsonElement property in requestDocument.RootElement.EnumerateArray()) { - var bytes = JsonSerializer.SerializeToUtf8Bytes(requestDocument.RootElement, typeof(JsonElement)); + var bytes = JsonSerializer.SerializeToUtf8Bytes(property, typeof(JsonElement)); cloudEvents.Add(s_eventFormatter.DecodeStructuredEvent(bytes)); } - else if (requestDocument.RootElement.ValueKind == JsonValueKind.Array) - { - foreach (JsonElement property in requestDocument.RootElement.EnumerateArray()) - { - var bytes = JsonSerializer.SerializeToUtf8Bytes(property, typeof(JsonElement)); - cloudEvents.Add(s_eventFormatter.DecodeStructuredEvent(bytes)); - } - } + return cloudEvents; } } diff --git a/sdk/eventgrid/Microsoft.Azure.CloudNative.CloudEvents.EventGrid/tests/CloudNativeLiveTests.cs b/sdk/eventgrid/Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents/tests/CloudNativeLiveTests.cs similarity index 96% rename from sdk/eventgrid/Microsoft.Azure.CloudNative.CloudEvents.EventGrid/tests/CloudNativeLiveTests.cs rename to sdk/eventgrid/Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents/tests/CloudNativeLiveTests.cs index 5905a4e4f415c..3ba34cdba3ab3 100644 --- a/sdk/eventgrid/Microsoft.Azure.CloudNative.CloudEvents.EventGrid/tests/CloudNativeLiveTests.cs +++ b/sdk/eventgrid/Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents/tests/CloudNativeLiveTests.cs @@ -10,7 +10,7 @@ using System.Threading.Tasks; using CloudEvent = CloudNative.CloudEvents.CloudEvent; -namespace Microsoft.Azure.CloudNative.CloudEvents.EventGrid.Tests +namespace Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents.Tests { public class CloudNativeLiveTests : EventGridLiveTestBase { diff --git a/sdk/eventgrid/Microsoft.Azure.CloudNative.CloudEvents.EventGrid/tests/Microsoft.Azure.CloudNative.CloudEvents.EventGrid.Tests.csproj b/sdk/eventgrid/Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents/tests/Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents.Tests.csproj similarity index 79% rename from sdk/eventgrid/Microsoft.Azure.CloudNative.CloudEvents.EventGrid/tests/Microsoft.Azure.CloudNative.CloudEvents.EventGrid.Tests.csproj rename to sdk/eventgrid/Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents/tests/Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents.Tests.csproj index 6673007f01b71..0c6b7f94bab7c 100644 --- a/sdk/eventgrid/Microsoft.Azure.CloudNative.CloudEvents.EventGrid/tests/Microsoft.Azure.CloudNative.CloudEvents.EventGrid.Tests.csproj +++ b/sdk/eventgrid/Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents/tests/Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents.Tests.csproj @@ -6,18 +6,20 @@ $(NoWarn);CS1591 - - - + - + + + + + diff --git a/sdk/eventgrid/Microsoft.Azure.CloudNative.CloudEvents.EventGrid/tests/SessionRecords/CloudNativeLiveTests/CanPublishCloudEvent.json b/sdk/eventgrid/Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents/tests/SessionRecords/CloudNativeLiveTests/CanPublishCloudEvent.json similarity index 100% rename from sdk/eventgrid/Microsoft.Azure.CloudNative.CloudEvents.EventGrid/tests/SessionRecords/CloudNativeLiveTests/CanPublishCloudEvent.json rename to sdk/eventgrid/Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents/tests/SessionRecords/CloudNativeLiveTests/CanPublishCloudEvent.json diff --git a/sdk/eventgrid/Microsoft.Azure.CloudNative.CloudEvents.EventGrid/tests/SessionRecords/CloudNativeLiveTests/CanPublishCloudEventAsync.json b/sdk/eventgrid/Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents/tests/SessionRecords/CloudNativeLiveTests/CanPublishCloudEventAsync.json similarity index 100% rename from sdk/eventgrid/Microsoft.Azure.CloudNative.CloudEvents.EventGrid/tests/SessionRecords/CloudNativeLiveTests/CanPublishCloudEventAsync.json rename to sdk/eventgrid/Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents/tests/SessionRecords/CloudNativeLiveTests/CanPublishCloudEventAsync.json From f8b44cff81f185063bd06710b459de77de7ef539 Mon Sep 17 00:00:00 2001 From: JoshLove-msft <54595583+JoshLove-msft@users.noreply.github.com> Date: Tue, 1 Dec 2020 12:42:21 -0800 Subject: [PATCH 3/4] Fix NUnit casing --- ...zure.Messaging.EventGrid.CloudNativeCloudEvents.Tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/eventgrid/Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents/tests/Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents.Tests.csproj b/sdk/eventgrid/Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents/tests/Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents.Tests.csproj index 0c6b7f94bab7c..c7f3d2d1d53c6 100644 --- a/sdk/eventgrid/Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents/tests/Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents.Tests.csproj +++ b/sdk/eventgrid/Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents/tests/Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents.Tests.csproj @@ -9,7 +9,7 @@ - + From ac45ff9d84f71558680f8f98a9bbd854682f8253 Mon Sep 17 00:00:00 2001 From: JoshLove-msft <54595583+JoshLove-msft@users.noreply.github.com> Date: Tue, 1 Dec 2020 13:21:19 -0800 Subject: [PATCH 4/4] Export API --- ...essaging.EventGrid.CloudNativeCloudEvents.netstandard2.0.cs} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename sdk/eventgrid/Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents/api/{Microsoft.Azure.CloudNative.CloudEvents.EventGrid.netstandard2.0.cs => Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents.netstandard2.0.cs} (91%) diff --git a/sdk/eventgrid/Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents/api/Microsoft.Azure.CloudNative.CloudEvents.EventGrid.netstandard2.0.cs b/sdk/eventgrid/Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents/api/Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents.netstandard2.0.cs similarity index 91% rename from sdk/eventgrid/Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents/api/Microsoft.Azure.CloudNative.CloudEvents.EventGrid.netstandard2.0.cs rename to sdk/eventgrid/Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents/api/Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents.netstandard2.0.cs index d503fa50e4b62..9a79af973fc23 100644 --- a/sdk/eventgrid/Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents/api/Microsoft.Azure.CloudNative.CloudEvents.EventGrid.netstandard2.0.cs +++ b/sdk/eventgrid/Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents/api/Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents.netstandard2.0.cs @@ -1,4 +1,4 @@ -namespace Microsoft.Azure.CloudNative.CloudEvents.EventGrid +namespace Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents { public static partial class EventGridPublisherClientExtensions {