diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 1eff521897..4b5b456a93 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -2,7 +2,8 @@ "permissions": { "allow": [ "Bash(yarn nx g:*)", - "Bash(npx vitest:*)" + "Bash(npx vitest:*)", + "Bash(git show:*)" ] } } diff --git a/test/DistEvents/.gitignore b/test/DistEvents/.gitignore new file mode 100644 index 0000000000..8dd4607a4b --- /dev/null +++ b/test/DistEvents/.gitignore @@ -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 \ No newline at end of file diff --git a/test/DistEvents/DistDemoApp.AspNetCoreDapr/DistDemoApp.AspNetCoreDapr.csproj b/test/DistEvents/DistDemoApp.AspNetCoreDapr/DistDemoApp.AspNetCoreDapr.csproj new file mode 100644 index 0000000000..8801131096 --- /dev/null +++ b/test/DistEvents/DistDemoApp.AspNetCoreDapr/DistDemoApp.AspNetCoreDapr.csproj @@ -0,0 +1,39 @@ + + + + net10.0 + enable + enable + DistDemoApp + MongoDb + + + + + + + + + + + + + + + + + + $(DefineConstants);DISTDEMO_USE_MONGODB + + + + $(DefineConstants);DISTDEMO_USE_EFCORE + + + + + Always + + + + diff --git a/test/DistEvents/DistDemoApp.AspNetCoreDapr/DistDemoAppAspNetCoreDaprModule.cs b/test/DistEvents/DistDemoApp.AspNetCoreDapr/DistDemoAppAspNetCoreDaprModule.cs new file mode 100644 index 0000000000..843a4af81b --- /dev/null +++ b/test/DistEvents/DistDemoApp.AspNetCoreDapr/DistDemoAppAspNetCoreDaprModule.cs @@ -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(options => + { + options.HttpEndpoint = "http://localhost:3500"; + }); + + Configure(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(); + }); + } +} diff --git a/test/DistEvents/DistDemoApp.AspNetCoreDapr/Program.cs b/test/DistEvents/DistDemoApp.AspNetCoreDapr/Program.cs new file mode 100644 index 0000000000..f5d3f8c8ef --- /dev/null +++ b/test/DistEvents/DistDemoApp.AspNetCoreDapr/Program.cs @@ -0,0 +1,12 @@ +using DistDemoApp; +using Dapr; +using Volo.Abp; + +var builder = WebApplication.CreateBuilder(args); +builder.Host.UseAutofac(); + +await builder.AddApplicationAsync(); + +var app = builder.Build(); +await app.InitializeApplicationAsync(); +await app.RunAsync("http://localhost:8090"); diff --git a/test/DistEvents/DistDemoApp.AspNetCoreDapr/ProviderScenarioController.cs b/test/DistEvents/DistDemoApp.AspNetCoreDapr/ProviderScenarioController.cs new file mode 100644 index 0000000000..ff6de4f5b6 --- /dev/null +++ b/test/DistEvents/DistDemoApp.AspNetCoreDapr/ProviderScenarioController.cs @@ -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 RunAsync() + { + await _scenarioRunner.RunAsync(DistEventScenarioProfile.DaprWeb()); + return Ok(new { Status = "ScenarioCompleted", Profile = "dapr-web" }); + } +} diff --git a/test/DistEvents/DistDemoApp.AspNetCoreDapr/ProviderScenarioEventHandler.cs b/test/DistEvents/DistDemoApp.AspNetCoreDapr/ProviderScenarioEventHandler.cs new file mode 100644 index 0000000000..b26844d7c5 --- /dev/null +++ b/test/DistEvents/DistDemoApp.AspNetCoreDapr/ProviderScenarioEventHandler.cs @@ -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, + ITransientDependency +{ + public Task HandleEventAsync(ProviderScenarioEvent eventData) + { + Console.WriteLine($"Dapr ASP.NET Core handler received ProviderScenarioEvent: {eventData.Value}"); + return Task.CompletedTask; + } +} diff --git a/test/DistEvents/DistDemoApp.AspNetCoreDapr/appsettings.json b/test/DistEvents/DistDemoApp.AspNetCoreDapr/appsettings.json new file mode 100644 index 0000000000..711c4a34f7 --- /dev/null +++ b/test/DistEvents/DistDemoApp.AspNetCoreDapr/appsettings.json @@ -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" + } +} diff --git a/test/DistEvents/DistDemoApp.AzureEmulator/DistDemoApp.AzureEmulator.csproj b/test/DistEvents/DistDemoApp.AzureEmulator/DistDemoApp.AzureEmulator.csproj new file mode 100644 index 0000000000..d96ef9fda5 --- /dev/null +++ b/test/DistEvents/DistDemoApp.AzureEmulator/DistDemoApp.AzureEmulator.csproj @@ -0,0 +1,37 @@ + + + + Exe + net10.0 + DistDemoApp + MongoDb + + + + + + + + + + + + + + + + + $(DefineConstants);DISTDEMO_USE_MONGODB + + + + $(DefineConstants);DISTDEMO_USE_EFCORE + + + + + Always + + + + diff --git a/test/DistEvents/DistDemoApp.AzureEmulator/DistDemoAppAzureEmulatorModule.cs b/test/DistEvents/DistDemoApp.AzureEmulator/DistDemoAppAzureEmulatorModule.cs new file mode 100644 index 0000000000..2dd0c59c36 --- /dev/null +++ b/test/DistEvents/DistDemoApp.AzureEmulator/DistDemoAppAzureEmulatorModule.cs @@ -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(); + context.Services.AddSingleton(); +#if DISTDEMO_USE_MONGODB + context.ConfigureDistDemoMongoInfrastructure(); +#else + context.ConfigureDistDemoEntityFrameworkInfrastructure(); +#endif + + Configure(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(options => + { + options.ConnectionName = "Default"; + options.SubscriberName = "DistDemoAzureSubscriber"; + options.TopicName = "DistDemoAzureTopic"; + }); + } +} diff --git a/test/DistEvents/DistDemoApp.AzureEmulator/EmulatorProcessorPool.cs b/test/DistEvents/DistDemoApp.AzureEmulator/EmulatorProcessorPool.cs new file mode 100644 index 0000000000..84891ae804 --- /dev/null +++ b/test/DistEvents/DistDemoApp.AzureEmulator/EmulatorProcessorPool.cs @@ -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 Logger { get; set; } + + private bool _isDisposed; + private readonly AbpAzureServiceBusOptions _options; + private readonly IConnectionPool _connectionPool; + private readonly ConcurrentDictionary> _processors; + + public EmulatorProcessorPool( + IOptions options, + IConnectionPool connectionPool) + { + _options = options.Value; + _connectionPool = connectionPool; + _processors = new ConcurrentDictionary>(); + Logger = NullLogger.Instance; + } + + public Task GetAsync(string subscriptionName, string topicName, string connectionName) + { + var processor = _processors.GetOrAdd( + $"{topicName}-{subscriptionName}", + new Lazy(() => + { + 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(); + } +} diff --git a/test/DistEvents/DistDemoApp.AzureEmulator/EmulatorPublisherPool.cs b/test/DistEvents/DistDemoApp.AzureEmulator/EmulatorPublisherPool.cs new file mode 100644 index 0000000000..f3c9c0a854 --- /dev/null +++ b/test/DistEvents/DistDemoApp.AzureEmulator/EmulatorPublisherPool.cs @@ -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 Logger { get; set; } + + private bool _isDisposed; + private readonly IConnectionPool _connectionPool; + private readonly ConcurrentDictionary> _publishers; + + public EmulatorPublisherPool(IConnectionPool connectionPool) + { + _connectionPool = connectionPool; + _publishers = new ConcurrentDictionary>(); + Logger = NullLogger.Instance; + } + + public Task GetAsync(string topicName, string? connectionName) + { + var sender = _publishers.GetOrAdd( + topicName, + new Lazy(() => + { + 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(); + } +} diff --git a/test/DistEvents/DistDemoApp.AzureEmulator/Program.cs b/test/DistEvents/DistDemoApp.AzureEmulator/Program.cs new file mode 100644 index 0000000000..a5375dad49 --- /dev/null +++ b/test/DistEvents/DistDemoApp.AzureEmulator/Program.cs @@ -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(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() + .RunAsync(DistEventScenarioProfile.AzureEmulator())); + + application.Shutdown(); + } +} diff --git a/test/DistEvents/DistDemoApp.AzureEmulator/appsettings.json b/test/DistEvents/DistDemoApp.AzureEmulator/appsettings.json new file mode 100644 index 0000000000..4502f1e483 --- /dev/null +++ b/test/DistEvents/DistDemoApp.AzureEmulator/appsettings.json @@ -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" + } +} diff --git a/test/DistEvents/DistDemoApp.EfCoreRabbitMq/DistDemoApp.EfCoreRabbitMq.csproj b/test/DistEvents/DistDemoApp.EfCoreRabbitMq/DistDemoApp.EfCoreRabbitMq.csproj index c3b8719b3f..156de09a79 100644 --- a/test/DistEvents/DistDemoApp.EfCoreRabbitMq/DistDemoApp.EfCoreRabbitMq.csproj +++ b/test/DistEvents/DistDemoApp.EfCoreRabbitMq/DistDemoApp.EfCoreRabbitMq.csproj @@ -4,14 +4,30 @@ Exe net10.0 DistDemoApp + EntityFrameworkCore - + + + + + + + + + + $(DefineConstants);DISTDEMO_USE_MONGODB + + + + $(DefineConstants);DISTDEMO_USE_EFCORE + + runtime; build; native; contentfiles; analyzers diff --git a/test/DistEvents/DistDemoApp.EfCoreRabbitMq/DistDemoAppEfCoreRabbitMqModule.cs b/test/DistEvents/DistDemoApp.EfCoreRabbitMq/DistDemoAppEfCoreRabbitMqModule.cs index da2e7a1445..363373441d 100644 --- a/test/DistEvents/DistDemoApp.EfCoreRabbitMq/DistDemoAppEfCoreRabbitMqModule.cs +++ b/test/DistEvents/DistDemoApp.EfCoreRabbitMq/DistDemoAppEfCoreRabbitMqModule.cs @@ -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(options => +#if DISTDEMO_USE_MONGODB + context.ConfigureDistDemoMongoInfrastructure(); +#else + context.ConfigureDistDemoEntityFrameworkInfrastructure(); +#endif + + Configure(options => { - options.AddDefaultRepositories(); + // options.Outboxes.Configure(config => + // { + // config.UseDbContext(); + // }); + // + // options.Inboxes.Configure(config => + // { + // config.UseDbContext(); + // }); }); - Configure(options => + Configure(options => { - options.UseSqlServer(); + options.Connections.Default.HostName = "localhost"; }); - - Configure(options => + + Configure(options => { - options.Outboxes.Configure(config => - { - config.UseDbContext(); - }); - - options.Inboxes.Configure(config => - { - config.UseDbContext(); - }); + options.ConnectionName = "Default"; + options.ClientName = "DistDemoApp"; + options.ExchangeName = "DistDemo"; }); + } } } \ No newline at end of file diff --git a/test/DistEvents/DistDemoApp.EfCoreRabbitMq/Migrations/20260304073807_Update-10.2.Designer.cs b/test/DistEvents/DistDemoApp.EfCoreRabbitMq/Migrations/20260304073807_Update-10.2.Designer.cs new file mode 100644 index 0000000000..718cebec33 --- /dev/null +++ b/test/DistEvents/DistDemoApp.EfCoreRabbitMq/Migrations/20260304073807_Update-10.2.Designer.cs @@ -0,0 +1,182 @@ +// +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 + { + /// + 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("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Text") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.HasKey("Id"); + + b.ToTable("TodoItems"); + }); + + modelBuilder.Entity("DistDemoApp.TodoSummary", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("Day") + .HasColumnType("tinyint"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Month") + .HasColumnType("tinyint"); + + b.Property("TotalCount") + .HasColumnType("int"); + + b.Property("Year") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("TodoSummaries"); + }); + + modelBuilder.Entity("Volo.Abp.EntityFrameworkCore.DistributedEvents.IncomingEventRecord", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("EventData") + .IsRequired() + .HasColumnType("varbinary(max)"); + + b.Property("EventName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("HandledTime") + .HasColumnType("datetime2"); + + b.Property("MessageId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("NextRetryTime") + .HasColumnType("datetime2"); + + b.Property("RetryCount") + .HasColumnType("int"); + + b.Property("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("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("EventData") + .IsRequired() + .HasColumnType("varbinary(max)"); + + b.Property("EventName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.HasKey("Id"); + + b.HasIndex("CreationTime"); + + b.ToTable("AbpEventOutbox", (string)null); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/test/DistEvents/DistDemoApp.EfCoreRabbitMq/Migrations/20260304073807_Update-10.2.cs b/test/DistEvents/DistDemoApp.EfCoreRabbitMq/Migrations/20260304073807_Update-10.2.cs new file mode 100644 index 0000000000..a3bcf90174 --- /dev/null +++ b/test/DistEvents/DistDemoApp.EfCoreRabbitMq/Migrations/20260304073807_Update-10.2.cs @@ -0,0 +1,233 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace DistDemoApp.Migrations +{ + /// + public partial class Update102 : Migration + { + /// + 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( + name: "ExtraProperties", + table: "TodoSummaries", + type: "nvarchar(max)", + nullable: false, + defaultValue: "", + oldClrType: typeof(string), + oldType: "nvarchar(max)", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "ConcurrencyStamp", + table: "TodoSummaries", + type: "nvarchar(40)", + maxLength: 40, + nullable: false, + defaultValue: "", + oldClrType: typeof(string), + oldType: "nvarchar(40)", + oldMaxLength: 40, + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "ExtraProperties", + table: "TodoItems", + type: "nvarchar(max)", + nullable: false, + defaultValue: "", + oldClrType: typeof(string), + oldType: "nvarchar(max)", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "ConcurrencyStamp", + table: "TodoItems", + type: "nvarchar(40)", + maxLength: 40, + nullable: false, + defaultValue: "", + oldClrType: typeof(string), + oldType: "nvarchar(40)", + oldMaxLength: 40, + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "ExtraProperties", + table: "AbpEventOutbox", + type: "nvarchar(max)", + nullable: false, + defaultValue: "", + oldClrType: typeof(string), + oldType: "nvarchar(max)", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "MessageId", + table: "AbpEventInbox", + type: "nvarchar(450)", + nullable: false, + defaultValue: "", + oldClrType: typeof(string), + oldType: "nvarchar(450)", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "ExtraProperties", + table: "AbpEventInbox", + type: "nvarchar(max)", + nullable: false, + defaultValue: "", + oldClrType: typeof(string), + oldType: "nvarchar(max)", + oldNullable: true); + + migrationBuilder.AddColumn( + name: "HandledTime", + table: "AbpEventInbox", + type: "datetime2", + nullable: true); + + migrationBuilder.AddColumn( + name: "RetryCount", + table: "AbpEventInbox", + type: "int", + nullable: false, + defaultValue: 0); + + migrationBuilder.AddColumn( + 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" }); + } + + /// + 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( + name: "ExtraProperties", + table: "TodoSummaries", + type: "nvarchar(max)", + nullable: true, + oldClrType: typeof(string), + oldType: "nvarchar(max)"); + + migrationBuilder.AlterColumn( + name: "ConcurrencyStamp", + table: "TodoSummaries", + type: "nvarchar(40)", + maxLength: 40, + nullable: true, + oldClrType: typeof(string), + oldType: "nvarchar(40)", + oldMaxLength: 40); + + migrationBuilder.AlterColumn( + name: "ExtraProperties", + table: "TodoItems", + type: "nvarchar(max)", + nullable: true, + oldClrType: typeof(string), + oldType: "nvarchar(max)"); + + migrationBuilder.AlterColumn( + name: "ConcurrencyStamp", + table: "TodoItems", + type: "nvarchar(40)", + maxLength: 40, + nullable: true, + oldClrType: typeof(string), + oldType: "nvarchar(40)", + oldMaxLength: 40); + + migrationBuilder.AlterColumn( + name: "ExtraProperties", + table: "AbpEventOutbox", + type: "nvarchar(max)", + nullable: true, + oldClrType: typeof(string), + oldType: "nvarchar(max)"); + + migrationBuilder.AlterColumn( + name: "MessageId", + table: "AbpEventInbox", + type: "nvarchar(450)", + nullable: true, + oldClrType: typeof(string), + oldType: "nvarchar(450)"); + + migrationBuilder.AlterColumn( + name: "ExtraProperties", + table: "AbpEventInbox", + type: "nvarchar(max)", + nullable: true, + oldClrType: typeof(string), + oldType: "nvarchar(max)"); + + migrationBuilder.AddColumn( + name: "Processed", + table: "AbpEventInbox", + type: "bit", + nullable: false, + defaultValue: false); + + migrationBuilder.CreateIndex( + name: "IX_AbpEventInbox_Processed_CreationTime", + table: "AbpEventInbox", + columns: new[] { "Processed", "CreationTime" }); + } + } +} diff --git a/test/DistEvents/DistDemoApp.EfCoreRabbitMq/Migrations/TodoDbContextModelSnapshot.cs b/test/DistEvents/DistDemoApp.EfCoreRabbitMq/Migrations/TodoDbContextModelSnapshot.cs index 57e8c14442..1f12a89a1c 100644 --- a/test/DistEvents/DistDemoApp.EfCoreRabbitMq/Migrations/TodoDbContextModelSnapshot.cs +++ b/test/DistEvents/DistDemoApp.EfCoreRabbitMq/Migrations/TodoDbContextModelSnapshot.cs @@ -7,6 +7,8 @@ using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Volo.Abp.EntityFrameworkCore; +#nullable disable + namespace DistDemoApp.Migrations { [DbContext(typeof(TodoDbContext))] @@ -17,9 +19,10 @@ namespace DistDemoApp.Migrations #pragma warning disable 612, 618 modelBuilder .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.SqlServer) - .HasAnnotation("Relational:MaxIdentifierLength", 128) - .HasAnnotation("ProductVersion", "5.0.9") - .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + .HasAnnotation("ProductVersion", "10.0.2") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); modelBuilder.Entity("DistDemoApp.TodoItem", b => { @@ -28,6 +31,7 @@ namespace DistDemoApp.Migrations b.Property("ConcurrencyStamp") .IsConcurrencyToken() + .IsRequired() .HasMaxLength(40) .HasColumnType("nvarchar(40)") .HasColumnName("ConcurrencyStamp"); @@ -41,6 +45,7 @@ namespace DistDemoApp.Migrations .HasColumnName("CreatorId"); b.Property("ExtraProperties") + .IsRequired() .HasColumnType("nvarchar(max)") .HasColumnName("ExtraProperties"); @@ -58,11 +63,13 @@ namespace DistDemoApp.Migrations { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("int") - .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); b.Property("ConcurrencyStamp") .IsConcurrencyToken() + .IsRequired() .HasMaxLength(40) .HasColumnType("nvarchar(40)") .HasColumnName("ConcurrencyStamp"); @@ -71,6 +78,7 @@ namespace DistDemoApp.Migrations .HasColumnType("tinyint"); b.Property("ExtraProperties") + .IsRequired() .HasColumnType("nvarchar(max)") .HasColumnName("ExtraProperties"); @@ -107,25 +115,33 @@ namespace DistDemoApp.Migrations .HasColumnType("nvarchar(256)"); b.Property("ExtraProperties") + .IsRequired() .HasColumnType("nvarchar(max)") .HasColumnName("ExtraProperties"); + b.Property("HandledTime") + .HasColumnType("datetime2"); + b.Property("MessageId") + .IsRequired() .HasColumnType("nvarchar(450)"); - b.Property("Processed") - .HasColumnType("bit"); - - b.Property("ProcessedTime") + b.Property("NextRetryTime") .HasColumnType("datetime2"); + b.Property("RetryCount") + .HasColumnType("int"); + + b.Property("Status") + .HasColumnType("int"); + b.HasKey("Id"); b.HasIndex("MessageId"); - b.HasIndex("Processed", "CreationTime"); + b.HasIndex("Status", "CreationTime"); - b.ToTable("AbpEventInbox"); + b.ToTable("AbpEventInbox", (string)null); }); modelBuilder.Entity("Volo.Abp.EntityFrameworkCore.DistributedEvents.OutgoingEventRecord", b => @@ -147,12 +163,15 @@ namespace DistDemoApp.Migrations .HasColumnType("nvarchar(256)"); b.Property("ExtraProperties") + .IsRequired() .HasColumnType("nvarchar(max)") .HasColumnName("ExtraProperties"); b.HasKey("Id"); - b.ToTable("AbpEventOutbox"); + b.HasIndex("CreationTime"); + + b.ToTable("AbpEventOutbox", (string)null); }); #pragma warning restore 612, 618 } diff --git a/test/DistEvents/DistDemoApp.EfCoreRabbitMq/Program.cs b/test/DistEvents/DistDemoApp.EfCoreRabbitMq/Program.cs index 597b29ae22..3cee486e96 100644 --- a/test/DistEvents/DistDemoApp.EfCoreRabbitMq/Program.cs +++ b/test/DistEvents/DistDemoApp.EfCoreRabbitMq/Program.cs @@ -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 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(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().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(); - }); + application.Shutdown(); + } + } } } diff --git a/test/DistEvents/DistDemoApp.EfCoreRabbitMq/TodoDbContext.cs b/test/DistEvents/DistDemoApp.EfCoreRabbitMq/TodoDbContext.cs deleted file mode 100644 index 5a1ddd2c3f..0000000000 --- a/test/DistEvents/DistDemoApp.EfCoreRabbitMq/TodoDbContext.cs +++ /dev/null @@ -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, IHasEventOutbox, IHasEventInbox - { - public DbSet TodoItems { get; set; } - public DbSet TodoSummaries { get; set; } - public DbSet OutgoingEvents { get; set; } - public DbSet IncomingEvents { get; set; } - - public TodoDbContext(DbContextOptions options) - : base(options) - { - - } - - protected override void OnModelCreating(ModelBuilder modelBuilder) - { - base.OnModelCreating(modelBuilder); - - modelBuilder.ConfigureEventOutbox(); - modelBuilder.ConfigureEventInbox(); - - modelBuilder.Entity(b => - { - b.Property(x => x.Text).IsRequired().HasMaxLength(128); - }); - } - } -} \ No newline at end of file diff --git a/test/DistEvents/DistDemoApp.EfCoreRabbitMq/TodoDbContextFactory.cs b/test/DistEvents/DistDemoApp.EfCoreRabbitMq/TodoDbContextFactory.cs deleted file mode 100644 index 97be637acc..0000000000 --- a/test/DistEvents/DistDemoApp.EfCoreRabbitMq/TodoDbContextFactory.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System.IO; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Design; -using Microsoft.Extensions.Configuration; - -namespace DistDemoApp -{ - public class TodoDbContextFactory : IDesignTimeDbContextFactory - { - public TodoDbContext CreateDbContext(string[] args) - { - var configuration = BuildConfiguration(); - - var builder = new DbContextOptionsBuilder() - .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(); - } - } -} \ No newline at end of file diff --git a/test/DistEvents/DistDemoApp.EfCoreRabbitMq/appsettings.json b/test/DistEvents/DistDemoApp.EfCoreRabbitMq/appsettings.json index 393be04a6c..91cc668167 100644 --- a/test/DistEvents/DistDemoApp.EfCoreRabbitMq/appsettings.json +++ b/test/DistEvents/DistDemoApp.EfCoreRabbitMq/appsettings.json @@ -1,6 +1,6 @@ { "ConnectionStrings": { - "Default": "Server=(LocalDb)\\MSSQLLocalDB;Database=DistEventsDemo;Trusted_Connection=True;TrustServerCertificate=True" + "Default": "Server=localhost,1433;Database=DistEventsDemo;User Id=sa;Password=AbpDemo_123456;TrustServerCertificate=True" }, "RabbitMQ": { "Connections": { diff --git a/test/DistEvents/DistDemoApp.MongoDbKafka/DistDemoApp.MongoDbKafka.csproj b/test/DistEvents/DistDemoApp.MongoDbKafka/DistDemoApp.MongoDbKafka.csproj index abeb206500..ad384a51dd 100644 --- a/test/DistEvents/DistDemoApp.MongoDbKafka/DistDemoApp.MongoDbKafka.csproj +++ b/test/DistEvents/DistDemoApp.MongoDbKafka/DistDemoApp.MongoDbKafka.csproj @@ -4,14 +4,30 @@ Exe net10.0 DistDemoApp + MongoDb - + + + + + + + + + + $(DefineConstants);DISTDEMO_USE_MONGODB + + + + $(DefineConstants);DISTDEMO_USE_EFCORE + + Always diff --git a/test/DistEvents/DistDemoApp.MongoDbKafka/DistDemoAppMongoDbKafkaModule.cs b/test/DistEvents/DistDemoApp.MongoDbKafka/DistDemoAppMongoDbKafkaModule.cs index b2e41b6ca7..b9439da27b 100644 --- a/test/DistEvents/DistDemoApp.MongoDbKafka/DistDemoAppMongoDbKafkaModule.cs +++ b/test/DistEvents/DistDemoApp.MongoDbKafka/DistDemoAppMongoDbKafkaModule.cs @@ -1,37 +1,42 @@ -using Microsoft.Extensions.DependencyInjection; -using Volo.Abp.EventBus.Distributed; using Volo.Abp.EventBus.Kafka; +using Volo.Abp.Kafka; using Volo.Abp.Modularity; -using Volo.Abp.MongoDB; -using Volo.Abp.MongoDB.DistributedEvents; namespace DistDemoApp { +#if DISTDEMO_USE_MONGODB [DependsOn( - typeof(AbpMongoDbModule), + typeof(DistDemoAppMongoDbInfrastructureModule), typeof(AbpEventBusKafkaModule), typeof(DistDemoAppSharedModule) )] +#else + [DependsOn( + typeof(DistDemoAppEntityFrameworkCoreInfrastructureModule), + typeof(AbpEventBusKafkaModule), + typeof(DistDemoAppSharedModule) + )] +#endif public class DistDemoAppMongoDbKafkaModule : AbpModule { public override void ConfigureServices(ServiceConfigurationContext context) { - context.Services.AddMongoDbContext(options => +#if DISTDEMO_USE_MONGODB + context.ConfigureDistDemoMongoInfrastructure(); +#else + context.ConfigureDistDemoEntityFrameworkInfrastructure(); +#endif + + Configure(options => { - options.AddDefaultRepositories(); + options.Connections.Default.BootstrapServers = "localhost:9092"; }); - Configure(options => + Configure(options => { - options.Outboxes.Configure(config => - { - config.UseMongoDbContext(); - }); - - options.Inboxes.Configure(config => - { - config.UseMongoDbContext(); - }); + options.ConnectionName = "Default"; + options.TopicName = "DistDemoTopic"; + options.GroupId = "DistDemoApp"; }); } } diff --git a/test/DistEvents/DistDemoApp.MongoDbKafka/Program.cs b/test/DistEvents/DistDemoApp.MongoDbKafka/Program.cs index b048c17389..4d324bce0a 100644 --- a/test/DistEvents/DistDemoApp.MongoDbKafka/Program.cs +++ b/test/DistEvents/DistDemoApp.MongoDbKafka/Program.cs @@ -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 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(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().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(); - }); } } diff --git a/test/DistEvents/DistDemoApp.MongoDbKafka/TodoMongoDbContext.cs b/test/DistEvents/DistDemoApp.MongoDbKafka/TodoMongoDbContext.cs deleted file mode 100644 index a7f1b78f86..0000000000 --- a/test/DistEvents/DistDemoApp.MongoDbKafka/TodoMongoDbContext.cs +++ /dev/null @@ -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 TodoItems => Collection(); - public IMongoCollection TodoSummaries => Collection(); - - public IMongoCollection OutgoingEvents - { - get => Collection(); - set {} - } - public IMongoCollection IncomingEvents - { - get => Collection(); - set {} - } - } - -} diff --git a/test/DistEvents/DistDemoApp.MongoDbKafka/appsettings.json b/test/DistEvents/DistDemoApp.MongoDbKafka/appsettings.json index f9ee345d5a..d6d1351b25 100644 --- a/test/DistEvents/DistDemoApp.MongoDbKafka/appsettings.json +++ b/test/DistEvents/DistDemoApp.MongoDbKafka/appsettings.json @@ -1,6 +1,6 @@ { "ConnectionStrings": { - "Default": "mongodb://localhost:27018,localhost:27019,localhost:27020/DistEventsDemo" + "Default": "mongodb://localhost:27017/DistEventsDemo?retryWrites=false" }, "Kafka": { "Connections": { diff --git a/test/DistEvents/DistDemoApp.MongoDbRebus/DistDemoApp.MongoDbRebus.csproj b/test/DistEvents/DistDemoApp.MongoDbRebus/DistDemoApp.MongoDbRebus.csproj index 0b04220e3e..49b6d118d2 100644 --- a/test/DistEvents/DistDemoApp.MongoDbRebus/DistDemoApp.MongoDbRebus.csproj +++ b/test/DistEvents/DistDemoApp.MongoDbRebus/DistDemoApp.MongoDbRebus.csproj @@ -4,14 +4,30 @@ Exe net10.0 DistDemoApp + MongoDb - + + + + + + + + + + $(DefineConstants);DISTDEMO_USE_MONGODB + + + + $(DefineConstants);DISTDEMO_USE_EFCORE + + Always diff --git a/test/DistEvents/DistDemoApp.MongoDbRebus/DistDemoAppMongoDbRebusModule.cs b/test/DistEvents/DistDemoApp.MongoDbRebus/DistDemoAppMongoDbRebusModule.cs index 21dab7b9b5..702ffc3f62 100644 --- a/test/DistEvents/DistDemoApp.MongoDbRebus/DistDemoAppMongoDbRebusModule.cs +++ b/test/DistEvents/DistDemoApp.MongoDbRebus/DistDemoAppMongoDbRebusModule.cs @@ -1,19 +1,22 @@ -using Microsoft.Extensions.DependencyInjection; -using Rebus.Persistence.InMem; using Rebus.Transport.InMem; -using Volo.Abp.EventBus.Distributed; using Volo.Abp.EventBus.Rebus; using Volo.Abp.Modularity; -using Volo.Abp.MongoDB; -using Volo.Abp.MongoDB.DistributedEvents; namespace DistDemoApp { +#if DISTDEMO_USE_MONGODB [DependsOn( - typeof(AbpMongoDbModule), + typeof(DistDemoAppMongoDbInfrastructureModule), typeof(AbpEventBusRebusModule), typeof(DistDemoAppSharedModule) )] +#else + [DependsOn( + typeof(DistDemoAppEntityFrameworkCoreInfrastructureModule), + typeof(AbpEventBusRebusModule), + typeof(DistDemoAppSharedModule) + )] +#endif public class DistDemoAppMongoDbRebusModule : AbpModule { public override void PreConfigureServices(ServiceConfigurationContext context) @@ -24,30 +27,17 @@ namespace DistDemoApp options.Configurer = rebusConfigurer => { rebusConfigurer.Transport(t => t.UseInMemoryTransport(new InMemNetwork(), "eventbus")); - rebusConfigurer.Subscriptions(s => s.StoreInMemory()); }; }); } public override void ConfigureServices(ServiceConfigurationContext context) { - context.Services.AddMongoDbContext(options => - { - options.AddDefaultRepositories(); - }); - - Configure(options => - { - options.Outboxes.Configure(config => - { - config.UseMongoDbContext(); - }); - - options.Inboxes.Configure(config => - { - config.UseMongoDbContext(); - }); - }); +#if DISTDEMO_USE_MONGODB + context.ConfigureDistDemoMongoInfrastructure(); +#else + context.ConfigureDistDemoEntityFrameworkInfrastructure(); +#endif } } } diff --git a/test/DistEvents/DistDemoApp.MongoDbRebus/Program.cs b/test/DistEvents/DistDemoApp.MongoDbRebus/Program.cs index 9f8c1e6c56..17a11b5f17 100644 --- a/test/DistEvents/DistDemoApp.MongoDbRebus/Program.cs +++ b/test/DistEvents/DistDemoApp.MongoDbRebus/Program.cs @@ -1,9 +1,5 @@ -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; @@ -13,48 +9,16 @@ namespace DistDemoApp { 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 -// { -// Log.CloseAndFlush(); -// } - using (var application = AbpApplicationFactory.Create(options => { options.UseAutofac(); - options.Services.AddSerilog((serviceProvider, c) => + options.Services.AddSerilog((_, _) => { - // c.Enrich.FromLogContext() - // .WriteTo.Async(c => c.File("Logs/logs.txt")) - // .WriteTo.Async(c => c.Console()) - // .WriteTo.AbpStudio(serviceProvider); }); options.Services.AddLogging(c => c.AddSerilog()); })) { - Log.Information("Starting Volo.AbpIo.DbMigrator."); + Log.Information("Starting DistDemoApp.MongoDbRebus."); application.Initialize(); @@ -68,18 +32,5 @@ namespace DistDemoApp } } - - internal static IHostBuilder CreateHostBuilder(string[] args) => - Host.CreateDefaultBuilder(args) - .UseAutofac() - .UseSerilog() - .ConfigureAppConfiguration((context, config) => - { - //setup your additional configuration sources - }) - .ConfigureServices((hostContext, services) => - { - services.AddApplication(); - }); } } diff --git a/test/DistEvents/DistDemoApp.MongoDbRebus/TodoMongoDbContext.cs b/test/DistEvents/DistDemoApp.MongoDbRebus/TodoMongoDbContext.cs deleted file mode 100644 index 95370bb4d2..0000000000 --- a/test/DistEvents/DistDemoApp.MongoDbRebus/TodoMongoDbContext.cs +++ /dev/null @@ -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 TodoItems => Collection(); - public IMongoCollection TodoSummaries => Collection(); - - public IMongoCollection OutgoingEvents => Collection(); - - public IMongoCollection IncomingEvents => Collection(); - } - -} diff --git a/test/DistEvents/DistDemoApp.MongoDbRebus/appsettings.json b/test/DistEvents/DistDemoApp.MongoDbRebus/appsettings.json index f9ee345d5a..d6d1351b25 100644 --- a/test/DistEvents/DistDemoApp.MongoDbRebus/appsettings.json +++ b/test/DistEvents/DistDemoApp.MongoDbRebus/appsettings.json @@ -1,6 +1,6 @@ { "ConnectionStrings": { - "Default": "mongodb://localhost:27018,localhost:27019,localhost:27020/DistEventsDemo" + "Default": "mongodb://localhost:27017/DistEventsDemo?retryWrites=false" }, "Kafka": { "Connections": { diff --git a/test/DistEvents/DistDemoApp.Persistence.EntityFrameworkCore/DistDemoApp.Persistence.EntityFrameworkCore.csproj b/test/DistEvents/DistDemoApp.Persistence.EntityFrameworkCore/DistDemoApp.Persistence.EntityFrameworkCore.csproj new file mode 100644 index 0000000000..2adc9e976e --- /dev/null +++ b/test/DistEvents/DistDemoApp.Persistence.EntityFrameworkCore/DistDemoApp.Persistence.EntityFrameworkCore.csproj @@ -0,0 +1,18 @@ + + + + net10.0 + DistDemoApp + EntityFrameworkCore + + + + + + + + + + + + diff --git a/test/DistEvents/DistDemoApp.Persistence.EntityFrameworkCore/DistDemoAppEntityFrameworkCoreInfrastructureModule.cs b/test/DistEvents/DistDemoApp.Persistence.EntityFrameworkCore/DistDemoAppEntityFrameworkCoreInfrastructureModule.cs new file mode 100644 index 0000000000..1c7c094953 --- /dev/null +++ b/test/DistEvents/DistDemoApp.Persistence.EntityFrameworkCore/DistDemoAppEntityFrameworkCoreInfrastructureModule.cs @@ -0,0 +1,12 @@ +using Volo.Abp.EntityFrameworkCore.SqlServer; +using Volo.Abp.Modularity; + +namespace DistDemoApp; + +[DependsOn( + typeof(AbpEntityFrameworkCoreSqlServerModule), + typeof(DistDemoAppSharedModule) +)] +public class DistDemoAppEntityFrameworkCoreInfrastructureModule : AbpModule +{ +} diff --git a/test/DistEvents/DistDemoApp.Persistence.EntityFrameworkCore/DistDemoEntityFrameworkServiceCollectionExtensions.cs b/test/DistEvents/DistDemoApp.Persistence.EntityFrameworkCore/DistDemoEntityFrameworkServiceCollectionExtensions.cs new file mode 100644 index 0000000000..f2aa5f874e --- /dev/null +++ b/test/DistEvents/DistDemoApp.Persistence.EntityFrameworkCore/DistDemoEntityFrameworkServiceCollectionExtensions.cs @@ -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(options => + { + options.AddDefaultRepositories(); + }); + + context.Services.Configure(options => + { + options.UseSqlServer(); + }); + } +} diff --git a/test/DistEvents/DistDemoApp.Persistence.EntityFrameworkCore/TodoDbContext.cs b/test/DistEvents/DistDemoApp.Persistence.EntityFrameworkCore/TodoDbContext.cs new file mode 100644 index 0000000000..a352e4a5b0 --- /dev/null +++ b/test/DistEvents/DistDemoApp.Persistence.EntityFrameworkCore/TodoDbContext.cs @@ -0,0 +1,34 @@ +using Microsoft.EntityFrameworkCore; +using Volo.Abp.EntityFrameworkCore; +using Volo.Abp.EntityFrameworkCore.DistributedEvents; + +namespace DistDemoApp; + +public class TodoDbContext : AbpDbContext, IHasEventOutbox, IHasEventInbox +{ + public DbSet TodoItems { get; set; } = null!; + + public DbSet TodoSummaries { get; set; } = null!; + + public DbSet OutgoingEvents { get; set; } = null!; + + public DbSet IncomingEvents { get; set; } = null!; + + public TodoDbContext(DbContextOptions options) + : base(options) + { + } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + base.OnModelCreating(modelBuilder); + + modelBuilder.ConfigureEventOutbox(); + modelBuilder.ConfigureEventInbox(); + + modelBuilder.Entity(b => + { + b.Property(x => x.Text).IsRequired().HasMaxLength(128); + }); + } +} diff --git a/test/DistEvents/DistDemoApp.Persistence.EntityFrameworkCore/TodoDbContextFactory.cs b/test/DistEvents/DistDemoApp.Persistence.EntityFrameworkCore/TodoDbContextFactory.cs new file mode 100644 index 0000000000..082c85bb29 --- /dev/null +++ b/test/DistEvents/DistDemoApp.Persistence.EntityFrameworkCore/TodoDbContextFactory.cs @@ -0,0 +1,28 @@ +using System.IO; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Design; +using Microsoft.Extensions.Configuration; + +namespace DistDemoApp; + +public class TodoDbContextFactory : IDesignTimeDbContextFactory +{ + public TodoDbContext CreateDbContext(string[] args) + { + var configuration = BuildConfiguration(); + + var builder = new DbContextOptionsBuilder() + .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(); + } +} diff --git a/test/DistEvents/DistDemoApp.Persistence.MongoDb/DistDemoApp.Persistence.MongoDb.csproj b/test/DistEvents/DistDemoApp.Persistence.MongoDb/DistDemoApp.Persistence.MongoDb.csproj new file mode 100644 index 0000000000..8c9e3e14c5 --- /dev/null +++ b/test/DistEvents/DistDemoApp.Persistence.MongoDb/DistDemoApp.Persistence.MongoDb.csproj @@ -0,0 +1,14 @@ + + + + net10.0 + DistDemoApp + MongoDb + + + + + + + + diff --git a/test/DistEvents/DistDemoApp.Persistence.MongoDb/DistDemoAppMongoDbInfrastructureModule.cs b/test/DistEvents/DistDemoApp.Persistence.MongoDb/DistDemoAppMongoDbInfrastructureModule.cs new file mode 100644 index 0000000000..390badca6f --- /dev/null +++ b/test/DistEvents/DistDemoApp.Persistence.MongoDb/DistDemoAppMongoDbInfrastructureModule.cs @@ -0,0 +1,12 @@ +using Volo.Abp.Modularity; +using Volo.Abp.MongoDB; + +namespace DistDemoApp; + +[DependsOn( + typeof(AbpMongoDbModule), + typeof(DistDemoAppSharedModule) +)] +public class DistDemoAppMongoDbInfrastructureModule : AbpModule +{ +} diff --git a/test/DistEvents/DistDemoApp.Persistence.MongoDb/DistDemoMongoDbContext.cs b/test/DistEvents/DistDemoApp.Persistence.MongoDb/DistDemoMongoDbContext.cs new file mode 100644 index 0000000000..4c63400dc3 --- /dev/null +++ b/test/DistEvents/DistDemoApp.Persistence.MongoDb/DistDemoMongoDbContext.cs @@ -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 TodoItems => Collection(); + + public IMongoCollection TodoSummaries => Collection(); + + public IMongoCollection OutgoingEvents + { + get => Collection(); + set { } + } + + public IMongoCollection IncomingEvents + { + get => Collection(); + set { } + } +} diff --git a/test/DistEvents/DistDemoApp.Persistence.MongoDb/DistDemoMongoServiceCollectionExtensions.cs b/test/DistEvents/DistDemoApp.Persistence.MongoDb/DistDemoMongoServiceCollectionExtensions.cs new file mode 100644 index 0000000000..48a8285b54 --- /dev/null +++ b/test/DistEvents/DistDemoApp.Persistence.MongoDb/DistDemoMongoServiceCollectionExtensions.cs @@ -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(options => + { + options.AddDefaultRepositories(); + }); + + context.Services.Configure(options => + { + if (string.IsNullOrWhiteSpace(options.ConnectionStrings.Default)) + { + options.ConnectionStrings.Default = DefaultMongoConnectionString; + } + }); + + context.Services.Configure(options => + { + options.Outboxes.Configure(config => + { + config.UseMongoDbContext(); + }); + + options.Inboxes.Configure(config => + { + config.UseMongoDbContext(); + }); + }); + } +} diff --git a/test/DistEvents/DistDemoApp.Shared/DemoService.cs b/test/DistEvents/DistDemoApp.Shared/DemoService.cs index c970485252..cc6d6f64c6 100644 --- a/test/DistEvents/DistDemoApp.Shared/DemoService.cs +++ b/test/DistEvents/DistDemoApp.Shared/DemoService.cs @@ -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 _todoItemRepository; + private readonly IDistEventScenarioRunner _scenarioRunner; - public DemoService(IRepository 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()); } } } \ No newline at end of file diff --git a/test/DistEvents/DistDemoApp.Shared/DistDemoAppHostedService.cs b/test/DistEvents/DistDemoApp.Shared/DistDemoAppHostedService.cs index ba72d6902a..90f27cb638 100644 --- a/test/DistEvents/DistDemoApp.Shared/DistDemoAppHostedService.cs +++ b/test/DistEvents/DistDemoApp.Shared/DistDemoAppHostedService.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Hosting; @@ -11,21 +11,22 @@ namespace DistDemoApp private readonly IAbpApplicationWithExternalServiceProvider _application; private readonly IServiceProvider _serviceProvider; private readonly DemoService _demoService; + private readonly IHostApplicationLifetime _hostApplicationLifetime; public DistDemoAppHostedService( IAbpApplicationWithExternalServiceProvider application, IServiceProvider serviceProvider, - DemoService demoService) + DemoService demoService, + IHostApplicationLifetime hostApplicationLifetime) { _application = application; _serviceProvider = serviceProvider; _demoService = demoService; + _hostApplicationLifetime = hostApplicationLifetime; } public async Task StartAsync(CancellationToken cancellationToken) { - _application.Initialize(_serviceProvider); - await _demoService.CreateTodoItemAsync(); } diff --git a/test/DistEvents/DistDemoApp.Shared/DistDemoAppSharedModule.cs b/test/DistEvents/DistDemoApp.Shared/DistDemoAppSharedModule.cs index 936264e828..09c458bf85 100644 --- a/test/DistEvents/DistDemoApp.Shared/DistDemoAppSharedModule.cs +++ b/test/DistEvents/DistDemoApp.Shared/DistDemoAppSharedModule.cs @@ -1,4 +1,4 @@ -using Medallion.Threading; +using Medallion.Threading; using Medallion.Threading.Redis; using Microsoft.Extensions.DependencyInjection; using StackExchange.Redis; @@ -21,7 +21,7 @@ namespace DistDemoApp { var configuration = context.Services.GetConfiguration(); - context.Services.AddHostedService(); + // context.Services.AddHostedService(); Configure(options => { diff --git a/test/DistEvents/DistDemoApp.Shared/DistEventScenarioProfile.cs b/test/DistEvents/DistDemoApp.Shared/DistEventScenarioProfile.cs new file mode 100644 index 0000000000..5dc360cfe9 --- /dev/null +++ b/test/DistEvents/DistDemoApp.Shared/DistEventScenarioProfile.cs @@ -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 + }; + } +} diff --git a/test/DistEvents/DistDemoApp.Shared/DistEventScenarioRunner.cs b/test/DistEvents/DistDemoApp.Shared/DistEventScenarioRunner.cs new file mode 100644 index 0000000000..a9601335f8 --- /dev/null +++ b/test/DistEvents/DistDemoApp.Shared/DistEventScenarioRunner.cs @@ -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(); + + var typedFromTypedPublish = profile.EnableTypedFromTypedScenario + ? new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously) + : null; + var typedFromAnonymousPublish = profile.EnableTypedFromAnonymousScenario + ? new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously) + : null; + var anonymousOnlyPublish = profile.EnableAnonymousOnlyScenario + ? new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously) + : null; + + using var typedSubscription = _distributedEventBus.Subscribe(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(eventData => + { + var converted = eventData.ConvertToTypedObject(); + if (converted is Dictionary 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); + } + } +} diff --git a/test/DistEvents/DistDemoApp.Shared/IDistEventScenarioRunner.cs b/test/DistEvents/DistDemoApp.Shared/IDistEventScenarioRunner.cs new file mode 100644 index 0000000000..6961ecdbaf --- /dev/null +++ b/test/DistEvents/DistDemoApp.Shared/IDistEventScenarioRunner.cs @@ -0,0 +1,8 @@ +using System.Threading.Tasks; + +namespace DistDemoApp; + +public interface IDistEventScenarioRunner +{ + Task RunAsync(DistEventScenarioProfile profile); +} diff --git a/test/DistEvents/DistDemoApp.Shared/ProviderScenarioEvent.cs b/test/DistEvents/DistDemoApp.Shared/ProviderScenarioEvent.cs new file mode 100644 index 0000000000..08dd2102c2 --- /dev/null +++ b/test/DistEvents/DistDemoApp.Shared/ProviderScenarioEvent.cs @@ -0,0 +1,9 @@ +using Volo.Abp.EventBus; + +namespace DistDemoApp; + +[EventName("DistDemoApp.ProviderScenarioEvent")] +public class ProviderScenarioEvent +{ + public int Value { get; set; } +} diff --git a/test/DistEvents/DistEventsDemo.slnx b/test/DistEvents/DistEventsDemo.slnx index 595e2e5d3e..d31f2b3262 100644 --- a/test/DistEvents/DistEventsDemo.slnx +++ b/test/DistEvents/DistEventsDemo.slnx @@ -1,5 +1,9 @@ + + + + diff --git a/test/DistEvents/dapr/components/pubsub.yaml b/test/DistEvents/dapr/components/pubsub.yaml new file mode 100644 index 0000000000..669a6149b5 --- /dev/null +++ b/test/DistEvents/dapr/components/pubsub.yaml @@ -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: "" diff --git a/test/DistEvents/docker-compose.yml b/test/DistEvents/docker-compose.yml new file mode 100644 index 0000000000..916b6542f7 --- /dev/null +++ b/test/DistEvents/docker-compose.yml @@ -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" diff --git a/test/DistEvents/servicebus-emulator/Config.json b/test/DistEvents/servicebus-emulator/Config.json new file mode 100644 index 0000000000..39908ff27d --- /dev/null +++ b/test/DistEvents/servicebus-emulator/Config.json @@ -0,0 +1,22 @@ +{ + "UserConfig": { + "Namespaces": [ + { + "Name": "sbemulatorns", + "Topics": [ + { + "Name": "DistDemoAzureTopic", + "Subscriptions": [ + { + "Name": "DistDemoAzureSubscriber" + } + ] + } + ] + } + ], + "Logging": { + "Type": "File" + } + } +}