Skip to content

Commit

Permalink
Merge pull request #1 from jacqueskang/amazon-sns
Browse files Browse the repository at this point in the history
Amazon sns
  • Loading branch information
jacqueskang authored Nov 21, 2018
2 parents c7c70a5 + 99f7441 commit 5bc1033
Show file tree
Hide file tree
Showing 36 changed files with 514 additions and 180 deletions.
81 changes: 60 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,55 +1,94 @@
# JKang.EventBus

A .NET Core ultra lightweight in-memory event bus implementation.
.NET Core event bus implementation supporting:
* In-memory event dispatching (publishing and subscription)
* publishing event to Amazon SNS

## NuGet packages

- [JKang.EventBus](https://www.nuget.org/packages/JKang.EventBus/)

## Sample:
## Quick start:

1. Create an event class
1. Create a console application with the following NuGet packages installed:
```console
> Install-Package Microsoft.Extensions.DependencyInjection
> Install-Package JKang.EventBus
```

2. Create an event class

```csharp
public class MessageSent
public class MyEvent
{
public MessageSent(string message) => Message = message;

public string Message { get; }
public string Message { get; set; }
}
```

2. Implement as many event handlers as you like
3. Optionally implement one or multiple handlers subscribing to the event

```csharp
public class MessageSentEventHandler : IEventHandler<MessageSent>
class MyEventHandler : IEventHandler<MyEvent>
{
public Task HandleEventAsync(MessageSent @event)
public Task HandleEventAsync(MyEvent @event)
{
Console.WriteLine(@event.Message)
Console.WriteLine($"Received message '{@event.Message}'");
return Task.CompletedTask;
}
}
```

3. register event handlers in IServiceCollection
4. Configure and register event bus using Dependency Injection

```csharp
// Startup.cs
public void ConfigureServices(IServiceCollection services)
static void Main(string[] args)
{
services
.AddEventBus()
.UseInMemory()
.AddEventHandler<MessageSent, MessageSentEventHandler>()
;
IServiceCollection services = new ServiceCollection();

services.AddEventBus(builder =>
{
builder.AddInMemoryEventBus(subscriber =>
{
subscriber.Subscribe<MyEvent, MyEventHandler>();
//subscriber.SubscribeAllHandledEvents<MyEventHandler>(); // other way
});
});
}
```

4. Publish the event
5. Publish an event

```csharp
IServiceProvider serviceProvider = services.BuildServiceProvider();
using (IServiceScope scope = serviceProvider.CreateScope())
{
IEventPublisher eventPublisher = scope.ServiceProvider.GetRequiredService<IEventPublisher>();
eventPublisher.PublishEventAsync(new MyEvent { Message = "Hello, event bus!" }).Wait();
}
```


## Publish event to Amazon Simple Notification Service (SNS)

1. Install NuGet package [JKang.EventBus.AmazonSns](https://www.nuget.org/packages/JKang.EventBus.AmazonSns/)

2. Configure publishing events to AWS SNS

```csharp
services.AddEventBus(builder =>
{
builder
//.AddInMemoryEventBus() // uncomment to keep using in-memory event bus in the same time
.PublishToAmazonSns(x => x.Region = "eu-west-3");
});
```

3. Optionally It's possible to customize AWS SNS topic name using annotation

```csharp
await _eventPublisher.PublishEventAsync(new MessageSent("Something happened!"));
[AmazonSnsTopic("my-event")]
public class MyEvent
{ }
```

Any contributions or comments are welcome!
Expand Down
25 changes: 13 additions & 12 deletions src/EventBus.sln
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ VisualStudioVersion = 15.0.27130.2020
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JKang.EventBus.Abstractions", "JKang.EventBus.Abstractions\JKang.EventBus.Abstractions.csproj", "{B32C9E22-C892-4F8C-8E49-30CBA5B971C1}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JKang.EventBus.InMemory", "JKang.EventBus.InMemory\JKang.EventBus.InMemory.csproj", "{21BFE809-6A56-4F61-9F80-0AEAE8184863}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{8C1896E4-9A8F-4A76-B3D1-CCBB0A2F8037}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Samples.EventBus.AspNetCore", "Samples.EventBus.AspNetCore\Samples.EventBus.AspNetCore.csproj", "{F0688B6D-EEE6-4AA3-BEC3-F73DD1FC0DA0}"
Expand All @@ -17,12 +15,14 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
..\README.md = ..\README.md
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JKang.EventBus.RabbitMq", "JKang.EventBus.RabbitMq\JKang.EventBus.RabbitMq.csproj", "{ADDAFEB3-047F-45B3-B039-3C3EDF4105DA}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JKang.EventBus.Core", "JKang.EventBus.Core\JKang.EventBus.Core.csproj", "{16EFDC3B-73CD-486C-9BD0-5700AFF8CCB4}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JKang.EventBus", "JKang.EventBus\JKang.EventBus.csproj", "{36024674-F10A-4A44-BC4E-24EBAA0D0CFC}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JKang.EventBus.AmazonSns", "JKang.EventBus.AmazonSns\JKang.EventBus.AmazonSns.csproj", "{C46D4B8E-4AAA-4889-A60A-89A9E9E10F50}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Samples.EventBus.ConsoleApp", "Samples.EventBus.Console\Samples.EventBus.ConsoleApp.csproj", "{CE18852E-385B-4C84-B023-F4135494BFDD}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -33,18 +33,10 @@ Global
{B32C9E22-C892-4F8C-8E49-30CBA5B971C1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B32C9E22-C892-4F8C-8E49-30CBA5B971C1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B32C9E22-C892-4F8C-8E49-30CBA5B971C1}.Release|Any CPU.Build.0 = Release|Any CPU
{21BFE809-6A56-4F61-9F80-0AEAE8184863}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{21BFE809-6A56-4F61-9F80-0AEAE8184863}.Debug|Any CPU.Build.0 = Debug|Any CPU
{21BFE809-6A56-4F61-9F80-0AEAE8184863}.Release|Any CPU.ActiveCfg = Release|Any CPU
{21BFE809-6A56-4F61-9F80-0AEAE8184863}.Release|Any CPU.Build.0 = Release|Any CPU
{F0688B6D-EEE6-4AA3-BEC3-F73DD1FC0DA0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F0688B6D-EEE6-4AA3-BEC3-F73DD1FC0DA0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F0688B6D-EEE6-4AA3-BEC3-F73DD1FC0DA0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F0688B6D-EEE6-4AA3-BEC3-F73DD1FC0DA0}.Release|Any CPU.Build.0 = Release|Any CPU
{ADDAFEB3-047F-45B3-B039-3C3EDF4105DA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{ADDAFEB3-047F-45B3-B039-3C3EDF4105DA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{ADDAFEB3-047F-45B3-B039-3C3EDF4105DA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{ADDAFEB3-047F-45B3-B039-3C3EDF4105DA}.Release|Any CPU.Build.0 = Release|Any CPU
{16EFDC3B-73CD-486C-9BD0-5700AFF8CCB4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{16EFDC3B-73CD-486C-9BD0-5700AFF8CCB4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{16EFDC3B-73CD-486C-9BD0-5700AFF8CCB4}.Release|Any CPU.ActiveCfg = Release|Any CPU
Expand All @@ -53,12 +45,21 @@ Global
{36024674-F10A-4A44-BC4E-24EBAA0D0CFC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{36024674-F10A-4A44-BC4E-24EBAA0D0CFC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{36024674-F10A-4A44-BC4E-24EBAA0D0CFC}.Release|Any CPU.Build.0 = Release|Any CPU
{C46D4B8E-4AAA-4889-A60A-89A9E9E10F50}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C46D4B8E-4AAA-4889-A60A-89A9E9E10F50}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C46D4B8E-4AAA-4889-A60A-89A9E9E10F50}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C46D4B8E-4AAA-4889-A60A-89A9E9E10F50}.Release|Any CPU.Build.0 = Release|Any CPU
{CE18852E-385B-4C84-B023-F4135494BFDD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CE18852E-385B-4C84-B023-F4135494BFDD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CE18852E-385B-4C84-B023-F4135494BFDD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CE18852E-385B-4C84-B023-F4135494BFDD}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{F0688B6D-EEE6-4AA3-BEC3-F73DD1FC0DA0} = {8C1896E4-9A8F-4A76-B3D1-CCBB0A2F8037}
{CE18852E-385B-4C84-B023-F4135494BFDD} = {8C1896E4-9A8F-4A76-B3D1-CCBB0A2F8037}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {D9478378-E22B-477A-87E9-C668E0620F58}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using JKang.EventBus;

namespace Microsoft.Extensions.DependencyInjection
{
public interface IEventBusBuilder
{
IServiceCollection Services { get; }

IEventBusBuilder UseSerializer<TEventSerializer>()
where TEventSerializer : class, IEventSerializer;

IEventBusBuilder AddEventPublisher<TEventPublisher>()
where TEventPublisher : class, IEventPublisher;
}
}
12 changes: 12 additions & 0 deletions src/JKang.EventBus.Abstractions/IEventBusSubscriber.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace JKang.EventBus
{
public interface IEventBusSubscriber
{
IEventBusSubscriber Subscribe<TEvent, TEventHandler>()
where TEvent: class
where TEventHandler: class, IEventHandler<TEvent>;

IEventBusSubscriber SubscribeAllHandledEvents<TEventHandler>()
where TEventHandler : class;
}
}
10 changes: 10 additions & 0 deletions src/JKang.EventBus.Abstractions/IEventPublisherProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using System;
using System.Collections.Generic;

namespace JKang.EventBus
{
public interface IEventPublisherProvider
{
IEnumerable<IEventPublisher> GetEventPublishers();
}
}
7 changes: 7 additions & 0 deletions src/JKang.EventBus.Abstractions/IEventSerializer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace JKang.EventBus
{
public interface IEventSerializer
{
string Serialize<TEvent>(TEvent @event);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,8 @@
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="2.1.1" />
</ItemGroup>

</Project>
20 changes: 20 additions & 0 deletions src/JKang.EventBus.AmazonSns/AmazonSnsEventBusBuilderExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using JKang.EventBus;
using JKang.EventBus.AmazonSns;
using System;

namespace Microsoft.Extensions.DependencyInjection
{
public static class AmazonSnsEventBusBuilderExtensions
{
public static IEventBusBuilder PublishToAmazonSns(this IEventBusBuilder builder,
Action<AmazonSnsEventPublisherOptions> setupActions)
{
builder.Services
.Configure(setupActions)
;

return builder
.AddEventPublisher<AmazonSnsEventPublisher>();
}
}
}
46 changes: 46 additions & 0 deletions src/JKang.EventBus.AmazonSns/AmazonSnsEventPublisher.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using Amazon;
using Amazon.SimpleNotificationService;
using Amazon.SimpleNotificationService.Model;
using Microsoft.Extensions.Options;
using System;
using System.Linq;
using System.Threading.Tasks;

namespace JKang.EventBus.AmazonSns
{
public class AmazonSnsEventPublisher : IEventPublisher
{
private readonly IEventSerializer _eventSerializer;
private readonly IOptions<AmazonSnsEventPublisherOptions> _options;

public AmazonSnsEventPublisher(
IEventSerializer eventSerializer,
IOptions<AmazonSnsEventPublisherOptions> options)
{
_eventSerializer = eventSerializer;
_options = options;
}

public async Task PublishEventAsync<TEvent>(TEvent @event)
{
var endpoint = RegionEndpoint.GetBySystemName(_options.Value.Region);
var client = new AmazonSimpleNotificationServiceClient(endpoint);

Type eventType = typeof(TEvent);
AmazonSnsTopicAttribute attr = eventType
.GetCustomAttributes(typeof(AmazonSnsTopicAttribute), inherit: false)
.OfType<AmazonSnsTopicAttribute>()
.FirstOrDefault();
string topicName = attr == null
? eventType.FullName.ToLower().Replace('.', '-')
: attr.Name;
var createTopicRequest = new CreateTopicRequest(topicName);
CreateTopicResponse createTopicResponse = await client.CreateTopicAsync(createTopicRequest);
string topicArn = createTopicResponse.TopicArn;

string message = _eventSerializer.Serialize(@event);
var publishRequest = new PublishRequest(topicArn, message);
PublishResponse publishResponse = await client.PublishAsync(publishRequest);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace JKang.EventBus.AmazonSns
{
public class AmazonSnsEventPublisherOptions
{
public string Region { get; set; } = "eu-west-1";
}
}
15 changes: 15 additions & 0 deletions src/JKang.EventBus.AmazonSns/AmazonSnsTopicAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System;

namespace JKang.EventBus.AmazonSns
{
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
public class AmazonSnsTopicAttribute: Attribute
{
public AmazonSnsTopicAttribute(string name)
{
Name = name;
}

public string Name { get; }
}
}
16 changes: 16 additions & 0 deletions src/JKang.EventBus.AmazonSns/JKang.EventBus.AmazonSns.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">

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

<ItemGroup>
<PackageReference Include="AWSSDK.SimpleNotificationService" Version="3.3.3.2" />
<PackageReference Include="Microsoft.Extensions.Options" Version="2.1.1" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\JKang.EventBus.Abstractions\JKang.EventBus.Abstractions.csproj" />
</ItemGroup>

</Project>
22 changes: 18 additions & 4 deletions src/JKang.EventBus.Core/DependencyInjection/EventBusBuilder.cs
Original file line number Diff line number Diff line change
@@ -1,20 +1,34 @@
using JKang.EventBus;
using JKang.EventBus.MultiChannel;
using Microsoft.Extensions.DependencyInjection;

namespace JKang.EventBus.DependencyInjection
{
public class EventBusBuilder : IEventBusBuilder
{
private readonly EventPublisherRegister _register = new EventPublisherRegister();

public EventBusBuilder(IServiceCollection services)
{
Services = services;
Services = services
.AddSingleton(_register)
.AddSingleton<IEventPublisherProvider, EventPublisherProvider>()
.AddSingleton<IEventPublisher, MasterEventBus>();
}

public IServiceCollection Services { get; }

IEventBusBuilder IEventBusBuilder.AddEventHandler<TEvent, TEventHandler>()
public IEventBusBuilder UseSerializer<TEventSerializer>()
where TEventSerializer : class, IEventSerializer
{
Services.AddSingleton<IEventSerializer, TEventSerializer>();
return this;
}

public IEventBusBuilder AddEventPublisher<TEventPublisher>()
where TEventPublisher : class, IEventPublisher
{
Services.AddScoped<IEventHandler<TEvent>, TEventHandler>();
_register.Add<TEventPublisher>();
Services.AddSingleton<TEventPublisher>();
return this;
}
}
Expand Down
Loading

0 comments on commit 5bc1033

Please sign in to comment.