From 67e096cc417d0ce12957da8c08f3e2d2b7fec281 Mon Sep 17 00:00:00 2001 From: Charley Wu Date: Mon, 10 May 2021 22:40:04 +0800 Subject: [PATCH 1/6] Rename folders --- examples/eventwebhook/consumer/Dockerfile | 20 +++++++++---------- examples/eventwebhook/consumer/README.md | 2 +- .../consumer/SendGridEventWebhookConsumer.sln | 8 ++++---- .../Controllers/EventWebhookController.cs | 0 .../Converters/CategoryConverter.cs | 0 .../EventWebhook/Converters/UriConverter.cs | 0 .../EventWebhook/EventWebhook.csproj | 0 .../EventWebhook/Models/BounceEvent.cs | 0 .../EventWebhook/Models/BounceEventType.cs | 0 .../EventWebhook/Models/Category.cs | 0 .../EventWebhook/Models/ClickEvent.cs | 0 .../EventWebhook/Models/DeferredEvent.cs | 0 .../EventWebhook/Models/DeliveredEvent.cs | 0 .../EventWebhook/Models/DroppedEvent.cs | 0 .../{Src => src}/EventWebhook/Models/Event.cs | 0 .../EventWebhook/Models/EventType.cs | 0 .../Models/GroupResubscribeEvent.cs | 0 .../Models/GroupUnsubscribeEvent.cs | 0 .../EventWebhook/Models/OpenEvent.cs | 0 .../{Src => src}/EventWebhook/Models/Pool.cs | 0 .../EventWebhook/Models/ProcessedEvent.cs | 0 .../EventWebhook/Models/SpamReportEvent.cs | 0 .../EventWebhook/Models/UnsubscribeEvent.cs | 0 .../EventWebhook/Parser/EventConverter.cs | 0 .../EventWebhook/Parser/EventParser.cs | 0 .../{Src => src}/EventWebhook/Program.cs | 0 .../{Src => src}/EventWebhook/Startup.cs | 0 .../Views/EventWebhook/Index.cshtml | 0 .../EventWebhook/appsettings.Development.json | 0 .../EventWebhook/appsettings.json | 0 .../EventWebhook.Tests/EventTests.cs | 0 .../EventWebhook.Tests.csproj | 2 +- .../EventWebhook.Tests/TestData/events.json | 0 .../.vscode/launch.json | 2 +- .../.vscode/tasks.json | 2 +- examples/inbound-webhook-handler/Dockerfile | 20 +++++++++---------- examples/inbound-webhook-handler/README.md | 2 +- .../SendGridInbound.sln | 8 ++++---- .../Inbound/Controllers/InboundController.cs | 0 .../{Src => src}/Inbound/Inbound.csproj | 0 .../Inbound/Models/InboundEmail.cs | 0 .../Inbound/Models/InboundEmailAddress.cs | 0 .../Inbound/Models/InboundEmailAttachment.cs | 0 .../Inbound/Models/InboundEmailEnvelope.cs | 0 .../Inbound/Parsers/InboundWebhookParser.cs | 0 .../{Src => src}/Inbound/Program.cs | 0 .../{Src => src}/Inbound/Startup.cs | 0 .../{Src => src}/Inbound/Util/Extensions.cs | 0 .../Util/InboundWebhookParserHelper.cs | 0 .../Inbound/Views/Inbound/Index.cshtml | 0 .../Inbound/appsettings.Development.json | 0 .../{Src => src}/Inbound/appsettings.json | 0 .../Inbound.Tests/Inbound.Tests.csproj | 2 +- .../IntegrationTests/InboundEndpointsTests.cs | 0 .../Parsers/InboundWebhookParserTests.cs | 0 .../sample_data/default_data.txt | 0 .../sample_data/raw_data_with_attachments.txt | 0 .../raw_email_with_attachments.txt | 0 58 files changed, 34 insertions(+), 34 deletions(-) rename examples/eventwebhook/consumer/{Src => src}/EventWebhook/Controllers/EventWebhookController.cs (100%) rename examples/eventwebhook/consumer/{Src => src}/EventWebhook/Converters/CategoryConverter.cs (100%) rename examples/eventwebhook/consumer/{Src => src}/EventWebhook/Converters/UriConverter.cs (100%) rename examples/eventwebhook/consumer/{Src => src}/EventWebhook/EventWebhook.csproj (100%) rename examples/eventwebhook/consumer/{Src => src}/EventWebhook/Models/BounceEvent.cs (100%) rename examples/eventwebhook/consumer/{Src => src}/EventWebhook/Models/BounceEventType.cs (100%) rename examples/eventwebhook/consumer/{Src => src}/EventWebhook/Models/Category.cs (100%) rename examples/eventwebhook/consumer/{Src => src}/EventWebhook/Models/ClickEvent.cs (100%) rename examples/eventwebhook/consumer/{Src => src}/EventWebhook/Models/DeferredEvent.cs (100%) rename examples/eventwebhook/consumer/{Src => src}/EventWebhook/Models/DeliveredEvent.cs (100%) rename examples/eventwebhook/consumer/{Src => src}/EventWebhook/Models/DroppedEvent.cs (100%) rename examples/eventwebhook/consumer/{Src => src}/EventWebhook/Models/Event.cs (100%) rename examples/eventwebhook/consumer/{Src => src}/EventWebhook/Models/EventType.cs (100%) rename examples/eventwebhook/consumer/{Src => src}/EventWebhook/Models/GroupResubscribeEvent.cs (100%) rename examples/eventwebhook/consumer/{Src => src}/EventWebhook/Models/GroupUnsubscribeEvent.cs (100%) rename examples/eventwebhook/consumer/{Src => src}/EventWebhook/Models/OpenEvent.cs (100%) rename examples/eventwebhook/consumer/{Src => src}/EventWebhook/Models/Pool.cs (100%) rename examples/eventwebhook/consumer/{Src => src}/EventWebhook/Models/ProcessedEvent.cs (100%) rename examples/eventwebhook/consumer/{Src => src}/EventWebhook/Models/SpamReportEvent.cs (100%) rename examples/eventwebhook/consumer/{Src => src}/EventWebhook/Models/UnsubscribeEvent.cs (100%) rename examples/eventwebhook/consumer/{Src => src}/EventWebhook/Parser/EventConverter.cs (100%) rename examples/eventwebhook/consumer/{Src => src}/EventWebhook/Parser/EventParser.cs (100%) rename examples/eventwebhook/consumer/{Src => src}/EventWebhook/Program.cs (100%) rename examples/eventwebhook/consumer/{Src => src}/EventWebhook/Startup.cs (100%) rename examples/eventwebhook/consumer/{Src => src}/EventWebhook/Views/EventWebhook/Index.cshtml (100%) rename examples/eventwebhook/consumer/{Src => src}/EventWebhook/appsettings.Development.json (100%) rename examples/eventwebhook/consumer/{Src => src}/EventWebhook/appsettings.json (100%) rename examples/eventwebhook/consumer/{Tests => tests}/EventWebhook.Tests/EventTests.cs (100%) rename examples/eventwebhook/consumer/{Tests => tests}/EventWebhook.Tests/EventWebhook.Tests.csproj (91%) rename examples/eventwebhook/consumer/{Tests => tests}/EventWebhook.Tests/TestData/events.json (100%) rename examples/inbound-webhook-handler/{Src => src}/Inbound/Controllers/InboundController.cs (100%) rename examples/inbound-webhook-handler/{Src => src}/Inbound/Inbound.csproj (100%) rename examples/inbound-webhook-handler/{Src => src}/Inbound/Models/InboundEmail.cs (100%) rename examples/inbound-webhook-handler/{Src => src}/Inbound/Models/InboundEmailAddress.cs (100%) rename examples/inbound-webhook-handler/{Src => src}/Inbound/Models/InboundEmailAttachment.cs (100%) rename examples/inbound-webhook-handler/{Src => src}/Inbound/Models/InboundEmailEnvelope.cs (100%) rename examples/inbound-webhook-handler/{Src => src}/Inbound/Parsers/InboundWebhookParser.cs (100%) rename examples/inbound-webhook-handler/{Src => src}/Inbound/Program.cs (100%) rename examples/inbound-webhook-handler/{Src => src}/Inbound/Startup.cs (100%) rename examples/inbound-webhook-handler/{Src => src}/Inbound/Util/Extensions.cs (100%) rename examples/inbound-webhook-handler/{Src => src}/Inbound/Util/InboundWebhookParserHelper.cs (100%) rename examples/inbound-webhook-handler/{Src => src}/Inbound/Views/Inbound/Index.cshtml (100%) rename examples/inbound-webhook-handler/{Src => src}/Inbound/appsettings.Development.json (100%) rename examples/inbound-webhook-handler/{Src => src}/Inbound/appsettings.json (100%) rename examples/inbound-webhook-handler/{Tests => tests}/Inbound.Tests/Inbound.Tests.csproj (95%) rename examples/inbound-webhook-handler/{Tests => tests}/Inbound.Tests/IntegrationTests/InboundEndpointsTests.cs (100%) rename examples/inbound-webhook-handler/{Tests => tests}/Inbound.Tests/Parsers/InboundWebhookParserTests.cs (100%) rename examples/inbound-webhook-handler/{Tests => tests}/Inbound.Tests/sample_data/default_data.txt (100%) rename examples/inbound-webhook-handler/{Tests => tests}/Inbound.Tests/sample_data/raw_data_with_attachments.txt (100%) rename examples/inbound-webhook-handler/{Tests => tests}/Inbound.Tests/sample_data/raw_email_with_attachments.txt (100%) diff --git a/examples/eventwebhook/consumer/Dockerfile b/examples/eventwebhook/consumer/Dockerfile index bebfb684b..b5172cfc6 100644 --- a/examples/eventwebhook/consumer/Dockerfile +++ b/examples/eventwebhook/consumer/Dockerfile @@ -1,21 +1,21 @@ FROM microsoft/dotnet:2.1-sdk AS build -WORKDIR /App +WORKDIR /app # copy csproj and restore as distinct layers COPY *.sln . -COPY Src/EventWebhook/*.csproj ./Src/EventWebhook/ -COPY Tests/EventWebhook.Tests/*.csproj ./Tests/EventWebhook.Tests/ +COPY src/EventWebhook/*.csproj ./src/EventWebhook/ +COPY tests/EventWebhook.Tests/*.csproj ./tests/EventWebhook.Tests/ RUN dotnet restore # copy everything else and build app -COPY Src/EventWebhook/. ./Src/EventWebhook/ -WORKDIR /App/Src/EventWebhook -RUN dotnet publish -c Release -o Out +COPY src/EventWebhook/. ./src/EventWebhook/ +WORKDIR /app/src/EventWebhook +RUN dotnet publish -c Release -o out FROM microsoft/dotnet:2.1-aspnetcore-runtime AS runtime -WORKDIR /App -COPY --from=build /App/Src/EventWebhook/Out ./ +WORKDIR /app +COPY --from=build /app/src/EventWebhook/out ./ -RUN echo "ASPNETCORE_URLS=http://0.0.0.0:\$PORT\nDOTNET_RUNNING_IN_CONTAINER=true" > /App/SetupHerokuEnv.sh && chmod +x /App/SetupHerokuEnv.sh +RUN echo "ASPNETCORE_URLS=http://0.0.0.0:\$PORT\nDOTNET_RUNNING_IN_CONTAINER=true" > /app/SetupHerokuEnv.sh && chmod +x /app/SetupHerokuEnv.sh -CMD /bin/bash -c "source /App/SetupHerokuEnv.sh && dotnet EventWebhook.dll" \ No newline at end of file +CMD /bin/bash -c "source /app/SetupHerokuEnv.sh && dotnet EventWebhook.dll" \ No newline at end of file diff --git a/examples/eventwebhook/consumer/README.md b/examples/eventwebhook/consumer/README.md index 9ec23f614..e089e8d52 100644 --- a/examples/eventwebhook/consumer/README.md +++ b/examples/eventwebhook/consumer/README.md @@ -42,7 +42,7 @@ cd sendgrid-csharp/examples/eventwebhook/consumer dotnet restore -dotnet run --project .\Src\EventWebhook\EventWebhook.csproj +dotnet run --project .\src\EventWebhook\EventWebhook.csproj ``` Above will start server listening on a random port like below diff --git a/examples/eventwebhook/consumer/SendGridEventWebhookConsumer.sln b/examples/eventwebhook/consumer/SendGridEventWebhookConsumer.sln index edc1dedce..00eb188e6 100644 --- a/examples/eventwebhook/consumer/SendGridEventWebhookConsumer.sln +++ b/examples/eventwebhook/consumer/SendGridEventWebhookConsumer.sln @@ -3,13 +3,13 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 VisualStudioVersion = 15.0.26124.0 MinimumVisualStudioVersion = 15.0.26124.0 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Src", "Src", "{B08185CF-3F2E-4638-877B-587F5F60CA74}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{B08185CF-3F2E-4638-877B-587F5F60CA74}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EventWebhook", "Src\EventWebhook\EventWebhook.csproj", "{3897C29A-AE26-4FE5-8421-71896EC935C5}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EventWebhook", "src\EventWebhook\EventWebhook.csproj", "{3897C29A-AE26-4FE5-8421-71896EC935C5}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{81CAC535-9854-47AD-9D3E-385AC2668C35}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{81CAC535-9854-47AD-9D3E-385AC2668C35}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EventWebhook.Tests", "Tests\EventWebhook.Tests\EventWebhook.Tests.csproj", "{5C6AA0EB-57B7-4E76-804A-70F7A7DF4FC0}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EventWebhook.Tests", "tests\EventWebhook.Tests\EventWebhook.Tests.csproj", "{5C6AA0EB-57B7-4E76-804A-70F7A7DF4FC0}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/examples/eventwebhook/consumer/Src/EventWebhook/Controllers/EventWebhookController.cs b/examples/eventwebhook/consumer/src/EventWebhook/Controllers/EventWebhookController.cs similarity index 100% rename from examples/eventwebhook/consumer/Src/EventWebhook/Controllers/EventWebhookController.cs rename to examples/eventwebhook/consumer/src/EventWebhook/Controllers/EventWebhookController.cs diff --git a/examples/eventwebhook/consumer/Src/EventWebhook/Converters/CategoryConverter.cs b/examples/eventwebhook/consumer/src/EventWebhook/Converters/CategoryConverter.cs similarity index 100% rename from examples/eventwebhook/consumer/Src/EventWebhook/Converters/CategoryConverter.cs rename to examples/eventwebhook/consumer/src/EventWebhook/Converters/CategoryConverter.cs diff --git a/examples/eventwebhook/consumer/Src/EventWebhook/Converters/UriConverter.cs b/examples/eventwebhook/consumer/src/EventWebhook/Converters/UriConverter.cs similarity index 100% rename from examples/eventwebhook/consumer/Src/EventWebhook/Converters/UriConverter.cs rename to examples/eventwebhook/consumer/src/EventWebhook/Converters/UriConverter.cs diff --git a/examples/eventwebhook/consumer/Src/EventWebhook/EventWebhook.csproj b/examples/eventwebhook/consumer/src/EventWebhook/EventWebhook.csproj similarity index 100% rename from examples/eventwebhook/consumer/Src/EventWebhook/EventWebhook.csproj rename to examples/eventwebhook/consumer/src/EventWebhook/EventWebhook.csproj diff --git a/examples/eventwebhook/consumer/Src/EventWebhook/Models/BounceEvent.cs b/examples/eventwebhook/consumer/src/EventWebhook/Models/BounceEvent.cs similarity index 100% rename from examples/eventwebhook/consumer/Src/EventWebhook/Models/BounceEvent.cs rename to examples/eventwebhook/consumer/src/EventWebhook/Models/BounceEvent.cs diff --git a/examples/eventwebhook/consumer/Src/EventWebhook/Models/BounceEventType.cs b/examples/eventwebhook/consumer/src/EventWebhook/Models/BounceEventType.cs similarity index 100% rename from examples/eventwebhook/consumer/Src/EventWebhook/Models/BounceEventType.cs rename to examples/eventwebhook/consumer/src/EventWebhook/Models/BounceEventType.cs diff --git a/examples/eventwebhook/consumer/Src/EventWebhook/Models/Category.cs b/examples/eventwebhook/consumer/src/EventWebhook/Models/Category.cs similarity index 100% rename from examples/eventwebhook/consumer/Src/EventWebhook/Models/Category.cs rename to examples/eventwebhook/consumer/src/EventWebhook/Models/Category.cs diff --git a/examples/eventwebhook/consumer/Src/EventWebhook/Models/ClickEvent.cs b/examples/eventwebhook/consumer/src/EventWebhook/Models/ClickEvent.cs similarity index 100% rename from examples/eventwebhook/consumer/Src/EventWebhook/Models/ClickEvent.cs rename to examples/eventwebhook/consumer/src/EventWebhook/Models/ClickEvent.cs diff --git a/examples/eventwebhook/consumer/Src/EventWebhook/Models/DeferredEvent.cs b/examples/eventwebhook/consumer/src/EventWebhook/Models/DeferredEvent.cs similarity index 100% rename from examples/eventwebhook/consumer/Src/EventWebhook/Models/DeferredEvent.cs rename to examples/eventwebhook/consumer/src/EventWebhook/Models/DeferredEvent.cs diff --git a/examples/eventwebhook/consumer/Src/EventWebhook/Models/DeliveredEvent.cs b/examples/eventwebhook/consumer/src/EventWebhook/Models/DeliveredEvent.cs similarity index 100% rename from examples/eventwebhook/consumer/Src/EventWebhook/Models/DeliveredEvent.cs rename to examples/eventwebhook/consumer/src/EventWebhook/Models/DeliveredEvent.cs diff --git a/examples/eventwebhook/consumer/Src/EventWebhook/Models/DroppedEvent.cs b/examples/eventwebhook/consumer/src/EventWebhook/Models/DroppedEvent.cs similarity index 100% rename from examples/eventwebhook/consumer/Src/EventWebhook/Models/DroppedEvent.cs rename to examples/eventwebhook/consumer/src/EventWebhook/Models/DroppedEvent.cs diff --git a/examples/eventwebhook/consumer/Src/EventWebhook/Models/Event.cs b/examples/eventwebhook/consumer/src/EventWebhook/Models/Event.cs similarity index 100% rename from examples/eventwebhook/consumer/Src/EventWebhook/Models/Event.cs rename to examples/eventwebhook/consumer/src/EventWebhook/Models/Event.cs diff --git a/examples/eventwebhook/consumer/Src/EventWebhook/Models/EventType.cs b/examples/eventwebhook/consumer/src/EventWebhook/Models/EventType.cs similarity index 100% rename from examples/eventwebhook/consumer/Src/EventWebhook/Models/EventType.cs rename to examples/eventwebhook/consumer/src/EventWebhook/Models/EventType.cs diff --git a/examples/eventwebhook/consumer/Src/EventWebhook/Models/GroupResubscribeEvent.cs b/examples/eventwebhook/consumer/src/EventWebhook/Models/GroupResubscribeEvent.cs similarity index 100% rename from examples/eventwebhook/consumer/Src/EventWebhook/Models/GroupResubscribeEvent.cs rename to examples/eventwebhook/consumer/src/EventWebhook/Models/GroupResubscribeEvent.cs diff --git a/examples/eventwebhook/consumer/Src/EventWebhook/Models/GroupUnsubscribeEvent.cs b/examples/eventwebhook/consumer/src/EventWebhook/Models/GroupUnsubscribeEvent.cs similarity index 100% rename from examples/eventwebhook/consumer/Src/EventWebhook/Models/GroupUnsubscribeEvent.cs rename to examples/eventwebhook/consumer/src/EventWebhook/Models/GroupUnsubscribeEvent.cs diff --git a/examples/eventwebhook/consumer/Src/EventWebhook/Models/OpenEvent.cs b/examples/eventwebhook/consumer/src/EventWebhook/Models/OpenEvent.cs similarity index 100% rename from examples/eventwebhook/consumer/Src/EventWebhook/Models/OpenEvent.cs rename to examples/eventwebhook/consumer/src/EventWebhook/Models/OpenEvent.cs diff --git a/examples/eventwebhook/consumer/Src/EventWebhook/Models/Pool.cs b/examples/eventwebhook/consumer/src/EventWebhook/Models/Pool.cs similarity index 100% rename from examples/eventwebhook/consumer/Src/EventWebhook/Models/Pool.cs rename to examples/eventwebhook/consumer/src/EventWebhook/Models/Pool.cs diff --git a/examples/eventwebhook/consumer/Src/EventWebhook/Models/ProcessedEvent.cs b/examples/eventwebhook/consumer/src/EventWebhook/Models/ProcessedEvent.cs similarity index 100% rename from examples/eventwebhook/consumer/Src/EventWebhook/Models/ProcessedEvent.cs rename to examples/eventwebhook/consumer/src/EventWebhook/Models/ProcessedEvent.cs diff --git a/examples/eventwebhook/consumer/Src/EventWebhook/Models/SpamReportEvent.cs b/examples/eventwebhook/consumer/src/EventWebhook/Models/SpamReportEvent.cs similarity index 100% rename from examples/eventwebhook/consumer/Src/EventWebhook/Models/SpamReportEvent.cs rename to examples/eventwebhook/consumer/src/EventWebhook/Models/SpamReportEvent.cs diff --git a/examples/eventwebhook/consumer/Src/EventWebhook/Models/UnsubscribeEvent.cs b/examples/eventwebhook/consumer/src/EventWebhook/Models/UnsubscribeEvent.cs similarity index 100% rename from examples/eventwebhook/consumer/Src/EventWebhook/Models/UnsubscribeEvent.cs rename to examples/eventwebhook/consumer/src/EventWebhook/Models/UnsubscribeEvent.cs diff --git a/examples/eventwebhook/consumer/Src/EventWebhook/Parser/EventConverter.cs b/examples/eventwebhook/consumer/src/EventWebhook/Parser/EventConverter.cs similarity index 100% rename from examples/eventwebhook/consumer/Src/EventWebhook/Parser/EventConverter.cs rename to examples/eventwebhook/consumer/src/EventWebhook/Parser/EventConverter.cs diff --git a/examples/eventwebhook/consumer/Src/EventWebhook/Parser/EventParser.cs b/examples/eventwebhook/consumer/src/EventWebhook/Parser/EventParser.cs similarity index 100% rename from examples/eventwebhook/consumer/Src/EventWebhook/Parser/EventParser.cs rename to examples/eventwebhook/consumer/src/EventWebhook/Parser/EventParser.cs diff --git a/examples/eventwebhook/consumer/Src/EventWebhook/Program.cs b/examples/eventwebhook/consumer/src/EventWebhook/Program.cs similarity index 100% rename from examples/eventwebhook/consumer/Src/EventWebhook/Program.cs rename to examples/eventwebhook/consumer/src/EventWebhook/Program.cs diff --git a/examples/eventwebhook/consumer/Src/EventWebhook/Startup.cs b/examples/eventwebhook/consumer/src/EventWebhook/Startup.cs similarity index 100% rename from examples/eventwebhook/consumer/Src/EventWebhook/Startup.cs rename to examples/eventwebhook/consumer/src/EventWebhook/Startup.cs diff --git a/examples/eventwebhook/consumer/Src/EventWebhook/Views/EventWebhook/Index.cshtml b/examples/eventwebhook/consumer/src/EventWebhook/Views/EventWebhook/Index.cshtml similarity index 100% rename from examples/eventwebhook/consumer/Src/EventWebhook/Views/EventWebhook/Index.cshtml rename to examples/eventwebhook/consumer/src/EventWebhook/Views/EventWebhook/Index.cshtml diff --git a/examples/eventwebhook/consumer/Src/EventWebhook/appsettings.Development.json b/examples/eventwebhook/consumer/src/EventWebhook/appsettings.Development.json similarity index 100% rename from examples/eventwebhook/consumer/Src/EventWebhook/appsettings.Development.json rename to examples/eventwebhook/consumer/src/EventWebhook/appsettings.Development.json diff --git a/examples/eventwebhook/consumer/Src/EventWebhook/appsettings.json b/examples/eventwebhook/consumer/src/EventWebhook/appsettings.json similarity index 100% rename from examples/eventwebhook/consumer/Src/EventWebhook/appsettings.json rename to examples/eventwebhook/consumer/src/EventWebhook/appsettings.json diff --git a/examples/eventwebhook/consumer/Tests/EventWebhook.Tests/EventTests.cs b/examples/eventwebhook/consumer/tests/EventWebhook.Tests/EventTests.cs similarity index 100% rename from examples/eventwebhook/consumer/Tests/EventWebhook.Tests/EventTests.cs rename to examples/eventwebhook/consumer/tests/EventWebhook.Tests/EventTests.cs diff --git a/examples/eventwebhook/consumer/Tests/EventWebhook.Tests/EventWebhook.Tests.csproj b/examples/eventwebhook/consumer/tests/EventWebhook.Tests/EventWebhook.Tests.csproj similarity index 91% rename from examples/eventwebhook/consumer/Tests/EventWebhook.Tests/EventWebhook.Tests.csproj rename to examples/eventwebhook/consumer/tests/EventWebhook.Tests/EventWebhook.Tests.csproj index 2f6ed144e..77985c810 100644 --- a/examples/eventwebhook/consumer/Tests/EventWebhook.Tests/EventWebhook.Tests.csproj +++ b/examples/eventwebhook/consumer/tests/EventWebhook.Tests/EventWebhook.Tests.csproj @@ -14,7 +14,7 @@ - + diff --git a/examples/eventwebhook/consumer/Tests/EventWebhook.Tests/TestData/events.json b/examples/eventwebhook/consumer/tests/EventWebhook.Tests/TestData/events.json similarity index 100% rename from examples/eventwebhook/consumer/Tests/EventWebhook.Tests/TestData/events.json rename to examples/eventwebhook/consumer/tests/EventWebhook.Tests/TestData/events.json diff --git a/examples/inbound-webhook-handler/.vscode/launch.json b/examples/inbound-webhook-handler/.vscode/launch.json index 47b437d9b..f6a64a4c5 100644 --- a/examples/inbound-webhook-handler/.vscode/launch.json +++ b/examples/inbound-webhook-handler/.vscode/launch.json @@ -11,7 +11,7 @@ "preLaunchTask": "build", "program": "${workspaceFolder}/src/inbound/bin/Debug/netcoreapp2.1/inbound.dll", "args": [], - "cwd": "${workspaceFolder}/src/inbound", + "cwd": "${workspaceFolder}/src/Inbound", "stopAtEntry": false, "internalConsoleOptions": "openOnSessionStart", "launchBrowser": { diff --git a/examples/inbound-webhook-handler/.vscode/tasks.json b/examples/inbound-webhook-handler/.vscode/tasks.json index 25a4d86b5..6c359bace 100644 --- a/examples/inbound-webhook-handler/.vscode/tasks.json +++ b/examples/inbound-webhook-handler/.vscode/tasks.json @@ -7,7 +7,7 @@ "type": "process", "args": [ "build", - "${workspaceFolder}/src/inbound/inbound.csproj" + "${workspaceFolder}/src/Inbound/Inbound.csproj" ], "problemMatcher": "$msCompile" } diff --git a/examples/inbound-webhook-handler/Dockerfile b/examples/inbound-webhook-handler/Dockerfile index 5d5f9b080..e420c8fa5 100644 --- a/examples/inbound-webhook-handler/Dockerfile +++ b/examples/inbound-webhook-handler/Dockerfile @@ -1,21 +1,21 @@ FROM microsoft/dotnet:2.1-sdk AS build -WORKDIR /App +WORKDIR /app # copy csproj and restore as distinct layers COPY *.sln . -COPY Src/Inbound/*.csproj ./Src/Inbound/ -COPY Tests/Inbound.Tests/*.csproj ./Tests/Inbound.Tests/ +COPY src/Inbound/*.csproj ./src/Inbound/ +COPY tests/Inbound.Tests/*.csproj ./tests/Inbound.Tests/ RUN dotnet restore # copy everything else and build app -COPY Src/Inbound/. ./Src/Inbound/ -WORKDIR /App/Src/Inbound -RUN dotnet publish -c Release -o Out +COPY src/Inbound/. ./src/Inbound/ +WORKDIR /app/src/Inbound +RUN dotnet publish -c Release -o out FROM microsoft/dotnet:2.1-aspnetcore-runtime AS runtime -WORKDIR /App -COPY --from=build /App/Src/Inbound/Out ./ +WORKDIR /app +COPY --from=build /app/src/Inbound/out ./ -RUN echo "ASPNETCORE_URLS=http://0.0.0.0:\$PORT\nDOTNET_RUNNING_IN_CONTAINER=true" > /App/SetupHerokuEnv.sh && chmod +x /App/SetupHerokuEnv.sh +RUN echo "ASPNETCORE_URLS=http://0.0.0.0:\$PORT\nDOTNET_RUNNING_IN_CONTAINER=true" > /app/SetupHerokuEnv.sh && chmod +x /app/SetupHerokuEnv.sh -CMD /bin/bash -c "source /App/SetupHerokuEnv.sh && dotnet Inbound.dll" +CMD /bin/bash -c "source /app/SetupHerokuEnv.sh && dotnet Inbound.dll" diff --git a/examples/inbound-webhook-handler/README.md b/examples/inbound-webhook-handler/README.md index 2560a2483..907e2cfdd 100644 --- a/examples/inbound-webhook-handler/README.md +++ b/examples/inbound-webhook-handler/README.md @@ -39,7 +39,7 @@ cd sendgrid-csharp/examples/inbound-webhook-handler dotnet restore -dotnet run --project .\Src\Inbound\Inbound.csproj +dotnet run --project .\src\Inbound\Inbound.csproj ``` Above will start server listening on a random port like below diff --git a/examples/inbound-webhook-handler/SendGridInbound.sln b/examples/inbound-webhook-handler/SendGridInbound.sln index 55234eeeb..0566bfad1 100644 --- a/examples/inbound-webhook-handler/SendGridInbound.sln +++ b/examples/inbound-webhook-handler/SendGridInbound.sln @@ -3,13 +3,13 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 VisualStudioVersion = 15.0.26124.0 MinimumVisualStudioVersion = 15.0.26124.0 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Src", "Src", "{5E71A0CA-F2E2-4762-B020-29F1D8682F75}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{5E71A0CA-F2E2-4762-B020-29F1D8682F75}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Inbound", "Src\Inbound\Inbound.csproj", "{9449C214-54EF-40A9-AAB3-4FE212BECA23}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Inbound", "src\Inbound\Inbound.csproj", "{9449C214-54EF-40A9-AAB3-4FE212BECA23}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{1446F41E-1766-4B3E-B7AC-C8766A3E1751}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{1446F41E-1766-4B3E-B7AC-C8766A3E1751}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Inbound.Tests", "Tests\Inbound.Tests\Inbound.Tests.csproj", "{0AF26ED1-3F2D-40F5-9A01-FE5955A8F927}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Inbound.Tests", "tests\Inbound.Tests\Inbound.Tests.csproj", "{0AF26ED1-3F2D-40F5-9A01-FE5955A8F927}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/examples/inbound-webhook-handler/Src/Inbound/Controllers/InboundController.cs b/examples/inbound-webhook-handler/src/Inbound/Controllers/InboundController.cs similarity index 100% rename from examples/inbound-webhook-handler/Src/Inbound/Controllers/InboundController.cs rename to examples/inbound-webhook-handler/src/Inbound/Controllers/InboundController.cs diff --git a/examples/inbound-webhook-handler/Src/Inbound/Inbound.csproj b/examples/inbound-webhook-handler/src/Inbound/Inbound.csproj similarity index 100% rename from examples/inbound-webhook-handler/Src/Inbound/Inbound.csproj rename to examples/inbound-webhook-handler/src/Inbound/Inbound.csproj diff --git a/examples/inbound-webhook-handler/Src/Inbound/Models/InboundEmail.cs b/examples/inbound-webhook-handler/src/Inbound/Models/InboundEmail.cs similarity index 100% rename from examples/inbound-webhook-handler/Src/Inbound/Models/InboundEmail.cs rename to examples/inbound-webhook-handler/src/Inbound/Models/InboundEmail.cs diff --git a/examples/inbound-webhook-handler/Src/Inbound/Models/InboundEmailAddress.cs b/examples/inbound-webhook-handler/src/Inbound/Models/InboundEmailAddress.cs similarity index 100% rename from examples/inbound-webhook-handler/Src/Inbound/Models/InboundEmailAddress.cs rename to examples/inbound-webhook-handler/src/Inbound/Models/InboundEmailAddress.cs diff --git a/examples/inbound-webhook-handler/Src/Inbound/Models/InboundEmailAttachment.cs b/examples/inbound-webhook-handler/src/Inbound/Models/InboundEmailAttachment.cs similarity index 100% rename from examples/inbound-webhook-handler/Src/Inbound/Models/InboundEmailAttachment.cs rename to examples/inbound-webhook-handler/src/Inbound/Models/InboundEmailAttachment.cs diff --git a/examples/inbound-webhook-handler/Src/Inbound/Models/InboundEmailEnvelope.cs b/examples/inbound-webhook-handler/src/Inbound/Models/InboundEmailEnvelope.cs similarity index 100% rename from examples/inbound-webhook-handler/Src/Inbound/Models/InboundEmailEnvelope.cs rename to examples/inbound-webhook-handler/src/Inbound/Models/InboundEmailEnvelope.cs diff --git a/examples/inbound-webhook-handler/Src/Inbound/Parsers/InboundWebhookParser.cs b/examples/inbound-webhook-handler/src/Inbound/Parsers/InboundWebhookParser.cs similarity index 100% rename from examples/inbound-webhook-handler/Src/Inbound/Parsers/InboundWebhookParser.cs rename to examples/inbound-webhook-handler/src/Inbound/Parsers/InboundWebhookParser.cs diff --git a/examples/inbound-webhook-handler/Src/Inbound/Program.cs b/examples/inbound-webhook-handler/src/Inbound/Program.cs similarity index 100% rename from examples/inbound-webhook-handler/Src/Inbound/Program.cs rename to examples/inbound-webhook-handler/src/Inbound/Program.cs diff --git a/examples/inbound-webhook-handler/Src/Inbound/Startup.cs b/examples/inbound-webhook-handler/src/Inbound/Startup.cs similarity index 100% rename from examples/inbound-webhook-handler/Src/Inbound/Startup.cs rename to examples/inbound-webhook-handler/src/Inbound/Startup.cs diff --git a/examples/inbound-webhook-handler/Src/Inbound/Util/Extensions.cs b/examples/inbound-webhook-handler/src/Inbound/Util/Extensions.cs similarity index 100% rename from examples/inbound-webhook-handler/Src/Inbound/Util/Extensions.cs rename to examples/inbound-webhook-handler/src/Inbound/Util/Extensions.cs diff --git a/examples/inbound-webhook-handler/Src/Inbound/Util/InboundWebhookParserHelper.cs b/examples/inbound-webhook-handler/src/Inbound/Util/InboundWebhookParserHelper.cs similarity index 100% rename from examples/inbound-webhook-handler/Src/Inbound/Util/InboundWebhookParserHelper.cs rename to examples/inbound-webhook-handler/src/Inbound/Util/InboundWebhookParserHelper.cs diff --git a/examples/inbound-webhook-handler/Src/Inbound/Views/Inbound/Index.cshtml b/examples/inbound-webhook-handler/src/Inbound/Views/Inbound/Index.cshtml similarity index 100% rename from examples/inbound-webhook-handler/Src/Inbound/Views/Inbound/Index.cshtml rename to examples/inbound-webhook-handler/src/Inbound/Views/Inbound/Index.cshtml diff --git a/examples/inbound-webhook-handler/Src/Inbound/appsettings.Development.json b/examples/inbound-webhook-handler/src/Inbound/appsettings.Development.json similarity index 100% rename from examples/inbound-webhook-handler/Src/Inbound/appsettings.Development.json rename to examples/inbound-webhook-handler/src/Inbound/appsettings.Development.json diff --git a/examples/inbound-webhook-handler/Src/Inbound/appsettings.json b/examples/inbound-webhook-handler/src/Inbound/appsettings.json similarity index 100% rename from examples/inbound-webhook-handler/Src/Inbound/appsettings.json rename to examples/inbound-webhook-handler/src/Inbound/appsettings.json diff --git a/examples/inbound-webhook-handler/Tests/Inbound.Tests/Inbound.Tests.csproj b/examples/inbound-webhook-handler/tests/Inbound.Tests/Inbound.Tests.csproj similarity index 95% rename from examples/inbound-webhook-handler/Tests/Inbound.Tests/Inbound.Tests.csproj rename to examples/inbound-webhook-handler/tests/Inbound.Tests/Inbound.Tests.csproj index 6d21a9f9d..b59378b93 100644 --- a/examples/inbound-webhook-handler/Tests/Inbound.Tests/Inbound.Tests.csproj +++ b/examples/inbound-webhook-handler/tests/Inbound.Tests/Inbound.Tests.csproj @@ -20,7 +20,7 @@ - + diff --git a/examples/inbound-webhook-handler/Tests/Inbound.Tests/IntegrationTests/InboundEndpointsTests.cs b/examples/inbound-webhook-handler/tests/Inbound.Tests/IntegrationTests/InboundEndpointsTests.cs similarity index 100% rename from examples/inbound-webhook-handler/Tests/Inbound.Tests/IntegrationTests/InboundEndpointsTests.cs rename to examples/inbound-webhook-handler/tests/Inbound.Tests/IntegrationTests/InboundEndpointsTests.cs diff --git a/examples/inbound-webhook-handler/Tests/Inbound.Tests/Parsers/InboundWebhookParserTests.cs b/examples/inbound-webhook-handler/tests/Inbound.Tests/Parsers/InboundWebhookParserTests.cs similarity index 100% rename from examples/inbound-webhook-handler/Tests/Inbound.Tests/Parsers/InboundWebhookParserTests.cs rename to examples/inbound-webhook-handler/tests/Inbound.Tests/Parsers/InboundWebhookParserTests.cs diff --git a/examples/inbound-webhook-handler/Tests/Inbound.Tests/sample_data/default_data.txt b/examples/inbound-webhook-handler/tests/Inbound.Tests/sample_data/default_data.txt similarity index 100% rename from examples/inbound-webhook-handler/Tests/Inbound.Tests/sample_data/default_data.txt rename to examples/inbound-webhook-handler/tests/Inbound.Tests/sample_data/default_data.txt diff --git a/examples/inbound-webhook-handler/Tests/Inbound.Tests/sample_data/raw_data_with_attachments.txt b/examples/inbound-webhook-handler/tests/Inbound.Tests/sample_data/raw_data_with_attachments.txt similarity index 100% rename from examples/inbound-webhook-handler/Tests/Inbound.Tests/sample_data/raw_data_with_attachments.txt rename to examples/inbound-webhook-handler/tests/Inbound.Tests/sample_data/raw_data_with_attachments.txt diff --git a/examples/inbound-webhook-handler/Tests/Inbound.Tests/sample_data/raw_email_with_attachments.txt b/examples/inbound-webhook-handler/tests/Inbound.Tests/sample_data/raw_email_with_attachments.txt similarity index 100% rename from examples/inbound-webhook-handler/Tests/Inbound.Tests/sample_data/raw_email_with_attachments.txt rename to examples/inbound-webhook-handler/tests/Inbound.Tests/sample_data/raw_email_with_attachments.txt From d78c52b5012da12f864103991016565233ea83bf Mon Sep 17 00:00:00 2001 From: Charley Wu Date: Mon, 10 May 2021 22:47:07 +0800 Subject: [PATCH 2/6] Upgrade from .NET Core 2.1 to .NET Core 3.1 - https://devblogs.microsoft.com/dotnet/net-core-2-1-will-reach-end-of-support-on-august-21-2021/ --- Dockerfile | 10 +- ExampleCoreProject/ExampleCoreProject.csproj | 8 +- examples/eventwebhook/consumer/Dockerfile | 4 +- .../Controllers/EventWebhookController.cs | 25 +- .../Controllers/HomeController.cs | 14 + .../Converters/CategoryConverter.cs | 51 +-- .../EventWebhook/Converters/EventConverter.cs | 104 ++++++ .../Converters/UnixDateTimeConverter.cs | 26 ++ .../EventWebhook/Converters/UriConverter.cs | 37 +-- .../Converters/ValueTypeStringConverter.cs | 102 ++++++ .../src/EventWebhook/EventWebhook.csproj | 16 +- .../src/EventWebhook/Models/BounceEvent.cs | 10 +- .../src/EventWebhook/Models/Category.cs | 12 +- .../src/EventWebhook/Models/ClickEvent.cs | 11 +- .../src/EventWebhook/Models/DeferredEvent.cs | 10 +- .../src/EventWebhook/Models/DeliveredEvent.cs | 5 + .../src/EventWebhook/Models/DroppedEvent.cs | 5 + .../consumer/src/EventWebhook/Models/Event.cs | 22 +- .../Models/GroupResubscribeEvent.cs | 8 +- .../Models/GroupUnsubscribeEvent.cs | 9 +- .../src/EventWebhook/Models/OpenEvent.cs | 5 + .../consumer/src/EventWebhook/Models/Pool.cs | 1 + .../src/EventWebhook/Models/ProcessedEvent.cs | 5 + .../EventWebhook/Models/SpamReportEvent.cs | 8 +- .../EventWebhook/Models/UnsubscribeEvent.cs | 8 +- .../src/EventWebhook/Parser/EventConverter.cs | 57 ---- .../src/EventWebhook/Parser/EventParser.cs | 45 ++- .../consumer/src/EventWebhook/Program.cs | 24 +- .../consumer/src/EventWebhook/Startup.cs | 25 +- .../Views/{EventWebhook => Home}/Index.cshtml | 0 .../tests/EventWebhook.Tests/EventTests.cs | 311 +++++++++--------- .../EventWebhook.Tests.csproj | 15 +- .../.vscode/launch.json | 2 +- examples/inbound-webhook-handler/Dockerfile | 4 +- .../src/Inbound/Controllers/HomeController.cs | 14 + .../Inbound/Controllers/InboundController.cs | 32 +- .../src/Inbound/Inbound.csproj | 15 +- .../src/Inbound/Models/InboundEmail.cs | 5 +- .../src/Inbound/Models/InboundEmailAddress.cs | 10 +- .../Inbound/Models/InboundEmailAttachment.cs | 15 +- .../Inbound/Models/InboundEmailEnvelope.cs | 8 +- .../Inbound/Parsers/InboundWebhookParser.cs | 95 +++--- .../src/Inbound/Program.cs | 22 +- .../src/Inbound/Startup.cs | 25 +- .../Util/InboundWebhookParserHelper.cs | 14 +- .../Views/{Inbound => Home}/Index.cshtml | 0 .../tests/Inbound.Tests/Inbound.Tests.csproj | 34 +- .../IntegrationTests/InboundEndpointsTests.cs | 48 +-- .../Parsers/InboundWebhookParserTests.cs | 28 +- ...xtensions.DependencyInjection.Tests.csproj | 8 +- tests/SendGrid.Tests/SendGrid.Tests.csproj | 10 +- 51 files changed, 772 insertions(+), 610 deletions(-) create mode 100644 examples/eventwebhook/consumer/src/EventWebhook/Controllers/HomeController.cs create mode 100644 examples/eventwebhook/consumer/src/EventWebhook/Converters/EventConverter.cs create mode 100644 examples/eventwebhook/consumer/src/EventWebhook/Converters/UnixDateTimeConverter.cs create mode 100644 examples/eventwebhook/consumer/src/EventWebhook/Converters/ValueTypeStringConverter.cs delete mode 100644 examples/eventwebhook/consumer/src/EventWebhook/Parser/EventConverter.cs rename examples/eventwebhook/consumer/src/EventWebhook/Views/{EventWebhook => Home}/Index.cshtml (100%) create mode 100644 examples/inbound-webhook-handler/src/Inbound/Controllers/HomeController.cs rename examples/inbound-webhook-handler/src/Inbound/Views/{Inbound => Home}/Index.cshtml (100%) diff --git a/Dockerfile b/Dockerfile index a9ee12341..a69fbb6bb 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,16 +1,8 @@ -FROM mono:latest - -ENV FrameworkPathOverride /usr/lib/mono/4.5/ +FROM mcr.microsoft.com/dotnet/sdk:3.1 RUN apt-get update \ && apt-get install -y curl make apt-transport-https -RUN curl -sSL https://packages.microsoft.com/config/ubuntu/19.10/packages-microsoft-prod.deb -o packages-microsoft-prod.deb \ - && dpkg --install packages-microsoft-prod.deb - -RUN apt-get update \ - && apt-get install -y dotnet-sdk-2.1 - COPY prism/prism/nginx/cert.crt /usr/local/share/ca-certificates/cert.crt RUN update-ca-certificates diff --git a/ExampleCoreProject/ExampleCoreProject.csproj b/ExampleCoreProject/ExampleCoreProject.csproj index 0d5601d03..0eb216c75 100644 --- a/ExampleCoreProject/ExampleCoreProject.csproj +++ b/ExampleCoreProject/ExampleCoreProject.csproj @@ -1,7 +1,7 @@  - netcoreapp2.1 + netcoreapp3.1 Exe false @@ -16,9 +16,9 @@ - - - + + + diff --git a/examples/eventwebhook/consumer/Dockerfile b/examples/eventwebhook/consumer/Dockerfile index b5172cfc6..2ffcecb17 100644 --- a/examples/eventwebhook/consumer/Dockerfile +++ b/examples/eventwebhook/consumer/Dockerfile @@ -1,4 +1,4 @@ -FROM microsoft/dotnet:2.1-sdk AS build +FROM mcr.microsoft.com/dotnet/sdk:3.1 AS build WORKDIR /app # copy csproj and restore as distinct layers @@ -12,7 +12,7 @@ COPY src/EventWebhook/. ./src/EventWebhook/ WORKDIR /app/src/EventWebhook RUN dotnet publish -c Release -o out -FROM microsoft/dotnet:2.1-aspnetcore-runtime AS runtime +FROM mcr.microsoft.com/dotnet/aspnet:3.1 AS runtime WORKDIR /app COPY --from=build /app/src/EventWebhook/out ./ diff --git a/examples/eventwebhook/consumer/src/EventWebhook/Controllers/EventWebhookController.cs b/examples/eventwebhook/consumer/src/EventWebhook/Controllers/EventWebhookController.cs index ea544a0f2..956057105 100644 --- a/examples/eventwebhook/consumer/src/EventWebhook/Controllers/EventWebhookController.cs +++ b/examples/eventwebhook/consumer/src/EventWebhook/Controllers/EventWebhookController.cs @@ -1,34 +1,23 @@ -using EventWebhook.Models; +using System.Threading.Tasks; using EventWebhook.Parser; using Microsoft.AspNetCore.Mvc; -using System.Collections.Generic; -using System.Threading.Tasks; namespace EventWebhook.Controllers { - [Route("/")] - public class EventWebhookController : Controller + [Route("/events")] + [ApiController] + public class EventWebhookController : ControllerBase { - /// - /// GET : Index page - /// - [Route("")] - public IActionResult Index() - { - return View(); - } - /// /// POST : Event webhook handler /// /// - [Route("/events")] [HttpPost] public async Task Events() { - IEnumerable events = await EventParser.ParseAsync(Request.Body); + var events = await EventParser.ParseAsync(Request.Body); - return Ok(); - } + return Ok(events); + } } } diff --git a/examples/eventwebhook/consumer/src/EventWebhook/Controllers/HomeController.cs b/examples/eventwebhook/consumer/src/EventWebhook/Controllers/HomeController.cs new file mode 100644 index 000000000..a6b3c9873 --- /dev/null +++ b/examples/eventwebhook/consumer/src/EventWebhook/Controllers/HomeController.cs @@ -0,0 +1,14 @@ +using Microsoft.AspNetCore.Mvc; + +namespace Inbound.Controllers +{ + [Route("/")] + public class HomeController : Controller + { + // GET + public IActionResult Index() + { + return View(); + } + } +} \ No newline at end of file diff --git a/examples/eventwebhook/consumer/src/EventWebhook/Converters/CategoryConverter.cs b/examples/eventwebhook/consumer/src/EventWebhook/Converters/CategoryConverter.cs index 966dc2af6..b66320faa 100644 --- a/examples/eventwebhook/consumer/src/EventWebhook/Converters/CategoryConverter.cs +++ b/examples/eventwebhook/consumer/src/EventWebhook/Converters/CategoryConverter.cs @@ -1,49 +1,34 @@ -using EventWebhook.Models; -using Newtonsoft.Json; -using System; +using System; using System.Linq; +using System.Text.Json; +using System.Text.Json.Serialization; +using EventWebhook.Models; namespace EventWebhook.Converters { - public class CategoryConverter : JsonConverter + public class CategoryConverter : JsonConverter { - private readonly Type[] _types; - - public CategoryConverter() - { - _types = new Type[] { typeof(string), typeof(string[]) }; - } - - public override bool CanConvert(Type objectType) + public override Category Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { - return _types.Any(t => t == objectType); + return reader.TokenType == JsonTokenType.StartArray + ? new Category(JsonSerializer.Deserialize(ref reader), true) + : new Category(new []{reader.GetString()},false); } - public override bool CanWrite => true; - - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + public override void Write(Utf8JsonWriter writer, Category value, JsonSerializerOptions options) { - if (reader.TokenType == JsonToken.StartArray) + if (value.IsArray) { - return new Category(serializer.Deserialize(reader), JsonToken.StartArray); + writer.WriteStartArray(); + foreach (var item in value.Value) + { + writer.WriteStringValue(item); + } + writer.WriteEndArray(); } else { - return new Category(new[] { serializer.Deserialize(reader) }, reader.TokenType); - } - } - - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) - { - if (value is Category category) - { - if (category.IsArray) - { - serializer.Serialize(writer, category); - } else - { - serializer.Serialize(writer, category.Value[0]); - } + writer.WriteStringValue(value.Value.FirstOrDefault()); } } } diff --git a/examples/eventwebhook/consumer/src/EventWebhook/Converters/EventConverter.cs b/examples/eventwebhook/consumer/src/EventWebhook/Converters/EventConverter.cs new file mode 100644 index 000000000..24823475e --- /dev/null +++ b/examples/eventwebhook/consumer/src/EventWebhook/Converters/EventConverter.cs @@ -0,0 +1,104 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text.Json; +using System.Text.Json.Serialization; +using System.Reflection; +using System.Runtime.Serialization; +using EventWebhook.Models; + +namespace EventWebhook.Converters +{ + public class EventConverter : JsonConverter> + { + private static readonly IDictionary EnumNameFor = new Dictionary(); + + static EventConverter() + { + var enumType = typeof(EventType); + foreach (var name in enumType.GetEnumNames()) + { + var field = enumType.GetField(name, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static); + var enumMemberAttribute = field?.GetCustomAttribute(true); + if (enumMemberAttribute == null) continue; + EnumNameFor[enumMemberAttribute.Value] = name; + } + } + public override IEnumerable Read(ref Utf8JsonReader reader, Type typeToConvert, + JsonSerializerOptions options) + { + if (reader.TokenType != JsonTokenType.StartArray) + { + throw new JsonException($"Unrecognized token: {reader.TokenType}"); + } + + var elementType = typeToConvert.IsArray + ? typeToConvert.GetElementType() + : typeToConvert.GenericTypeArguments.FirstOrDefault(); + if (elementType == null) + { + throw new JsonException($"Impossible to read JSON array to fill type: {typeToConvert.Name}"); + } + + var list = typeToConvert.IsArray || typeToConvert.IsAbstract + ? (IList) Activator.CreateInstance(typeof(List<>).MakeGenericType(elementType)) + : (IList) Activator.CreateInstance(typeToConvert); + while (reader.Read() && reader.TokenType != JsonTokenType.EndArray) + { + list.Add(ReadObject(ref reader, elementType, options)); + } + + if (!typeToConvert.IsArray) + { + return (IEnumerable) list; + } + + var array = Array.CreateInstance(elementType, list.Count); + list.CopyTo(array, 0); + return (Event[]) array; + } + + private static Event ReadObject(ref Utf8JsonReader reader, Type elementType, JsonSerializerOptions options) + { + using var doc = JsonDocument.ParseValue(ref reader); + if (!doc.RootElement.TryGetProperty("event", out var eventProperty)) + { + throw new JsonException("event property not found"); + } + + var eventTypeString = eventProperty.GetString(); + if (EnumNameFor.TryGetValue(eventTypeString, out var enumName)) + { + eventTypeString = enumName; + } + + if (!Enum.TryParse(eventTypeString, true, out var eventType)) + { + throw new JsonException($"event type not found: [{eventTypeString}]"); + } + + var typeName = string.Join(".", typeof(Event).Namespace, eventType + "Event"); + var type = Type.GetType(typeName); + if (type == null) + { + throw new JsonException($"event type not found: [{typeName}]"); + } + + using var utf8Json = new MemoryStream(); + using (var utf8JsonWriter = new Utf8JsonWriter(utf8Json)) + { + doc.RootElement.WriteTo(utf8JsonWriter); + } + + utf8Json.Seek(0, SeekOrigin.Begin); + return (Event) JsonSerializer.Deserialize(utf8Json.ToArray(), type, options); + } + + public override void Write(Utf8JsonWriter writer, IEnumerable value, JsonSerializerOptions options) + { + JsonSerializer.Serialize(writer, value, value.GetType(), options); + } + } +} \ No newline at end of file diff --git a/examples/eventwebhook/consumer/src/EventWebhook/Converters/UnixDateTimeConverter.cs b/examples/eventwebhook/consumer/src/EventWebhook/Converters/UnixDateTimeConverter.cs new file mode 100644 index 000000000..670721adc --- /dev/null +++ b/examples/eventwebhook/consumer/src/EventWebhook/Converters/UnixDateTimeConverter.cs @@ -0,0 +1,26 @@ +using System; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace EventWebhook.Converters +{ + public class UnixDateTimeConverter : JsonConverter + { + private static readonly DateTime UnixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + + public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.String && long.TryParse(reader.GetString(),out var seconds)) + { + return DateTimeOffset.FromUnixTimeSeconds(seconds).UtcDateTime; + } + return DateTimeOffset.FromUnixTimeSeconds(reader.GetInt64()).UtcDateTime; + } + + public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options) + { + var seconds = (long)(value.ToUniversalTime() - UnixEpoch).TotalSeconds; + writer.WriteNumberValue(seconds); + } + } +} \ No newline at end of file diff --git a/examples/eventwebhook/consumer/src/EventWebhook/Converters/UriConverter.cs b/examples/eventwebhook/consumer/src/EventWebhook/Converters/UriConverter.cs index 06c55f1e8..fc67960f1 100644 --- a/examples/eventwebhook/consumer/src/EventWebhook/Converters/UriConverter.cs +++ b/examples/eventwebhook/consumer/src/EventWebhook/Converters/UriConverter.cs @@ -1,40 +1,19 @@ -using Newtonsoft.Json; -using System; +using System; +using System.Text.Json; +using System.Text.Json.Serialization; namespace EventWebhook.Converters { - public class UriConverter : JsonConverter + public class UriConverter : JsonConverter { - public override bool CanConvert(Type objectType) => objectType == typeof(string); - - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + public override Uri Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { - if (reader.TokenType == JsonToken.Null) - { - return null; - } - - if (reader.TokenType == JsonToken.String) - { - return new Uri((string)reader.Value); - } - - throw new InvalidOperationException("Invalid Url"); + return new Uri(reader.GetString()); } - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + public override void Write(Utf8JsonWriter writer, Uri value, JsonSerializerOptions options) { - if (null == value) - { - writer.WriteNull(); - return; - } - - if (value is Uri) - { - writer.WriteValue(((Uri)value).OriginalString); - return; - } + writer.WriteStringValue(value.OriginalString); } } } diff --git a/examples/eventwebhook/consumer/src/EventWebhook/Converters/ValueTypeStringConverter.cs b/examples/eventwebhook/consumer/src/EventWebhook/Converters/ValueTypeStringConverter.cs new file mode 100644 index 000000000..7f9fa2b30 --- /dev/null +++ b/examples/eventwebhook/consumer/src/EventWebhook/Converters/ValueTypeStringConverter.cs @@ -0,0 +1,102 @@ +using System; +using System.ComponentModel; +using System.Globalization; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace EventWebhook.Converters +{ + public class ValueTypeStringConverter : JsonConverter + { + public override bool CanConvert(Type typeToConvert) + { + return typeToConvert.IsValueType; + } + + public override object Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (typeToConvert == typeof(decimal)) + { + if (reader.TokenType == JsonTokenType.Number && reader.TryGetDecimal(out var value)) + { + return value; + } + if (decimal.TryParse(reader.GetString(), NumberStyles.Currency, CultureInfo.InvariantCulture, + out var @decimal)) + { + return @decimal; + } + } + if (typeToConvert == typeof(float)) + { + if (reader.TokenType == JsonTokenType.Number && reader.TryGetSingle(out var value)) + { + return value; + } + if (float.TryParse(reader.GetString(), NumberStyles.Float, CultureInfo.InvariantCulture, + out var @float)) + { + return @float; + } + } + if (typeToConvert == typeof(double)) + { + if (reader.TokenType == JsonTokenType.Number && reader.TryGetDouble(out var value)) + { + return value; + } + if (double.TryParse(reader.GetString(), NumberStyles.Float, CultureInfo.InvariantCulture, + out var @double)) + { + return @double; + } + } + if (typeToConvert == typeof(int)) + { + if (reader.TokenType == JsonTokenType.Number && reader.TryGetInt32(out var value)) + { + return value; + } + if (int.TryParse(reader.GetString(), NumberStyles.Float, CultureInfo.InvariantCulture, out var integer)) + { + return integer; + } + } + + if (typeToConvert == typeof(bool)) + { + if (reader.TokenType == JsonTokenType.False || reader.TokenType == JsonTokenType.False) + { + return reader.GetBoolean(); + } + if (bool.TryParse(reader.GetString(), out var @bool)) + { + return @bool; + } + } + return TypeDescriptor.GetConverter(typeToConvert).ConvertFromInvariantString(reader.GetString()); + } + + public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options) + { + switch (value) + { + case decimal decimalValue: + writer.WriteStringValue(decimalValue.ToString(CultureInfo.InvariantCulture)); + break; + case float floatValue: + writer.WriteStringValue(floatValue.ToString(CultureInfo.InvariantCulture)); + break; + case double doubleValue: + writer.WriteStringValue(doubleValue.ToString(CultureInfo.InvariantCulture)); + break; + case bool boolValue: + writer.WriteStringValue(boolValue.ToString().ToLowerInvariant()); + break; + default: + writer.WriteStringValue(value.ToString()); + break; + } + } + } +} \ No newline at end of file diff --git a/examples/eventwebhook/consumer/src/EventWebhook/EventWebhook.csproj b/examples/eventwebhook/consumer/src/EventWebhook/EventWebhook.csproj index 1318472b7..d4b7cb306 100644 --- a/examples/eventwebhook/consumer/src/EventWebhook/EventWebhook.csproj +++ b/examples/eventwebhook/consumer/src/EventWebhook/EventWebhook.csproj @@ -1,18 +1,22 @@ - netcoreapp2.1 + netcoreapp3.1 - - + + PreserveNewest + + + appsettings.json + PreserveNewest + - - - + + diff --git a/examples/eventwebhook/consumer/src/EventWebhook/Models/BounceEvent.cs b/examples/eventwebhook/consumer/src/EventWebhook/Models/BounceEvent.cs index 484c8911b..075468109 100644 --- a/examples/eventwebhook/consumer/src/EventWebhook/Models/BounceEvent.cs +++ b/examples/eventwebhook/consumer/src/EventWebhook/Models/BounceEvent.cs @@ -1,11 +1,15 @@ -using Newtonsoft.Json; -using Newtonsoft.Json.Converters; +using System.Text.Json.Serialization; namespace EventWebhook.Models { public class BounceEvent : DroppedEvent { - [JsonConverter(typeof(StringEnumConverter))] + [JsonConverter(typeof(JsonStringEnumConverter))] public BounceEventType BounceType { get; set; } + + public BounceEvent() + { + EventType = EventType.Bounce; + } } } diff --git a/examples/eventwebhook/consumer/src/EventWebhook/Models/Category.cs b/examples/eventwebhook/consumer/src/EventWebhook/Models/Category.cs index b6762e74d..67209f9d6 100644 --- a/examples/eventwebhook/consumer/src/EventWebhook/Models/Category.cs +++ b/examples/eventwebhook/consumer/src/EventWebhook/Models/Category.cs @@ -1,19 +1,19 @@ -using Newtonsoft.Json; +using System.Text.Json.Serialization; +using Microsoft.Extensions.Primitives; namespace EventWebhook.Models { public class Category { - public string[] Value { get; } - private JsonToken _jsonToken; + public StringValues Value { get; } - public Category(string[] value, JsonToken jsonToken) + public Category(StringValues value, bool isArray) { Value = value; - _jsonToken = jsonToken; + IsArray = isArray; } [JsonIgnore] - public bool IsArray => _jsonToken == JsonToken.StartArray; + public bool IsArray { get; } } } diff --git a/examples/eventwebhook/consumer/src/EventWebhook/Models/ClickEvent.cs b/examples/eventwebhook/consumer/src/EventWebhook/Models/ClickEvent.cs index 94a8be67c..40442cc86 100644 --- a/examples/eventwebhook/consumer/src/EventWebhook/Models/ClickEvent.cs +++ b/examples/eventwebhook/consumer/src/EventWebhook/Models/ClickEvent.cs @@ -1,6 +1,6 @@ -using EventWebhook.Converters; -using Newtonsoft.Json; -using System; +using System; +using System.Text.Json.Serialization; +using EventWebhook.Converters; namespace EventWebhook.Models { @@ -8,5 +8,10 @@ public class ClickEvent : OpenEvent { [JsonConverter(typeof(UriConverter))] public Uri Url { get; set; } + + public ClickEvent() + { + EventType = EventType.Click; + } } } diff --git a/examples/eventwebhook/consumer/src/EventWebhook/Models/DeferredEvent.cs b/examples/eventwebhook/consumer/src/EventWebhook/Models/DeferredEvent.cs index 2704527a7..1c0e21a8a 100644 --- a/examples/eventwebhook/consumer/src/EventWebhook/Models/DeferredEvent.cs +++ b/examples/eventwebhook/consumer/src/EventWebhook/Models/DeferredEvent.cs @@ -1,8 +1,16 @@ -namespace EventWebhook.Models +using System.Text.Json.Serialization; +using EventWebhook.Converters; + +namespace EventWebhook.Models { public class DeferredEvent : DeliveredEvent { + [JsonConverter(typeof(ValueTypeStringConverter))] public int Attempt { get; set; } + public DeferredEvent() + { + EventType = EventType.Deferred; + } } } diff --git a/examples/eventwebhook/consumer/src/EventWebhook/Models/DeliveredEvent.cs b/examples/eventwebhook/consumer/src/EventWebhook/Models/DeliveredEvent.cs index 0a0b7df05..18edce9af 100644 --- a/examples/eventwebhook/consumer/src/EventWebhook/Models/DeliveredEvent.cs +++ b/examples/eventwebhook/consumer/src/EventWebhook/Models/DeliveredEvent.cs @@ -3,5 +3,10 @@ public class DeliveredEvent : Event { public string Response { get; set; } + + public DeliveredEvent() + { + EventType = EventType.Delivered; + } } } diff --git a/examples/eventwebhook/consumer/src/EventWebhook/Models/DroppedEvent.cs b/examples/eventwebhook/consumer/src/EventWebhook/Models/DroppedEvent.cs index d3f38649e..39317d390 100644 --- a/examples/eventwebhook/consumer/src/EventWebhook/Models/DroppedEvent.cs +++ b/examples/eventwebhook/consumer/src/EventWebhook/Models/DroppedEvent.cs @@ -4,5 +4,10 @@ public class DroppedEvent : Event { public string Reason { get; set; } public string Status { get; set; } + + public DroppedEvent() + { + EventType = EventType.Dropped; + } } } diff --git a/examples/eventwebhook/consumer/src/EventWebhook/Models/Event.cs b/examples/eventwebhook/consumer/src/EventWebhook/Models/Event.cs index ef23f9a00..7ddb99d86 100644 --- a/examples/eventwebhook/consumer/src/EventWebhook/Models/Event.cs +++ b/examples/eventwebhook/consumer/src/EventWebhook/Models/Event.cs @@ -1,9 +1,7 @@ -using EventWebhook.Converters; -using Newtonsoft.Json; -using Newtonsoft.Json.Converters; -using Newtonsoft.Json.Linq; -using System; +using System; using System.Collections.Generic; +using System.Text.Json.Serialization; +using EventWebhook.Converters; namespace EventWebhook.Models { @@ -14,20 +12,20 @@ public class Event [JsonConverter(typeof(UnixDateTimeConverter))] public DateTime Timestamp { get; set; } - [JsonProperty("smtp-id")] + [JsonPropertyName("smtp-id")] public string SmtpId { get; set; } - [JsonProperty("event")] - [JsonConverter(typeof(StringEnumConverter))] + [JsonPropertyName("event")] + [JsonConverter(typeof(JsonStringEnumMemberConverter))] public EventType EventType { get; set; } [JsonConverter(typeof(CategoryConverter))] public Category Category { get; set; } - [JsonProperty("sg_event_id")] + [JsonPropertyName("sg_event_id")] public string SendGridEventId { get; set; } - [JsonProperty("sg_message_id")] + [JsonPropertyName("sg_message_id")] public string SendGridMessageId { get; set; } public string TLS { get; set; } @@ -35,10 +33,10 @@ public class Event [JsonExtensionData] public IDictionary UniqueArgs { get; set; } - [JsonProperty("marketing_campaign_id")] + [JsonPropertyName("marketing_campaign_id")] public string MarketingCampainId { get; set; } - [JsonProperty("marketing_campaign_name")] + [JsonPropertyName("marketing_campaign_name")] public string MarketingCampainName { get; set; } } diff --git a/examples/eventwebhook/consumer/src/EventWebhook/Models/GroupResubscribeEvent.cs b/examples/eventwebhook/consumer/src/EventWebhook/Models/GroupResubscribeEvent.cs index 4034c5384..485bab7ac 100644 --- a/examples/eventwebhook/consumer/src/EventWebhook/Models/GroupResubscribeEvent.cs +++ b/examples/eventwebhook/consumer/src/EventWebhook/Models/GroupResubscribeEvent.cs @@ -1,4 +1,10 @@ namespace EventWebhook.Models { - public class GroupResubscribeEvent : GroupUnsubscribeEvent { } + public class GroupResubscribeEvent : GroupUnsubscribeEvent + { + public GroupResubscribeEvent() + { + EventType = EventType.GroupResubscribe; + } + } } diff --git a/examples/eventwebhook/consumer/src/EventWebhook/Models/GroupUnsubscribeEvent.cs b/examples/eventwebhook/consumer/src/EventWebhook/Models/GroupUnsubscribeEvent.cs index 4763182f2..4830eac66 100644 --- a/examples/eventwebhook/consumer/src/EventWebhook/Models/GroupUnsubscribeEvent.cs +++ b/examples/eventwebhook/consumer/src/EventWebhook/Models/GroupUnsubscribeEvent.cs @@ -1,10 +1,15 @@ -using Newtonsoft.Json; +using System.Text.Json.Serialization; namespace EventWebhook.Models { public class GroupUnsubscribeEvent : ClickEvent { - [JsonProperty("asm_group_id")] + [JsonPropertyName("asm_group_id")] public int AsmGroupId { get; set; } + + public GroupUnsubscribeEvent() + { + EventType = EventType.GroupUnsubscribe; + } } } diff --git a/examples/eventwebhook/consumer/src/EventWebhook/Models/OpenEvent.cs b/examples/eventwebhook/consumer/src/EventWebhook/Models/OpenEvent.cs index 81439ba38..10321aba4 100644 --- a/examples/eventwebhook/consumer/src/EventWebhook/Models/OpenEvent.cs +++ b/examples/eventwebhook/consumer/src/EventWebhook/Models/OpenEvent.cs @@ -5,5 +5,10 @@ public class OpenEvent : Event public string UserAgent { get; set; } public string IP { get; set; } + + public OpenEvent() + { + EventType = EventType.Open; + } } } diff --git a/examples/eventwebhook/consumer/src/EventWebhook/Models/Pool.cs b/examples/eventwebhook/consumer/src/EventWebhook/Models/Pool.cs index 0d534d6ce..1a44dbd2c 100644 --- a/examples/eventwebhook/consumer/src/EventWebhook/Models/Pool.cs +++ b/examples/eventwebhook/consumer/src/EventWebhook/Models/Pool.cs @@ -3,6 +3,7 @@ public class Pool { public string Name { get; set; } + public int Id { get; set; } } } diff --git a/examples/eventwebhook/consumer/src/EventWebhook/Models/ProcessedEvent.cs b/examples/eventwebhook/consumer/src/EventWebhook/Models/ProcessedEvent.cs index 648429470..0c2af3f85 100644 --- a/examples/eventwebhook/consumer/src/EventWebhook/Models/ProcessedEvent.cs +++ b/examples/eventwebhook/consumer/src/EventWebhook/Models/ProcessedEvent.cs @@ -3,5 +3,10 @@ public class ProcessedEvent : Event { public Pool Pool { get; set; } + + public ProcessedEvent() + { + EventType = EventType.Processed; + } } } diff --git a/examples/eventwebhook/consumer/src/EventWebhook/Models/SpamReportEvent.cs b/examples/eventwebhook/consumer/src/EventWebhook/Models/SpamReportEvent.cs index 0f1b6c738..1a64940c7 100644 --- a/examples/eventwebhook/consumer/src/EventWebhook/Models/SpamReportEvent.cs +++ b/examples/eventwebhook/consumer/src/EventWebhook/Models/SpamReportEvent.cs @@ -1,4 +1,10 @@ namespace EventWebhook.Models { - public class SpamReportEvent : Event { } + public class SpamReportEvent : Event + { + public SpamReportEvent() + { + EventType = EventType.SpamReport; + } + } } diff --git a/examples/eventwebhook/consumer/src/EventWebhook/Models/UnsubscribeEvent.cs b/examples/eventwebhook/consumer/src/EventWebhook/Models/UnsubscribeEvent.cs index 350dbf09e..dcb29648f 100644 --- a/examples/eventwebhook/consumer/src/EventWebhook/Models/UnsubscribeEvent.cs +++ b/examples/eventwebhook/consumer/src/EventWebhook/Models/UnsubscribeEvent.cs @@ -1,4 +1,10 @@ namespace EventWebhook.Models { - public class UnsubscribeEvent : Event { } + public class UnsubscribeEvent : Event + { + public UnsubscribeEvent() + { + EventType = EventType.Unsubscribe; + } + } } diff --git a/examples/eventwebhook/consumer/src/EventWebhook/Parser/EventConverter.cs b/examples/eventwebhook/consumer/src/EventWebhook/Parser/EventConverter.cs deleted file mode 100644 index 7a5602525..000000000 --- a/examples/eventwebhook/consumer/src/EventWebhook/Parser/EventConverter.cs +++ /dev/null @@ -1,57 +0,0 @@ -using EventWebhook.Models; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using System; -using System.Collections.Generic; - -namespace EventWebhook.Parser -{ - public class EventConverter : JsonConverter - { - private static readonly Dictionary> eventConverters = - new Dictionary>() - { - { EventType.Bounce, (json) => JsonConvert.DeserializeObject(json) }, - { EventType.Click, (json) => JsonConvert.DeserializeObject(json) }, - { EventType.Deferred, (json) => JsonConvert.DeserializeObject(json) }, - { EventType.Delivered, (json) => JsonConvert.DeserializeObject(json) }, - { EventType.Dropped, (json) => JsonConvert.DeserializeObject(json) }, - { EventType.GroupResubscribe, (json) => JsonConvert.DeserializeObject(json) }, - { EventType.GroupUnsubscribe, (json) => JsonConvert.DeserializeObject(json) }, - { EventType.Open, (json) => JsonConvert.DeserializeObject(json) }, - { EventType.Processed, (json) => JsonConvert.DeserializeObject(json) }, - { EventType.SpamReport, (json) => JsonConvert.DeserializeObject(json) }, - { EventType.Unsubscribe, (json) => JsonConvert.DeserializeObject(json) }, - }; - - private static Event DeserializeEvent(EventType type, string json) - { - if (!eventConverters.ContainsKey(type)) - { - throw new ArgumentOutOfRangeException($"Unknown event type: {type.ToString()}"); - } - - return eventConverters.GetValueOrDefault(type)(json); - } - - public override bool CanConvert(Type objectType) => typeof(Event) == objectType; - - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) - { - var jsonObject = JObject.Load(reader); - - jsonObject.TryGetValue("event", StringComparison.OrdinalIgnoreCase, out JToken eventTypeJsonProperty); - - var eventType = (EventType)eventTypeJsonProperty.ToObject(typeof(EventType)); - - var webhookEvent = DeserializeEvent(eventType, jsonObject.ToString()); - - return webhookEvent; - } - - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) - { - throw new NotImplementedException(); - } - } -} diff --git a/examples/eventwebhook/consumer/src/EventWebhook/Parser/EventParser.cs b/examples/eventwebhook/consumer/src/EventWebhook/Parser/EventParser.cs index 31b09b5e7..4906f1fb4 100644 --- a/examples/eventwebhook/consumer/src/EventWebhook/Parser/EventParser.cs +++ b/examples/eventwebhook/consumer/src/EventWebhook/Parser/EventParser.cs @@ -1,46 +1,39 @@ -using EventWebhook.Models; -using Newtonsoft.Json; -using System.Collections.Generic; +using System.Collections.Generic; using System.IO; -using System.Text; +using System.Text.Json; using System.Threading.Tasks; +using EventWebhook.Converters; +using EventWebhook.Models; namespace EventWebhook.Parser { public class EventParser { - public static async Task> ParseAsync(string json) + private static readonly JsonSerializerOptions SerializerOptions = new JsonSerializerOptions { - using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(json))) + PropertyNameCaseInsensitive = true, + PropertyNamingPolicy = JsonNamingPolicy.CamelCase, + Converters = { - return await ParseAsync(stream); + new EventConverter() } - } + }; - public static async Task> ParseAsync(Stream stream) + public static async Task> ParseAsync(Stream stream, JsonSerializerOptions options = null) { - var reader = new StreamReader(stream); - - var json = await reader.ReadToEndAsync(); - - return JsonConvert.DeserializeObject>(json, new EventConverter()); + return await JsonSerializer.DeserializeAsync>(stream, options ?? SerializerOptions); } - public static IEnumerable Parse(string json) + public static IEnumerable Parse(string json, JsonSerializerOptions options = null) { - using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(json))) - { - return Parse(stream); - } + return JsonSerializer.Deserialize>(json, options ?? SerializerOptions); } - public static IEnumerable Parse(Stream stream) + public static IEnumerable Parse(Stream stream, JsonSerializerOptions options = null) { - var reader = new StreamReader(stream); - - var json = reader.ReadToEnd(); - - return JsonConvert.DeserializeObject>(json, new EventConverter()); + using var buffer = new MemoryStream(); + stream.CopyTo(buffer); + return JsonSerializer.Deserialize>(buffer.ToArray(), options ?? SerializerOptions); } } -} +} \ No newline at end of file diff --git a/examples/eventwebhook/consumer/src/EventWebhook/Program.cs b/examples/eventwebhook/consumer/src/EventWebhook/Program.cs index 3e5ac6ad8..7c427f079 100644 --- a/examples/eventwebhook/consumer/src/EventWebhook/Program.cs +++ b/examples/eventwebhook/consumer/src/EventWebhook/Program.cs @@ -1,12 +1,5 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore; -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.Logging; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Hosting; namespace EventWebhook { @@ -14,11 +7,14 @@ public class Program { public static void Main(string[] args) { - CreateWebHostBuilder(args).Build().Run(); + CreateHostBuilder(args).Build().Run(); } - - public static IWebHostBuilder CreateWebHostBuilder(string[] args) => - WebHost.CreateDefaultBuilder(args) - .UseStartup(); + + public static IHostBuilder CreateHostBuilder(string[] args) => + Host.CreateDefaultBuilder(args) + .ConfigureWebHostDefaults(webBuilder => + { + webBuilder.UseStartup(); + }); } } diff --git a/examples/eventwebhook/consumer/src/EventWebhook/Startup.cs b/examples/eventwebhook/consumer/src/EventWebhook/Startup.cs index b3e6f8b9a..9db23d01e 100644 --- a/examples/eventwebhook/consumer/src/EventWebhook/Startup.cs +++ b/examples/eventwebhook/consumer/src/EventWebhook/Startup.cs @@ -1,15 +1,9 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; +using System.Text.Json; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.HttpsPolicy; -using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; +using Microsoft.Extensions.Hosting; namespace EventWebhook { @@ -25,11 +19,17 @@ public Startup(IConfiguration configuration) // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { - services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); + services.AddControllersWithViews() + .AddJsonOptions(options => + { + options.JsonSerializerOptions.PropertyNameCaseInsensitive = true; + options.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase; + options.JsonSerializerOptions.IgnoreNullValues = true; + }); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. - public void Configure(IApplicationBuilder app, IHostingEnvironment env) + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { @@ -41,7 +41,10 @@ public void Configure(IApplicationBuilder app, IHostingEnvironment env) } app.UseHttpsRedirection(); - app.UseMvc(); + app.UseRouting(); + app.UseEndpoints(endpoints => { + endpoints.MapControllers(); + }); } } } diff --git a/examples/eventwebhook/consumer/src/EventWebhook/Views/EventWebhook/Index.cshtml b/examples/eventwebhook/consumer/src/EventWebhook/Views/Home/Index.cshtml similarity index 100% rename from examples/eventwebhook/consumer/src/EventWebhook/Views/EventWebhook/Index.cshtml rename to examples/eventwebhook/consumer/src/EventWebhook/Views/Home/Index.cshtml diff --git a/examples/eventwebhook/consumer/tests/EventWebhook.Tests/EventTests.cs b/examples/eventwebhook/consumer/tests/EventWebhook.Tests/EventTests.cs index 94741a3e0..6e4dec9af 100644 --- a/examples/eventwebhook/consumer/tests/EventWebhook.Tests/EventTests.cs +++ b/examples/eventwebhook/consumer/tests/EventWebhook.Tests/EventTests.cs @@ -1,11 +1,10 @@ -using EventWebhook.Models; -using EventWebhook.Parser; -using Shouldly; using System; -using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; +using EventWebhook.Models; +using EventWebhook.Parser; +using Shouldly; using Xunit; namespace EventWebhook.Tests @@ -15,31 +14,29 @@ public class EventTests [Fact] public async Task AllEvents() { - var jsonStream = new MemoryStream(File.ReadAllBytes("TestData/events.json")); - - IEnumerable events = await EventParser.ParseAsync(jsonStream); + var events = await EventParser.ParseAsync(File.OpenRead("TestData/events.json")); events.Count().ShouldBeGreaterThanOrEqualTo(1); } [Fact] - public async Task ProcessedEventTest() + public void ProcessedEventTest() { var json = @" [ { - 'email': 'example@test.com', - 'timestamp': 1513299569, - 'smtp-id': '<14c5d75ce93.dfd.64b469@ismtpd-555>', - 'event': 'processed', - 'category': 'cat facts', - 'sg_event_id': 'sg_event_id', - 'sg_message_id': 'sg_message_id' + ""email"": ""example@test.com"", + ""timestamp"": 1513299569, + ""smtp-id"": ""<14c5d75ce93.dfd.64b469@ismtpd-555>"", + ""event"": ""processed"", + ""category"": ""cat facts"", + ""sg_event_id"": ""sg_event_id"", + ""sg_message_id"": ""sg_message_id"" } ] "; - IEnumerable events = await EventParser.ParseAsync(json); - events.Count().ShouldBe(1); + var events = EventParser.Parse(json).ToList(); + events.Count.ShouldBe(1); var processedEvent = events.Single(); processedEvent.Email.ShouldBe("example@test.com"); processedEvent.Timestamp.ShouldBe(DateTime.UnixEpoch.AddSeconds(1513299569)); @@ -51,87 +48,87 @@ public async Task ProcessedEventTest() } [Fact] - public async Task DefferedEventTest() + public void DeferredEventTest() { var json = @" [ { - 'email': 'example@test.com', - 'timestamp': 1513299569, - 'smtp-id': '<14c5d75ce93.dfd.64b469@ismtpd-555>', - 'event': 'deferred', - 'category': 'cat facts', - 'sg_event_id': 'sg_event_id', - 'sg_message_id': 'sg_message_id', - 'response': '400 try again later', - 'attempt': '5' + ""email"": ""example@test.com"", + ""timestamp"": 1513299569, + ""smtp-id"": ""<14c5d75ce93.dfd.64b469@ismtpd-555>"", + ""event"": ""deferred"", + ""category"": ""cat facts"", + ""sg_event_id"": ""sg_event_id"", + ""sg_message_id"": ""sg_message_id"", + ""response"": ""400 try again later"", + ""attempt"": ""5"" } ] "; - IEnumerable events = await EventParser.ParseAsync(json); - events.Count().ShouldBe(1); - var defferedEvent = (DeferredEvent)events.Single(); - defferedEvent.Email.ShouldBe("example@test.com"); - defferedEvent.Timestamp.ShouldBe(DateTime.UnixEpoch.AddSeconds(1513299569)); - defferedEvent.SmtpId.ShouldBe("<14c5d75ce93.dfd.64b469@ismtpd-555>"); - defferedEvent.EventType.ShouldBe(EventType.Deferred); - defferedEvent.Category.Value[0].ShouldBe("cat facts"); - defferedEvent.SendGridEventId.ShouldBe("sg_event_id"); - defferedEvent.SendGridMessageId.ShouldBe("sg_message_id"); - defferedEvent.Response.ShouldBe("400 try again later"); - defferedEvent.Attempt.ShouldBe(5); + var events = EventParser.Parse(json).ToList(); + events.Count.ShouldBe(1); + var deferredEvent = (DeferredEvent)events.Single(); + deferredEvent.Email.ShouldBe("example@test.com"); + deferredEvent.Timestamp.ShouldBe(DateTime.UnixEpoch.AddSeconds(1513299569)); + deferredEvent.SmtpId.ShouldBe("<14c5d75ce93.dfd.64b469@ismtpd-555>"); + deferredEvent.EventType.ShouldBe(EventType.Deferred); + deferredEvent.Category.Value[0].ShouldBe("cat facts"); + deferredEvent.SendGridEventId.ShouldBe("sg_event_id"); + deferredEvent.SendGridMessageId.ShouldBe("sg_message_id"); + deferredEvent.Response.ShouldBe("400 try again later"); + deferredEvent.Attempt.ShouldBe(5); } [Fact] - public async Task DeleveredEventTest() + public void DeleveredEventTest() { var json = @" [ { - 'email': 'example@test.com', - 'timestamp': 1513299569, - 'smtp-id': '<14c5d75ce93.dfd.64b469@ismtpd-555>', - 'event': 'delivered', - 'category': 'cat facts', - 'sg_event_id': 'sg_event_id', - 'sg_message_id': 'sg_message_id', - 'response': '200 OK' + ""email"": ""example@test.com"", + ""timestamp"": 1513299569, + ""smtp-id"": ""<14c5d75ce93.dfd.64b469@ismtpd-555>"", + ""event"": ""delivered"", + ""category"": ""cat facts"", + ""sg_event_id"": ""sg_event_id"", + ""sg_message_id"": ""sg_message_id"", + ""response"": ""200 OK"" } ] "; - IEnumerable events = await EventParser.ParseAsync(json); - events.Count().ShouldBe(1); - var defferedEvent = (DeliveredEvent)events.Single(); - defferedEvent.Email.ShouldBe("example@test.com"); - defferedEvent.Timestamp.ShouldBe(DateTime.UnixEpoch.AddSeconds(1513299569)); - defferedEvent.SmtpId.ShouldBe("<14c5d75ce93.dfd.64b469@ismtpd-555>"); - defferedEvent.EventType.ShouldBe(EventType.Delivered); - defferedEvent.Category.Value[0].ShouldBe("cat facts"); - defferedEvent.SendGridEventId.ShouldBe("sg_event_id"); - defferedEvent.SendGridMessageId.ShouldBe("sg_message_id"); - defferedEvent.Response.ShouldBe("200 OK"); + var events = EventParser.Parse(json).ToList(); + events.Count.ShouldBe(1); + var deferredEvent = (DeliveredEvent)events.Single(); + deferredEvent.Email.ShouldBe("example@test.com"); + deferredEvent.Timestamp.ShouldBe(DateTime.UnixEpoch.AddSeconds(1513299569)); + deferredEvent.SmtpId.ShouldBe("<14c5d75ce93.dfd.64b469@ismtpd-555>"); + deferredEvent.EventType.ShouldBe(EventType.Delivered); + deferredEvent.Category.Value[0].ShouldBe("cat facts"); + deferredEvent.SendGridEventId.ShouldBe("sg_event_id"); + deferredEvent.SendGridMessageId.ShouldBe("sg_message_id"); + deferredEvent.Response.ShouldBe("200 OK"); } [Fact] - public async Task OpenEventTest() + public void OpenEventTest() { var json = @" [ { - 'email': 'example@test.com', - 'timestamp': 1513299569, - 'smtp-id': '<14c5d75ce93.dfd.64b469@ismtpd-555>', - 'event': 'open', - 'category': 'cat facts', - 'sg_event_id': 'sg_event_id', - 'sg_message_id': 'sg_message_id', - 'useragent': 'Mozilla/4.0 (compatible; MSIE 6.1; Windows XP; .NET CLR 1.1.4322; .NET CLR 2.0.50727)', - 'ip': '255.255.255.255' + ""email"": ""example@test.com"", + ""timestamp"": 1513299569, + ""smtp-id"": ""<14c5d75ce93.dfd.64b469@ismtpd-555>"", + ""event"": ""open"", + ""category"": ""cat facts"", + ""sg_event_id"": ""sg_event_id"", + ""sg_message_id"": ""sg_message_id"", + ""useragent"": ""Mozilla/4.0 (compatible; MSIE 6.1; Windows XP; .NET CLR 1.1.4322; .NET CLR 2.0.50727)"", + ""ip"": ""255.255.255.255"" } ] "; - IEnumerable events = await EventParser.ParseAsync(json); - events.Count().ShouldBe(1); + var events = EventParser.Parse(json).ToList(); + events.Count.ShouldBe(1); var openEvent = (OpenEvent)events.Single(); openEvent.Email.ShouldBe("example@test.com"); openEvent.Timestamp.ShouldBe(DateTime.UnixEpoch.AddSeconds(1513299569)); @@ -146,26 +143,26 @@ public async Task OpenEventTest() } [Fact] - public async Task ClickEventTest() + public void ClickEventTest() { var json = @" [ { - 'email': 'example@test.com', - 'timestamp': 1513299569, - 'smtp-id': '<14c5d75ce93.dfd.64b469@ismtpd-555>', - 'event': 'click', - 'category': 'cat facts', - 'sg_event_id': 'sg_event_id', - 'sg_message_id': 'sg_message_id', - 'useragent': 'Mozilla/4.0 (compatible; MSIE 6.1; Windows XP; .NET CLR 1.1.4322; .NET CLR 2.0.50727)', - 'ip': '255.255.255.255', - 'url': 'http://www.sendgrid.com/' + ""email"": ""example@test.com"", + ""timestamp"": 1513299569, + ""smtp-id"": ""<14c5d75ce93.dfd.64b469@ismtpd-555>"", + ""event"": ""click"", + ""category"": ""cat facts"", + ""sg_event_id"": ""sg_event_id"", + ""sg_message_id"": ""sg_message_id"", + ""useragent"": ""Mozilla/4.0 (compatible; MSIE 6.1; Windows XP; .NET CLR 1.1.4322; .NET CLR 2.0.50727)"", + ""ip"": ""255.255.255.255"", + ""url"": ""http://www.sendgrid.com/"" } ] "; - IEnumerable events = await EventParser.ParseAsync(json); - events.Count().ShouldBe(1); + var events = EventParser.Parse(json).ToList(); + events.Count.ShouldBe(1); var clickEvent = (ClickEvent)events.Single(); clickEvent.Email.ShouldBe("example@test.com"); clickEvent.Timestamp.ShouldBe(DateTime.UnixEpoch.AddSeconds(1513299569)); @@ -177,30 +174,28 @@ public async Task ClickEventTest() clickEvent.UserAgent.ShouldBe("Mozilla/4.0 (compatible; MSIE 6.1; Windows XP; .NET CLR 1.1.4322; .NET CLR 2.0.50727)"); clickEvent.IP.ShouldBe("255.255.255.255"); clickEvent.Url.ToString().ShouldBe("http://www.sendgrid.com/"); - - } [Fact] - public async Task BounceEventTest() + public void BounceEventTest() { var json = @" [ { - 'email': 'example@test.com', - 'timestamp': 1513299569, - 'smtp-id': '<14c5d75ce93.dfd.64b469@ismtpd-555>', - 'event': 'bounce', - 'category': 'cat facts', - 'sg_event_id': 'sg_event_id', - 'sg_message_id': 'sg_message_id', - 'reason': '500 unknown recipient', - 'status': '5.0.0' + ""email"": ""example@test.com"", + ""timestamp"": 1513299569, + ""smtp-id"": ""<14c5d75ce93.dfd.64b469@ismtpd-555>"", + ""event"": ""bounce"", + ""category"": ""cat facts"", + ""sg_event_id"": ""sg_event_id"", + ""sg_message_id"": ""sg_message_id"", + ""reason"": ""500 unknown recipient"", + ""status"": ""5.0.0"" } ] "; - IEnumerable events = await EventParser.ParseAsync(json); - events.Count().ShouldBe(1); + var events = EventParser.Parse(json).ToList(); + events.Count.ShouldBe(1); var bounceEvent = (BounceEvent)events.Single(); bounceEvent.Email.ShouldBe("example@test.com"); bounceEvent.Timestamp.ShouldBe(DateTime.UnixEpoch.AddSeconds(1513299569)); @@ -214,25 +209,25 @@ public async Task BounceEventTest() } [Fact] - public async Task DroppedEventTest() + public void DroppedEventTest() { var json = @" [ { - 'email': 'example@test.com', - 'timestamp': 1513299569, - 'smtp-id': '<14c5d75ce93.dfd.64b469@ismtpd-555>', - 'event': 'dropped', - 'category': 'cat facts', - 'sg_event_id': 'sg_event_id', - 'sg_message_id': 'sg_message_id', - 'reason': 'Bounced Address', - 'status': '5.0.0' + ""email"": ""example@test.com"", + ""timestamp"": 1513299569, + ""smtp-id"": ""<14c5d75ce93.dfd.64b469@ismtpd-555>"", + ""event"": ""dropped"", + ""category"": ""cat facts"", + ""sg_event_id"": ""sg_event_id"", + ""sg_message_id"": ""sg_message_id"", + ""reason"": ""Bounced Address"", + ""status"": ""5.0.0"" } ] "; - IEnumerable events = await EventParser.ParseAsync(json); - events.Count().ShouldBe(1); + var events = EventParser.Parse(json).ToList(); + events.Count.ShouldBe(1); var droppedEvent = (DroppedEvent)events.Single(); droppedEvent.Email.ShouldBe("example@test.com"); droppedEvent.Timestamp.ShouldBe(DateTime.UnixEpoch.AddSeconds(1513299569)); @@ -246,23 +241,23 @@ public async Task DroppedEventTest() } [Fact] - public async Task SpamReportEventTest() + public void SpamReportEventTest() { var json = @" [ { - 'email': 'example@test.com', - 'timestamp': 1513299569, - 'smtp-id': '<14c5d75ce93.dfd.64b469@ismtpd-555>', - 'event': 'spamreport', - 'category': 'cat facts', - 'sg_event_id': 'sg_event_id', - 'sg_message_id': 'sg_message_id' + ""email"": ""example@test.com"", + ""timestamp"": 1513299569, + ""smtp-id"": ""<14c5d75ce93.dfd.64b469@ismtpd-555>"", + ""event"": ""spamreport"", + ""category"": ""cat facts"", + ""sg_event_id"": ""sg_event_id"", + ""sg_message_id"": ""sg_message_id"" } ] "; - IEnumerable events = await EventParser.ParseAsync(json); - events.Count().ShouldBe(1); + var events = EventParser.Parse(json).ToList(); + events.Count.ShouldBe(1); var spamReportEvent = (SpamReportEvent)events.Single(); spamReportEvent.Email.ShouldBe("example@test.com"); spamReportEvent.Timestamp.ShouldBe(DateTime.UnixEpoch.AddSeconds(1513299569)); @@ -274,23 +269,23 @@ public async Task SpamReportEventTest() } [Fact] - public async Task UnsubscribeEventTest() + public void UnsubscribeEventTest() { var json = @" [ { - 'email': 'example@test.com', - 'timestamp': 1513299569, - 'smtp-id': '<14c5d75ce93.dfd.64b469@ismtpd-555>', - 'event': 'unsubscribe', - 'category': 'cat facts', - 'sg_event_id': 'sg_event_id', - 'sg_message_id': 'sg_message_id' + ""email"": ""example@test.com"", + ""timestamp"": 1513299569, + ""smtp-id"": ""<14c5d75ce93.dfd.64b469@ismtpd-555>"", + ""event"": ""unsubscribe"", + ""category"": ""cat facts"", + ""sg_event_id"": ""sg_event_id"", + ""sg_message_id"": ""sg_message_id"" } ] "; - IEnumerable events = await EventParser.ParseAsync(json); - events.Count().ShouldBe(1); + var events = EventParser.Parse(json).ToList(); + events.Count.ShouldBe(1); var spamReportEvent = (UnsubscribeEvent)events.Single(); spamReportEvent.Email.ShouldBe("example@test.com"); spamReportEvent.Timestamp.ShouldBe(DateTime.UnixEpoch.AddSeconds(1513299569)); @@ -302,27 +297,27 @@ public async Task UnsubscribeEventTest() } [Fact] - public async Task GroupUnsubscribeEventTest() + public void GroupUnsubscribeEventTest() { var json = @" [ { - 'email': 'example@test.com', - 'timestamp': 1513299569, - 'smtp-id': '<14c5d75ce93.dfd.64b469@ismtpd-555>', - 'event': 'group_unsubscribe', - 'category': 'cat facts', - 'sg_event_id': 'sg_event_id', - 'sg_message_id': 'sg_message_id', - 'useragent': 'Mozilla/4.0 (compatible; MSIE 6.1; Windows XP; .NET CLR 1.1.4322; .NET CLR 2.0.50727)', - 'ip': '255.255.255.255', - 'url': 'http://www.sendgrid.com/', - 'asm_group_id': 10 + ""email"": ""example@test.com"", + ""timestamp"": 1513299569, + ""smtp-id"": ""<14c5d75ce93.dfd.64b469@ismtpd-555>"", + ""event"": ""group_unsubscribe"", + ""category"": ""cat facts"", + ""sg_event_id"": ""sg_event_id"", + ""sg_message_id"": ""sg_message_id"", + ""useragent"": ""Mozilla/4.0 (compatible; MSIE 6.1; Windows XP; .NET CLR 1.1.4322; .NET CLR 2.0.50727)"", + ""ip"": ""255.255.255.255"", + ""url"": ""http://www.sendgrid.com/"", + ""asm_group_id"": 10 } ] "; - IEnumerable events = await EventParser.ParseAsync(json); - events.Count().ShouldBe(1); + var events = EventParser.Parse(json).ToList(); + events.Count.ShouldBe(1); var groupUnSubscribeEvent = (GroupUnsubscribeEvent)events.Single(); groupUnSubscribeEvent.Email.ShouldBe("example@test.com"); groupUnSubscribeEvent.Timestamp.ShouldBe(DateTime.UnixEpoch.AddSeconds(1513299569)); @@ -338,27 +333,27 @@ public async Task GroupUnsubscribeEventTest() } [Fact] - public async Task GroupResubscribeEventTest() + public void GroupResubscribeEventTest() { var json = @" [ { - 'email': 'example@test.com', - 'timestamp': 1513299569, - 'smtp-id': '<14c5d75ce93.dfd.64b469@ismtpd-555>', - 'event': 'group_resubscribe', - 'category': 'cat facts', - 'sg_event_id': 'sg_event_id', - 'sg_message_id': 'sg_message_id', - 'useragent': 'Mozilla/4.0 (compatible; MSIE 6.1; Windows XP; .NET CLR 1.1.4322; .NET CLR 2.0.50727)', - 'ip': '255.255.255.255', - 'url': 'http://www.sendgrid.com/', - 'asm_group_id': 10 + ""email"": ""example@test.com"", + ""timestamp"": 1513299569, + ""smtp-id"": ""<14c5d75ce93.dfd.64b469@ismtpd-555>"", + ""event"": ""group_resubscribe"", + ""category"": ""cat facts"", + ""sg_event_id"": ""sg_event_id"", + ""sg_message_id"": ""sg_message_id"", + ""useragent"": ""Mozilla/4.0 (compatible; MSIE 6.1; Windows XP; .NET CLR 1.1.4322; .NET CLR 2.0.50727)"", + ""ip"": ""255.255.255.255"", + ""url"": ""http://www.sendgrid.com/"", + ""asm_group_id"": 10 } ] "; - IEnumerable events = await EventParser.ParseAsync(json); - events.Count().ShouldBe(1); + var events = EventParser.Parse(json).ToList(); + events.Count.ShouldBe(1); var groupUnSubscribeEvent = (GroupResubscribeEvent)events.Single(); groupUnSubscribeEvent.Email.ShouldBe("example@test.com"); groupUnSubscribeEvent.Timestamp.ShouldBe(DateTime.UnixEpoch.AddSeconds(1513299569)); diff --git a/examples/eventwebhook/consumer/tests/EventWebhook.Tests/EventWebhook.Tests.csproj b/examples/eventwebhook/consumer/tests/EventWebhook.Tests/EventWebhook.Tests.csproj index 77985c810..fa534b22d 100644 --- a/examples/eventwebhook/consumer/tests/EventWebhook.Tests/EventWebhook.Tests.csproj +++ b/examples/eventwebhook/consumer/tests/EventWebhook.Tests/EventWebhook.Tests.csproj @@ -1,16 +1,15 @@ - netcoreapp2.1 - + netcoreapp3.1 false - - - - + + + + @@ -18,8 +17,8 @@ - - Always + + PreserveNewest diff --git a/examples/inbound-webhook-handler/.vscode/launch.json b/examples/inbound-webhook-handler/.vscode/launch.json index f6a64a4c5..ad8887e68 100644 --- a/examples/inbound-webhook-handler/.vscode/launch.json +++ b/examples/inbound-webhook-handler/.vscode/launch.json @@ -9,7 +9,7 @@ "type": "coreclr", "request": "launch", "preLaunchTask": "build", - "program": "${workspaceFolder}/src/inbound/bin/Debug/netcoreapp2.1/inbound.dll", + "program": "${workspaceFolder}/src/Inbound/bin/Debug/netcoreapp3.1/Inbound.dll", "args": [], "cwd": "${workspaceFolder}/src/Inbound", "stopAtEntry": false, diff --git a/examples/inbound-webhook-handler/Dockerfile b/examples/inbound-webhook-handler/Dockerfile index e420c8fa5..803993d9a 100644 --- a/examples/inbound-webhook-handler/Dockerfile +++ b/examples/inbound-webhook-handler/Dockerfile @@ -1,4 +1,4 @@ -FROM microsoft/dotnet:2.1-sdk AS build +FROM mcr.microsoft.com/dotnet/sdk:3.1 AS build WORKDIR /app # copy csproj and restore as distinct layers @@ -12,7 +12,7 @@ COPY src/Inbound/. ./src/Inbound/ WORKDIR /app/src/Inbound RUN dotnet publish -c Release -o out -FROM microsoft/dotnet:2.1-aspnetcore-runtime AS runtime +FROM mcr.microsoft.com/dotnet/aspnet:3.1 AS runtime WORKDIR /app COPY --from=build /app/src/Inbound/out ./ diff --git a/examples/inbound-webhook-handler/src/Inbound/Controllers/HomeController.cs b/examples/inbound-webhook-handler/src/Inbound/Controllers/HomeController.cs new file mode 100644 index 000000000..a6b3c9873 --- /dev/null +++ b/examples/inbound-webhook-handler/src/Inbound/Controllers/HomeController.cs @@ -0,0 +1,14 @@ +using Microsoft.AspNetCore.Mvc; + +namespace Inbound.Controllers +{ + [Route("/")] + public class HomeController : Controller + { + // GET + public IActionResult Index() + { + return View(); + } + } +} \ No newline at end of file diff --git a/examples/inbound-webhook-handler/src/Inbound/Controllers/InboundController.cs b/examples/inbound-webhook-handler/src/Inbound/Controllers/InboundController.cs index a8fa52b83..b04894826 100644 --- a/examples/inbound-webhook-handler/src/Inbound/Controllers/InboundController.cs +++ b/examples/inbound-webhook-handler/src/Inbound/Controllers/InboundController.cs @@ -1,40 +1,20 @@ +using System.Threading.Tasks; using Inbound.Parsers; using Microsoft.AspNetCore.Mvc; -using Newtonsoft.Json; -using System; -using System.Collections.Generic; namespace Inbound.Controllers { - [Route("/")] + [Route("/inbound")] [ApiController] - public class InboundController : Controller + public class InboundController : ControllerBase { - [HttpGet] - public IActionResult Index() - { - return View(); - } - // Process POST from Inbound Parse and print received data. [HttpPost] - [Route("inbound")] - public IActionResult InboundParse() + public async Task InboundParse() { - InboundWebhookParser _inboundParser = new InboundWebhookParser(Request.Body); - - var inboundEmail = _inboundParser.Parse(); + var inboundEmail = await InboundWebhookParser.ParseAsync(Request.Body); - return Ok(); - } - - private void Log(IDictionary keyValues) - { - if(keyValues == null) - { - return; - } - Console.WriteLine(JsonConvert.SerializeObject(keyValues)); + return Ok(inboundEmail); } } } \ No newline at end of file diff --git a/examples/inbound-webhook-handler/src/Inbound/Inbound.csproj b/examples/inbound-webhook-handler/src/Inbound/Inbound.csproj index 95d6c7bfb..e6f53ce34 100644 --- a/examples/inbound-webhook-handler/src/Inbound/Inbound.csproj +++ b/examples/inbound-webhook-handler/src/Inbound/Inbound.csproj @@ -1,16 +1,21 @@ - netcoreapp2.1 + netcoreapp3.1 - + + PreserveNewest + + + appsettings.json + PreserveNewest + - + - - + diff --git a/examples/inbound-webhook-handler/src/Inbound/Models/InboundEmail.cs b/examples/inbound-webhook-handler/src/Inbound/Models/InboundEmail.cs index b3aa5dd03..bd6e251e7 100644 --- a/examples/inbound-webhook-handler/src/Inbound/Models/InboundEmail.cs +++ b/examples/inbound-webhook-handler/src/Inbound/Models/InboundEmail.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Text; +using System.Text.Json.Serialization; namespace Inbound.Models { @@ -14,6 +15,7 @@ public class InboundEmail /// /// The headers. /// + [JsonIgnore] public KeyValuePair[] Headers { get; set; } /// @@ -121,6 +123,7 @@ public class InboundEmail /// /// The charsets. /// + [JsonIgnore] public KeyValuePair[] Charsets { get; set; } /// @@ -140,6 +143,4 @@ public class InboundEmail /// public string RawEmail { get; set; } } - - } diff --git a/examples/inbound-webhook-handler/src/Inbound/Models/InboundEmailAddress.cs b/examples/inbound-webhook-handler/src/Inbound/Models/InboundEmailAddress.cs index 43e0ea724..689ee4b4f 100644 --- a/examples/inbound-webhook-handler/src/Inbound/Models/InboundEmailAddress.cs +++ b/examples/inbound-webhook-handler/src/Inbound/Models/InboundEmailAddress.cs @@ -1,4 +1,4 @@ -using Newtonsoft.Json; +using System.Text.Json.Serialization; namespace Inbound.Models { @@ -13,7 +13,7 @@ public class InboundEmailAddress /// /// The email. /// - [JsonProperty("email", NullValueHandling = NullValueHandling.Ignore)] + [JsonPropertyName("email")] public string Email { get; set; } /// @@ -22,7 +22,7 @@ public class InboundEmailAddress /// /// The name. /// - [JsonProperty("name", NullValueHandling = NullValueHandling.Ignore)] + [JsonPropertyName("name")] public string Name { get; set; } /// @@ -36,6 +36,4 @@ public InboundEmailAddress(string email, string name) Name = name; } } - - -} +} \ No newline at end of file diff --git a/examples/inbound-webhook-handler/src/Inbound/Models/InboundEmailAttachment.cs b/examples/inbound-webhook-handler/src/Inbound/Models/InboundEmailAttachment.cs index b548cc44c..1ec9476a1 100644 --- a/examples/inbound-webhook-handler/src/Inbound/Models/InboundEmailAttachment.cs +++ b/examples/inbound-webhook-handler/src/Inbound/Models/InboundEmailAttachment.cs @@ -1,5 +1,5 @@ -using Newtonsoft.Json; -using System.IO; +using System.IO; +using System.Text.Json.Serialization; namespace Inbound.Models { @@ -22,7 +22,7 @@ public class InboundEmailAttachment /// /// The content-type. /// - [JsonProperty("type", NullValueHandling = NullValueHandling.Ignore)] + [JsonPropertyName("type")] public string ContentType { get; set; } /// @@ -31,6 +31,7 @@ public class InboundEmailAttachment /// /// The data. /// + [JsonIgnore] public Stream Data { get; set; } /// @@ -39,7 +40,7 @@ public class InboundEmailAttachment /// /// The name of the file. /// - [JsonProperty("filename", NullValueHandling = NullValueHandling.Ignore)] + [JsonPropertyName("filename")] public string FileName { get; set; } /// @@ -48,7 +49,7 @@ public class InboundEmailAttachment /// /// The name. /// - [JsonProperty("name", NullValueHandling = NullValueHandling.Ignore)] + [JsonPropertyName("name")] public string Name { get; set; } /// @@ -57,9 +58,7 @@ public class InboundEmailAttachment /// /// The content identifier. /// - [JsonProperty("content-id", NullValueHandling = NullValueHandling.Ignore)] + [JsonPropertyName("content-id")] public string ContentId { get; set; } } - - } diff --git a/examples/inbound-webhook-handler/src/Inbound/Models/InboundEmailEnvelope.cs b/examples/inbound-webhook-handler/src/Inbound/Models/InboundEmailEnvelope.cs index f201cb0c7..8922fe95b 100644 --- a/examples/inbound-webhook-handler/src/Inbound/Models/InboundEmailEnvelope.cs +++ b/examples/inbound-webhook-handler/src/Inbound/Models/InboundEmailEnvelope.cs @@ -1,4 +1,4 @@ -using Newtonsoft.Json; +using System.Text.Json.Serialization; namespace Inbound.Models { @@ -13,7 +13,7 @@ public class InboundEmailEnvelope /// /// To. /// - [JsonProperty("to", NullValueHandling = NullValueHandling.Ignore)] + [JsonPropertyName("to")] public string[] To { get; set; } /// @@ -22,9 +22,7 @@ public class InboundEmailEnvelope /// /// From. /// - [JsonProperty("from", NullValueHandling = NullValueHandling.Ignore)] + [JsonPropertyName("from")] public string From { get; set; } } - - } diff --git a/examples/inbound-webhook-handler/src/Inbound/Parsers/InboundWebhookParser.cs b/examples/inbound-webhook-handler/src/Inbound/Parsers/InboundWebhookParser.cs index 29f79037f..e5a10f784 100644 --- a/examples/inbound-webhook-handler/src/Inbound/Parsers/InboundWebhookParser.cs +++ b/examples/inbound-webhook-handler/src/Inbound/Parsers/InboundWebhookParser.cs @@ -1,33 +1,30 @@ -using HttpMultipartParser; -using Inbound.Models; -using Inbound.Util; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; +using System.Text.Json; +using System.Threading.Tasks; +using HttpMultipartParser; +using Inbound.Models; +using Inbound.Util; namespace Inbound.Parsers { public class InboundWebhookParser { - private readonly Stream _payload; - - public InboundWebhookParser(Stream stream) + public static async Task ParseAsync(Stream stream) { - _payload = new MemoryStream(); - stream.CopyTo(_payload); - } + var payload = new MemoryStream(); + + // https://docs.microsoft.com/dotnet/core/compatibility/aspnetcore#http-synchronous-io-disabled-in-all-servers + await stream.CopyToAsync(payload); - public InboundEmail Parse() - { // It's important to rewind the stream - _payload.Position = 0; + payload.Position = 0; // Parse the multipart content received from SendGrid - var parser = new MultipartFormDataParser(_payload, Encoding.UTF8); + var parser = await MultipartFormDataParser.ParseAsync(payload); // Convert the 'headers' from a string into array of KeyValuePair var rawHeaders = parser @@ -37,24 +34,25 @@ public InboundEmail Parse() var headers = rawHeaders .Select(header => { - var splitHeader = header.Split(new[] { ": " }, StringSplitOptions.RemoveEmptyEntries); + var splitHeader = header.Split(new[] {": "}, StringSplitOptions.RemoveEmptyEntries); var key = splitHeader[0]; var value = splitHeader.Length > 1 ? splitHeader[1] : null; return new KeyValuePair(key, value); - }).ToArray(); + }) + .ToArray(); // Raw email var rawEmail = parser.GetParameterValue("email", string.Empty); - + // Combine the 'attachment-info' and Files into an array of Attachments - var attachmentInfoAsJObject = JObject.Parse(parser.GetParameterValue("attachment-info", "{}")); - var attachments = attachmentInfoAsJObject - .Properties() - .Select(prop => + var attachmentInfoAsJsonElement = JsonDocument.Parse(parser.GetParameterValue("attachment-info", "{}")).RootElement; + var attachments = new List(); + if (attachmentInfoAsJsonElement.ValueKind == JsonValueKind.Object) + { + foreach (var prop in attachmentInfoAsJsonElement.EnumerateObject()) { - var attachment = prop.Value.ToObject(); + var attachment = ToObject(prop.Value); attachment.Id = prop.Name; - var file = parser.Files.FirstOrDefault(f => f.Name == prop.Name); if (file != null) { @@ -62,39 +60,41 @@ public InboundEmail Parse() if (string.IsNullOrEmpty(attachment.ContentType)) attachment.ContentType = file.ContentType; if (string.IsNullOrEmpty(attachment.FileName)) attachment.FileName = file.FileName; } - - return attachment; - }).ToArray(); + attachments.Add(attachment); + } + } // Convert the 'envelope' from a JSON string into a strongly typed object - var envelope = JsonConvert.DeserializeObject(parser.GetParameterValue("envelope", "{}")); + var envelope = JsonSerializer.Deserialize(parser.GetParameterValue("envelope", "{}")); // Convert the 'charset' from a string into array of KeyValuePair - var charsetsAsJObject = JObject.Parse(parser.GetParameterValue("charsets", "{}")); - var charsets = charsetsAsJObject - .Properties() - .Select(prop => + var charsetsAsJsonElement = JsonDocument.Parse(parser.GetParameterValue("charsets", "{}")).RootElement; + var charsets = new List>(); + if (charsetsAsJsonElement.ValueKind == JsonValueKind.Object) + { + foreach (var prop in charsetsAsJsonElement.EnumerateObject()) { - var key = prop.Name; - var value = Encoding.GetEncoding(prop.Value.ToString()); - return new KeyValuePair(key, value); - }).ToArray(); + var value = prop.Value.GetString(); + if (string.IsNullOrWhiteSpace(value)) continue; + charsets.Add(new KeyValuePair(prop.Name,Encoding.GetEncoding(value))); + } + } // Create a dictionary of parsers, one parser for each desired encoding. // This is necessary because MultipartFormDataParser can only handle one // encoding and SendGrid can use different encodings for parameters such // as "from", "to", "text" and "html". var encodedParsers = charsets - .Where(c => c.Value != Encoding.UTF8) + .Where(c => !Equals(c.Value, Encoding.UTF8)) .Select(c => c.Value) .Distinct() .Select(encoding => { - _payload.Position = 0; // It's important to rewind the stream + payload.Position = 0; // It's important to rewind the stream return new { Encoding = encoding, - Parser = new MultipartFormDataParser(_payload, encoding) + Parser = MultipartFormDataParser.Parse(payload) }; }) .Union(new[] @@ -116,10 +116,10 @@ public InboundEmail Parse() var cc = InboundWebhookParserHelper.ParseEmailAddresses(rawCc); // Arrange the InboundEmail - var inboundEmail = new InboundEmail + return new InboundEmail { - Attachments = attachments, - Charsets = charsets, + Attachments = attachments.ToArray(), + Charsets = charsets.ToArray(), Dkim = InboundWebhookParserHelper.GetEncodedValue("dkim", charsets, encodedParsers, null), Envelope = envelope, From = from, @@ -135,8 +135,17 @@ public InboundEmail Parse() Cc = cc, RawEmail = rawEmail }; + } - return inboundEmail; + private static T ToObject(JsonElement element, JsonSerializerOptions options = null) + { + using var buffer = new MemoryStream(); + using (var writer = new Utf8JsonWriter(buffer)) + { + element.WriteTo(writer); + } + buffer.Seek(0, SeekOrigin.Begin); + return JsonSerializer.Deserialize(buffer.ToArray(), options); } } } \ No newline at end of file diff --git a/examples/inbound-webhook-handler/src/Inbound/Program.cs b/examples/inbound-webhook-handler/src/Inbound/Program.cs index c2828bab0..db1ce2018 100644 --- a/examples/inbound-webhook-handler/src/Inbound/Program.cs +++ b/examples/inbound-webhook-handler/src/Inbound/Program.cs @@ -1,12 +1,5 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore; -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.Logging; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Hosting; namespace Inbound { @@ -14,11 +7,14 @@ public class Program { public static void Main(string[] args) { - CreateWebHostBuilder(args).Build().Run(); + CreateHostBuilder(args).Build().Run(); } - public static IWebHostBuilder CreateWebHostBuilder(string[] args) => - WebHost.CreateDefaultBuilder(args) - .UseStartup(); + public static IHostBuilder CreateHostBuilder(string[] args) => + Host.CreateDefaultBuilder(args) + .ConfigureWebHostDefaults(webBuilder => + { + webBuilder.UseStartup(); + }); } } diff --git a/examples/inbound-webhook-handler/src/Inbound/Startup.cs b/examples/inbound-webhook-handler/src/Inbound/Startup.cs index 4b9879581..af71ca2ea 100644 --- a/examples/inbound-webhook-handler/src/Inbound/Startup.cs +++ b/examples/inbound-webhook-handler/src/Inbound/Startup.cs @@ -1,15 +1,9 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; +using System.Text.Json; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.HttpsPolicy; -using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; +using Microsoft.Extensions.Hosting; namespace Inbound { @@ -25,11 +19,17 @@ public Startup(IConfiguration configuration) // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { - services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); + services.AddControllersWithViews() + .AddJsonOptions(options => + { + options.JsonSerializerOptions.PropertyNameCaseInsensitive = true; + options.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase; + options.JsonSerializerOptions.IgnoreNullValues = true; + }); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. - public void Configure(IApplicationBuilder app, IHostingEnvironment env) + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { @@ -41,7 +41,10 @@ public void Configure(IApplicationBuilder app, IHostingEnvironment env) } app.UseHttpsRedirection(); - app.UseMvc(); + app.UseRouting(); + app.UseEndpoints(endpoints =>{ + endpoints.MapControllers(); + }); } } } diff --git a/examples/inbound-webhook-handler/src/Inbound/Util/InboundWebhookParserHelper.cs b/examples/inbound-webhook-handler/src/Inbound/Util/InboundWebhookParserHelper.cs index e8f134542..844822398 100644 --- a/examples/inbound-webhook-handler/src/Inbound/Util/InboundWebhookParserHelper.cs +++ b/examples/inbound-webhook-handler/src/Inbound/Util/InboundWebhookParserHelper.cs @@ -1,10 +1,10 @@ -using HttpMultipartParser; -using Inbound.Models; -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Text.RegularExpressions; +using HttpMultipartParser; +using Inbound.Models; namespace Inbound.Util { @@ -13,7 +13,7 @@ public static class InboundWebhookParserHelper public static InboundEmailAddress[] ParseEmailAddresses(string rawEmailAddresses) { // Split on commas that have an even number of double-quotes following them - const string SPLIT_EMAIL_ADDRESSES = ",(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)"; + const string splitEmailAddresses = ",(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)"; /* When we stop supporting .NET 4.5.2 we will be able to use the following: @@ -21,9 +21,9 @@ public static InboundEmailAddress[] ParseEmailAddresses(string rawEmailAddresses */ if (string.IsNullOrEmpty(rawEmailAddresses)) return Enumerable.Empty().ToArray(); - var rawEmails = Regex.Split(rawEmailAddresses, SPLIT_EMAIL_ADDRESSES); + var rawEmails = Regex.Split(rawEmailAddresses, splitEmailAddresses); var addresses = rawEmails - .Select(rawEmail => ParseEmailAddress(rawEmail)) + .Select(ParseEmailAddress) .Where(address => address != null) .ToArray(); return addresses; @@ -66,7 +66,7 @@ private static MultipartFormDataParser GetEncodedParser(string parameterName, IE private static Encoding GetEncoding(string parameterName, IEnumerable> charsets) { - var encoding = charsets.Where(c => c.Key == parameterName); + var encoding = charsets.Where(c => c.Key == parameterName).ToList(); return encoding.Any() ? encoding.First().Value : Encoding.UTF8; } } diff --git a/examples/inbound-webhook-handler/src/Inbound/Views/Inbound/Index.cshtml b/examples/inbound-webhook-handler/src/Inbound/Views/Home/Index.cshtml similarity index 100% rename from examples/inbound-webhook-handler/src/Inbound/Views/Inbound/Index.cshtml rename to examples/inbound-webhook-handler/src/Inbound/Views/Home/Index.cshtml diff --git a/examples/inbound-webhook-handler/tests/Inbound.Tests/Inbound.Tests.csproj b/examples/inbound-webhook-handler/tests/Inbound.Tests/Inbound.Tests.csproj index b59378b93..6fd7280c3 100644 --- a/examples/inbound-webhook-handler/tests/Inbound.Tests/Inbound.Tests.csproj +++ b/examples/inbound-webhook-handler/tests/Inbound.Tests/Inbound.Tests.csproj @@ -1,22 +1,16 @@ - netcoreapp2.1 - + netcoreapp3.1 false - - - - - - - - all - runtime; build; native; contentfiles; analyzers - + + + + + @@ -24,20 +18,8 @@ - - C:\Program Files\dotnet\sdk\NuGetFallbackFolder\microsoft.aspnetcore\2.1.1\lib\netstandard2.0\Microsoft.AspNetCore.dll - - - - - - Always - - - Always - - - Always + + PreserveNewest diff --git a/examples/inbound-webhook-handler/tests/Inbound.Tests/IntegrationTests/InboundEndpointsTests.cs b/examples/inbound-webhook-handler/tests/Inbound.Tests/IntegrationTests/InboundEndpointsTests.cs index bd3edcf2f..70847de5a 100644 --- a/examples/inbound-webhook-handler/tests/Inbound.Tests/IntegrationTests/InboundEndpointsTests.cs +++ b/examples/inbound-webhook-handler/tests/Inbound.Tests/IntegrationTests/InboundEndpointsTests.cs @@ -3,6 +3,7 @@ using System.IO; using System.Net; using System.Net.Http; +using System.Net.Http.Headers; using System.Threading.Tasks; using Xunit; @@ -10,58 +11,59 @@ namespace Inbound.Tests.IntegrationTests { public class InboundEndpointsTests : IClassFixture> { - private readonly WebApplicationFactory applicationFactory; + private readonly WebApplicationFactory _factory; public InboundEndpointsTests(WebApplicationFactory factory) - => applicationFactory = factory; + => _factory = factory; [Fact] public async Task Get_IndexPageReturnsSuccessAndCorrectContentType() { - const string URL = "/"; - - var client = applicationFactory.CreateClient(); - var response = await client.GetAsync(URL); + var client = _factory.CreateClient(); + var response = await client.GetAsync("/"); response.EnsureSuccessStatusCode(); response.Content.Headers.ContentType.MediaType.ShouldBe("text/html"); } [Fact] - public async Task Get_InboundEndpointReturnsNotFound() + public async Task Get_InboundEndpointShouldNotReturnsOk() { - const string URL = "/inbound"; - var client = applicationFactory.CreateClient(); - var response = await client.GetAsync(URL); - response.StatusCode.ShouldBe(HttpStatusCode.NotFound); + var client = _factory.CreateClient(); + var response = await client.GetAsync("/inbound"); + response.StatusCode.ShouldNotBe(HttpStatusCode.OK); } [Fact] public async Task Post_InboundEndpointWithDefaultPayload() { - const string URL = "/inbound"; - var data = File.ReadAllTextAsync("sample_data/default_data.txt").Result; + var data = await File.ReadAllTextAsync("sample_data/default_data.txt"); - var content = new StringContent(data); + using var content = new StringContent(data); content.Headers.Clear(); - content.Headers.Add("Content-Type", "multipart/form-data; boundary=xYzZY"); + content.Headers.ContentType = new MediaTypeHeaderValue("multipart/form-data") + { + Parameters = { new NameValueHeaderValue("boundary","xYzZY") } + }; - var client = applicationFactory.CreateClient(); - var response = await client.PostAsync(URL, content); + var client = _factory.CreateClient(); + var response = await client.PostAsync("/inbound", content); response.EnsureSuccessStatusCode(); } [Fact] public async Task Post_InboundEndpointWithRawPayloadWithAttachments() { - const string URL = "/inbound"; - var data = File.ReadAllTextAsync("sample_data/raw_data_with_attachments.txt").Result; + var data = await File.ReadAllTextAsync("sample_data/raw_data_with_attachments.txt"); - var content = new StringContent(data); + using var content = new StringContent(data); content.Headers.Clear(); - content.Headers.Add("Content-Type", "multipart/form-data; boundary=xYzZY"); + content.Headers.ContentType = new MediaTypeHeaderValue("multipart/form-data") + { + Parameters = { new NameValueHeaderValue("boundary","xYzZY") } + }; - var client = applicationFactory.CreateClient(); - var response = await client.PostAsync(URL, content); + var client = _factory.CreateClient(); + var response = await client.PostAsync("/inbound", content); response.EnsureSuccessStatusCode(); } } diff --git a/examples/inbound-webhook-handler/tests/Inbound.Tests/Parsers/InboundWebhookParserTests.cs b/examples/inbound-webhook-handler/tests/Inbound.Tests/Parsers/InboundWebhookParserTests.cs index 3d2a8696e..968f0e4af 100644 --- a/examples/inbound-webhook-handler/tests/Inbound.Tests/Parsers/InboundWebhookParserTests.cs +++ b/examples/inbound-webhook-handler/tests/Inbound.Tests/Parsers/InboundWebhookParserTests.cs @@ -1,10 +1,10 @@ -using Inbound.Models; -using Inbound.Parsers; +using Inbound.Parsers; using Shouldly; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; +using System.Threading.Tasks; using Xunit; namespace Inbound.Tests.Parsers @@ -12,15 +12,11 @@ namespace Inbound.Tests.Parsers public class InboundWebhookParserTests { [Fact] - public async void DefaultPayloadWithoutAttachments() + public async Task DefaultPayloadWithoutAttachments() { - Stream stream = new MemoryStream(); - await File.OpenRead("sample_data/default_data.txt").CopyToAsync(stream); - stream.Position = 0; - - var parser = new InboundWebhookParser(stream); - - InboundEmail inboundEmail = parser.Parse(); + var stream = File.OpenRead("sample_data/default_data.txt"); + + var inboundEmail = await InboundWebhookParser.ParseAsync(stream); inboundEmail.ShouldNotBeNull(); @@ -72,15 +68,11 @@ public async void DefaultPayloadWithoutAttachments() } [Fact] - public async void RawPayloadWithAttachments() + public async Task RawPayloadWithAttachments() { - Stream stream = new MemoryStream(); - await File.OpenRead("sample_data/raw_data_with_attachments.txt").CopyToAsync(stream); - stream.Position = 0; - - var parser = new InboundWebhookParser(stream); - - InboundEmail inboundEmail = parser.Parse(); + var stream = File.OpenRead("sample_data/raw_data_with_attachments.txt"); + + var inboundEmail = await InboundWebhookParser.ParseAsync(stream); inboundEmail.ShouldNotBeNull(); diff --git a/tests/SendGrid.Extensions.DependencyInjection.Tests/SendGrid.Extensions.DependencyInjection.Tests.csproj b/tests/SendGrid.Extensions.DependencyInjection.Tests/SendGrid.Extensions.DependencyInjection.Tests.csproj index 96da4a46c..50941a04e 100644 --- a/tests/SendGrid.Extensions.DependencyInjection.Tests/SendGrid.Extensions.DependencyInjection.Tests.csproj +++ b/tests/SendGrid.Extensions.DependencyInjection.Tests/SendGrid.Extensions.DependencyInjection.Tests.csproj @@ -1,7 +1,7 @@  - netcoreapp2.1 + netcoreapp3.1 true false @@ -11,10 +11,10 @@ - - + + - + diff --git a/tests/SendGrid.Tests/SendGrid.Tests.csproj b/tests/SendGrid.Tests/SendGrid.Tests.csproj index f61ad8027..cab63e765 100644 --- a/tests/SendGrid.Tests/SendGrid.Tests.csproj +++ b/tests/SendGrid.Tests/SendGrid.Tests.csproj @@ -1,7 +1,7 @@  - netcoreapp2.1 + netcoreapp3.1 true false @@ -11,12 +11,12 @@ - - + + - + - + From 909ca6c75a3c7527025cd44f344dcd71a26c51d8 Mon Sep 17 00:00:00 2001 From: Charley Wu Date: Fri, 4 Jun 2021 08:04:17 +0800 Subject: [PATCH 3/6] HttpClient throws OperationCanceledException instead of TaskCanceledException since .NET Core 3.0 - https://github.com/dotnet/runtime/issues/21965 --- src/SendGrid/Reliability/RetryDelegatingHandler.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SendGrid/Reliability/RetryDelegatingHandler.cs b/src/SendGrid/Reliability/RetryDelegatingHandler.cs index 617663d84..f480aec5b 100644 --- a/src/SendGrid/Reliability/RetryDelegatingHandler.cs +++ b/src/SendGrid/Reliability/RetryDelegatingHandler.cs @@ -63,7 +63,7 @@ protected override async Task SendAsync(HttpRequestMessage sent = true; } - catch (TaskCanceledException) + catch (OperationCanceledException) { numberOfAttempts++; From 8b6589e7978bfdc712f07e3c42e753e333ebcf38 Mon Sep 17 00:00:00 2001 From: Charley Wu Date: Wed, 16 Jun 2021 07:54:28 +0800 Subject: [PATCH 4/6] chore: tuning Dockerfile - merge RUN commands - curl is installed in `mcr.microsoft.com/dotnet/sdk:3.1` --- Dockerfile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Dockerfile b/Dockerfile index a69fbb6bb..005486060 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,10 +1,10 @@ FROM mcr.microsoft.com/dotnet/sdk:3.1 -RUN apt-get update \ - && apt-get install -y curl make apt-transport-https - COPY prism/prism/nginx/cert.crt /usr/local/share/ca-certificates/cert.crt -RUN update-ca-certificates + +RUN apt-get update \ + && apt-get install -y make apt-transport-https \ + && update-ca-certificates COPY . . From c19ea38dc2f3e7f4692a6e30e362dcd434d3b354 Mon Sep 17 00:00:00 2001 From: Charley Wu Date: Fri, 4 Jun 2021 19:30:13 +0800 Subject: [PATCH 5/6] chore: update dependencies --- ExampleCoreProject/ExampleCoreProject.csproj | 6 +++--- ExampleNet45Project/ExampleNet45.csproj | 2 +- .../consumer/src/EventWebhook/EventWebhook.csproj | 2 +- .../eventwebhook/consumer/src/EventWebhook/Startup.cs | 3 ++- .../tests/EventWebhook.Tests/EventWebhook.Tests.csproj | 6 +++--- .../inbound-webhook-handler/src/Inbound/Inbound.csproj | 2 +- .../tests/Inbound.Tests/Inbound.Tests.csproj | 8 ++++---- src/SendGrid/SendGrid.csproj | 2 +- .../SendGrid.Extensions.DependencyInjection.Tests.csproj | 8 ++++---- tests/SendGrid.Tests/SendGrid.Tests.csproj | 8 ++++---- 10 files changed, 24 insertions(+), 23 deletions(-) diff --git a/ExampleCoreProject/ExampleCoreProject.csproj b/ExampleCoreProject/ExampleCoreProject.csproj index 0eb216c75..58da3e236 100644 --- a/ExampleCoreProject/ExampleCoreProject.csproj +++ b/ExampleCoreProject/ExampleCoreProject.csproj @@ -16,9 +16,9 @@ - - - + + + diff --git a/ExampleNet45Project/ExampleNet45.csproj b/ExampleNet45Project/ExampleNet45.csproj index e2bdaec5e..3db276096 100644 --- a/ExampleNet45Project/ExampleNet45.csproj +++ b/ExampleNet45Project/ExampleNet45.csproj @@ -18,7 +18,7 @@ - + diff --git a/examples/eventwebhook/consumer/src/EventWebhook/EventWebhook.csproj b/examples/eventwebhook/consumer/src/EventWebhook/EventWebhook.csproj index d4b7cb306..6b81ca833 100644 --- a/examples/eventwebhook/consumer/src/EventWebhook/EventWebhook.csproj +++ b/examples/eventwebhook/consumer/src/EventWebhook/EventWebhook.csproj @@ -15,7 +15,7 @@ - + diff --git a/examples/eventwebhook/consumer/src/EventWebhook/Startup.cs b/examples/eventwebhook/consumer/src/EventWebhook/Startup.cs index 9db23d01e..f4267786f 100644 --- a/examples/eventwebhook/consumer/src/EventWebhook/Startup.cs +++ b/examples/eventwebhook/consumer/src/EventWebhook/Startup.cs @@ -1,4 +1,5 @@ using System.Text.Json; +using System.Text.Json.Serialization; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; @@ -24,7 +25,7 @@ public void ConfigureServices(IServiceCollection services) { options.JsonSerializerOptions.PropertyNameCaseInsensitive = true; options.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase; - options.JsonSerializerOptions.IgnoreNullValues = true; + options.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull; }); } diff --git a/examples/eventwebhook/consumer/tests/EventWebhook.Tests/EventWebhook.Tests.csproj b/examples/eventwebhook/consumer/tests/EventWebhook.Tests/EventWebhook.Tests.csproj index fa534b22d..73bdb1b93 100644 --- a/examples/eventwebhook/consumer/tests/EventWebhook.Tests/EventWebhook.Tests.csproj +++ b/examples/eventwebhook/consumer/tests/EventWebhook.Tests/EventWebhook.Tests.csproj @@ -6,10 +6,10 @@ - + - - + + diff --git a/examples/inbound-webhook-handler/src/Inbound/Inbound.csproj b/examples/inbound-webhook-handler/src/Inbound/Inbound.csproj index e6f53ce34..e0d047fc8 100644 --- a/examples/inbound-webhook-handler/src/Inbound/Inbound.csproj +++ b/examples/inbound-webhook-handler/src/Inbound/Inbound.csproj @@ -15,7 +15,7 @@ - + diff --git a/examples/inbound-webhook-handler/tests/Inbound.Tests/Inbound.Tests.csproj b/examples/inbound-webhook-handler/tests/Inbound.Tests/Inbound.Tests.csproj index 6fd7280c3..0d7dfc26a 100644 --- a/examples/inbound-webhook-handler/tests/Inbound.Tests/Inbound.Tests.csproj +++ b/examples/inbound-webhook-handler/tests/Inbound.Tests/Inbound.Tests.csproj @@ -6,11 +6,11 @@ - - + + - - + + diff --git a/src/SendGrid/SendGrid.csproj b/src/SendGrid/SendGrid.csproj index c6033a698..7aa2b1494 100644 --- a/src/SendGrid/SendGrid.csproj +++ b/src/SendGrid/SendGrid.csproj @@ -44,7 +44,7 @@ - + diff --git a/tests/SendGrid.Extensions.DependencyInjection.Tests/SendGrid.Extensions.DependencyInjection.Tests.csproj b/tests/SendGrid.Extensions.DependencyInjection.Tests/SendGrid.Extensions.DependencyInjection.Tests.csproj index 50941a04e..353956942 100644 --- a/tests/SendGrid.Extensions.DependencyInjection.Tests/SendGrid.Extensions.DependencyInjection.Tests.csproj +++ b/tests/SendGrid.Extensions.DependencyInjection.Tests/SendGrid.Extensions.DependencyInjection.Tests.csproj @@ -11,10 +11,10 @@ - - - - + + + + diff --git a/tests/SendGrid.Tests/SendGrid.Tests.csproj b/tests/SendGrid.Tests/SendGrid.Tests.csproj index cab63e765..72dead4f0 100644 --- a/tests/SendGrid.Tests/SendGrid.Tests.csproj +++ b/tests/SendGrid.Tests/SendGrid.Tests.csproj @@ -11,10 +11,10 @@ - - - - + + + + From fa179360513580dec69638012c6f33c8d88a7c73 Mon Sep 17 00:00:00 2001 From: Charley Wu Date: Fri, 22 Apr 2022 18:12:22 +0800 Subject: [PATCH 6/6] chore: use the ASP.NET Core shared framework - https://docs.microsoft.com/aspnet/core/fundamentals/target-aspnetcore#use-the-aspnet-core-shared-framework --- ExampleCoreProject/ExampleCoreProject.csproj | 4 +--- .../SendGrid.Extensions.DependencyInjection.Tests.csproj | 5 ++++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/ExampleCoreProject/ExampleCoreProject.csproj b/ExampleCoreProject/ExampleCoreProject.csproj index 58da3e236..42acb21cb 100644 --- a/ExampleCoreProject/ExampleCoreProject.csproj +++ b/ExampleCoreProject/ExampleCoreProject.csproj @@ -16,9 +16,7 @@ - - - + diff --git a/tests/SendGrid.Extensions.DependencyInjection.Tests/SendGrid.Extensions.DependencyInjection.Tests.csproj b/tests/SendGrid.Extensions.DependencyInjection.Tests/SendGrid.Extensions.DependencyInjection.Tests.csproj index 353956942..329434ee5 100644 --- a/tests/SendGrid.Extensions.DependencyInjection.Tests/SendGrid.Extensions.DependencyInjection.Tests.csproj +++ b/tests/SendGrid.Extensions.DependencyInjection.Tests/SendGrid.Extensions.DependencyInjection.Tests.csproj @@ -11,7 +11,10 @@ - + + + +