Skip to content

Commit

Permalink
Merge pull request #527 from PeterKneale/feature/476-Add_sample_appli…
Browse files Browse the repository at this point in the history
…cation

Add sample application
  • Loading branch information
martincostello authored Apr 18, 2019
2 parents 5e24a34 + 35d8568 commit f3a05e3
Show file tree
Hide file tree
Showing 21 changed files with 657 additions and 0 deletions.
23 changes: 23 additions & 0 deletions JustSaying.sln
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,14 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{A94633F2-29F
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{E22A50F2-9952-4483-8AD1-09BE354FB3E4}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{10067D40-00F2-4B06-B73B-381DE95E6DD3}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JustSaying.Sample.Restaurant.Models", "samples\JustSaying.Sample.Restaurant.Models\JustSaying.Sample.Restaurant.Models.csproj", "{0F64EB5C-6784-4870-A3E9-460EB78ED53D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JustSaying.Sample.Restaurant.KitchenConsole", "samples\JustSaying.Sample.Restaurant.KitchenConsole\JustSaying.Sample.Restaurant.KitchenConsole.csproj", "{55D91685-60BF-42E9-B166-E037F8FBA4F5}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JustSaying.Sample.Restaurant.OrderingApi", "samples\JustSaying.Sample.Restaurant.OrderingApi\JustSaying.Sample.Restaurant.OrderingApi.csproj", "{C40BB811-EDF8-47A4-93F5-2563E15C5CC1}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -94,6 +102,18 @@ Global
{FC6E028F-01DA-47A5-895A-5C1DD27981D4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FC6E028F-01DA-47A5-895A-5C1DD27981D4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FC6E028F-01DA-47A5-895A-5C1DD27981D4}.Release|Any CPU.Build.0 = Release|Any CPU
{0F64EB5C-6784-4870-A3E9-460EB78ED53D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0F64EB5C-6784-4870-A3E9-460EB78ED53D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0F64EB5C-6784-4870-A3E9-460EB78ED53D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0F64EB5C-6784-4870-A3E9-460EB78ED53D}.Release|Any CPU.Build.0 = Release|Any CPU
{55D91685-60BF-42E9-B166-E037F8FBA4F5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{55D91685-60BF-42E9-B166-E037F8FBA4F5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{55D91685-60BF-42E9-B166-E037F8FBA4F5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{55D91685-60BF-42E9-B166-E037F8FBA4F5}.Release|Any CPU.Build.0 = Release|Any CPU
{C40BB811-EDF8-47A4-93F5-2563E15C5CC1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C40BB811-EDF8-47A4-93F5-2563E15C5CC1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C40BB811-EDF8-47A4-93F5-2563E15C5CC1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C40BB811-EDF8-47A4-93F5-2563E15C5CC1}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -109,6 +129,9 @@ Global
{949EC37A-A278-4D02-A358-CC6F76B6E4CF} = {F0BCBE5F-2132-422D-B17B-23B7FCC4A8A8}
{1B9BB1E2-E46B-4E2B-A172-61ABA8B35B62} = {A94633F2-29F2-48C6-840A-C5370B300AE2}
{FC6E028F-01DA-47A5-895A-5C1DD27981D4} = {A94633F2-29F2-48C6-840A-C5370B300AE2}
{0F64EB5C-6784-4870-A3E9-460EB78ED53D} = {10067D40-00F2-4B06-B73B-381DE95E6DD3}
{55D91685-60BF-42E9-B166-E037F8FBA4F5} = {10067D40-00F2-4B06-B73B-381DE95E6DD3}
{C40BB811-EDF8-47A4-93F5-2563E15C5CC1} = {10067D40-00F2-4B06-B73B-381DE95E6DD3}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {18FBDF85-C124-4444-9F03-D0D4F2B3A612}
Expand Down
25 changes: 25 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,31 @@ At this point, the power tool is only able to move an arbitrary number of messag
JustSaying.Tools.exe move -from "source_queue_name" -to "destination_queue_name" -in "region" -count "1"
````

## Sample Application

- To run the sample application against a simulated AWS SQS / SNS endpoint run this container
```sh
docker pull pafortin/goaws
docker run -d --name goaws -p 4100:4100 pafortin/goaws
```
- Alternatively to use your real AWS account
- Locate the setup code `services.AddJustSaying(...)` in both [`Program.cs`](./samples/JustSaying.Sample.Restaurant.KitchenConsole/Program.cs) and [`Startup.cs`](./samples/JustSaying.Sample.Restaurant.JustSaying.Sample.Restaurant.OrderingApi/Startup.cs)
- Remove the references to the 'ServiceUrl`
- Add references to `x.WithCredentials(...)` supplying your real aws credentials
- Execute both `KitchenConsole` and `OrderingApi` applications
- Demonstrates
- Publishing messages to a SNS Topic from a WebApi application and Console Application
- Receiving messages from a SQS queue subscribed to a SNS topic in a WebApi application and Console Application
- Further samples in progress
- Demonstrate use of `PublishMetaData`
- Demonstrate integration with [CorrelationId](https://www.nuget.org/packages/CorrelationId/)
- Demonstrate use of Cancellation Tokens
- Add acceptance tests project
- Add dockerfile for api, console, aws and tests
- Demonstrate docker-compose executing acceptance tests against other images
## Contributing...
Please read the [contributing guide](./.github/CONTRIBUTING.md "Contributing to JustSaying").
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using System;
using Amazon;
using Microsoft.Extensions.Configuration;

namespace JustSaying.Sample.Restaurant.KitchenConsole
{
public static class ConfigurationExtensions
{
private const string AWSServiceUrlKey = "AWSServiceUrl";

private const string AWSRegionKey = "AWSRegion";

public static bool HasAWSServiceUrl(this IConfiguration configuration)
{
return !string.IsNullOrWhiteSpace(configuration[AWSServiceUrlKey]);
}

public static Uri GetAWSServiceUri(this IConfiguration configuration)
{
return new Uri(configuration[AWSServiceUrlKey]);
}

public static RegionEndpoint GetAWSRegion(this IConfiguration configuration)
{
return RegionEndpoint.GetBySystemName(configuration[AWSRegionKey]);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.2</TargetFramework>
<NoWarn>$(NoWarn);CA1031;CA2007</NoWarn>
</PropertyGroup>

<ItemGroup>
<None Remove="appsettings.json" />
</ItemGroup>

<ItemGroup>
<Content Include="appsettings.json" CopyToPublishDirectory="PreserveNewest" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="2.2.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.2.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="2.2.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="2.2.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\JustSaying.Extensions.DependencyInjection.Microsoft\JustSaying.Extensions.DependencyInjection.Microsoft.csproj" />
<ProjectReference Include="..\..\JustSaying\JustSaying.csproj" />
<ProjectReference Include="..\JustSaying.Sample.Restaurant.Models\JustSaying.Sample.Restaurant.Models.csproj" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
using System;
using System.Threading.Tasks;
using JustSaying.Messaging;
using JustSaying.Messaging.MessageHandling;
using JustSaying.Sample.Restaurant.Models;
using Microsoft.Extensions.Logging;

namespace JustSaying.Sample.Restaurant.KitchenConsole
{
public class OrderPlacedEventHandler : IHandlerAsync<OrderPlacedEvent>
{
private readonly IMessagePublisher _publisher;
private readonly ILogger<OrderPlacedEventHandler> _logger;

/// <summary>
/// Handles messages of type OrderPlacedEvent
/// Takes a dependency on IMessagePublisher so that further messages can be published
/// </summary>
public OrderPlacedEventHandler(IMessagePublisher publisher, ILogger<OrderPlacedEventHandler> log)
{
_publisher = publisher;
_logger = log;
}

public async Task<bool> Handle(OrderPlacedEvent message)
{
// Returning true would indicate:
// The message was handled successfully
// The message can be removed from the queue.
// Returning false would indicate:
// The message was not handled successfully
// The message handling should be retried (configured by default)
// The message should be moved to the error queue if all retries fail

try
{
_logger.LogInformation("Order {orderId} for {description} received", message.OrderId, message.Description);

// This is where you would actually handle the order placement
// Intentionally left empty for the sake of this being a sample application

_logger.LogInformation("Order {orderId} ready", message.OrderId);

var orderReadyEvent = new OrderReadyEvent
{
OrderId = message.OrderId
};

await _publisher.PublishAsync(orderReadyEvent).ConfigureAwait(false);
return true;
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to handle message for {orderId}", message.OrderId);
return false;
}
}
}
}
83 changes: 83 additions & 0 deletions samples/JustSaying.Sample.Restaurant.KitchenConsole/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
using System;
using System.Threading.Tasks;
using JustSaying.Sample.Restaurant.Models;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

namespace JustSaying.Sample.Restaurant.KitchenConsole
{
internal class Program
{
public static async Task Main()
{
Console.Title = "KitchenConsole";

await new HostBuilder()
.ConfigureAppConfiguration((hostContext, config) =>
{
config.AddJsonFile("appsettings.json", optional: false);
config.AddJsonFile($"appsettings.{hostContext.HostingEnvironment.EnvironmentName}.json", optional: true);
config.AddEnvironmentVariables();
})
.ConfigureLogging(loggingBuilder => loggingBuilder.AddConsole())
.ConfigureServices((hostContext, services) =>
{
var configuration = hostContext.Configuration;
services.AddJustSaying(config =>
{
config.Client(x =>
{
if (configuration.HasAWSServiceUrl())
{
// The AWS client SDK allows specifying a custom HTTP endpoint.
// For testing purposes it is useful to specify a value that
// points to a docker image such as `p4tin/goaws` or `localstack/localstack`
x.WithServiceUri(configuration.GetAWSServiceUri())
.WithAnonymousCredentials();
}
else
{
// The real AWS environment will require some means of authentication
//x.WithBasicCredentials("###", "###");
//x.WithSessionCredentials("###", "###", "###");
}
});

config.Messaging(x =>
{
// Configures which AWS Region to operate in
x.WithRegion(configuration.GetAWSRegion());
});

config.Subscriptions(x =>
{
// Creates the following if they do not already exist
// - a SQS queue of name `orderplacedevent`
// - a SQS queue of name `orderplacedevent_error`
// - a SNS topic of name `orderplacedevent`
// - a SNS topic subscription on topic 'orderplacedevent' and queue 'orderplacedevent'
x.ForTopic<OrderPlacedEvent>();
});

config.Publications(x =>
{
// Creates the following if they do not already exist
// - a SNS topic of name `orderreadyevent`
x.WithTopic<OrderReadyEvent>();
});
});

// Added a message handler for message type for 'OrderPlacedEvent' on topic 'orderplacedevent' and queue 'orderplacedevent'
services.AddJustSayingHandler<OrderPlacedEvent, OrderPlacedEventHandler>();

// Add a background service that is listening for messages related to the above subscriptions
services.AddHostedService<Subscriber>();
})
.UseConsoleLifetime()
.Build()
.RunAsync();
}
}
}
32 changes: 32 additions & 0 deletions samples/JustSaying.Sample.Restaurant.KitchenConsole/Subscriber.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

namespace JustSaying.Sample.Restaurant.KitchenConsole
{
/// <summary>
/// A background service responsible for starting the bus which listens for
/// messages on the configured queues
/// </summary>
public class Subscriber : BackgroundService
{
private readonly IMessagingBus _bus;
private readonly ILogger<Subscriber> _logger;

public Subscriber(IMessagingBus bus, ILogger<Subscriber> logger)
{
_bus = bus;
_logger = logger;
}

protected override Task ExecuteAsync(CancellationToken stoppingToken)
{
_logger.LogInformation("Kitchen subscriber running");

_bus.Start(stoppingToken);

return Task.CompletedTask;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"AWSRegion": "eu-west-1",
"AWSServiceUrl": "http://localhost:4100",
"Logging": {
"LogLevel": {
"Default": "Information",
"System": "Warning",
"Microsoft": "Warning"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\..\JustSaying.Models\JustSaying.Models.csproj" />
</ItemGroup>

</Project>
11 changes: 11 additions & 0 deletions samples/JustSaying.Sample.Restaurant.Models/OrderPlacedEvent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using JustSaying.Models;

namespace JustSaying.Sample.Restaurant.Models
{
public class OrderPlacedEvent : Message
{
public int OrderId { get; set; }

public string Description { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using JustSaying.Models;

namespace JustSaying.Sample.Restaurant.Models
{
public class OrderReadyEvent : Message
{
public int OrderId { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using System;
using Amazon;
using Microsoft.Extensions.Configuration;

namespace JustSaying.Sample.Restaurant.OrderingApi
{
public static class ConfigurationExtensions
{
private const string AWSServiceUrlKey = "AWSServiceUrl";

private const string AWSRegionKey = "AWSRegion";

public static bool HasAWSServiceUrl(this IConfiguration configuration)
{
return !string.IsNullOrWhiteSpace(configuration[AWSServiceUrlKey]);
}

public static Uri GetAWSServiceUri(this IConfiguration configuration)
{
return new Uri(configuration[AWSServiceUrlKey]);
}

public static RegionEndpoint GetAWSRegion(this IConfiguration configuration)
{
return RegionEndpoint.GetBySystemName(configuration[AWSRegionKey]);
}
}
}
Loading

0 comments on commit f3a05e3

Please sign in to comment.