mirror of https://github.com/abpframework/abp.git
Browse Source
Introduce a new DistEvents test/demo suite and supporting infra. - Add AspNetCoreDapr and AzureEmulator sample apps (modules, programs, controllers, event handlers, appsettings). - Add persistence projects for EntityFrameworkCore and MongoDB, including EF Core migrations and updated model snapshot. - Update EfCoreRabbitMq project to support selectable DB provider (DistDemoDbProvider) and refactor RabbitMQ/Dapr event-bus configuration. - Add shared demo utilities (scenario runner/profile/hosted service), Dapr pubsub component, docker-compose and Service Bus emulator config. - Add comprehensive Visual Studio/.NET .gitignore and tweak .claude local permissions to allow "Bash(git show:*)".pull/25023/head
53 changed files with 2073 additions and 346 deletions
@ -0,0 +1,398 @@ |
|||
## Ignore Visual Studio temporary files, build results, and |
|||
## files generated by popular Visual Studio add-ons. |
|||
## |
|||
## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore |
|||
|
|||
# User-specific files |
|||
*.rsuser |
|||
*.suo |
|||
*.user |
|||
*.userosscache |
|||
*.sln.docstates |
|||
|
|||
# User-specific files (MonoDevelop/Xamarin Studio) |
|||
*.userprefs |
|||
|
|||
# Mono auto generated files |
|||
mono_crash.* |
|||
|
|||
# Build results |
|||
[Dd]ebug/ |
|||
[Dd]ebugPublic/ |
|||
[Rr]elease/ |
|||
[Rr]eleases/ |
|||
x64/ |
|||
x86/ |
|||
[Ww][Ii][Nn]32/ |
|||
[Aa][Rr][Mm]/ |
|||
[Aa][Rr][Mm]64/ |
|||
bld/ |
|||
[Bb]in/ |
|||
[Oo]bj/ |
|||
[Ll]og/ |
|||
[Ll]ogs/ |
|||
|
|||
# Visual Studio 2015/2017 cache/options directory |
|||
.vs/ |
|||
# Uncomment if you have tasks that create the project's static files in wwwroot |
|||
#wwwroot/ |
|||
|
|||
# Visual Studio 2017 auto generated files |
|||
Generated\ Files/ |
|||
|
|||
# MSTest test Results |
|||
[Tt]est[Rr]esult*/ |
|||
[Bb]uild[Ll]og.* |
|||
|
|||
# NUnit |
|||
*.VisualState.xml |
|||
TestResult.xml |
|||
nunit-*.xml |
|||
|
|||
# Build Results of an ATL Project |
|||
[Dd]ebugPS/ |
|||
[Rr]eleasePS/ |
|||
dlldata.c |
|||
|
|||
# Benchmark Results |
|||
BenchmarkDotNet.Artifacts/ |
|||
|
|||
# .NET Core |
|||
project.lock.json |
|||
project.fragment.lock.json |
|||
artifacts/ |
|||
|
|||
# ASP.NET Scaffolding |
|||
ScaffoldingReadMe.txt |
|||
|
|||
# StyleCop |
|||
StyleCopReport.xml |
|||
|
|||
# Files built by Visual Studio |
|||
*_i.c |
|||
*_p.c |
|||
*_h.h |
|||
*.ilk |
|||
*.meta |
|||
*.obj |
|||
*.iobj |
|||
*.pch |
|||
*.pdb |
|||
*.ipdb |
|||
*.pgc |
|||
*.pgd |
|||
*.rsp |
|||
*.sbr |
|||
*.tlb |
|||
*.tli |
|||
*.tlh |
|||
*.tmp |
|||
*.tmp_proj |
|||
*_wpftmp.csproj |
|||
*.log |
|||
*.tlog |
|||
*.vspscc |
|||
*.vssscc |
|||
.builds |
|||
*.pidb |
|||
*.svclog |
|||
*.scc |
|||
|
|||
# Chutzpah Test files |
|||
_Chutzpah* |
|||
|
|||
# Visual C++ cache files |
|||
ipch/ |
|||
*.aps |
|||
*.ncb |
|||
*.opendb |
|||
*.opensdf |
|||
*.sdf |
|||
*.cachefile |
|||
*.VC.db |
|||
*.VC.VC.opendb |
|||
|
|||
# Visual Studio profiler |
|||
*.psess |
|||
*.vsp |
|||
*.vspx |
|||
*.sap |
|||
|
|||
# Visual Studio Trace Files |
|||
*.e2e |
|||
|
|||
# TFS 2012 Local Workspace |
|||
$tf/ |
|||
|
|||
# Guidance Automation Toolkit |
|||
*.gpState |
|||
|
|||
# ReSharper is a .NET coding add-in |
|||
_ReSharper*/ |
|||
*.[Rr]e[Ss]harper |
|||
*.DotSettings.user |
|||
|
|||
# TeamCity is a build add-in |
|||
_TeamCity* |
|||
|
|||
# DotCover is a Code Coverage Tool |
|||
*.dotCover |
|||
|
|||
# AxoCover is a Code Coverage Tool |
|||
.axoCover/* |
|||
!.axoCover/settings.json |
|||
|
|||
# Coverlet is a free, cross platform Code Coverage Tool |
|||
coverage*.json |
|||
coverage*.xml |
|||
coverage*.info |
|||
|
|||
# Visual Studio code coverage results |
|||
*.coverage |
|||
*.coveragexml |
|||
|
|||
# NCrunch |
|||
_NCrunch_* |
|||
.*crunch*.local.xml |
|||
nCrunchTemp_* |
|||
|
|||
# MightyMoose |
|||
*.mm.* |
|||
AutoTest.Net/ |
|||
|
|||
# Web workbench (sass) |
|||
.sass-cache/ |
|||
|
|||
# Installshield output folder |
|||
[Ee]xpress/ |
|||
|
|||
# DocProject is a documentation generator add-in |
|||
DocProject/buildhelp/ |
|||
DocProject/Help/*.HxT |
|||
DocProject/Help/*.HxC |
|||
DocProject/Help/*.hhc |
|||
DocProject/Help/*.hhk |
|||
DocProject/Help/*.hhp |
|||
DocProject/Help/Html2 |
|||
DocProject/Help/html |
|||
|
|||
# Click-Once directory |
|||
publish/ |
|||
|
|||
# Publish Web Output |
|||
*.[Pp]ublish.xml |
|||
*.azurePubxml |
|||
# Note: Comment the next line if you want to checkin your web deploy settings, |
|||
# but database connection strings (with potential passwords) will be unencrypted |
|||
*.pubxml |
|||
*.publishproj |
|||
|
|||
# Microsoft Azure Web App publish settings. Comment the next line if you want to |
|||
# checkin your Azure Web App publish settings, but sensitive information contained |
|||
# in these scripts will be unencrypted |
|||
PublishScripts/ |
|||
|
|||
# NuGet Packages |
|||
*.nupkg |
|||
# NuGet Symbol Packages |
|||
*.snupkg |
|||
# The packages folder can be ignored because of Package Restore |
|||
**/[Pp]ackages/* |
|||
# except build/, which is used as an MSBuild target. |
|||
!**/[Pp]ackages/build/ |
|||
# Uncomment if necessary however generally it will be regenerated when needed |
|||
#!**/[Pp]ackages/repositories.config |
|||
# NuGet v3's project.json files produces more ignorable files |
|||
*.nuget.props |
|||
*.nuget.targets |
|||
|
|||
# Microsoft Azure Build Output |
|||
csx/ |
|||
*.build.csdef |
|||
|
|||
# Microsoft Azure Emulator |
|||
ecf/ |
|||
rcf/ |
|||
|
|||
# Windows Store app package directories and files |
|||
AppPackages/ |
|||
BundleArtifacts/ |
|||
Package.StoreAssociation.xml |
|||
_pkginfo.txt |
|||
*.appx |
|||
*.appxbundle |
|||
*.appxupload |
|||
|
|||
# Visual Studio cache files |
|||
# files ending in .cache can be ignored |
|||
*.[Cc]ache |
|||
# but keep track of directories ending in .cache |
|||
!?*.[Cc]ache/ |
|||
|
|||
# Others |
|||
ClientBin/ |
|||
~$* |
|||
*~ |
|||
*.dbmdl |
|||
*.dbproj.schemaview |
|||
*.jfm |
|||
*.pfx |
|||
*.publishsettings |
|||
orleans.codegen.cs |
|||
|
|||
# Including strong name files can present a security risk |
|||
# (https://github.com/github/gitignore/pull/2483#issue-259490424) |
|||
#*.snk |
|||
|
|||
# Since there are multiple workflows, uncomment next line to ignore bower_components |
|||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) |
|||
#bower_components/ |
|||
|
|||
# RIA/Silverlight projects |
|||
Generated_Code/ |
|||
|
|||
# Backup & report files from converting an old project file |
|||
# to a newer Visual Studio version. Backup files are not needed, |
|||
# because we have git ;-) |
|||
_UpgradeReport_Files/ |
|||
Backup*/ |
|||
UpgradeLog*.XML |
|||
UpgradeLog*.htm |
|||
ServiceFabricBackup/ |
|||
*.rptproj.bak |
|||
|
|||
# SQL Server files |
|||
*.mdf |
|||
*.ldf |
|||
*.ndf |
|||
|
|||
# Business Intelligence projects |
|||
*.rdl.data |
|||
*.bim.layout |
|||
*.bim_*.settings |
|||
*.rptproj.rsuser |
|||
*- [Bb]ackup.rdl |
|||
*- [Bb]ackup ([0-9]).rdl |
|||
*- [Bb]ackup ([0-9][0-9]).rdl |
|||
|
|||
# Microsoft Fakes |
|||
FakesAssemblies/ |
|||
|
|||
# GhostDoc plugin setting file |
|||
*.GhostDoc.xml |
|||
|
|||
# Node.js Tools for Visual Studio |
|||
.ntvs_analysis.dat |
|||
node_modules/ |
|||
|
|||
# Visual Studio 6 build log |
|||
*.plg |
|||
|
|||
# Visual Studio 6 workspace options file |
|||
*.opt |
|||
|
|||
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) |
|||
*.vbw |
|||
|
|||
# Visual Studio 6 auto-generated project file (contains which files were open etc.) |
|||
*.vbp |
|||
|
|||
# Visual Studio 6 workspace and project file (working project files containing files to include in project) |
|||
*.dsw |
|||
*.dsp |
|||
|
|||
# Visual Studio 6 technical files |
|||
*.ncb |
|||
*.aps |
|||
|
|||
# Visual Studio LightSwitch build output |
|||
**/*.HTMLClient/GeneratedArtifacts |
|||
**/*.DesktopClient/GeneratedArtifacts |
|||
**/*.DesktopClient/ModelManifest.xml |
|||
**/*.Server/GeneratedArtifacts |
|||
**/*.Server/ModelManifest.xml |
|||
_Pvt_Extensions |
|||
|
|||
# Paket dependency manager |
|||
.paket/paket.exe |
|||
paket-files/ |
|||
|
|||
# FAKE - F# Make |
|||
.fake/ |
|||
|
|||
# CodeRush personal settings |
|||
.cr/personal |
|||
|
|||
# Python Tools for Visual Studio (PTVS) |
|||
__pycache__/ |
|||
*.pyc |
|||
|
|||
# Cake - Uncomment if you are using it |
|||
# tools/** |
|||
# !tools/packages.config |
|||
|
|||
# Tabs Studio |
|||
*.tss |
|||
|
|||
# Telerik's JustMock configuration file |
|||
*.jmconfig |
|||
|
|||
# BizTalk build output |
|||
*.btp.cs |
|||
*.btm.cs |
|||
*.odx.cs |
|||
*.xsd.cs |
|||
|
|||
# OpenCover UI analysis results |
|||
OpenCover/ |
|||
|
|||
# Azure Stream Analytics local run output |
|||
ASALocalRun/ |
|||
|
|||
# MSBuild Binary and Structured Log |
|||
*.binlog |
|||
|
|||
# NVidia Nsight GPU debugger configuration file |
|||
*.nvuser |
|||
|
|||
# MFractors (Xamarin productivity tool) working folder |
|||
.mfractor/ |
|||
|
|||
# Local History for Visual Studio |
|||
.localhistory/ |
|||
|
|||
# Visual Studio History (VSHistory) files |
|||
.vshistory/ |
|||
|
|||
# BeatPulse healthcheck temp database |
|||
healthchecksdb |
|||
|
|||
# Backup folder for Package Reference Convert tool in Visual Studio 2017 |
|||
MigrationBackup/ |
|||
|
|||
# Ionide (cross platform F# VS Code tools) working folder |
|||
.ionide/ |
|||
|
|||
# Fody - auto-generated XML schema |
|||
FodyWeavers.xsd |
|||
|
|||
# VS Code files for those working on multiple tools |
|||
.vscode/* |
|||
!.vscode/settings.json |
|||
!.vscode/tasks.json |
|||
!.vscode/launch.json |
|||
!.vscode/extensions.json |
|||
*.code-workspace |
|||
|
|||
# Local History for Visual Studio Code |
|||
.history/ |
|||
|
|||
# Windows Installer files from build outputs |
|||
*.cab |
|||
*.msi |
|||
*.msix |
|||
*.msm |
|||
*.msp |
|||
|
|||
# JetBrains Rider |
|||
*.sln.iml |
|||
@ -0,0 +1,39 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk.Web"> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>net10.0</TargetFramework> |
|||
<Nullable>enable</Nullable> |
|||
<ImplicitUsings>enable</ImplicitUsings> |
|||
<RootNamespace>DistDemoApp</RootNamespace> |
|||
<DistDemoDbProvider>MongoDb</DistDemoDbProvider> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<ProjectReference Include="..\..\..\framework\src\Volo.Abp.Autofac\Volo.Abp.Autofac.csproj" /> |
|||
<ProjectReference Include="..\..\..\framework\src\Volo.Abp.AspNetCore.Mvc.Dapr.EventBus\Volo.Abp.AspNetCore.Mvc.Dapr.EventBus.csproj" /> |
|||
<ProjectReference Include="..\DistDemoApp.Shared\DistDemoApp.Shared.csproj" /> |
|||
</ItemGroup> |
|||
|
|||
<ItemGroup Condition="'$(DistDemoDbProvider)' == 'MongoDb'"> |
|||
<ProjectReference Include="..\DistDemoApp.Persistence.MongoDb\DistDemoApp.Persistence.MongoDb.csproj" /> |
|||
</ItemGroup> |
|||
|
|||
<ItemGroup Condition="'$(DistDemoDbProvider)' == 'EntityFrameworkCore'"> |
|||
<ProjectReference Include="..\DistDemoApp.Persistence.EntityFrameworkCore\DistDemoApp.Persistence.EntityFrameworkCore.csproj" /> |
|||
</ItemGroup> |
|||
|
|||
<PropertyGroup Condition="'$(DistDemoDbProvider)' == 'MongoDb'"> |
|||
<DefineConstants>$(DefineConstants);DISTDEMO_USE_MONGODB</DefineConstants> |
|||
</PropertyGroup> |
|||
|
|||
<PropertyGroup Condition="'$(DistDemoDbProvider)' == 'EntityFrameworkCore'"> |
|||
<DefineConstants>$(DefineConstants);DISTDEMO_USE_EFCORE</DefineConstants> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<None Update="appsettings.json"> |
|||
<CopyToOutputDirectory>Always</CopyToOutputDirectory> |
|||
</None> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
@ -0,0 +1,67 @@ |
|||
using Dapr; |
|||
using Volo.Abp; |
|||
using Volo.Abp.AspNetCore.Mvc.Dapr.EventBus; |
|||
using Volo.Abp.Autofac; |
|||
using Volo.Abp.Dapr; |
|||
using Volo.Abp.EventBus.Dapr; |
|||
using Volo.Abp.Modularity; |
|||
|
|||
namespace DistDemoApp; |
|||
|
|||
#if DISTDEMO_USE_MONGODB
|
|||
[DependsOn( |
|||
typeof(DistDemoAppMongoDbInfrastructureModule), |
|||
typeof(AbpAspNetCoreMvcDaprEventBusModule), |
|||
typeof(DistDemoAppSharedModule), |
|||
typeof(AbpAutofacModule) |
|||
)] |
|||
#else
|
|||
[DependsOn( |
|||
typeof(DistDemoAppEntityFrameworkCoreInfrastructureModule), |
|||
typeof(AbpAspNetCoreMvcDaprEventBusModule), |
|||
typeof(DistDemoAppSharedModule), |
|||
typeof(AbpAutofacModule) |
|||
)] |
|||
#endif
|
|||
public class DistDemoAppAspNetCoreDaprModule : AbpModule |
|||
{ |
|||
public override void ConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
#if DISTDEMO_USE_MONGODB
|
|||
context.ConfigureDistDemoMongoInfrastructure(); |
|||
#else
|
|||
context.ConfigureDistDemoEntityFrameworkInfrastructure(); |
|||
#endif
|
|||
|
|||
Configure<AbpDaprOptions>(options => |
|||
{ |
|||
options.HttpEndpoint = "http://localhost:3500"; |
|||
}); |
|||
|
|||
Configure<AbpDaprEventBusOptions>(options => |
|||
{ |
|||
options.PubSubName = "pubsub"; |
|||
}); |
|||
} |
|||
|
|||
public override void OnApplicationInitialization(ApplicationInitializationContext context) |
|||
{ |
|||
var app = context.GetApplicationBuilder(); |
|||
var env = context.GetEnvironment(); |
|||
|
|||
if (env.IsDevelopment()) |
|||
{ |
|||
app.UseExceptionHandler("/Error"); |
|||
} |
|||
|
|||
app.UseHttpsRedirection(); |
|||
app.UseStaticFiles(); |
|||
app.UseRouting(); |
|||
app.UseCloudEvents(); |
|||
app.UseConfiguredEndpoints(endpoints => |
|||
{ |
|||
endpoints.MapControllers(); |
|||
endpoints.MapSubscribeHandler(); |
|||
}); |
|||
} |
|||
} |
|||
@ -0,0 +1,12 @@ |
|||
using DistDemoApp; |
|||
using Dapr; |
|||
using Volo.Abp; |
|||
|
|||
var builder = WebApplication.CreateBuilder(args); |
|||
builder.Host.UseAutofac(); |
|||
|
|||
await builder.AddApplicationAsync<DistDemoAppAspNetCoreDaprModule>(); |
|||
|
|||
var app = builder.Build(); |
|||
await app.InitializeApplicationAsync(); |
|||
await app.RunAsync("http://localhost:8090"); |
|||
@ -0,0 +1,23 @@ |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Volo.Abp.AspNetCore.Mvc; |
|||
|
|||
namespace DistDemoApp; |
|||
|
|||
[ApiController] |
|||
[Route("api/dist-demo/dapr")] |
|||
public class ProviderScenarioController : AbpController |
|||
{ |
|||
private readonly IDistEventScenarioRunner _scenarioRunner; |
|||
|
|||
public ProviderScenarioController(IDistEventScenarioRunner scenarioRunner) |
|||
{ |
|||
_scenarioRunner = scenarioRunner; |
|||
} |
|||
|
|||
[HttpGet] |
|||
public async Task<IActionResult> RunAsync() |
|||
{ |
|||
await _scenarioRunner.RunAsync(DistEventScenarioProfile.DaprWeb()); |
|||
return Ok(new { Status = "ScenarioCompleted", Profile = "dapr-web" }); |
|||
} |
|||
} |
|||
@ -0,0 +1,17 @@ |
|||
using System; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.EventBus.Distributed; |
|||
|
|||
namespace DistDemoApp; |
|||
|
|||
public class ProviderScenarioEventHandler : |
|||
IDistributedEventHandler<ProviderScenarioEvent>, |
|||
ITransientDependency |
|||
{ |
|||
public Task HandleEventAsync(ProviderScenarioEvent eventData) |
|||
{ |
|||
Console.WriteLine($"Dapr ASP.NET Core handler received ProviderScenarioEvent: {eventData.Value}"); |
|||
return Task.CompletedTask; |
|||
} |
|||
} |
|||
@ -0,0 +1,14 @@ |
|||
{ |
|||
"ConnectionStrings": { |
|||
"Default": "mongodb://localhost:27017/DistEventsDemo?retryWrites=false" |
|||
}, |
|||
"Dapr": { |
|||
"HttpEndpoint": "http://localhost:3500" |
|||
}, |
|||
"DaprEventBus": { |
|||
"PubSubName": "pubsub" |
|||
}, |
|||
"Redis": { |
|||
"Configuration": "127.0.0.1" |
|||
} |
|||
} |
|||
@ -0,0 +1,37 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<PropertyGroup> |
|||
<OutputType>Exe</OutputType> |
|||
<TargetFramework>net10.0</TargetFramework> |
|||
<RootNamespace>DistDemoApp</RootNamespace> |
|||
<DistDemoDbProvider>MongoDb</DistDemoDbProvider> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<ProjectReference Include="..\..\..\framework\src\Volo.Abp.EventBus.Azure\Volo.Abp.EventBus.Azure.csproj" /> |
|||
<ProjectReference Include="..\DistDemoApp.Shared\DistDemoApp.Shared.csproj" /> |
|||
</ItemGroup> |
|||
|
|||
<ItemGroup Condition="'$(DistDemoDbProvider)' == 'MongoDb'"> |
|||
<ProjectReference Include="..\DistDemoApp.Persistence.MongoDb\DistDemoApp.Persistence.MongoDb.csproj" /> |
|||
</ItemGroup> |
|||
|
|||
<ItemGroup Condition="'$(DistDemoDbProvider)' == 'EntityFrameworkCore'"> |
|||
<ProjectReference Include="..\DistDemoApp.Persistence.EntityFrameworkCore\DistDemoApp.Persistence.EntityFrameworkCore.csproj" /> |
|||
</ItemGroup> |
|||
|
|||
<PropertyGroup Condition="'$(DistDemoDbProvider)' == 'MongoDb'"> |
|||
<DefineConstants>$(DefineConstants);DISTDEMO_USE_MONGODB</DefineConstants> |
|||
</PropertyGroup> |
|||
|
|||
<PropertyGroup Condition="'$(DistDemoDbProvider)' == 'EntityFrameworkCore'"> |
|||
<DefineConstants>$(DefineConstants);DISTDEMO_USE_EFCORE</DefineConstants> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<None Update="appsettings.json"> |
|||
<CopyToOutputDirectory>Always</CopyToOutputDirectory> |
|||
</None> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
@ -0,0 +1,51 @@ |
|||
using Azure.Messaging.ServiceBus; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Volo.Abp.EventBus.Azure; |
|||
using Volo.Abp.Modularity; |
|||
using Volo.Abp.AzureServiceBus; |
|||
|
|||
namespace DistDemoApp; |
|||
|
|||
#if DISTDEMO_USE_MONGODB
|
|||
[DependsOn( |
|||
typeof(DistDemoAppMongoDbInfrastructureModule), |
|||
typeof(AbpEventBusAzureModule), |
|||
typeof(DistDemoAppSharedModule) |
|||
)] |
|||
#else
|
|||
[DependsOn( |
|||
typeof(DistDemoAppEntityFrameworkCoreInfrastructureModule), |
|||
typeof(AbpEventBusAzureModule), |
|||
typeof(DistDemoAppSharedModule) |
|||
)] |
|||
#endif
|
|||
public class DistDemoAppAzureEmulatorModule : AbpModule |
|||
{ |
|||
public override void ConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
context.Services.AddSingleton<IPublisherPool, EmulatorPublisherPool>(); |
|||
context.Services.AddSingleton<IProcessorPool, EmulatorProcessorPool>(); |
|||
#if DISTDEMO_USE_MONGODB
|
|||
context.ConfigureDistDemoMongoInfrastructure(); |
|||
#else
|
|||
context.ConfigureDistDemoEntityFrameworkInfrastructure(); |
|||
#endif
|
|||
|
|||
Configure<AbpAzureServiceBusOptions>(options => |
|||
{ |
|||
options.Connections.Default.ConnectionString = |
|||
"Endpoint=sb://localhost:5673;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=SAS_KEY_VALUE;UseDevelopmentEmulator=true;"; |
|||
options.Connections.Default.Processor = new ServiceBusProcessorOptions |
|||
{ |
|||
AutoCompleteMessages = false |
|||
}; |
|||
}); |
|||
|
|||
Configure<AbpAzureEventBusOptions>(options => |
|||
{ |
|||
options.ConnectionName = "Default"; |
|||
options.SubscriberName = "DistDemoAzureSubscriber"; |
|||
options.TopicName = "DistDemoAzureTopic"; |
|||
}); |
|||
} |
|||
} |
|||
@ -0,0 +1,79 @@ |
|||
using System; |
|||
using System.Collections.Concurrent; |
|||
using System.Linq; |
|||
using System.Threading.Tasks; |
|||
using Azure.Messaging.ServiceBus; |
|||
using Microsoft.Extensions.Logging; |
|||
using Microsoft.Extensions.Logging.Abstractions; |
|||
using Microsoft.Extensions.Options; |
|||
using Volo.Abp.AzureServiceBus; |
|||
using Volo.Abp.DependencyInjection; |
|||
|
|||
namespace DistDemoApp; |
|||
|
|||
public class EmulatorProcessorPool : IProcessorPool, ISingletonDependency |
|||
{ |
|||
public ILogger<EmulatorProcessorPool> Logger { get; set; } |
|||
|
|||
private bool _isDisposed; |
|||
private readonly AbpAzureServiceBusOptions _options; |
|||
private readonly IConnectionPool _connectionPool; |
|||
private readonly ConcurrentDictionary<string, Lazy<ServiceBusProcessor>> _processors; |
|||
|
|||
public EmulatorProcessorPool( |
|||
IOptions<AbpAzureServiceBusOptions> options, |
|||
IConnectionPool connectionPool) |
|||
{ |
|||
_options = options.Value; |
|||
_connectionPool = connectionPool; |
|||
_processors = new ConcurrentDictionary<string, Lazy<ServiceBusProcessor>>(); |
|||
Logger = NullLogger<EmulatorProcessorPool>.Instance; |
|||
} |
|||
|
|||
public Task<ServiceBusProcessor> GetAsync(string subscriptionName, string topicName, string connectionName) |
|||
{ |
|||
var processor = _processors.GetOrAdd( |
|||
$"{topicName}-{subscriptionName}", |
|||
new Lazy<ServiceBusProcessor>(() => |
|||
{ |
|||
var config = _options.Connections.GetOrDefault(connectionName); |
|||
var client = _connectionPool.GetClient(connectionName); |
|||
return client.CreateProcessor(topicName, subscriptionName, config.Processor); |
|||
}) |
|||
).Value; |
|||
|
|||
return Task.FromResult(processor); |
|||
} |
|||
|
|||
public async ValueTask DisposeAsync() |
|||
{ |
|||
if (_isDisposed) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
_isDisposed = true; |
|||
if (!_processors.Any()) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
foreach (var item in _processors.Values) |
|||
{ |
|||
var processor = item.Value; |
|||
if (processor.IsProcessing) |
|||
{ |
|||
await processor.StopProcessingAsync(); |
|||
} |
|||
|
|||
if (!processor.IsClosed) |
|||
{ |
|||
await processor.CloseAsync(); |
|||
} |
|||
|
|||
await processor.DisposeAsync(); |
|||
} |
|||
|
|||
_processors.Clear(); |
|||
} |
|||
} |
|||
@ -0,0 +1,64 @@ |
|||
using System; |
|||
using System.Collections.Concurrent; |
|||
using System.Linq; |
|||
using System.Threading.Tasks; |
|||
using Azure.Messaging.ServiceBus; |
|||
using Microsoft.Extensions.Logging; |
|||
using Microsoft.Extensions.Logging.Abstractions; |
|||
using Volo.Abp.AzureServiceBus; |
|||
using Volo.Abp.DependencyInjection; |
|||
|
|||
#nullable enable |
|||
namespace DistDemoApp; |
|||
|
|||
public class EmulatorPublisherPool : IPublisherPool, ISingletonDependency |
|||
{ |
|||
public ILogger<EmulatorPublisherPool> Logger { get; set; } |
|||
|
|||
private bool _isDisposed; |
|||
private readonly IConnectionPool _connectionPool; |
|||
private readonly ConcurrentDictionary<string, Lazy<ServiceBusSender>> _publishers; |
|||
|
|||
public EmulatorPublisherPool(IConnectionPool connectionPool) |
|||
{ |
|||
_connectionPool = connectionPool; |
|||
_publishers = new ConcurrentDictionary<string, Lazy<ServiceBusSender>>(); |
|||
Logger = NullLogger<EmulatorPublisherPool>.Instance; |
|||
} |
|||
|
|||
public Task<ServiceBusSender> GetAsync(string topicName, string? connectionName) |
|||
{ |
|||
var sender = _publishers.GetOrAdd( |
|||
topicName, |
|||
new Lazy<ServiceBusSender>(() => |
|||
{ |
|||
var client = _connectionPool.GetClient(connectionName); |
|||
return client.CreateSender(topicName); |
|||
}) |
|||
).Value; |
|||
|
|||
return Task.FromResult(sender); |
|||
} |
|||
|
|||
public async ValueTask DisposeAsync() |
|||
{ |
|||
if (_isDisposed) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
_isDisposed = true; |
|||
if (!_publishers.Any()) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
foreach (var publisher in _publishers.Values) |
|||
{ |
|||
await publisher.Value.CloseAsync(); |
|||
await publisher.Value.DisposeAsync(); |
|||
} |
|||
|
|||
_publishers.Clear(); |
|||
} |
|||
} |
|||
@ -0,0 +1,32 @@ |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Serilog; |
|||
using Volo.Abp; |
|||
using Volo.Abp.Threading; |
|||
|
|||
namespace DistDemoApp; |
|||
|
|||
public class Program |
|||
{ |
|||
public static void Main(string[] args) |
|||
{ |
|||
using var application = AbpApplicationFactory.Create<DistDemoAppAzureEmulatorModule>(options => |
|||
{ |
|||
options.UseAutofac(); |
|||
options.Services.AddSerilog((serviceProvider, configuration) => |
|||
{ |
|||
}); |
|||
options.Services.AddLogging(c => c.AddSerilog()); |
|||
}); |
|||
|
|||
Log.Information("Starting DistDemoApp.AzureEmulator."); |
|||
|
|||
application.Initialize(); |
|||
|
|||
AsyncHelper.RunSync(() => application |
|||
.ServiceProvider |
|||
.GetRequiredService<IDistEventScenarioRunner>() |
|||
.RunAsync(DistEventScenarioProfile.AzureEmulator())); |
|||
|
|||
application.Shutdown(); |
|||
} |
|||
} |
|||
@ -0,0 +1,22 @@ |
|||
{ |
|||
"ConnectionStrings": { |
|||
"Default": "mongodb://localhost:27017/DistEventsDemo?retryWrites=false" |
|||
}, |
|||
"Azure": { |
|||
"ServiceBus": { |
|||
"Connections": { |
|||
"Default": { |
|||
"ConnectionString": "Endpoint=sb://localhost:5673;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=SAS_KEY_VALUE;UseDevelopmentEmulator=true;" |
|||
} |
|||
} |
|||
}, |
|||
"EventBus": { |
|||
"ConnectionName": "Default", |
|||
"SubscriberName": "DistDemoAzureSubscriber", |
|||
"TopicName": "DistDemoAzureTopic" |
|||
} |
|||
}, |
|||
"Redis": { |
|||
"Configuration": "127.0.0.1" |
|||
} |
|||
} |
|||
@ -1,44 +1,59 @@ |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Volo.Abp.EntityFrameworkCore; |
|||
using Volo.Abp.EntityFrameworkCore.DistributedEvents; |
|||
using Volo.Abp.EntityFrameworkCore.SqlServer; |
|||
using Volo.Abp.EventBus.Distributed; |
|||
using Volo.Abp.EventBus.RabbitMq; |
|||
using Volo.Abp.Modularity; |
|||
using Volo.Abp.RabbitMQ; |
|||
|
|||
namespace DistDemoApp |
|||
{ |
|||
#if DISTDEMO_USE_MONGODB
|
|||
[DependsOn( |
|||
typeof(AbpEntityFrameworkCoreSqlServerModule), |
|||
typeof(DistDemoAppMongoDbInfrastructureModule), |
|||
typeof(AbpEventBusRabbitMqModule), |
|||
typeof(DistDemoAppSharedModule) |
|||
)] |
|||
#else
|
|||
[DependsOn( |
|||
typeof(DistDemoAppEntityFrameworkCoreInfrastructureModule), |
|||
typeof(AbpEventBusRabbitMqModule), |
|||
typeof(DistDemoAppSharedModule) |
|||
)] |
|||
#endif
|
|||
public class DistDemoAppEfCoreRabbitMqModule : AbpModule |
|||
{ |
|||
public override void ConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
context.Services.AddAbpDbContext<TodoDbContext>(options => |
|||
#if DISTDEMO_USE_MONGODB
|
|||
context.ConfigureDistDemoMongoInfrastructure(); |
|||
#else
|
|||
context.ConfigureDistDemoEntityFrameworkInfrastructure(); |
|||
#endif
|
|||
|
|||
Configure<AbpDistributedEventBusOptions>(options => |
|||
{ |
|||
options.AddDefaultRepositories(); |
|||
// options.Outboxes.Configure(config =>
|
|||
// {
|
|||
// config.UseDbContext<TodoDbContext>();
|
|||
// });
|
|||
//
|
|||
// options.Inboxes.Configure(config =>
|
|||
// {
|
|||
// config.UseDbContext<TodoDbContext>();
|
|||
// });
|
|||
}); |
|||
|
|||
Configure<AbpDbContextOptions>(options => |
|||
Configure<AbpRabbitMqOptions>(options => |
|||
{ |
|||
options.UseSqlServer(); |
|||
options.Connections.Default.HostName = "localhost"; |
|||
}); |
|||
|
|||
Configure<AbpDistributedEventBusOptions>(options => |
|||
|
|||
Configure<AbpRabbitMqEventBusOptions>(options => |
|||
{ |
|||
options.Outboxes.Configure(config => |
|||
{ |
|||
config.UseDbContext<TodoDbContext>(); |
|||
}); |
|||
|
|||
options.Inboxes.Configure(config => |
|||
{ |
|||
config.UseDbContext<TodoDbContext>(); |
|||
}); |
|||
options.ConnectionName = "Default"; |
|||
options.ClientName = "DistDemoApp"; |
|||
options.ExchangeName = "DistDemo"; |
|||
}); |
|||
|
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,182 @@ |
|||
// <auto-generated />
|
|||
using System; |
|||
using DistDemoApp; |
|||
using Microsoft.EntityFrameworkCore; |
|||
using Microsoft.EntityFrameworkCore.Infrastructure; |
|||
using Microsoft.EntityFrameworkCore.Metadata; |
|||
using Microsoft.EntityFrameworkCore.Migrations; |
|||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion; |
|||
using Volo.Abp.EntityFrameworkCore; |
|||
|
|||
#nullable disable |
|||
|
|||
namespace DistDemoApp.Migrations |
|||
{ |
|||
[DbContext(typeof(TodoDbContext))] |
|||
[Migration("20260304073807_Update-10.2")] |
|||
partial class Update102 |
|||
{ |
|||
/// <inheritdoc />
|
|||
protected override void BuildTargetModel(ModelBuilder modelBuilder) |
|||
{ |
|||
#pragma warning disable 612, 618
|
|||
modelBuilder |
|||
.HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.SqlServer) |
|||
.HasAnnotation("ProductVersion", "10.0.2") |
|||
.HasAnnotation("Relational:MaxIdentifierLength", 128); |
|||
|
|||
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); |
|||
|
|||
modelBuilder.Entity("DistDemoApp.TodoItem", b => |
|||
{ |
|||
b.Property<Guid>("Id") |
|||
.HasColumnType("uniqueidentifier"); |
|||
|
|||
b.Property<string>("ConcurrencyStamp") |
|||
.IsConcurrencyToken() |
|||
.IsRequired() |
|||
.HasMaxLength(40) |
|||
.HasColumnType("nvarchar(40)") |
|||
.HasColumnName("ConcurrencyStamp"); |
|||
|
|||
b.Property<DateTime>("CreationTime") |
|||
.HasColumnType("datetime2") |
|||
.HasColumnName("CreationTime"); |
|||
|
|||
b.Property<Guid?>("CreatorId") |
|||
.HasColumnType("uniqueidentifier") |
|||
.HasColumnName("CreatorId"); |
|||
|
|||
b.Property<string>("ExtraProperties") |
|||
.IsRequired() |
|||
.HasColumnType("nvarchar(max)") |
|||
.HasColumnName("ExtraProperties"); |
|||
|
|||
b.Property<string>("Text") |
|||
.IsRequired() |
|||
.HasMaxLength(128) |
|||
.HasColumnType("nvarchar(128)"); |
|||
|
|||
b.HasKey("Id"); |
|||
|
|||
b.ToTable("TodoItems"); |
|||
}); |
|||
|
|||
modelBuilder.Entity("DistDemoApp.TodoSummary", b => |
|||
{ |
|||
b.Property<int>("Id") |
|||
.ValueGeneratedOnAdd() |
|||
.HasColumnType("int"); |
|||
|
|||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); |
|||
|
|||
b.Property<string>("ConcurrencyStamp") |
|||
.IsConcurrencyToken() |
|||
.IsRequired() |
|||
.HasMaxLength(40) |
|||
.HasColumnType("nvarchar(40)") |
|||
.HasColumnName("ConcurrencyStamp"); |
|||
|
|||
b.Property<byte>("Day") |
|||
.HasColumnType("tinyint"); |
|||
|
|||
b.Property<string>("ExtraProperties") |
|||
.IsRequired() |
|||
.HasColumnType("nvarchar(max)") |
|||
.HasColumnName("ExtraProperties"); |
|||
|
|||
b.Property<byte>("Month") |
|||
.HasColumnType("tinyint"); |
|||
|
|||
b.Property<int>("TotalCount") |
|||
.HasColumnType("int"); |
|||
|
|||
b.Property<int>("Year") |
|||
.HasColumnType("int"); |
|||
|
|||
b.HasKey("Id"); |
|||
|
|||
b.ToTable("TodoSummaries"); |
|||
}); |
|||
|
|||
modelBuilder.Entity("Volo.Abp.EntityFrameworkCore.DistributedEvents.IncomingEventRecord", b => |
|||
{ |
|||
b.Property<Guid>("Id") |
|||
.HasColumnType("uniqueidentifier"); |
|||
|
|||
b.Property<DateTime>("CreationTime") |
|||
.HasColumnType("datetime2") |
|||
.HasColumnName("CreationTime"); |
|||
|
|||
b.Property<byte[]>("EventData") |
|||
.IsRequired() |
|||
.HasColumnType("varbinary(max)"); |
|||
|
|||
b.Property<string>("EventName") |
|||
.IsRequired() |
|||
.HasMaxLength(256) |
|||
.HasColumnType("nvarchar(256)"); |
|||
|
|||
b.Property<string>("ExtraProperties") |
|||
.IsRequired() |
|||
.HasColumnType("nvarchar(max)") |
|||
.HasColumnName("ExtraProperties"); |
|||
|
|||
b.Property<DateTime?>("HandledTime") |
|||
.HasColumnType("datetime2"); |
|||
|
|||
b.Property<string>("MessageId") |
|||
.IsRequired() |
|||
.HasColumnType("nvarchar(450)"); |
|||
|
|||
b.Property<DateTime?>("NextRetryTime") |
|||
.HasColumnType("datetime2"); |
|||
|
|||
b.Property<int>("RetryCount") |
|||
.HasColumnType("int"); |
|||
|
|||
b.Property<int>("Status") |
|||
.HasColumnType("int"); |
|||
|
|||
b.HasKey("Id"); |
|||
|
|||
b.HasIndex("MessageId"); |
|||
|
|||
b.HasIndex("Status", "CreationTime"); |
|||
|
|||
b.ToTable("AbpEventInbox", (string)null); |
|||
}); |
|||
|
|||
modelBuilder.Entity("Volo.Abp.EntityFrameworkCore.DistributedEvents.OutgoingEventRecord", b => |
|||
{ |
|||
b.Property<Guid>("Id") |
|||
.HasColumnType("uniqueidentifier"); |
|||
|
|||
b.Property<DateTime>("CreationTime") |
|||
.HasColumnType("datetime2") |
|||
.HasColumnName("CreationTime"); |
|||
|
|||
b.Property<byte[]>("EventData") |
|||
.IsRequired() |
|||
.HasColumnType("varbinary(max)"); |
|||
|
|||
b.Property<string>("EventName") |
|||
.IsRequired() |
|||
.HasMaxLength(256) |
|||
.HasColumnType("nvarchar(256)"); |
|||
|
|||
b.Property<string>("ExtraProperties") |
|||
.IsRequired() |
|||
.HasColumnType("nvarchar(max)") |
|||
.HasColumnName("ExtraProperties"); |
|||
|
|||
b.HasKey("Id"); |
|||
|
|||
b.HasIndex("CreationTime"); |
|||
|
|||
b.ToTable("AbpEventOutbox", (string)null); |
|||
}); |
|||
#pragma warning restore 612, 618
|
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,233 @@ |
|||
using System; |
|||
using Microsoft.EntityFrameworkCore.Migrations; |
|||
|
|||
#nullable disable |
|||
|
|||
namespace DistDemoApp.Migrations |
|||
{ |
|||
/// <inheritdoc />
|
|||
public partial class Update102 : Migration |
|||
{ |
|||
/// <inheritdoc />
|
|||
protected override void Up(MigrationBuilder migrationBuilder) |
|||
{ |
|||
migrationBuilder.DropIndex( |
|||
name: "IX_AbpEventInbox_Processed_CreationTime", |
|||
table: "AbpEventInbox"); |
|||
|
|||
migrationBuilder.DropColumn( |
|||
name: "Processed", |
|||
table: "AbpEventInbox"); |
|||
|
|||
migrationBuilder.RenameColumn( |
|||
name: "ProcessedTime", |
|||
table: "AbpEventInbox", |
|||
newName: "NextRetryTime"); |
|||
|
|||
migrationBuilder.AlterColumn<string>( |
|||
name: "ExtraProperties", |
|||
table: "TodoSummaries", |
|||
type: "nvarchar(max)", |
|||
nullable: false, |
|||
defaultValue: "", |
|||
oldClrType: typeof(string), |
|||
oldType: "nvarchar(max)", |
|||
oldNullable: true); |
|||
|
|||
migrationBuilder.AlterColumn<string>( |
|||
name: "ConcurrencyStamp", |
|||
table: "TodoSummaries", |
|||
type: "nvarchar(40)", |
|||
maxLength: 40, |
|||
nullable: false, |
|||
defaultValue: "", |
|||
oldClrType: typeof(string), |
|||
oldType: "nvarchar(40)", |
|||
oldMaxLength: 40, |
|||
oldNullable: true); |
|||
|
|||
migrationBuilder.AlterColumn<string>( |
|||
name: "ExtraProperties", |
|||
table: "TodoItems", |
|||
type: "nvarchar(max)", |
|||
nullable: false, |
|||
defaultValue: "", |
|||
oldClrType: typeof(string), |
|||
oldType: "nvarchar(max)", |
|||
oldNullable: true); |
|||
|
|||
migrationBuilder.AlterColumn<string>( |
|||
name: "ConcurrencyStamp", |
|||
table: "TodoItems", |
|||
type: "nvarchar(40)", |
|||
maxLength: 40, |
|||
nullable: false, |
|||
defaultValue: "", |
|||
oldClrType: typeof(string), |
|||
oldType: "nvarchar(40)", |
|||
oldMaxLength: 40, |
|||
oldNullable: true); |
|||
|
|||
migrationBuilder.AlterColumn<string>( |
|||
name: "ExtraProperties", |
|||
table: "AbpEventOutbox", |
|||
type: "nvarchar(max)", |
|||
nullable: false, |
|||
defaultValue: "", |
|||
oldClrType: typeof(string), |
|||
oldType: "nvarchar(max)", |
|||
oldNullable: true); |
|||
|
|||
migrationBuilder.AlterColumn<string>( |
|||
name: "MessageId", |
|||
table: "AbpEventInbox", |
|||
type: "nvarchar(450)", |
|||
nullable: false, |
|||
defaultValue: "", |
|||
oldClrType: typeof(string), |
|||
oldType: "nvarchar(450)", |
|||
oldNullable: true); |
|||
|
|||
migrationBuilder.AlterColumn<string>( |
|||
name: "ExtraProperties", |
|||
table: "AbpEventInbox", |
|||
type: "nvarchar(max)", |
|||
nullable: false, |
|||
defaultValue: "", |
|||
oldClrType: typeof(string), |
|||
oldType: "nvarchar(max)", |
|||
oldNullable: true); |
|||
|
|||
migrationBuilder.AddColumn<DateTime>( |
|||
name: "HandledTime", |
|||
table: "AbpEventInbox", |
|||
type: "datetime2", |
|||
nullable: true); |
|||
|
|||
migrationBuilder.AddColumn<int>( |
|||
name: "RetryCount", |
|||
table: "AbpEventInbox", |
|||
type: "int", |
|||
nullable: false, |
|||
defaultValue: 0); |
|||
|
|||
migrationBuilder.AddColumn<int>( |
|||
name: "Status", |
|||
table: "AbpEventInbox", |
|||
type: "int", |
|||
nullable: false, |
|||
defaultValue: 0); |
|||
|
|||
migrationBuilder.CreateIndex( |
|||
name: "IX_AbpEventOutbox_CreationTime", |
|||
table: "AbpEventOutbox", |
|||
column: "CreationTime"); |
|||
|
|||
migrationBuilder.CreateIndex( |
|||
name: "IX_AbpEventInbox_Status_CreationTime", |
|||
table: "AbpEventInbox", |
|||
columns: new[] { "Status", "CreationTime" }); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
protected override void Down(MigrationBuilder migrationBuilder) |
|||
{ |
|||
migrationBuilder.DropIndex( |
|||
name: "IX_AbpEventOutbox_CreationTime", |
|||
table: "AbpEventOutbox"); |
|||
|
|||
migrationBuilder.DropIndex( |
|||
name: "IX_AbpEventInbox_Status_CreationTime", |
|||
table: "AbpEventInbox"); |
|||
|
|||
migrationBuilder.DropColumn( |
|||
name: "HandledTime", |
|||
table: "AbpEventInbox"); |
|||
|
|||
migrationBuilder.DropColumn( |
|||
name: "RetryCount", |
|||
table: "AbpEventInbox"); |
|||
|
|||
migrationBuilder.DropColumn( |
|||
name: "Status", |
|||
table: "AbpEventInbox"); |
|||
|
|||
migrationBuilder.RenameColumn( |
|||
name: "NextRetryTime", |
|||
table: "AbpEventInbox", |
|||
newName: "ProcessedTime"); |
|||
|
|||
migrationBuilder.AlterColumn<string>( |
|||
name: "ExtraProperties", |
|||
table: "TodoSummaries", |
|||
type: "nvarchar(max)", |
|||
nullable: true, |
|||
oldClrType: typeof(string), |
|||
oldType: "nvarchar(max)"); |
|||
|
|||
migrationBuilder.AlterColumn<string>( |
|||
name: "ConcurrencyStamp", |
|||
table: "TodoSummaries", |
|||
type: "nvarchar(40)", |
|||
maxLength: 40, |
|||
nullable: true, |
|||
oldClrType: typeof(string), |
|||
oldType: "nvarchar(40)", |
|||
oldMaxLength: 40); |
|||
|
|||
migrationBuilder.AlterColumn<string>( |
|||
name: "ExtraProperties", |
|||
table: "TodoItems", |
|||
type: "nvarchar(max)", |
|||
nullable: true, |
|||
oldClrType: typeof(string), |
|||
oldType: "nvarchar(max)"); |
|||
|
|||
migrationBuilder.AlterColumn<string>( |
|||
name: "ConcurrencyStamp", |
|||
table: "TodoItems", |
|||
type: "nvarchar(40)", |
|||
maxLength: 40, |
|||
nullable: true, |
|||
oldClrType: typeof(string), |
|||
oldType: "nvarchar(40)", |
|||
oldMaxLength: 40); |
|||
|
|||
migrationBuilder.AlterColumn<string>( |
|||
name: "ExtraProperties", |
|||
table: "AbpEventOutbox", |
|||
type: "nvarchar(max)", |
|||
nullable: true, |
|||
oldClrType: typeof(string), |
|||
oldType: "nvarchar(max)"); |
|||
|
|||
migrationBuilder.AlterColumn<string>( |
|||
name: "MessageId", |
|||
table: "AbpEventInbox", |
|||
type: "nvarchar(450)", |
|||
nullable: true, |
|||
oldClrType: typeof(string), |
|||
oldType: "nvarchar(450)"); |
|||
|
|||
migrationBuilder.AlterColumn<string>( |
|||
name: "ExtraProperties", |
|||
table: "AbpEventInbox", |
|||
type: "nvarchar(max)", |
|||
nullable: true, |
|||
oldClrType: typeof(string), |
|||
oldType: "nvarchar(max)"); |
|||
|
|||
migrationBuilder.AddColumn<bool>( |
|||
name: "Processed", |
|||
table: "AbpEventInbox", |
|||
type: "bit", |
|||
nullable: false, |
|||
defaultValue: false); |
|||
|
|||
migrationBuilder.CreateIndex( |
|||
name: "IX_AbpEventInbox_Processed_CreationTime", |
|||
table: "AbpEventInbox", |
|||
columns: new[] { "Processed", "CreationTime" }); |
|||
} |
|||
} |
|||
} |
|||
@ -1,57 +1,34 @@ |
|||
using System; |
|||
using System.Threading.Tasks; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Microsoft.Extensions.Hosting; |
|||
using Serilog; |
|||
using Serilog.Events; |
|||
using Volo.Abp; |
|||
using Volo.Abp.Threading; |
|||
|
|||
namespace DistDemoApp |
|||
{ |
|||
public class Program |
|||
{ |
|||
public static async Task<int> Main(string[] args) |
|||
public static void Main(string[] args) |
|||
{ |
|||
Log.Logger = new LoggerConfiguration() |
|||
#if DEBUG
|
|||
.MinimumLevel.Debug() |
|||
#else
|
|||
.MinimumLevel.Information() |
|||
#endif
|
|||
.MinimumLevel.Override("Microsoft", LogEventLevel.Warning) |
|||
.Enrich.FromLogContext() |
|||
.WriteTo.Async(c => c.File("Logs/logs.txt")) |
|||
.WriteTo.Async(c => c.Console()) |
|||
.CreateLogger(); |
|||
|
|||
try |
|||
{ |
|||
Log.Information("Starting console host."); |
|||
await CreateHostBuilder(args).RunConsoleAsync(); |
|||
return 0; |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
Log.Fatal(ex, "Host terminated unexpectedly!"); |
|||
return 1; |
|||
} |
|||
finally |
|||
using (var application = AbpApplicationFactory.Create<DistDemoAppEfCoreRabbitMqModule>(options => |
|||
{ |
|||
options.UseAutofac(); |
|||
options.Services.AddSerilog((_, _) => |
|||
{ |
|||
}); |
|||
options.Services.AddLogging(c => c.AddSerilog()); |
|||
})) |
|||
{ |
|||
Log.CloseAndFlush(); |
|||
} |
|||
Log.Information("Starting DistDemoApp.EfCoreRabbitMq."); |
|||
application.Initialize(); |
|||
|
|||
} |
|||
AsyncHelper.RunSync( |
|||
() => application |
|||
.ServiceProvider |
|||
.GetRequiredService<DemoService>().CreateTodoItemAsync() |
|||
); |
|||
|
|||
internal static IHostBuilder CreateHostBuilder(string[] args) => |
|||
Host.CreateDefaultBuilder(args) |
|||
.UseAutofac() |
|||
.UseSerilog() |
|||
.ConfigureAppConfiguration((context, config) => |
|||
{ |
|||
//setup your additional configuration sources
|
|||
}) |
|||
.ConfigureServices((hostContext, services) => |
|||
{ |
|||
services.AddApplication<DistDemoAppEfCoreRabbitMqModule>(); |
|||
}); |
|||
application.Shutdown(); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -1,34 +0,0 @@ |
|||
using Microsoft.EntityFrameworkCore; |
|||
using Volo.Abp.Domain.Entities; |
|||
using Volo.Abp.EntityFrameworkCore; |
|||
using Volo.Abp.EntityFrameworkCore.DistributedEvents; |
|||
|
|||
namespace DistDemoApp |
|||
{ |
|||
public class TodoDbContext : AbpDbContext<TodoDbContext>, IHasEventOutbox, IHasEventInbox |
|||
{ |
|||
public DbSet<TodoItem> TodoItems { get; set; } |
|||
public DbSet<TodoSummary> TodoSummaries { get; set; } |
|||
public DbSet<OutgoingEventRecord> OutgoingEvents { get; set; } |
|||
public DbSet<IncomingEventRecord> IncomingEvents { get; set; } |
|||
|
|||
public TodoDbContext(DbContextOptions<TodoDbContext> options) |
|||
: base(options) |
|||
{ |
|||
|
|||
} |
|||
|
|||
protected override void OnModelCreating(ModelBuilder modelBuilder) |
|||
{ |
|||
base.OnModelCreating(modelBuilder); |
|||
|
|||
modelBuilder.ConfigureEventOutbox(); |
|||
modelBuilder.ConfigureEventInbox(); |
|||
|
|||
modelBuilder.Entity<TodoItem>(b => |
|||
{ |
|||
b.Property(x => x.Text).IsRequired().HasMaxLength(128); |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
@ -1,29 +0,0 @@ |
|||
using System.IO; |
|||
using Microsoft.EntityFrameworkCore; |
|||
using Microsoft.EntityFrameworkCore.Design; |
|||
using Microsoft.Extensions.Configuration; |
|||
|
|||
namespace DistDemoApp |
|||
{ |
|||
public class TodoDbContextFactory : IDesignTimeDbContextFactory<TodoDbContext> |
|||
{ |
|||
public TodoDbContext CreateDbContext(string[] args) |
|||
{ |
|||
var configuration = BuildConfiguration(); |
|||
|
|||
var builder = new DbContextOptionsBuilder<TodoDbContext>() |
|||
.UseSqlServer(configuration.GetConnectionString("Default")); |
|||
|
|||
return new TodoDbContext(builder.Options); |
|||
} |
|||
|
|||
private static IConfigurationRoot BuildConfiguration() |
|||
{ |
|||
var builder = new ConfigurationBuilder() |
|||
.SetBasePath(Directory.GetCurrentDirectory()) |
|||
.AddJsonFile("appsettings.json", optional: false); |
|||
|
|||
return builder.Build(); |
|||
} |
|||
} |
|||
} |
|||
@ -1,57 +1,36 @@ |
|||
using System; |
|||
using System.Threading.Tasks; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Microsoft.Extensions.Hosting; |
|||
using Serilog; |
|||
using Serilog.Events; |
|||
using Volo.Abp; |
|||
using Volo.Abp.Threading; |
|||
|
|||
namespace DistDemoApp |
|||
{ |
|||
public class Program |
|||
{ |
|||
public static async Task<int> Main(string[] args) |
|||
public static void Main(string[] args) |
|||
{ |
|||
Log.Logger = new LoggerConfiguration() |
|||
#if DEBUG
|
|||
.MinimumLevel.Debug() |
|||
#else
|
|||
.MinimumLevel.Information() |
|||
#endif
|
|||
.MinimumLevel.Override("Microsoft", LogEventLevel.Warning) |
|||
.Enrich.FromLogContext() |
|||
.WriteTo.Async(c => c.File("Logs/logs.txt")) |
|||
.WriteTo.Async(c => c.Console()) |
|||
.CreateLogger(); |
|||
|
|||
try |
|||
{ |
|||
Log.Information("Starting console host."); |
|||
await CreateHostBuilder(args).RunConsoleAsync(); |
|||
return 0; |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
Log.Fatal(ex, "Host terminated unexpectedly!"); |
|||
return 1; |
|||
} |
|||
finally |
|||
using (var application = AbpApplicationFactory.Create<DistDemoAppMongoDbKafkaModule>(options => |
|||
{ |
|||
options.UseAutofac(); |
|||
options.Services.AddSerilog((_, _) => |
|||
{ |
|||
}); |
|||
options.Services.AddLogging(c => c.AddSerilog()); |
|||
})) |
|||
{ |
|||
Log.CloseAndFlush(); |
|||
Log.Information("Starting DistDemoApp.MongoDbKafka."); |
|||
|
|||
application.Initialize(); |
|||
|
|||
AsyncHelper.RunSync( |
|||
() => application |
|||
.ServiceProvider |
|||
.GetRequiredService<DemoService>().CreateTodoItemAsync() |
|||
); |
|||
|
|||
application.Shutdown(); |
|||
} |
|||
|
|||
} |
|||
|
|||
internal static IHostBuilder CreateHostBuilder(string[] args) => |
|||
Host.CreateDefaultBuilder(args) |
|||
.UseAutofac() |
|||
.UseSerilog() |
|||
.ConfigureAppConfiguration((context, config) => |
|||
{ |
|||
//setup your additional configuration sources
|
|||
}) |
|||
.ConfigureServices((hostContext, services) => |
|||
{ |
|||
services.AddApplication<DistDemoAppMongoDbKafkaModule>(); |
|||
}); |
|||
} |
|||
} |
|||
|
|||
@ -1,26 +0,0 @@ |
|||
using MongoDB.Driver; |
|||
using Volo.Abp.Data; |
|||
using Volo.Abp.MongoDB; |
|||
using Volo.Abp.MongoDB.DistributedEvents; |
|||
|
|||
namespace DistDemoApp |
|||
{ |
|||
[ConnectionStringName("Default")] |
|||
public class TodoMongoDbContext : AbpMongoDbContext, IHasEventOutbox, IHasEventInbox |
|||
{ |
|||
public IMongoCollection<TodoItem> TodoItems => Collection<TodoItem>(); |
|||
public IMongoCollection<TodoSummary> TodoSummaries => Collection<TodoSummary>(); |
|||
|
|||
public IMongoCollection<OutgoingEventRecord> OutgoingEvents |
|||
{ |
|||
get => Collection<OutgoingEventRecord>(); |
|||
set {} |
|||
} |
|||
public IMongoCollection<IncomingEventRecord> IncomingEvents |
|||
{ |
|||
get => Collection<IncomingEventRecord>(); |
|||
set {} |
|||
} |
|||
} |
|||
|
|||
} |
|||
@ -1,19 +0,0 @@ |
|||
using MongoDB.Driver; |
|||
using Volo.Abp.Data; |
|||
using Volo.Abp.MongoDB; |
|||
using Volo.Abp.MongoDB.DistributedEvents; |
|||
|
|||
namespace DistDemoApp |
|||
{ |
|||
[ConnectionStringName("Default")] |
|||
public class TodoMongoDbContext : AbpMongoDbContext, IHasEventOutbox, IHasEventInbox |
|||
{ |
|||
public IMongoCollection<TodoItem> TodoItems => Collection<TodoItem>(); |
|||
public IMongoCollection<TodoSummary> TodoSummaries => Collection<TodoSummary>(); |
|||
|
|||
public IMongoCollection<OutgoingEventRecord> OutgoingEvents => Collection<OutgoingEventRecord>(); |
|||
|
|||
public IMongoCollection<IncomingEventRecord> IncomingEvents => Collection<IncomingEventRecord>(); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,18 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>net10.0</TargetFramework> |
|||
<RootNamespace>DistDemoApp</RootNamespace> |
|||
<DistDemoDbProvider>EntityFrameworkCore</DistDemoDbProvider> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<ProjectReference Include="..\..\..\framework\src\Volo.Abp.EntityFrameworkCore.SqlServer\Volo.Abp.EntityFrameworkCore.SqlServer.csproj" /> |
|||
<ProjectReference Include="..\DistDemoApp.Shared\DistDemoApp.Shared.csproj" /> |
|||
</ItemGroup> |
|||
|
|||
<ItemGroup> |
|||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
@ -0,0 +1,12 @@ |
|||
using Volo.Abp.EntityFrameworkCore.SqlServer; |
|||
using Volo.Abp.Modularity; |
|||
|
|||
namespace DistDemoApp; |
|||
|
|||
[DependsOn( |
|||
typeof(AbpEntityFrameworkCoreSqlServerModule), |
|||
typeof(DistDemoAppSharedModule) |
|||
)] |
|||
public class DistDemoAppEntityFrameworkCoreInfrastructureModule : AbpModule |
|||
{ |
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Volo.Abp.EntityFrameworkCore; |
|||
using Volo.Abp.Modularity; |
|||
|
|||
namespace DistDemoApp; |
|||
|
|||
public static class DistDemoEntityFrameworkServiceCollectionExtensions |
|||
{ |
|||
public static void ConfigureDistDemoEntityFrameworkInfrastructure(this ServiceConfigurationContext context) |
|||
{ |
|||
context.Services.AddAbpDbContext<TodoDbContext>(options => |
|||
{ |
|||
options.AddDefaultRepositories(); |
|||
}); |
|||
|
|||
context.Services.Configure<AbpDbContextOptions>(options => |
|||
{ |
|||
options.UseSqlServer(); |
|||
}); |
|||
} |
|||
} |
|||
@ -0,0 +1,34 @@ |
|||
using Microsoft.EntityFrameworkCore; |
|||
using Volo.Abp.EntityFrameworkCore; |
|||
using Volo.Abp.EntityFrameworkCore.DistributedEvents; |
|||
|
|||
namespace DistDemoApp; |
|||
|
|||
public class TodoDbContext : AbpDbContext<TodoDbContext>, IHasEventOutbox, IHasEventInbox |
|||
{ |
|||
public DbSet<TodoItem> TodoItems { get; set; } = null!; |
|||
|
|||
public DbSet<TodoSummary> TodoSummaries { get; set; } = null!; |
|||
|
|||
public DbSet<OutgoingEventRecord> OutgoingEvents { get; set; } = null!; |
|||
|
|||
public DbSet<IncomingEventRecord> IncomingEvents { get; set; } = null!; |
|||
|
|||
public TodoDbContext(DbContextOptions<TodoDbContext> options) |
|||
: base(options) |
|||
{ |
|||
} |
|||
|
|||
protected override void OnModelCreating(ModelBuilder modelBuilder) |
|||
{ |
|||
base.OnModelCreating(modelBuilder); |
|||
|
|||
modelBuilder.ConfigureEventOutbox(); |
|||
modelBuilder.ConfigureEventInbox(); |
|||
|
|||
modelBuilder.Entity<TodoItem>(b => |
|||
{ |
|||
b.Property(x => x.Text).IsRequired().HasMaxLength(128); |
|||
}); |
|||
} |
|||
} |
|||
@ -0,0 +1,28 @@ |
|||
using System.IO; |
|||
using Microsoft.EntityFrameworkCore; |
|||
using Microsoft.EntityFrameworkCore.Design; |
|||
using Microsoft.Extensions.Configuration; |
|||
|
|||
namespace DistDemoApp; |
|||
|
|||
public class TodoDbContextFactory : IDesignTimeDbContextFactory<TodoDbContext> |
|||
{ |
|||
public TodoDbContext CreateDbContext(string[] args) |
|||
{ |
|||
var configuration = BuildConfiguration(); |
|||
|
|||
var builder = new DbContextOptionsBuilder<TodoDbContext>() |
|||
.UseSqlServer(configuration.GetConnectionString("Default")); |
|||
|
|||
return new TodoDbContext(builder.Options); |
|||
} |
|||
|
|||
private static IConfigurationRoot BuildConfiguration() |
|||
{ |
|||
var builder = new ConfigurationBuilder() |
|||
.SetBasePath(Directory.GetCurrentDirectory()) |
|||
.AddJsonFile("appsettings.json", optional: false); |
|||
|
|||
return builder.Build(); |
|||
} |
|||
} |
|||
@ -0,0 +1,14 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>net10.0</TargetFramework> |
|||
<RootNamespace>DistDemoApp</RootNamespace> |
|||
<DistDemoDbProvider>MongoDb</DistDemoDbProvider> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<ProjectReference Include="..\..\..\framework\src\Volo.Abp.MongoDB\Volo.Abp.MongoDB.csproj" /> |
|||
<ProjectReference Include="..\DistDemoApp.Shared\DistDemoApp.Shared.csproj" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
@ -0,0 +1,12 @@ |
|||
using Volo.Abp.Modularity; |
|||
using Volo.Abp.MongoDB; |
|||
|
|||
namespace DistDemoApp; |
|||
|
|||
[DependsOn( |
|||
typeof(AbpMongoDbModule), |
|||
typeof(DistDemoAppSharedModule) |
|||
)] |
|||
public class DistDemoAppMongoDbInfrastructureModule : AbpModule |
|||
{ |
|||
} |
|||
@ -0,0 +1,26 @@ |
|||
using MongoDB.Driver; |
|||
using Volo.Abp.Data; |
|||
using Volo.Abp.MongoDB; |
|||
using Volo.Abp.MongoDB.DistributedEvents; |
|||
|
|||
namespace DistDemoApp; |
|||
|
|||
[ConnectionStringName("Default")] |
|||
public class DistDemoMongoDbContext : AbpMongoDbContext, IHasEventOutbox, IHasEventInbox |
|||
{ |
|||
public IMongoCollection<TodoItem> TodoItems => Collection<TodoItem>(); |
|||
|
|||
public IMongoCollection<TodoSummary> TodoSummaries => Collection<TodoSummary>(); |
|||
|
|||
public IMongoCollection<OutgoingEventRecord> OutgoingEvents |
|||
{ |
|||
get => Collection<OutgoingEventRecord>(); |
|||
set { } |
|||
} |
|||
|
|||
public IMongoCollection<IncomingEventRecord> IncomingEvents |
|||
{ |
|||
get => Collection<IncomingEventRecord>(); |
|||
set { } |
|||
} |
|||
} |
|||
@ -0,0 +1,42 @@ |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Volo.Abp.Data; |
|||
using Volo.Abp.EventBus.Distributed; |
|||
using Volo.Abp.Modularity; |
|||
using Volo.Abp.MongoDB; |
|||
using Volo.Abp.MongoDB.DistributedEvents; |
|||
|
|||
namespace DistDemoApp; |
|||
|
|||
public static class DistDemoMongoServiceCollectionExtensions |
|||
{ |
|||
private const string DefaultMongoConnectionString = "mongodb://localhost:27017/DistEventsDemo?retryWrites=false"; |
|||
|
|||
public static void ConfigureDistDemoMongoInfrastructure(this ServiceConfigurationContext context) |
|||
{ |
|||
context.Services.AddMongoDbContext<DistDemoMongoDbContext>(options => |
|||
{ |
|||
options.AddDefaultRepositories(); |
|||
}); |
|||
|
|||
context.Services.Configure<AbpDbConnectionOptions>(options => |
|||
{ |
|||
if (string.IsNullOrWhiteSpace(options.ConnectionStrings.Default)) |
|||
{ |
|||
options.ConnectionStrings.Default = DefaultMongoConnectionString; |
|||
} |
|||
}); |
|||
|
|||
context.Services.Configure<AbpDistributedEventBusOptions>(options => |
|||
{ |
|||
options.Outboxes.Configure(config => |
|||
{ |
|||
config.UseMongoDbContext<DistDemoMongoDbContext>(); |
|||
}); |
|||
|
|||
options.Inboxes.Configure(config => |
|||
{ |
|||
config.UseMongoDbContext<DistDemoMongoDbContext>(); |
|||
}); |
|||
}); |
|||
} |
|||
} |
|||
@ -1,29 +1,21 @@ |
|||
using System; |
|||
using System; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.Domain.Repositories; |
|||
|
|||
namespace DistDemoApp |
|||
{ |
|||
public class DemoService : ITransientDependency |
|||
{ |
|||
private readonly IRepository<TodoItem, Guid> _todoItemRepository; |
|||
private readonly IDistEventScenarioRunner _scenarioRunner; |
|||
|
|||
public DemoService(IRepository<TodoItem, Guid> todoItemRepository) |
|||
public DemoService(IDistEventScenarioRunner scenarioRunner) |
|||
{ |
|||
_todoItemRepository = todoItemRepository; |
|||
_scenarioRunner = scenarioRunner; |
|||
} |
|||
|
|||
public async Task CreateTodoItemAsync() |
|||
|
|||
public virtual async Task CreateTodoItemAsync() |
|||
{ |
|||
var todoItem = await _todoItemRepository.InsertAsync( |
|||
new TodoItem |
|||
{ |
|||
Text = "todo item " + DateTime.Now.Ticks |
|||
} |
|||
); |
|||
|
|||
Console.WriteLine("Created a new todo item: " + todoItem); |
|||
await _scenarioRunner.RunAsync(DistEventScenarioProfile.Default()); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,60 @@ |
|||
namespace DistDemoApp; |
|||
|
|||
public class DistEventScenarioProfile |
|||
{ |
|||
public string Name { get; set; } = "default"; |
|||
|
|||
public string AnonymousOnlyEventName { get; set; } = "dist-demo.anonymous-only"; |
|||
|
|||
public string AnonymousOnlyMessage { get; set; } = "hello-anonymous"; |
|||
|
|||
public int TypedFromTypedValue { get; set; } = 7; |
|||
|
|||
public int TypedFromAnonymousValue { get; set; } = 11; |
|||
|
|||
public bool EnableTypedFromTypedScenario { get; set; } = true; |
|||
|
|||
public bool EnableTypedFromAnonymousScenario { get; set; } = true; |
|||
|
|||
public bool EnableAnonymousOnlyScenario { get; set; } = true; |
|||
|
|||
public bool OnUnitOfWorkComplete { get; set; } = true; |
|||
|
|||
public bool UseOutbox { get; set; } = true; |
|||
|
|||
public bool UseUnitOfWork { get; set; } = true; |
|||
|
|||
public int WarmupDelayMs { get; set; } = 1500; |
|||
|
|||
public int TimeoutSeconds { get; set; } = 60; |
|||
|
|||
public static DistEventScenarioProfile Default() |
|||
{ |
|||
return new DistEventScenarioProfile(); |
|||
} |
|||
|
|||
public static DistEventScenarioProfile DaprWeb() |
|||
{ |
|||
return new DistEventScenarioProfile |
|||
{ |
|||
Name = "dapr-web", |
|||
AnonymousOnlyEventName = "dist-demo.dapr.anonymous-only", |
|||
AnonymousOnlyMessage = "hello-dapr-web", |
|||
EnableTypedFromTypedScenario = false, |
|||
EnableTypedFromAnonymousScenario = false, |
|||
EnableAnonymousOnlyScenario = false |
|||
}; |
|||
} |
|||
|
|||
public static DistEventScenarioProfile AzureEmulator() |
|||
{ |
|||
return new DistEventScenarioProfile |
|||
{ |
|||
Name = "azure-emulator", |
|||
AnonymousOnlyEventName = "DistDemoApp.Azure.AnonymousOnly", |
|||
AnonymousOnlyMessage = "hello-azure-emulator", |
|||
TypedFromTypedValue = 21, |
|||
TypedFromAnonymousValue = 34 |
|||
}; |
|||
} |
|||
} |
|||
@ -0,0 +1,134 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.EventBus; |
|||
using Volo.Abp.EventBus.Distributed; |
|||
using Volo.Abp.Uow; |
|||
|
|||
namespace DistDemoApp; |
|||
|
|||
public class DistEventScenarioRunner : IDistEventScenarioRunner, ITransientDependency |
|||
{ |
|||
private readonly IDistributedEventBus _distributedEventBus; |
|||
private readonly IUnitOfWorkManager _unitOfWorkManager; |
|||
|
|||
public DistEventScenarioRunner( |
|||
IDistributedEventBus distributedEventBus, |
|||
IUnitOfWorkManager unitOfWorkManager) |
|||
{ |
|||
_distributedEventBus = distributedEventBus; |
|||
_unitOfWorkManager = unitOfWorkManager; |
|||
} |
|||
|
|||
public async Task RunAsync(DistEventScenarioProfile profile) |
|||
{ |
|||
var typedEventName = EventNameAttribute.GetNameOrDefault<ProviderScenarioEvent>(); |
|||
|
|||
var typedFromTypedPublish = profile.EnableTypedFromTypedScenario |
|||
? new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously) |
|||
: null; |
|||
var typedFromAnonymousPublish = profile.EnableTypedFromAnonymousScenario |
|||
? new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously) |
|||
: null; |
|||
var anonymousOnlyPublish = profile.EnableAnonymousOnlyScenario |
|||
? new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously) |
|||
: null; |
|||
|
|||
using var typedSubscription = _distributedEventBus.Subscribe<ProviderScenarioEvent>(eventData => |
|||
{ |
|||
if (typedFromTypedPublish != null && eventData.Value == profile.TypedFromTypedValue) |
|||
{ |
|||
typedFromTypedPublish.TrySetResult(eventData.Value); |
|||
} |
|||
|
|||
if (typedFromAnonymousPublish != null && eventData.Value == profile.TypedFromAnonymousValue) |
|||
{ |
|||
typedFromAnonymousPublish.TrySetResult(eventData.Value); |
|||
} |
|||
|
|||
return Task.CompletedTask; |
|||
}); |
|||
|
|||
IDisposable? anonymousOnlySubscription = null; |
|||
if (profile.EnableAnonymousOnlyScenario) |
|||
{ |
|||
anonymousOnlySubscription = _distributedEventBus.Subscribe( |
|||
profile.AnonymousOnlyEventName, |
|||
new SingleInstanceHandlerFactory( |
|||
new ActionEventHandler<AnonymousEventData>(eventData => |
|||
{ |
|||
var converted = eventData.ConvertToTypedObject(); |
|||
if (converted is Dictionary<string, object> payload && |
|||
payload.TryGetValue("Message", out var message) && |
|||
message?.ToString() == profile.AnonymousOnlyMessage) |
|||
{ |
|||
anonymousOnlyPublish!.TrySetResult(true); |
|||
} |
|||
|
|||
return Task.CompletedTask; |
|||
}))); |
|||
} |
|||
|
|||
await Task.Delay(profile.WarmupDelayMs); |
|||
|
|||
if (profile.UseUnitOfWork) |
|||
{ |
|||
using var uow = _unitOfWorkManager.Begin(); |
|||
await PublishScenarioEventsAsync(profile, typedEventName); |
|||
await uow.CompleteAsync(); |
|||
} |
|||
else |
|||
{ |
|||
await PublishScenarioEventsAsync(profile, typedEventName); |
|||
} |
|||
|
|||
if (typedFromTypedPublish != null) |
|||
{ |
|||
await typedFromTypedPublish.Task.WaitAsync(TimeSpan.FromSeconds(profile.TimeoutSeconds)); |
|||
} |
|||
|
|||
if (typedFromAnonymousPublish != null) |
|||
{ |
|||
await typedFromAnonymousPublish.Task.WaitAsync(TimeSpan.FromSeconds(profile.TimeoutSeconds)); |
|||
} |
|||
|
|||
if (anonymousOnlyPublish != null) |
|||
{ |
|||
await anonymousOnlyPublish.Task.WaitAsync(TimeSpan.FromSeconds(profile.TimeoutSeconds)); |
|||
} |
|||
|
|||
anonymousOnlySubscription?.Dispose(); |
|||
|
|||
Console.WriteLine($"All distributed event scenarios passed ({profile.Name})."); |
|||
} |
|||
|
|||
private async Task PublishScenarioEventsAsync(DistEventScenarioProfile profile, string typedEventName) |
|||
{ |
|||
if (profile.EnableTypedFromTypedScenario) |
|||
{ |
|||
await _distributedEventBus.PublishAsync( |
|||
new ProviderScenarioEvent { Value = profile.TypedFromTypedValue }, |
|||
onUnitOfWorkComplete: profile.OnUnitOfWorkComplete, |
|||
useOutbox: profile.UseOutbox); |
|||
} |
|||
|
|||
if (profile.EnableTypedFromAnonymousScenario) |
|||
{ |
|||
await _distributedEventBus.PublishAsync( |
|||
typedEventName, |
|||
new { Value = profile.TypedFromAnonymousValue }, |
|||
onUnitOfWorkComplete: profile.OnUnitOfWorkComplete, |
|||
useOutbox: profile.UseOutbox); |
|||
} |
|||
|
|||
if (profile.EnableAnonymousOnlyScenario) |
|||
{ |
|||
await _distributedEventBus.PublishAsync( |
|||
profile.AnonymousOnlyEventName, |
|||
new { Message = profile.AnonymousOnlyMessage }, |
|||
onUnitOfWorkComplete: profile.OnUnitOfWorkComplete, |
|||
useOutbox: profile.UseOutbox); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,8 @@ |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace DistDemoApp; |
|||
|
|||
public interface IDistEventScenarioRunner |
|||
{ |
|||
Task RunAsync(DistEventScenarioProfile profile); |
|||
} |
|||
@ -0,0 +1,9 @@ |
|||
using Volo.Abp.EventBus; |
|||
|
|||
namespace DistDemoApp; |
|||
|
|||
[EventName("DistDemoApp.ProviderScenarioEvent")] |
|||
public class ProviderScenarioEvent |
|||
{ |
|||
public int Value { get; set; } |
|||
} |
|||
@ -0,0 +1,12 @@ |
|||
apiVersion: dapr.io/v1alpha1 |
|||
kind: Component |
|||
metadata: |
|||
name: pubsub |
|||
spec: |
|||
type: pubsub.redis |
|||
version: v1 |
|||
metadata: |
|||
- name: redisHost |
|||
value: redis:6379 |
|||
- name: redisPassword |
|||
value: "" |
|||
@ -0,0 +1,131 @@ |
|||
services: |
|||
rabbitmq: |
|||
image: rabbitmq:3.13-management |
|||
container_name: distevents-rabbitmq |
|||
ports: |
|||
- "5672:5672" |
|||
- "15672:15672" |
|||
environment: |
|||
RABBITMQ_DEFAULT_USER: guest |
|||
RABBITMQ_DEFAULT_PASS: guest |
|||
|
|||
zookeeper: |
|||
image: confluentinc/cp-zookeeper:7.6.0 |
|||
container_name: distevents-zookeeper |
|||
ports: |
|||
- "2181:2181" |
|||
environment: |
|||
ZOOKEEPER_CLIENT_PORT: "2181" |
|||
ZOOKEEPER_TICK_TIME: "2000" |
|||
|
|||
kafka: |
|||
image: confluentinc/cp-kafka:7.6.0 |
|||
container_name: distevents-kafka |
|||
depends_on: |
|||
- zookeeper |
|||
ports: |
|||
- "9092:9092" |
|||
environment: |
|||
KAFKA_BROKER_ID: "1" |
|||
KAFKA_ZOOKEEPER_CONNECT: "zookeeper:2181" |
|||
KAFKA_LISTENERS: "PLAINTEXT://0.0.0.0:9092" |
|||
KAFKA_ADVERTISED_LISTENERS: "PLAINTEXT://localhost:9092" |
|||
KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: "PLAINTEXT:PLAINTEXT" |
|||
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: "1" |
|||
KAFKA_AUTO_CREATE_TOPICS_ENABLE: "true" |
|||
|
|||
mongodb: |
|||
image: mongo:7 |
|||
container_name: distevents-mongodb |
|||
command: ["mongod", "--replSet", "rs0", "--bind_ip_all"] |
|||
ports: |
|||
- "27017:27017" |
|||
healthcheck: |
|||
test: ["CMD", "mongosh", "--quiet", "--eval", "db.adminCommand('ping').ok"] |
|||
interval: 5s |
|||
timeout: 3s |
|||
retries: 20 |
|||
|
|||
mongodb-rs-init: |
|||
image: mongo:7 |
|||
container_name: distevents-mongodb-rs-init |
|||
depends_on: |
|||
mongodb: |
|||
condition: service_healthy |
|||
restart: "no" |
|||
command: |
|||
[ |
|||
"mongosh", |
|||
"--host", "mongodb:27017", |
|||
"--quiet", |
|||
"--eval", |
|||
"try { rs.status() } catch (e) { rs.initiate({_id:'rs0',members:[{_id:0,host:'mongodb:27017'}]}) }" |
|||
] |
|||
|
|||
redis: |
|||
image: redis:7-alpine |
|||
container_name: distevents-redis |
|||
ports: |
|||
- "6379:6379" |
|||
|
|||
dapr-placement: |
|||
image: daprio/dapr:1.14.4 |
|||
container_name: distevents-dapr-placement |
|||
command: ["./placement", "-port", "50006"] |
|||
ports: |
|||
- "50006:50006" |
|||
|
|||
daprd: |
|||
image: daprio/dapr:1.14.4 |
|||
container_name: distevents-daprd |
|||
depends_on: |
|||
- redis |
|||
- dapr-placement |
|||
command: |
|||
[ |
|||
"./daprd", |
|||
"--app-id", "dist-demo-dapr", |
|||
"--app-port", "8090", |
|||
"--app-channel-address", "host.docker.internal", |
|||
"--app-protocol", "http", |
|||
"--resources-path", "/components", |
|||
"--placement-host-address", "dapr-placement:50006", |
|||
"--dapr-http-port", "3500", |
|||
"--dapr-grpc-port", "50001" |
|||
] |
|||
volumes: |
|||
- ./dapr/components:/components |
|||
ports: |
|||
- "3500:3500" |
|||
- "50001:50001" |
|||
|
|||
servicebus-sql: |
|||
image: mcr.microsoft.com/azure-sql-edge:latest |
|||
container_name: distevents-servicebus-sql |
|||
environment: |
|||
ACCEPT_EULA: "Y" |
|||
MSSQL_SA_PASSWORD: "AbpDemo_123456" |
|||
|
|||
servicebus-emulator: |
|||
image: mcr.microsoft.com/azure-messaging/servicebus-emulator:latest |
|||
container_name: distevents-servicebus-emulator |
|||
depends_on: |
|||
- servicebus-sql |
|||
environment: |
|||
SQL_SERVER: servicebus-sql |
|||
MSSQL_SA_PASSWORD: "AbpDemo_123456" |
|||
ACCEPT_EULA: "Y" |
|||
volumes: |
|||
- ./servicebus-emulator/Config.json:/ServiceBus_Emulator/ConfigFiles/Config.json |
|||
ports: |
|||
- "5673:5672" |
|||
- "5300:5300" |
|||
|
|||
sqlserver: |
|||
image: mcr.microsoft.com/mssql/server:2022-latest |
|||
container_name: distevents-sqlserver |
|||
ports: |
|||
- "1433:1433" |
|||
environment: |
|||
ACCEPT_EULA: "Y" |
|||
MSSQL_SA_PASSWORD: "AbpDemo_123456" |
|||
@ -0,0 +1,22 @@ |
|||
{ |
|||
"UserConfig": { |
|||
"Namespaces": [ |
|||
{ |
|||
"Name": "sbemulatorns", |
|||
"Topics": [ |
|||
{ |
|||
"Name": "DistDemoAzureTopic", |
|||
"Subscriptions": [ |
|||
{ |
|||
"Name": "DistDemoAzureSubscriber" |
|||
} |
|||
] |
|||
} |
|||
] |
|||
} |
|||
], |
|||
"Logging": { |
|||
"Type": "File" |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue