Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
15ac2de003 | ||
|
|
9334511f78 | ||
|
|
4b5800e3fb | ||
|
|
27c8075092 | ||
|
|
74b5c8e3a1 | ||
|
|
823a8c9d1b | ||
|
|
fc74b10766 | ||
|
|
ffdc36dbd2 |
BIN
Producer.png
Normal file
|
After Width: | Height: | Size: 113 KiB |
142
README.md
@@ -1,18 +1,20 @@
|
||||
A solution for Blogging based on a Event-Driven architecture with DDD and CQRS. The full solution contains three applications.
|
||||
* A Web API which receives Commands to produces Domain Events also receives Queries to return JSON.
|
||||
* A Consumer App that reads the Event Stream and do a projection to a MongoDB database.
|
||||
A solution based on a Event-Driven architecture with DDD and CQRS. The solution contains the following applications.
|
||||
* A Producer Web API which receives Commands to produce Domain Events. This one also receives Queries and returns JSON.
|
||||
* A Consumer Console App that reads the Event Stream and do a projection to a MongoDB database.
|
||||
* A Web API for authentication and JWT generation.
|
||||
|
||||
[Checkout the Source Code on GitHub](https://github.com/ivanpaulovich/jambo)
|
||||
|
||||
#### Requirements
|
||||
* [Visual Studio 2017 + Update 3](https://www.visualstudio.com/en-us/news/releasenotes/vs2017-relnotes)
|
||||
* [.NET SDK 2.0](https://www.microsoft.com/net/download/core)
|
||||
* [.NET CORE SDK 2.0](https://www.microsoft.com/net/download/core)
|
||||
* [Docker](https://docs.docker.com/docker-for-windows/install/)
|
||||
|
||||
#### Environment setup
|
||||
|
||||
*If you already have valid connections strings for Kafka and MongoDB you could skip this topic and go to the Running the applications topic.*
|
||||
*If you already have valid connections for Kafka and MongoDB you could skip this step and go to Running the applications step.*
|
||||
|
||||
* Run the `./up-kafka-mongodb.sh` script to run Kafka and MongoDB as Docker Containers. Please wait until the ~800mb download to be complete.
|
||||
* Run the `./up-kafka-mongodb.sh` bash script to run Kafka and MongoDB as Docker Containers. Please wait until the ~800mb download to be complete.
|
||||
|
||||
```
|
||||
$ ./up-kafka-mongodb.sh
|
||||
@@ -45,88 +47,78 @@ CONTAINER ID IMAGE COMMAND CREATED
|
||||
ba28cf144478 mongo "docker-entrypoint..." 2 days ago Up 2 days 0.0.0.0:27017->27017/tcp setup_mongodb_1
|
||||
```
|
||||
|
||||
If Kafka is running good it will be working with the `10.0.75.1:9092` connection string and if MongoDB is running good it will be working at `mongodb://10.0.75.1:27017`.
|
||||
If Kafka is running well it will be working with the `10.0.75.1:9092` connection string.
|
||||
if MongoDB is running well it will be working at `mongodb://10.0.75.1:27017` connection string.
|
||||
|
||||
#### The Domain
|
||||

|
||||
## Running the applications
|
||||
|
||||
#### As Aplicações desta Solução
|
||||
* **Producer**: Web API que recebe os comandos de edição de conteúdo, produz Eventos de Domínio e publica as mensagens em um tópico no Kafka.
|
||||
* **Consumer**: Aplicativo Console que consome as mensagens do Kafka, deserializa em Eventos de Domínio e aplica nas agregações persistindo no MongoDB o novo estado.
|
||||
* **Auth**: Web API que gera tokens de autenticação para acesso ao WebAPI.
|
||||
You have two options to run the applications, one is by opening with Visual Studio 2017 and the other is by running dotnet core commands.
|
||||
|
||||
#### Por onde começar?
|
||||
Há duas formas de iniciar a solução.
|
||||
### Option 1 - Running with Visual Studio 2017
|
||||
|
||||
##### 1. O jeito fácil
|
||||
Open the three solutions on three Visual Studios them run the following projects.
|
||||
|
||||
Resolver os [pré-requisitos](https://github.com/ivanpaulovich/jambo/#prerequisitos), definir o projeto inicial como sendo o `docker-compose` e então apertar `Ctrl+F5` para executar todas as aplicações. Se tudo estiver correto, digite `docker ps` no seu terminal para verificar em quais portas cada aplicação está executando. Será algo assim:
|
||||
* `Jambo.Auth.UI`.
|
||||
* `Jambo.Consumer.UI`.
|
||||
* `Jambo.Producer.UI`.
|
||||
|
||||

|
||||
### Option 2 - Running with dotnet commands
|
||||
|
||||
A partir daí basta acessar:
|
||||
* Auth em http://localhost:32775/swagger/
|
||||
* Producer em http://localhost:32776/swagger/
|
||||
#### How to run the Bearer Authencation API
|
||||
|
||||
Leia o [o jeito não tão fácil](https://github.com/ivanpaulovich/jambo/#2-o-jeito-não-tão-fácil) para entender como criar um Token no Auth API para consumir os serviços do Producer API via swagger.
|
||||
1. Run the command `dotnet run` at `source\Auth\Jambo.Auth.UI` folder.
|
||||
```
|
||||
$ dotnet run
|
||||
Using launch settings from C:\git\jambo\source\Auth\Jambo.Auth.UI\Properties\launchSettings.json...
|
||||
Hosting environment: Development
|
||||
Content root path: C:\git\jambo\source\Auth\Jambo.Auth.UI
|
||||
Now listening on: http://localhost:16024
|
||||
Application started. Press Ctrl+C to shut down.
|
||||
```
|
||||
2. Navigate to the Swagger UI at (eg. http://localhost:16024/swagger).
|
||||
3. Post the following credentials:
|
||||
```
|
||||
{
|
||||
"username": "ivanpaulovich",
|
||||
"password": "mysecret"
|
||||
}
|
||||
```
|
||||
4. __Store the Bearer Token__ because you will need the token value to log on Producer API.
|
||||
```
|
||||
{
|
||||
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJhYzA4MmE3OS1lMWY3LTQ4MTktYmU1Mi1hOTQwMTBkM2VjZTciLCJzdWIiOiJzdHJpbmciLCJleHAiOjE1MTI0Nzg5ODgsImlzcyI6Imh0dHA6Ly9teWFjY291bnRhcGkiLCJhdWQiOiJodHRwOi8vbXlhY2NvdW50YXBpIn0.9YKGmKaptLBDcExHhPOQ3_j9TsdbkcRf8ZtvIkdq8Go",
|
||||
"expiration": "2017-12-05T13:03:08Z"
|
||||
}
|
||||
```
|
||||
#### How to run the Consumer API
|
||||
|
||||
##### 2. O jeito não tão fácil
|
||||
1. Run the command `dotnet run` at `source\Consumer\Jambo.Consumer.UI` folder
|
||||
|
||||
A outra opção é inicializar aplicação por aplicação, seguindo o seguintes passos:
|
||||
```
|
||||
$ dotnet run
|
||||
11/5/2017 11:17:20 AM Waiting for events..
|
||||
11/5/2017 11:18:20 AM Waiting for events..
|
||||
11/5/2017 11:19:20 AM Waiting for events..
|
||||
11/5/2017 11:20:20 AM Waiting for events..
|
||||
11/5/2017 11:21:20 AM Waiting for events..
|
||||
11/5/2017 11:22:20 AM Waiting for events..
|
||||
```
|
||||
|
||||
1. Execute o projeto **Jambo.Auth.WebAPI** e chame o método *Account/Token* com qualquer usuário e senha. *Guarde este token*.
|
||||
3. __Attention:__ keep the Console App running for events processing.
|
||||
|
||||

|
||||
#### How to run the Producer API
|
||||
|
||||

|
||||

|
||||
|
||||
3. Execute o projeto **Jambo.Producer.WebAPI** e clique no botão *Authorization* (topo direito da página).
|
||||
1. Run the command `dotnet run` at the `source\Producer\Jambo.Producer.UI` folder.
|
||||
|
||||
Digite `bearer + valor_do_token` e clique em fechar. Algo assim:
|
||||

|
||||
Chame os métodos para manutenção dos dados do Blog, Posts e Comentários.
|
||||

|
||||
```
|
||||
$ dotnet run
|
||||
Using launch settings from C:\git\jambo\source\Producer\Jambo.Producer.UI\Properties\launchSettings.json...
|
||||
Hosting environment: Development
|
||||
Content root path: C:\git\jambo\source\Producer\Jambo.Producer.UI
|
||||
Now listening on: http://localhost:16959
|
||||
Application started. Press Ctrl+C to shut down.
|
||||
```
|
||||
|
||||
2. Execute o projeto **Jambo.Consumer.Console** e garante que ele **contínua em execução**.
|
||||
|
||||

|
||||
|
||||
4. Visualize suas modificações
|
||||
|
||||

|
||||
|
||||
#### Demo
|
||||
* **Auth API**: http://jambo.westus.cloudapp.azure.com:7070/swagger/.
|
||||
* **Producer**: http://jambo.westus.cloudapp.azure.com:7080/swagger/.
|
||||
* **Consumer**: Executa em background neste servidor.
|
||||
|
||||
#### Próximos passos?
|
||||
1. Publicar os containers no Azure.
|
||||
2. Criar um CI/CD para atualizar os containers a cada commit.
|
||||
3. Criar testes de unidade, testes automatizados.
|
||||
4. Consumir serviços externos.
|
||||
5. Implementação alternativa de barramento: Azure Event Hubs
|
||||
6. Implementação alternativa de snapshot: Azure Cosmos DB
|
||||
7. Implementar um HealthCheck
|
||||
|
||||
#### Pré-requisitos
|
||||
|
||||
* [Visual Studio 2017 + Update 3](https://www.visualstudio.com/en-us/news/releasenotes/vs2017-relnotes)
|
||||
* [.NET SDK 2.0](https://www.microsoft.com/net/download/core)
|
||||
* [Docker](https://docs.docker.com/docker-for-windows/install/) (Opcional)
|
||||
* [Robomongo](https://robomongo.org/) (Opcional)
|
||||
|
||||
#### Agradecimentos
|
||||
Obrigado aos amigos que me estimularam a criar este projeto e estão sempre contribuindo e dando feedback.
|
||||
* [Vinicius Baldotto](https://github.com/Baldotto)
|
||||
* [André Paulovich](https://github.com/andrepaulovich)
|
||||
* André Mendes
|
||||
|
||||
Obrigado de verdade!
|
||||
|
||||
#### Deixe o seu feedback
|
||||
Agradeço todo comentário sobre o projeto. Envie suas dúvidas e sugestões no [Fórum](https://github.com/ivanpaulovich/jambo/issues).
|
||||
|
||||
#### Histórico de Versões
|
||||
* 10/set/2017:
|
||||
[](https://github.com/ivanpaulovich/jambo/releases/latest)
|
||||
2. Navigate to the Swagger UI (eg. http://localhost:14398/swagger).
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
version: '2'
|
||||
|
||||
services:
|
||||
jambo.auth.webapi:
|
||||
image: ivanpaulovich/jambo:auth.webapi
|
||||
links:
|
||||
- "mongodb:mongo"
|
||||
depends_on:
|
||||
- mongodb
|
||||
ports:
|
||||
- 7070:80
|
||||
jambo.producer.webapi:
|
||||
image: ivanpaulovich/jambo:producer.webapi
|
||||
ports:
|
||||
- 7080:80
|
||||
links:
|
||||
- "mongodb:mongo"
|
||||
depends_on:
|
||||
- mongodb
|
||||
- kafka
|
||||
environment:
|
||||
- ASPNETCORE_URLS=http://*:80
|
||||
- ServiceBus__ConnectionString=kafka:9092
|
||||
- ServiceBus__Topic=jambov32
|
||||
- MongoDB__ConnectionString=mongodb://mongodb:27017
|
||||
- MongoDB__Database=jambov32
|
||||
jambo.consumer.console:
|
||||
image: ivanpaulovich/jambo:consumer.console
|
||||
links:
|
||||
- "mongodb:mongo"
|
||||
depends_on:
|
||||
- mongodb
|
||||
- kafka
|
||||
environment:
|
||||
- ASPNETCORE_URLS=http://*:80
|
||||
- ServiceBus__ConnectionString=kafka:9092
|
||||
- ServiceBus__Topic=jambov32
|
||||
- MongoDB__ConnectionString=mongodb://mongodb:27017
|
||||
- MongoDB__Database=jambov32
|
||||
mongodb:
|
||||
image: mongo
|
||||
container_name: "mongodb"
|
||||
ports:
|
||||
- 27017:27017
|
||||
kafka:
|
||||
image: landoop/fast-data-dev:latest
|
||||
ports:
|
||||
- 2181:2181
|
||||
- 3030:3030
|
||||
- 8081-8083:8081-8083
|
||||
- 9581-9585:9581-9585
|
||||
- 9092:9092
|
||||
environment:
|
||||
- ADV_HOST=kafka
|
||||
|
Before Width: | Height: | Size: 52 KiB |
|
Before Width: | Height: | Size: 55 KiB |
|
Before Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 64 KiB |
|
Before Width: | Height: | Size: 53 KiB |
|
Before Width: | Height: | Size: 39 KiB |
@@ -6,9 +6,10 @@ services:
|
||||
ports:
|
||||
- 27017:27017
|
||||
kafka:
|
||||
image: landoop/fast-data-dev:latest
|
||||
image: spotify/kafka
|
||||
ports:
|
||||
- 3030:3030
|
||||
- 2181:2181
|
||||
- 9092:9092
|
||||
environment:
|
||||
- ADV_HOST=10.0.75.1
|
||||
- ADVERTISED_HOST=10.0.75.1
|
||||
- ADVERTISED_PORT=9092
|
||||
17
source/Auth/Jambo.Auth.Application/Commands/LoginCommand.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
namespace Jambo.Auth.Application.Commands
|
||||
{
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
[DataContract]
|
||||
public class LoginCommand
|
||||
{
|
||||
[Required]
|
||||
[DataMember]
|
||||
public string Username { get; set; }
|
||||
|
||||
[Required]
|
||||
[DataMember]
|
||||
public string Password { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -4,12 +4,6 @@
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="CommandHandlers\**" />
|
||||
<EmbeddedResource Remove="CommandHandlers\**" />
|
||||
<None Remove="CommandHandlers\**" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Mediatr" Version="3.0.1" />
|
||||
<PackageReference Include="System.ComponentModel.Annotations" Version="4.4.0" />
|
||||
@@ -0,0 +1,15 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<NoWarn>1701;1702;1705;NU1701;CS1591</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Jambo.Auth.Application\Jambo.Auth.Application.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,17 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using System.Security.Claims;
|
||||
using System.Text;
|
||||
using Jambo.Auth.Application.Commands;
|
||||
|
||||
namespace Jambo.Auth.UI
|
||||
namespace Jambo.Auth.UI
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using System.Security.Claims;
|
||||
using System.Text;
|
||||
using Jambo.Auth.Application.Commands;
|
||||
|
||||
[Route("api/[controller]")]
|
||||
public class AccountController : Controller
|
||||
{
|
||||
@@ -46,7 +44,7 @@ namespace Jambo.Auth.UI
|
||||
config.Issuer,
|
||||
config.Issuer,
|
||||
GetTokenClaims(user),
|
||||
expires: DateTime.UtcNow.AddDays(1),
|
||||
expires: DateTime.UtcNow.AddDays(7),
|
||||
signingCredentials: new SigningCredentials(
|
||||
new SymmetricSecurityKey(Encoding.UTF8.GetBytes(config.SecretKey)),
|
||||
SecurityAlgorithms.HmacSha256)
|
||||
@@ -57,9 +55,8 @@ namespace Jambo.Auth.UI
|
||||
{
|
||||
return new List<Claim>
|
||||
{
|
||||
new Claim(JwtRegisteredClaimNames.Jti, user.UserId.ToString()),
|
||||
new Claim(JwtRegisteredClaimNames.Sub, user.UserId.ToString()),
|
||||
new Claim(ClaimTypes.GroupSid, user.SchoolId.ToString()),
|
||||
new Claim(JwtRegisteredClaimNames.Jti, user.Username),
|
||||
new Claim(JwtRegisteredClaimNames.Sub, user.Password),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -3,4 +3,4 @@ ARG source
|
||||
WORKDIR /app
|
||||
EXPOSE 80
|
||||
COPY ${source:-obj/Docker/publish} .
|
||||
ENTRYPOINT ["dotnet", "Jambo.Auth.Infrastructure.dll"]
|
||||
ENTRYPOINT ["dotnet", "Jambo.Auth.UI.dll"]
|
||||
@@ -4,6 +4,16 @@
|
||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<NoWarn>1701;1702;1705;NU1701</NoWarn>
|
||||
<DocumentationFile>bin\Debug\netcoreapp2.0\Jambo.Auth.UI.xml</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="appsettings.Development.json" />
|
||||
<None Include="appsettings.json" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="1.0.0" />
|
||||
@@ -11,7 +21,6 @@
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Jambo.Auth.Application\Jambo.Auth.Application.csproj" />
|
||||
<ProjectReference Include="..\Jambo.Auth.UI\Jambo.Auth.UI.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,15 +1,8 @@
|
||||
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;
|
||||
|
||||
namespace Jambo.Auth.Infrastructure
|
||||
namespace Jambo.Auth.UI
|
||||
{
|
||||
using Microsoft.AspNetCore;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
|
||||
public class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
27
source/Auth/Jambo.Auth.UI/Properties/launchSettings.json
Normal file
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:16023/",
|
||||
"sslPort": 0
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"Jambo.Auth.UI": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
},
|
||||
"applicationUrl": "http://localhost:16024/"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Jambo.Auth.Infrastructure
|
||||
namespace Jambo.Auth.UI
|
||||
{
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
public class Startup
|
||||
{
|
||||
public Startup(IConfiguration configuration)
|
||||
@@ -12,7 +12,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Jambo.Domain\Jambo.Domain.csproj" />
|
||||
<ProjectReference Include="..\..\Shared\Jambo.Domain\Jambo.Domain.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,11 +1,11 @@
|
||||
using Jambo.Domain.Model;
|
||||
using Jambo.Domain.Model.Blogs;
|
||||
using Jambo.Domain.Model.Posts;
|
||||
using MongoDB.Bson.Serialization;
|
||||
using MongoDB.Driver;
|
||||
|
||||
namespace Jambo.Consumer.Infrastructure.DataAccess
|
||||
namespace Jambo.Consumer.Infrastructure.DataAccess
|
||||
{
|
||||
using Jambo.Domain.Model;
|
||||
using Jambo.Domain.Model.Blogs;
|
||||
using Jambo.Domain.Model.Posts;
|
||||
using MongoDB.Bson.Serialization;
|
||||
using MongoDB.Driver;
|
||||
|
||||
public class MongoContext
|
||||
{
|
||||
private readonly MongoClient mongoClient;
|
||||
@@ -1,12 +1,11 @@
|
||||
using Jambo.Domain.Model.Blogs;
|
||||
using Jambo.Domain.Model.Posts;
|
||||
using MongoDB.Driver;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Jambo.Consumer.Infrastructure.DataAccess.Repositories.Blogs
|
||||
namespace Jambo.Consumer.Infrastructure.DataAccess.Repositories.Blogs
|
||||
{
|
||||
using Jambo.Domain.Model.Blogs;
|
||||
using MongoDB.Driver;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
public class BlogReadOnlyRepository : IBlogReadOnlyRepository
|
||||
{
|
||||
private readonly MongoContext _mongoContext;
|
||||
@@ -1,10 +1,10 @@
|
||||
using Jambo.Domain.Model.Blogs;
|
||||
using MongoDB.Driver;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Jambo.Consumer.Infrastructure.DataAccess.Repositories.Blogs
|
||||
namespace Jambo.Consumer.Infrastructure.DataAccess.Repositories.Blogs
|
||||
{
|
||||
using Jambo.Domain.Model.Blogs;
|
||||
using MongoDB.Driver;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
public class BlogWriteOnlyRepository : IBlogWriteOnlyRepository
|
||||
{
|
||||
private readonly MongoContext mongoContext;
|
||||
@@ -1,12 +1,11 @@
|
||||
using Jambo.Domain.Model.Blogs;
|
||||
using Jambo.Domain.Model.Posts;
|
||||
using MongoDB.Driver;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Jambo.Consumer.Infrastructure.DataAccess.Repositories.Posts
|
||||
namespace Jambo.Consumer.Infrastructure.DataAccess.Repositories.Posts
|
||||
{
|
||||
using Jambo.Domain.Model.Posts;
|
||||
using MongoDB.Driver;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
public class PostReadOnlyRepository : IPostReadOnlyRepository
|
||||
{
|
||||
private readonly MongoContext _mongoContext;
|
||||
@@ -1,11 +1,10 @@
|
||||
using Jambo.Domain.Model.Blogs;
|
||||
using Jambo.Domain.Model.Posts;
|
||||
using MongoDB.Driver;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Jambo.Consumer.Infrastructure.DataAccess.Repositories.Posts
|
||||
namespace Jambo.Consumer.Infrastructure.DataAccess.Repositories.Posts
|
||||
{
|
||||
using Jambo.Domain.Model.Posts;
|
||||
using MongoDB.Driver;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
public class PostWriteOnlyRepository : IPostWriteOnlyRepository
|
||||
{
|
||||
private readonly MongoContext _mongoContext;
|
||||
@@ -27,11 +27,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Jambo.Consumer.Application\Jambo.Consumer.Application.csproj" />
|
||||
<ProjectReference Include="..\Jambo.Domain\Jambo.Domain.csproj" />
|
||||
<ProjectReference Include="..\..\Shared\Jambo.Domain\Jambo.Domain.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="CopyFiles" AfterTargets="build">
|
||||
<Copy DestinationFolder="..\Jambo.Consumer.UI\bin\Debug\netcoreapp2.0" SourceFiles="$(OutputPath)\Jambo.Consumer.Infrastructure.dll" SkipUnchangedFiles="false" />
|
||||
<Copy DestinationFolder="..\Jambo.Consumer.UI\bin\Debug\netcoreapp2.0" SourceFiles="$(OutputPath)\Jambo.Consumer.Infrastructure.pdb" SkipUnchangedFiles="false" />
|
||||
</Target>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,38 @@
|
||||
namespace Jambo.Consumer.Infrastructure.Modules
|
||||
{
|
||||
using Autofac;
|
||||
using Autofac.Features.Variance;
|
||||
using Jambo.Consumer.Application.DomainEventHandlers.Blogs;
|
||||
using MediatR;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
|
||||
public class MediatRModule : Autofac.Module
|
||||
{
|
||||
protected override void Load(ContainerBuilder builder)
|
||||
{
|
||||
builder.RegisterSource(new ContravariantRegistrationSource());
|
||||
|
||||
builder
|
||||
.RegisterType<Mediator>()
|
||||
.As<IMediator>()
|
||||
.InstancePerLifetimeScope();
|
||||
|
||||
builder
|
||||
.Register<SingleInstanceFactory>(ctx => {
|
||||
var c = ctx.Resolve<IComponentContext>();
|
||||
return t => { object o; return c.TryResolve(t, out o) ? o : null; };
|
||||
})
|
||||
.InstancePerLifetimeScope();
|
||||
|
||||
builder
|
||||
.Register<MultiInstanceFactory>(ctx => {
|
||||
var c = ctx.Resolve<IComponentContext>();
|
||||
return t => (IEnumerable<object>)c.Resolve(typeof(IEnumerable<>).MakeGenericType(t));
|
||||
})
|
||||
.InstancePerLifetimeScope();
|
||||
|
||||
builder.RegisterAssemblyTypes(typeof(BlogCreatedEventHandler).GetTypeInfo().Assembly).AsImplementedInterfaces(); // via assembly scan
|
||||
}
|
||||
}
|
||||
}
|
||||
121
source/Consumer/Jambo.Consumer.Infrastructure/ServiceBus/Bus.cs
Normal file
@@ -0,0 +1,121 @@
|
||||
namespace Jambo.Consumer.Infrastructure.ServiceBus
|
||||
{
|
||||
using Confluent.Kafka;
|
||||
using Confluent.Kafka.Serialization;
|
||||
using Jambo.Domain.Exceptions;
|
||||
using Jambo.Domain.Model;
|
||||
using Jambo.Domain.ServiceBus;
|
||||
using MediatR;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
public class Bus : ISubscriber
|
||||
{
|
||||
public readonly string brokerList;
|
||||
public readonly string topic;
|
||||
|
||||
private static Dictionary<string, object> constructConfig(string brokerList, bool enableAutoCommit) =>
|
||||
new Dictionary<string, object>
|
||||
{
|
||||
{ "group.id", "jambo-consumer" },
|
||||
{ "enable.auto.commit", enableAutoCommit },
|
||||
{ "auto.commit.interval.ms", 5000 },
|
||||
{ "statistics.interval.ms", 60000 },
|
||||
{ "bootstrap.servers", brokerList },
|
||||
{ "default.topic.config", new Dictionary<string, object>()
|
||||
{
|
||||
{ "auto.offset.reset", "smallest" }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public Bus(string brokerList, string topic)
|
||||
{
|
||||
this.brokerList = brokerList;
|
||||
this.topic = topic;
|
||||
}
|
||||
|
||||
public void Listen(IMediator mediator)
|
||||
{
|
||||
using (var consumer = new Consumer<string, string>(constructConfig(brokerList, true), new StringDeserializer(Encoding.UTF8), new StringDeserializer(Encoding.UTF8)))
|
||||
{
|
||||
consumer.OnPartitionEOF += (_, end)
|
||||
=> Console.WriteLine($"Reached end of topic {end.Topic} partition {end.Partition}, next message will be at offset {end.Offset}");
|
||||
|
||||
consumer.OnError += (_, error)
|
||||
=> Console.WriteLine($"Error: {error}");
|
||||
|
||||
consumer.OnConsumeError += (_, msg)
|
||||
=> Console.WriteLine($"Error consuming from topic/partition/offset {msg.Topic}/{msg.Partition}/{msg.Offset}: {msg.Error}");
|
||||
|
||||
consumer.OnOffsetsCommitted += (_, commit) =>
|
||||
{
|
||||
Console.WriteLine($"[{string.Join(", ", commit.Offsets)}]");
|
||||
|
||||
if (commit.Error)
|
||||
{
|
||||
Console.WriteLine($"Failed to commit offsets: {commit.Error}");
|
||||
}
|
||||
Console.WriteLine($"Successfully committed offsets: [{string.Join(", ", commit.Offsets)}]");
|
||||
};
|
||||
|
||||
consumer.OnPartitionsAssigned += (_, partitions) =>
|
||||
{
|
||||
Console.WriteLine($"Assigned partitions: [{string.Join(", ", partitions)}], member id: {consumer.MemberId}");
|
||||
consumer.Assign(partitions);
|
||||
};
|
||||
|
||||
consumer.OnPartitionsRevoked += (_, partitions) =>
|
||||
{
|
||||
Console.WriteLine($"Revoked partitions: [{string.Join(", ", partitions)}]");
|
||||
consumer.Unassign();
|
||||
};
|
||||
|
||||
consumer.OnStatistics += (_, json)
|
||||
=> Console.WriteLine($"Statistics: {json}");
|
||||
|
||||
consumer.Subscribe(this.topic);
|
||||
|
||||
Console.WriteLine($"Subscribed to: [{string.Join(", ", consumer.Subscription)}]");
|
||||
|
||||
var cancelled = false;
|
||||
Console.CancelKeyPress += (_, e) =>
|
||||
{
|
||||
e.Cancel = true; // prevent the process from terminating.
|
||||
cancelled = true;
|
||||
};
|
||||
|
||||
Console.WriteLine("Ctrl-C to exit.");
|
||||
while (!cancelled)
|
||||
{
|
||||
Message<string, string> msg;
|
||||
if (consumer.Consume(out msg, TimeSpan.FromSeconds(1)))
|
||||
{
|
||||
Console.WriteLine($"Topic: {msg.Topic} Partition: {msg.Partition} Offset: {msg.Offset} {msg.Value}");
|
||||
|
||||
try
|
||||
{
|
||||
Type eventType = Type.GetType(msg.Key);
|
||||
DomainEvent domainEvent = (DomainEvent)JsonConvert.DeserializeObject(msg.Value, eventType);
|
||||
mediator.Send(domainEvent).Wait();
|
||||
}
|
||||
catch (DomainException ex)
|
||||
{
|
||||
Console.WriteLine(ex.BusinessMessage);
|
||||
}
|
||||
catch (TransactionConflictException ex)
|
||||
{
|
||||
Console.WriteLine(ex.DomainEvent.ToString());
|
||||
}
|
||||
catch (JamboException ex)
|
||||
{
|
||||
Console.WriteLine(ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -28,7 +28,8 @@
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Jambo.Consumer.Application\Jambo.Consumer.Application.csproj" />
|
||||
<ProjectReference Include="..\Jambo.Domain\Jambo.Domain.csproj" />
|
||||
<ProjectReference Include="..\..\Shared\Jambo.Domain\Jambo.Domain.csproj" />
|
||||
<ProjectReference Include="..\Jambo.Consumer.Infrastructure\Jambo.Consumer.Infrastructure.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,19 +1,13 @@
|
||||
namespace Jambo.Consumer.Infrastructure
|
||||
{
|
||||
using Autofac;
|
||||
using Autofac.Configuration;
|
||||
using Autofac.Extensions.DependencyInjection;
|
||||
using Jambo.Domain.ServiceBus;
|
||||
using MediatR;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.Loader;
|
||||
using Autofac.Configuration;
|
||||
using Jambo.Consumer.Application.DomainEventHandlers.Blogs;
|
||||
|
||||
public class Startup
|
||||
{
|
||||
@@ -29,10 +23,6 @@
|
||||
|
||||
public IServiceProvider ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
LoadInfrastructureAssemblies();
|
||||
|
||||
services.AddMediatR(typeof(BlogCreatedEventHandler).GetTypeInfo().Assembly);
|
||||
|
||||
ContainerBuilder builder = new ContainerBuilder();
|
||||
builder.Populate(services);
|
||||
builder.RegisterModule(new ConfigurationModule(Configuration));
|
||||
@@ -42,28 +32,12 @@
|
||||
return serviceProvider;
|
||||
}
|
||||
|
||||
private void LoadInfrastructureAssemblies()
|
||||
{
|
||||
string[] fileNames = Directory.EnumerateFiles(AppDomain.CurrentDomain.BaseDirectory, "*.dll", SearchOption.TopDirectoryOnly)
|
||||
.Where(filePath => Path.GetFileName(filePath).StartsWith("Jambo.Consumer.Infrastructure", StringComparison.OrdinalIgnoreCase))
|
||||
.ToArray();
|
||||
|
||||
foreach (string file in fileNames)
|
||||
AssemblyLoadContext.Default.LoadFromAssemblyPath(file);
|
||||
}
|
||||
|
||||
public void Run()
|
||||
{
|
||||
IMediator mediator = serviceProvider.GetService<IMediator>();
|
||||
ISubscriber subscriber = serviceProvider.GetService<ISubscriber>();
|
||||
|
||||
subscriber.Listen(mediator);
|
||||
|
||||
while (true)
|
||||
{
|
||||
Console.WriteLine($"{DateTime.Now.ToString()} Waiting for events..");
|
||||
Thread.Sleep(1000 * 60);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,11 @@
|
||||
"BrokerList": "10.0.75.1:9092",
|
||||
"Topic": "jambov32"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Jambo.Consumer.Infrastructure.Modules.MediatRModule",
|
||||
"properties": {
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -3,15 +3,15 @@ Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.26730.3
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Jambo.Domain", "Jambo.Domain\Jambo.Domain.csproj", "{ED9F252F-10E5-4A65-ADA0-122D61D655A4}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Jambo.Consumer.Application", "Jambo.Consumer.Application\Jambo.Consumer.Application.csproj", "{601F90B1-4BE4-462E-8595-AAAA49B80405}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Jambo.Domain.UnitTests", "Jambo.Domain.UnitTests\Jambo.Domain.UnitTests.csproj", "{B59AD81D-93F9-425F-8F87-DF13561BE424}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Jambo.Consumer.Infrastructure", "Jambo.Consumer.Infrastructure\Jambo.Consumer.Infrastructure.csproj", "{645C9138-DA59-48C8-A15E-D720874DD148}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jambo.Consumer.UI", "Jambo.Consumer.UI\Jambo.Consumer.UI.csproj", "{E86878A7-CB0F-46A7-B918-BED5C45BA4C5}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Jambo.Consumer.UI", "Jambo.Consumer.UI\Jambo.Consumer.UI.csproj", "{E86878A7-CB0F-46A7-B918-BED5C45BA4C5}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Jambo.Domain", "..\Shared\Jambo.Domain\Jambo.Domain.csproj", "{B0475864-44AC-4A6A-9970-CC5EEA01C2CF}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Jambo.Domain.UnitTests", "..\Shared\Jambo.Domain.UnitTests\Jambo.Domain.UnitTests.csproj", "{04732413-3F55-4194-B406-2F84666B1F6C}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
@@ -19,18 +19,10 @@ Global
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{ED9F252F-10E5-4A65-ADA0-122D61D655A4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{ED9F252F-10E5-4A65-ADA0-122D61D655A4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{ED9F252F-10E5-4A65-ADA0-122D61D655A4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{ED9F252F-10E5-4A65-ADA0-122D61D655A4}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{601F90B1-4BE4-462E-8595-AAAA49B80405}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{601F90B1-4BE4-462E-8595-AAAA49B80405}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{601F90B1-4BE4-462E-8595-AAAA49B80405}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{601F90B1-4BE4-462E-8595-AAAA49B80405}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{B59AD81D-93F9-425F-8F87-DF13561BE424}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{B59AD81D-93F9-425F-8F87-DF13561BE424}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{B59AD81D-93F9-425F-8F87-DF13561BE424}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{B59AD81D-93F9-425F-8F87-DF13561BE424}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{645C9138-DA59-48C8-A15E-D720874DD148}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{645C9138-DA59-48C8-A15E-D720874DD148}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{645C9138-DA59-48C8-A15E-D720874DD148}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
@@ -39,6 +31,14 @@ Global
|
||||
{E86878A7-CB0F-46A7-B918-BED5C45BA4C5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E86878A7-CB0F-46A7-B918-BED5C45BA4C5}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E86878A7-CB0F-46A7-B918-BED5C45BA4C5}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{B0475864-44AC-4A6A-9970-CC5EEA01C2CF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{B0475864-44AC-4A6A-9970-CC5EEA01C2CF}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{B0475864-44AC-4A6A-9970-CC5EEA01C2CF}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{B0475864-44AC-4A6A-9970-CC5EEA01C2CF}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{04732413-3F55-4194-B406-2F84666B1F6C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{04732413-3F55-4194-B406-2F84666B1F6C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{04732413-3F55-4194-B406-2F84666B1F6C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{04732413-3F55-4194-B406-2F84666B1F6C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@@ -1,26 +0,0 @@
|
||||
using MediatR;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Text;
|
||||
|
||||
namespace Jambo.Auth.Application.Commands
|
||||
{
|
||||
[DataContract]
|
||||
public class LoginCommand : IRequest
|
||||
{
|
||||
[Required]
|
||||
[DataMember]
|
||||
public Guid UserId { get; private set; }
|
||||
|
||||
[Required]
|
||||
[DataMember]
|
||||
public Guid SchoolId { get; private set; }
|
||||
|
||||
public LoginCommand()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="1.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Jambo.Auth.Application\Jambo.Auth.Application.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,24 +0,0 @@
|
||||
namespace Jambo.Consumer.Infrastructure
|
||||
{
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System.IO;
|
||||
|
||||
class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
var builder = new ConfigurationBuilder()
|
||||
.SetBasePath(Directory.GetCurrentDirectory())
|
||||
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
|
||||
.AddEnvironmentVariables();
|
||||
|
||||
IConfigurationRoot configuration = builder.Build();
|
||||
IServiceCollection serviceCollection = new ServiceCollection();
|
||||
|
||||
Startup startup = new Startup(configuration);
|
||||
startup.ConfigureServices(serviceCollection);
|
||||
startup.Run();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
using Confluent.Kafka;
|
||||
using Confluent.Kafka.Serialization;
|
||||
using Jambo.Domain.Exceptions;
|
||||
using Jambo.Domain.Model;
|
||||
using Jambo.Domain.ServiceBus;
|
||||
using MediatR;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Jambo.Consumer.Infrastructure.ServiceBus
|
||||
{
|
||||
public class Bus : ISubscriber
|
||||
{
|
||||
public readonly string brokerList;
|
||||
public readonly string topic;
|
||||
|
||||
private readonly Consumer<string, string> consumer;
|
||||
|
||||
public Bus(string brokerList, string topic)
|
||||
{
|
||||
this.brokerList = brokerList;
|
||||
this.topic = topic;
|
||||
|
||||
consumer = new Consumer<string, string>(
|
||||
new Dictionary<string, object>()
|
||||
{
|
||||
{ "group.id", "consumer" },
|
||||
{ "bootstrap.servers", brokerList }
|
||||
}, new StringDeserializer(Encoding.UTF8), new StringDeserializer(Encoding.UTF8));
|
||||
}
|
||||
|
||||
public void Listen(IMediator mediator)
|
||||
{
|
||||
Task.Run(() =>
|
||||
{
|
||||
consumer.Assign(new List<TopicPartitionOffset>
|
||||
{
|
||||
new TopicPartitionOffset(topic, 0, 0)
|
||||
});
|
||||
|
||||
while (true)
|
||||
{
|
||||
Message<string, string> msg;
|
||||
|
||||
if (consumer.Consume(out msg, TimeSpan.FromSeconds(1)))
|
||||
{
|
||||
try
|
||||
{
|
||||
Type eventType = Type.GetType(msg.Key);
|
||||
DomainEvent domainEvent = (DomainEvent)JsonConvert.DeserializeObject(msg.Value, eventType);
|
||||
|
||||
Console.WriteLine($"CorrelationId: {domainEvent.Header.CorrelationId}");
|
||||
Console.WriteLine($"UserName: {domainEvent.Header.UserName}");
|
||||
Console.WriteLine($"CreatedDate: {domainEvent.CreatedDate}");
|
||||
Console.WriteLine($"Type: {msg.Key}");
|
||||
Console.WriteLine($"AggregateRootId: {domainEvent.AggregateRootId}");
|
||||
Console.WriteLine($"Version: {domainEvent.Version}");
|
||||
Console.WriteLine($"Raw: {msg.Value}");
|
||||
Console.WriteLine();
|
||||
|
||||
mediator.Send(domainEvent).Wait();
|
||||
}
|
||||
catch (DomainException ex)
|
||||
{
|
||||
Console.WriteLine(ex.BusinessMessage);
|
||||
}
|
||||
catch (TransactionConflictException ex)
|
||||
{
|
||||
Console.WriteLine(ex.AggregateRoot.ToString() + ex.DomainEvent.ToString());
|
||||
}
|
||||
catch (JamboException ex)
|
||||
{
|
||||
Console.WriteLine(ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
consumer.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
using Autofac;
|
||||
using Autofac.Extensions.DependencyInjection;
|
||||
using Jambo.Consumer.Application.DomainEventHandlers.Blogs;
|
||||
using Jambo.Consumer.Infrastructure.Modules;
|
||||
using Jambo.Domain.ServiceBus;
|
||||
using MediatR;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
|
||||
namespace Jambo.Consumer.Infrastructure
|
||||
{
|
||||
public class Startup
|
||||
{
|
||||
public Startup(IConfiguration configuration)
|
||||
{
|
||||
Configuration = configuration;
|
||||
}
|
||||
|
||||
public IConfiguration Configuration { get; }
|
||||
|
||||
IServiceProvider serviceProvider;
|
||||
|
||||
public IServiceProvider ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
services.AddMediatR(typeof(BlogCreatedEventHandler).GetTypeInfo().Assembly);
|
||||
|
||||
ContainerBuilder container = new ContainerBuilder();
|
||||
container.Populate(services);
|
||||
|
||||
container.RegisterModule(new ApplicationModule(
|
||||
Configuration.GetSection("MongoDB").GetValue<string>("ConnectionString"),
|
||||
Configuration.GetSection("MongoDB").GetValue<string>("Database")));
|
||||
|
||||
container.RegisterModule(new BusModule(
|
||||
Configuration.GetSection("ServiceBus").GetValue<string>("ConnectionString"),
|
||||
Configuration.GetSection("ServiceBus").GetValue<string>("Topic")));
|
||||
|
||||
serviceProvider = new AutofacServiceProvider(container.Build());
|
||||
|
||||
return serviceProvider;
|
||||
}
|
||||
|
||||
public void Run()
|
||||
{
|
||||
IMediator mediator = serviceProvider.GetService<IMediator>();
|
||||
ISubscriber subscriber = serviceProvider.GetService<ISubscriber>();
|
||||
|
||||
subscriber.Listen(mediator);
|
||||
|
||||
while (true)
|
||||
{
|
||||
Thread.Sleep(1000 * 60);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
using System;
|
||||
using Xunit;
|
||||
|
||||
namespace Jambo.Domain.UnitTests
|
||||
{
|
||||
public class UnitTest1
|
||||
{
|
||||
[Fact]
|
||||
public void Test1()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Jambo.Domain.Model.Posts.Events
|
||||
{
|
||||
public class PostCreatedDomainEvent : DomainEvent
|
||||
{
|
||||
public Guid BlogId { get; private set; }
|
||||
public int BlogVersion { get; private set; }
|
||||
|
||||
public PostCreatedDomainEvent(Guid aggregateRootId, int version,
|
||||
DateTime createdDate, Header header, Guid blogId, int blogVersion)
|
||||
: base(aggregateRootId, version, createdDate, header)
|
||||
{
|
||||
BlogId = blogId;
|
||||
BlogVersion = blogVersion;
|
||||
}
|
||||
|
||||
public static PostCreatedDomainEvent Create(AggregateRoot aggregateRoot,
|
||||
Guid blogId, int blogVersion)
|
||||
{
|
||||
if (aggregateRoot == null)
|
||||
throw new ArgumentNullException("aggregateRoot");
|
||||
|
||||
PostCreatedDomainEvent domainEvent = new PostCreatedDomainEvent(
|
||||
aggregateRoot.Id, aggregateRoot.Version, DateTime.UtcNow, null, blogId, blogVersion);
|
||||
|
||||
return domainEvent;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
using MediatR;
|
||||
using System;
|
||||
|
||||
namespace Jambo.Domain.ServiceBus
|
||||
{
|
||||
public interface ISubscriber : IDisposable
|
||||
{
|
||||
void Listen(IMediator mediator);
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Jambo.Domain\Jambo.Domain.csproj" />
|
||||
<ProjectReference Include="..\..\Shared\Jambo.Domain\Jambo.Domain.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -19,7 +19,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Jambo.Domain\Jambo.Domain.csproj" />
|
||||
<ProjectReference Include="..\..\Shared\Jambo.Domain\Jambo.Domain.csproj" />
|
||||
<ProjectReference Include="..\Jambo.Producer.Application\Jambo.Producer.Application.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||